updated to v1.1.0; resolves #35

This commit is contained in:
Steven Hildreth 2019-11-28 11:38:26 -06:00
parent 15c0c04504
commit 6fc03268b6
142 changed files with 3063 additions and 1501 deletions

View file

@ -25,7 +25,6 @@
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.0.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.4.0" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1">
<PrivateAssets>all</PrivateAssets>

View file

@ -18,7 +18,7 @@ namespace Roadie.Library.Tests
{
var sw = Stopwatch.StartNew();
var token = ServiceBase.TrackPlayToken(new ApplicationUser
var token = ServiceBase.TrackPlayToken(new User
{
Id = 1,
CreatedDate = DateTime.UtcNow

View file

@ -1,12 +1,10 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Roadie.Library.Configuration
namespace Roadie.Library.Configuration
{
public enum DbContexts : short
{
MySQL = 1,
File = 2
Unknown = 0,
SQLite = 1,
File = 2,
MySQL = 3
}
}
}

View file

@ -19,7 +19,7 @@ namespace Roadie.Library.Configuration
{
DatabaseFormat = FileDatabaseFormat.BSON;
DatabaseName = "roadie";
DatabaseFolder = @"M:\db";
DatabaseFolder = "data/db";
}
}
}

View file

@ -19,8 +19,7 @@ namespace Roadie.Library.Configuration
var keySetting = ApiKeys.FirstOrDefault(x => x.ApiName == "DiscogsConsumerKey");
if (keySetting != null)
return keySetting.Key;
Trace.WriteLine(
"Unable To Find Api Key with Key Name of 'DiscogsConsumerKey', Discogs Integration Disabled");
Trace.WriteLine("Unable To Find Api Key with Key Name of 'DiscogsConsumerKey', Discogs Integration Disabled", "Warning");
return null;
}
}
@ -32,8 +31,7 @@ namespace Roadie.Library.Configuration
var keySetting = ApiKeys.FirstOrDefault(x => x.ApiName == "DiscogsConsumerKey");
if (keySetting != null)
return keySetting.KeySecret;
Trace.WriteLine(
"Unable To Find Api Key with Key Name of 'DiscogsConsumerKey', Discogs Integration Disabled");
Trace.WriteLine("Unable To Find Api Key with Key Name of 'DiscogsConsumerKey', Discogs Integration Disabled", "Warning");
return null;
}
}
@ -77,7 +75,7 @@ namespace Roadie.Library.Configuration
var keySetting = ApiKeys.FirstOrDefault(x => x.ApiName == "LastFMApiKey");
if (keySetting != null)
return keySetting.Key;
Trace.WriteLine("Unable To Find Api Key with Key Name of 'LastFMApiKey', Last FM Integration Disabled");
Trace.WriteLine("Unable To Find Api Key with Key Name of 'LastFMApiKey', Last FM Integration Disabled", "Warning");
return null;
}
}
@ -89,7 +87,7 @@ namespace Roadie.Library.Configuration
var keySetting = ApiKeys.FirstOrDefault(x => x.ApiName == "LastFMApiKey");
if (keySetting != null)
return keySetting.KeySecret;
Trace.WriteLine("Unable To Find Api Key with Key Name of 'LastFMApiKey', Last FM Integration Disabled");
Trace.WriteLine("Unable To Find Api Key with Key Name of 'LastFMApiKey', Last FM Integration Disabled", "Warning");
return null;
}
}

View file

@ -9,7 +9,7 @@ namespace Roadie.Library.Configuration
{
public static string RoadieImageFolder = "__roadie_images";
public DbContexts DbContextToUse { get; set; }
public DbContexts DbContextToUse { get; set; } = DbContexts.SQLite;
/// <summary>
/// If the artist name is found in the values then use the key.
@ -81,7 +81,6 @@ namespace Roadie.Library.Configuration
}
public ImageSize LargeImageSize { get; set; }
public string LibraryFolder { get; set; }
public string ListenAddress { get; set; }
@ -151,7 +150,7 @@ namespace Roadie.Library.Configuration
public RoadieSettings()
{
DbContextToUse = DbContexts.MySQL;
DbContextToUse = DbContexts.SQLite;
ArtistNameReplace = new Dictionary<string, IEnumerable<string>>
{
{ "AC/DC", new List<string>{ "AC; DC", "AC;DC", "AC/ DC", "AC DC" }},
@ -159,10 +158,10 @@ namespace Roadie.Library.Configuration
};
DefaultTimeZone = "US / Central";
DontDoMetaDataProvidersSearchArtists = new List<string> { "Various Artists", "Sound Tracks" };
FileExtensionsToDelete = new List<string> { ".accurip", ".bmp", ".cue", ".dat", ".db", ".exe", ".gif", ".htm", ".html", ".ini", ".log", ".jpg", ".jpeg", ".par", ".par2", ".pdf", ".png", ".md5", ".mht", ".mpg", ".m3u", ".nfo", ".nzb", ".pls", ".sfv", ".srr", ".txt", ".url" };
InboundFolder = "M:/inbound";
FileExtensionsToDelete = new List<string> { ".accurip", ".cue", ".dat", ".db", ".exe", ".htm", ".html", ".ini", ".log", ".par", ".par2", ".pdf", ".md5", ".mht", ".mpg", ".m3u", ".nfo", ".nzb", ".pls", ".sfv", ".srr", ".txt", ".url" };
InboundFolder = "data/inbound";
LargeImageSize = new ImageSize { Width = 500, Height = 500 };
LibraryFolder = "M:/library";
LibraryFolder = "data/library";
MaximumImageSize = new ImageSize { Width = 2048, Height = 2048 };
MediumImageSize = new ImageSize { Width = 320, Height = 320 };
RecordNoResultSearches = true;
@ -174,7 +173,6 @@ namespace Roadie.Library.Configuration
SmtpFromAddress = "noreply@roadie.rocks";
SmtpPort = 587;
SmtpUsername = "roadie";
SmtpHost = "smtp.roadie.rocks";
SmtpUseSSl = true;
Inspector = new Inspector();

View file

@ -1,5 +1,4 @@
using Roadie.Library.Enums;
using Roadie.Library.Imaging;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
@ -10,12 +9,18 @@ namespace Roadie.Library.Data
[Table("artist")]
public partial class Artist : BeginAndEndNamedEntityBase
{
[Column("amgId")] [MaxLength(100)] public string AmgId { get; set; }
[Column("amgId")]
[MaxLength(100)]
public string AmgId { get; set; }
[Column("artistType", TypeName = "enum")]
public string ArtistType { get; set; }
[InverseProperty("Artist")] public ICollection<ArtistAssociation> AssociatedArtists { get; set; }
/// <summary>
/// Artists who this Artist is Associated To
/// </summary>
[InverseProperty("Artist")]
public virtual ICollection<ArtistAssociation> AssociatedArtists { get; set; }
[Column("bandStatus", TypeName = "enum")]
public BandStatus? BandStatus { get; set; }
@ -27,46 +32,77 @@ namespace Roadie.Library.Data
[Column("birthDate", TypeName = "date")]
public DateTime? BirthDate { get; set; }
public ICollection<Comment> Comments { get; set; }
[InverseProperty("Artist")]
public virtual ICollection<Comment> Comments { get; set; }
[Column("discogsId")] [MaxLength(50)] public string DiscogsId { get; set; }
[InverseProperty("Artist")]
public virtual ICollection<Credit> Credits { get; set; }
public ICollection<ArtistGenre> Genres { get; set; }
[Column("discogsId")]
[MaxLength(50)]
public string DiscogsId { get; set; }
[InverseProperty("Artist")]
public virtual ICollection<ArtistGenre> Genres { get; set; }
/// <summary>
/// Where the Artist is the Artist on the Track not on an Artist Release
/// </summary>
[InverseProperty("TrackArtist")]
public virtual ICollection<Track> Tracks { get; set; }
[Column("isniList", TypeName = "text")]
[MaxLength(65535)]
public string ISNI { get; set; }
[Column("iTunesId")] [MaxLength(100)] public string ITunesId { get; set; }
[Column("iTunesId")]
[MaxLength(100)]
public string ITunesId { get; set; }
[Column("lastPlayed")] public DateTime? LastPlayed { get; set; }
[Column("lastPlayed")]
public DateTime? LastPlayed { get; set; }
[Column("musicBrainzId")]
[MaxLength(100)]
public string MusicBrainzId { get; set; }
[Column("playedCount")] public int? PlayedCount { get; set; }
[Column("playedCount")]
public int? PlayedCount { get; set; }
[Column("profile", TypeName = "text")]
[MaxLength(65535)]
public string Profile { get; set; }
[Column("rank")] public decimal? Rank { get; set; }
[Column("rank")]
public decimal? Rank { get; set; }
[Column("rating")] public short? Rating { get; set; }
[Column("rating")]
public short? Rating { get; set; }
[Column("realName")] [MaxLength(500)] public string RealName { get; set; }
[Column("realName")]
[MaxLength(500)]
public string RealName { get; set; }
[Column("releaseCount")] public int? ReleaseCount { get; set; }
[Column("releaseCount")]
public int? ReleaseCount { get; set; }
//public List<Release> Releases { get; set; }
public ICollection<Release> Releases { get; set; }
public virtual ICollection<Release> Releases { get; set; }
[InverseProperty("Artist")] public ICollection<ArtistSimilar> SimilarArtists { get; set; }
/// <summary>
/// Artists who are similiar to this Artist
/// </summary>
[InverseProperty("Artist")]
public virtual ICollection<ArtistSimilar> SimilarArtists { get; set; }
[Column("spotifyId")] [MaxLength(100)] public string SpotifyId { get; set; }
[Column("spotifyId")]
[MaxLength(100)]
public string SpotifyId { get; set; }
[Column("trackCount")] public int? TrackCount { get; set; }
[Column("trackCount")]
public int? TrackCount { get; set; }
[InverseProperty("Artist")]
public virtual ICollection<UserArtist> UserArtists { get; set; }
public Artist()
{
@ -75,6 +111,8 @@ namespace Roadie.Library.Data
AssociatedArtists = new HashSet<ArtistAssociation>();
SimilarArtists = new HashSet<ArtistSimilar>();
Comments = new HashSet<Comment>();
UserArtists = new HashSet<UserArtist>();
Rating = 0;
Status = Statuses.Ok;
}

View file

@ -6,15 +6,20 @@ namespace Roadie.Library.Data
[Table("artistAssociation")]
public class ArtistAssociation
{
//[ForeignKey("artistId")]
public Artist Artist { get; set; }
[ForeignKey(nameof(ArtistId))]
[InverseProperty("AssociatedArtists")]
public virtual Artist Artist { get; set; }
[Column("artistId")] [Required] public int ArtistId { get; set; }
[Column("artistId")]
[Required]
public int ArtistId { get; set; }
//[ForeignKey("associatedArtistId")]
public Artist AssociatedArtist { get; set; }
[ForeignKey(nameof(AssociatedArtistId))]
public virtual Artist AssociatedArtist { get; set; }
[Column("associatedArtistId")] public int AssociatedArtistId { get; set; }
[Column("associatedArtistId")]
[Required]
public int AssociatedArtistId { get; set; }
[Key]
[Column("id")]

View file

@ -6,17 +6,25 @@ namespace Roadie.Library.Data
[Table("artistGenreTable")]
public class ArtistGenre
{
public Artist Artist { get; set; }
[Column("artistId")] [Required] public int ArtistId { get; set; }
public Genre Genre { get; set; }
[Column("genreId")] [Required] public int? GenreId { get; set; }
[Column("id")]
[Key]
[Column("id")]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Column("artistId")]
[Required]
public int ArtistId { get; set; }
[Column("genreId")]
[Required]
public int GenreId { get; set; }
[ForeignKey(nameof(ArtistId))]
[InverseProperty("Genres")]
public virtual Artist Artist { get; set; }
[ForeignKey(nameof(GenreId))]
[InverseProperty("Artists")]
public virtual Genre Genre { get; set; }
}
}

View file

@ -3,8 +3,6 @@ using Roadie.Library.Utility;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Security.Cryptography;
namespace Roadie.Library.Data
{
@ -29,8 +27,6 @@ namespace Roadie.Library.Data
public bool IsValid => !string.IsNullOrEmpty(Name);
public string SortNameValue => string.IsNullOrEmpty(SortName) ? Name : SortName;
public string GroupBy => SortNameValue.Substring(0, 1).ToUpper();
public static string CacheRegionUrn(Guid Id)
@ -55,7 +51,7 @@ namespace Roadie.Library.Data
public override string ToString()
{
return $"Id [{ Id }], Status [{ Status }], Name [{ Name }], SortName [{ SortNameValue}], RoadieId [{ RoadieId}]";
return $"Id [{ Id }], Status [{ Status }], Name [{ Name }], SortName [{ SortName }], RoadieId [{ RoadieId}]";
}
}
}

View file

@ -6,19 +6,23 @@ namespace Roadie.Library.Data
[Table("artistSimilar")]
public class ArtistSimilar
{
//[ForeignKey("artistId")]
public Artist Artist { get; set; }
[ForeignKey(nameof(ArtistId))]
[InverseProperty("SimilarArtists")]
public virtual Artist Artist { get; set; }
[Column("artistId")] [Required] public int ArtistId { get; set; }
[Column("artistId")]
[Required]
public int ArtistId { get; set; }
[Key]
[Column("id")]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
//[ForeignKey("associatedArtistId")]
public Artist SimilarArtist { get; set; }
[ForeignKey(nameof(SimilarArtistId))]
public virtual Artist SimilarArtist { get; set; }
[Column("similarArtistId")] public int SimilarArtistId { get; set; }
[Column("similarArtistId")]
public int SimilarArtistId { get; set; }
}
}

View file

@ -8,6 +8,7 @@ namespace Roadie.Library.Data
[Column("beginDate", TypeName = "date")]
public DateTime? BeginDate { get; set; }
[Column("endDate", TypeName = "date")] public DateTime? EndDate { get; set; }
[Column("endDate", TypeName = "date")]
public DateTime? EndDate { get; set; }
}
}

View file

@ -5,8 +5,10 @@ namespace Roadie.Library.Data
{
public abstract class BeginAndEndNamedEntityBase : NamedEntityBase
{
[Column("beginDate")] public DateTime? BeginDate { get; set; }
[Column("beginDate")]
public DateTime? BeginDate { get; set; }
[Column("endDate")] public DateTime? EndDate { get; set; }
[Column("endDate")]
public DateTime? EndDate { get; set; }
}
}

View file

@ -8,16 +8,27 @@ namespace Roadie.Library.Data
[Table("bookmark")]
public partial class Bookmark : EntityBase
{
[Column("bookmarkTargetId")] public int BookmarkTargetId { get; set; }
[Column("bookmarkTargetId")]
public int BookmarkTargetId { get; set; }
// public short? Type { get; set; }
[Column("bookmarkType")] public BookmarkType? BookmarkType { get; set; }
[Column("bookmarkType")]
public BookmarkType? BookmarkType { get; set; }
[Column("Comment")] [MaxLength(4000)] public string Comment { get; set; }
[Column("position")] public int? Position { get; set; }
public ApplicationUser User { get; set; }
[Column("Comment")]
[MaxLength(4000)]
public string Comment { get; set; }
[Column("userId")] [Required] public int UserId { get; set; }
[Column("position")]
public int? Position { get; set; }
[ForeignKey(nameof(UserId))]
[InverseProperty("Bookmarks")]
public virtual User User { get; set; }
[Column("userId")]
[Required]
public int UserId { get; set; }
}
}

View file

@ -12,8 +12,12 @@ namespace Roadie.Library.Data
[MaxLength(5000)]
public string Message { get; set; }
public ApplicationUser User { get; set; }
[ForeignKey(nameof(UserId))]
[InverseProperty("ChatMessages")]
public virtual User User { get; set; }
[Column("userId")] [Required] public int UserId { get; set; }
[Column("userId")]
[Required]
public int UserId { get; set; }
}
}

View file

@ -1,4 +1,5 @@
using Roadie.Library.Enums;
using Roadie.Library.Identity;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
@ -11,17 +12,18 @@ namespace Roadie.Library.Data
[Column("collectionCount")]
public int CollectionCount { get; set; }
[Column("collectionType")]
[Column("collectionType")]
public CollectionType? CollectionType { get; set; }
public ICollection<Comment> Comments { get; set; }
[InverseProperty("Collection")]
public virtual ICollection<Comment> Comments { get; set; }
[Column("description")]
[MaxLength(4000)]
public string Description { get; set; }
[Column("edition")]
[MaxLength(200)]
[Column("edition")]
[MaxLength(200)]
public string Edition { get; set; }
[Column("listInCSV", TypeName = "text")]
@ -32,9 +34,17 @@ namespace Roadie.Library.Data
[MaxLength(200)]
public string ListInCSVFormat { get; set; }
[Column("maintainerId")]
[Column("maintainerId")]
public int MaintainerId { get; set; }
public ICollection<CollectionRelease> Releases { get; set; }
[ForeignKey(nameof(MaintainerId))]
[InverseProperty(nameof(User.Collections))]
public virtual User Maintainer { get; set; }
[InverseProperty("Collection")]
public virtual ICollection<CollectionRelease> Releases { get; set; }
[InverseProperty("Collection")]
public virtual ICollection<CollectionMissing> MissingReleases { get; set; }
}
}

View file

@ -6,18 +6,30 @@ namespace Roadie.Library.Data
[Table("collectionMissing")]
public class CollectionMissing
{
[Column("artist")] [MaxLength(1000)] public string Artist { get; set; }
[Column("artist")]
[MaxLength(1000)]
public string Artist { get; set; }
[Column("collectionId")] public int CollectionId { get; set; }
[Column("collectionId")]
public int CollectionId { get; set; }
[ForeignKey(nameof(CollectionId))]
[InverseProperty("MissingReleases")]
public virtual Collection Collection { get; set; }
[Column("id")]
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Column("isArtistFound")] public bool IsArtistFound { get; set; }
[Column("isArtistFound")]
public bool IsArtistFound { get; set; }
[Column("position")] public int Position { get; set; }
[Column("release")] [MaxLength(1000)] public string Release { get; set; }
[Column("position")]
public int Position { get; set; }
[Column("release")]
[MaxLength(1000)]
public string Release { get; set; }
}
}

View file

@ -98,7 +98,9 @@ namespace Roadie.Library.Data
public Collection()
{
Releases = new HashSet<CollectionRelease>();
MissingReleases = new HashSet<CollectionMissing>();
Comments = new HashSet<Comment>();
ListInCSVFormat = "Position,Release,Artist";
CollectionType = Enums.CollectionType.Rank;
}
@ -128,19 +130,21 @@ namespace Roadie.Library.Data
};
configuration.BadDataFound = context =>
{
Trace.WriteLine($"PositionArtistReleases: Bad data found on row '{context.RawRow}'");
Trace.WriteLine($"PositionArtistReleases: Bad data found on row '{context.RawRow}'", "Warning");
};
var csv = new CsvReader(sr, configuration);
while (csv.Read())
using (var csv = new CsvReader(sr, configuration))
{
index++;
rows.Add(new PositionArtistRelease
while (csv.Read())
{
Index = index,
Position = csv.GetField<int>(PositionColumn),
Artist = SafeParser.ToString(csv.GetField<string>(ArtistColumn)),
Release = SafeParser.ToString(csv.GetField<string>(ReleaseColumn))
});
index++;
rows.Add(new PositionArtistRelease
{
Index = index,
Position = csv.GetField<int>(PositionColumn),
Artist = SafeParser.ToString(csv.GetField<string>(ArtistColumn)),
Release = SafeParser.ToString(csv.GetField<string>(ReleaseColumn))
});
}
}
}
@ -156,30 +160,5 @@ namespace Roadie.Library.Data
}
}
[Serializable]
public class PositionArtistRelease
{
public string Artist { get; set; }
/// <summary>
/// This is the index (position in the list regardless of the position number)
/// </summary>
[JsonIgnore]
public int Index { get; set; }
/// <summary>
/// This is the position number for the list (can be a year "1984" can be a number "14")
/// </summary>
public int Position { get; set; }
public string Release { get; set; }
[JsonIgnore] public Statuses Status { get; set; }
[JsonProperty("Status")] public string StatusVerbose => Status.ToString();
public override string ToString()
{
return string.Format("Position [{0}], Artist [{1}], Release [{2}]", Position, Artist, Release);
}
}
}

View file

@ -6,14 +6,23 @@ namespace Roadie.Library.Data
[Table("collectionrelease")]
public class CollectionRelease : EntityBase
{
public Collection Collection { get; set; }
[ForeignKey(nameof(CollectionId))]
[InverseProperty("Releases")]
public virtual Collection Collection { get; set; }
[Column("collectionId")] [Required] public int CollectionId { get; set; }
[Column("collectionId")]
[Required]
public int CollectionId { get; set; }
[Column("listNumber")] public int ListNumber { get; set; }
[Column("listNumber")]
public int ListNumber { get; set; }
public Release Release { get; set; }
[ForeignKey(nameof(ReleaseId))]
[InverseProperty("Collections")]
public virtual Release Release { get; set; }
[Column("releaseId")] [Required] public int ReleaseId { get; set; }
[Column("releaseId")]
[Required]
public int ReleaseId { get; set; }
}
}

View file

@ -9,34 +9,76 @@ namespace Roadie.Library.Data
[Table("comment")]
public partial class Comment : EntityBase
{
[Column("artistId")] public int? ArtistId { get; set; }
[Column("artistId")]
public int? ArtistId { get; set; }
[ForeignKey(nameof(ArtistId))]
[InverseProperty("Comments")]
public virtual Artist Artist { get; set; }
[Column("comment")]
[MaxLength(25500)]
[Required]
public string Cmt { get; set; }
[Column("collectionId")] public int? CollectionId { get; set; }
[Column("collectionId")]
public int? CollectionId { get; set; }
[Column("genreId")] public int? GenreId { get; set; }
[ForeignKey(nameof(CollectionId))]
[InverseProperty("Comments")]
public virtual Collection Collection { get; set; }
[NotMapped] public new bool? IsLocked { get; set; }
[Column("genreId")]
public int? GenreId { get; set; }
[Column("labelId")] public int? LabelId { get; set; }
[ForeignKey(nameof(GenreId))]
[InverseProperty("Comments")]
public virtual Genre Genre { get; set; }
[Column("playlistId")] public int? PlaylistId { get; set; }
[NotMapped]
public new bool? IsLocked { get; set; }
public ICollection<CommentReaction> Reactions { get; set; }
[Column("labelId")]
public int? LabelId { get; set; }
[Column("releaseId")] public int? ReleaseId { get; set; }
[ForeignKey(nameof(LabelId))]
[InverseProperty("Comments")]
public virtual Label Label { get; set; }
[Column("replyToCommentId")] public int? ReplyToCommentId { get; set; }
[Column("playlistId")]
public int? PlaylistId { get; set; }
[Column("trackId")] public int? TrackId { get; set; }
[ForeignKey(nameof(PlaylistId))]
[InverseProperty("Comments")]
public virtual Playlist Playlist { get; set; }
public ApplicationUser User { get; set; }
[InverseProperty("Comment")]
public virtual ICollection<CommentReaction> Reactions { get; set; }
[Column("userId")] [Required] public int UserId { get; set; }
[Column("releaseId")]
public int? ReleaseId { get; set; }
[ForeignKey(nameof(ReleaseId))]
[InverseProperty("Comments")]
public virtual Release Release { get; set; }
[Column("replyToCommentId")]
public int? ReplyToCommentId { get; set; }
[Column("trackId")]
public int? TrackId { get; set; }
[ForeignKey(nameof(TrackId))]
[InverseProperty("Comments")]
public virtual Track Track { get; set; }
[ForeignKey(nameof(UserId))]
[InverseProperty("Comments")]
public virtual User User { get; set; }
[Column("userId")]
[Required]
public int UserId { get; set; }
public Comment()
{

View file

@ -10,14 +10,25 @@ namespace Roadie.Library.Data
{
public Comment Comment { get; set; }
[Column("commentId")] [Required] public int CommentId { get; set; }
[NotMapped] public new bool? IsLocked { get; set; }
[Column("reaction")] public string Reaction { get; set; }
[Column("commentId")]
[Required]
public int CommentId { get; set; }
[NotMapped]
public new bool? IsLocked { get; set; }
[Column("reaction")]
public string Reaction { get; set; }
[NotMapped]
public Enums.CommentReaction ReactionValue => SafeParser.ToEnum<Enums.CommentReaction>(Reaction ?? "Unknown");
public ApplicationUser User { get; set; }
[Column("userId")] [Required] public int UserId { get; set; }
[ForeignKey(nameof(UserId))]
[InverseProperty("CommentReactions")]
public virtual User User { get; set; }
[Column("userId")]
[Required]
public int UserId { get; set; }
}
}

View file

@ -1,9 +1,9 @@
using FileContextCore;
using Microsoft.EntityFrameworkCore;
using Pomelo.EntityFrameworkCore.MySql.Infrastructure;
using Roadie.Library.Configuration;
using Roadie.Library.Data.Context.Implementation;
using System;
using System.IO;
namespace Roadie.Library.Data.Context
{
@ -13,6 +13,12 @@ namespace Roadie.Library.Data.Context
{
switch (configuration.DbContextToUse)
{
case DbContexts.SQLite:
var sqlLiteOptionsBuilder = new DbContextOptionsBuilder<SQLiteRoadieDbContext>();
var databaseName = Path.Combine(configuration.FileDatabaseOptions.DatabaseFolder, $"{ configuration.FileDatabaseOptions.DatabaseName }.db");
sqlLiteOptionsBuilder.UseSqlite($"Filename={databaseName}");
return new SQLiteRoadieDbContext(sqlLiteOptionsBuilder.Options);
case DbContexts.File:
var fileOptionsBuilder = new DbContextOptionsBuilder<MySQLRoadieDbContext>();
fileOptionsBuilder.UseFileContextDatabase(configuration.FileDatabaseOptions.DatabaseFormat.ToString().ToLower(),
@ -20,17 +26,19 @@ namespace Roadie.Library.Data.Context
location: configuration.FileDatabaseOptions.DatabaseFolder);
return new FileRoadieDbContext(fileOptionsBuilder.Options);
default:
case DbContexts.MySQL:
var mysqlOptionsBuilder = new DbContextOptionsBuilder<MySQLRoadieDbContext>();
mysqlOptionsBuilder.UseMySql(configuration.ConnectionString, mySqlOptions =>
{
mySqlOptions.ServerVersion(new Version(5, 5), ServerType.MariaDb);
mySqlOptions.EnableRetryOnFailure(
10,
TimeSpan.FromSeconds(30),
null);
});
return new MySQLRoadieDbContext(mysqlOptionsBuilder.Options);
default:
throw new NotImplementedException("Unknown DbContext Type");
}
}
}

View file

@ -42,8 +42,8 @@ namespace Roadie.Library.Data.Context
DbSet<UserArtist> UserArtists { get; set; }
DbSet<UserQue> UserQues { get; set; }
DbSet<UserRelease> UserReleases { get; set; }
DbSet<ApplicationRole> UserRoles { get; set; }
DbSet<ApplicationUser> Users { get; set; }
DbSet<UserRole> UserRoles { get; set; }
DbSet<User> Users { get; set; }
DbSet<UserTrack> UserTracks { get; set; }
DbSet<InviteToken> InviteTokens { get; set; }

View file

@ -169,11 +169,11 @@ namespace Roadie.Library.Data.Context.Implementation
}
else
{
randomReleases = await(from r in Releases
join ur in UserReleases on r.Id equals ur.ReleaseId into urg
from ur in urg.DefaultIfEmpty()
where (ur == null || (ur.UserId == userId && ur.IsDisliked == false))
select r)
randomReleases = await (from r in Releases
join ur in UserReleases on r.Id equals ur.ReleaseId into urg
from ur in urg.DefaultIfEmpty()
where (ur == null || (ur.UserId == userId && ur.IsDisliked == false))
select r)
.OrderBy(x => Guid.NewGuid())
.Take(randomLimit)
.ToListAsync();

View file

@ -188,7 +188,7 @@ namespace Roadie.Library.Data.Context.Implementation
WHERE ut.userId = {1} AND ut.isFavorite = 1) AND {2} = 1) OR {2} = 0)
order BY RIGHT( HEX( (1<<24) * (1+RAND()) ), 6)
LIMIT 0, {0}";
var ids = await Releases.FromSqlRaw(sql, randomLimit, userId, doOnlyFavorites ? "1" : "0", doOnlyRated ? "1" : "0").Select(x => x.Id).ToListAsync();
var ids = await Tracks.FromSqlRaw(sql, randomLimit, userId, doOnlyFavorites ? "1" : "0", doOnlyRated ? "1" : "0").Select(x => x.Id).ToListAsync();
var dict = ids.Select((id, i) => new { key = i, value = id }).ToDictionary(x => x.key, x => x.value);
return new SortedDictionary<int, int>(dict);
}

View file

@ -0,0 +1,111 @@
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Roadie.Library.Data.Context.Implementation
{
/// <summary>
/// SQLite implementation of DbContext
/// </summary>
public sealed class SQLiteRoadieDbContext : LinqDbContextBase
{
private static bool _created = false;
public SQLiteRoadieDbContext(DbContextOptions options)
: base(options)
{
if (!_created)
{
_created = true;
Database.EnsureCreated();
}
}
public override async Task<SortedDictionary<int, int>> RandomArtistIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
{
// TODO Rating?
var sql = @"SELECT a.id
FROM artist a
WHERE(a.id NOT IN(select artistId FROM userartist where userId = {1} and isDisliked = 1))
OR(a.id IN (select artistId FROM userartist where userId = {1} and isFavorite = 1)
AND {2} = 1)
order by random()
LIMIT 0, {0}";
var ids = await Artists.FromSqlRaw(sql, randomLimit, userId, doOnlyFavorites ? "1" : "0").Select(x => x.Id).ToListAsync();
var dict = ids.Select((id, i) => new { key = i, value = id }).ToDictionary(x => x.key, x => x.value);
return new SortedDictionary<int, int>(dict);
}
public override async Task<SortedDictionary<int, int>> RandomGenreIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
{
var sql = @"SELECT g.id
FROM genre g
order by random()
LIMIT 0, {0}";
var ids = await Genres.FromSqlRaw(sql, randomLimit).Select(x => x.Id).ToListAsync();
var dict = ids.Select((id, i) => new { key = i, value = id }).ToDictionary(x => x.key, x => x.value);
return new SortedDictionary<int, int>(dict);
}
public override async Task<SortedDictionary<int, int>> RandomLabelIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
{
var sql = @"SELECT l.id
FROM label l
order by random()
LIMIT 0, {0}";
var ids = await Labels.FromSqlRaw(sql, randomLimit).Select(x => x.Id).ToListAsync();
var dict = ids.Select((id, i) => new { key = i, value = id }).ToDictionary(x => x.key, x => x.value);
return new SortedDictionary<int, int>(dict);
}
public override async Task<SortedDictionary<int, int>> RandomReleaseIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
{
// TODO Rating?
var sql = @"SELECT r.id
FROM release r
WHERE (r.id NOT IN (select releaseId FROM userrelease where userId = {1} and isDisliked = 1))
OR (r.id IN (select releaseId FROM userrelease where userId = {1} and isFavorite = 1)
AND {2} = 1)
order by random()
LIMIT 0, {0}";
var ids = await Releases.FromSqlRaw(sql, randomLimit, userId, doOnlyFavorites ? "1" : "0").Select(x => x.Id).ToListAsync();
var dict = ids.Select((id, i) => new { key = i, value = id }).ToDictionary(x => x.key, x => x.value);
return new SortedDictionary<int, int>(dict);
}
public override async Task<SortedDictionary<int, int>> RandomTrackIds(int userId, int randomLimit, bool doOnlyFavorites = false, bool doOnlyRated = false)
{
// When using the regular 'FromSqlRaw' with parameters SQLite returns no records.
var df = doOnlyFavorites ? "1" : "0";
var dr = doOnlyRated ? "1" : "0";
var sql = @$"SELECT t.id
FROM track t
WHERE ((t.rating > 0 AND {dr} = 1) OR {dr} = 0)
AND ((t.id NOT IN (select tt.id
FROM track tt
JOIN releasemedia rm on (tt.releaseMediaId = rm.id)
JOIN userartist ua on (rm.id = ua.artistId)
WHERE ua.userId = {userId} AND ua.isDisliked = 1))
AND (t.id NOT IN (select tt.id
FROM track tt
JOIN releasemedia rm on (tt.releaseMediaId = rm.id)
JOIN userrelease ur on (rm.releaseId = ur.releaseId)
WHERE ur.userId = {userId} AND ur.isDisliked = 1))
AND (t.id NOT IN (select tt.id
FROM track tt
JOIN usertrack ut on (tt.id = ut.trackId)
WHERE ut.userId = {userId} AND ut.isDisliked = 1)))
AND ((t.id IN (select tt.id
FROM track tt
JOIN usertrack ut on (tt.id = ut.trackId)
WHERE ut.userId = {userId} AND ut.isFavorite = 1) AND {df} = 1) OR {df} = 0)
order by random()
LIMIT 0, {randomLimit}";
var ids = await Tracks.FromSqlRaw(sql, randomLimit).Select(x => x.Id).ToListAsync();
var dict = ids.Select((id, i) => new { key = i, value = id }).ToDictionary(x => x.key, x => x.value);
return new SortedDictionary<int, int>(dict);
}
}
}

View file

@ -65,9 +65,9 @@ namespace Roadie.Library.Data.Context
public DbSet<UserRelease> UserReleases { get; set; }
public DbSet<ApplicationRole> UserRoles { get; set; }
public DbSet<UserRole> UserRoles { get; set; }
public DbSet<ApplicationUser> Users { get; set; }
public DbSet<User> Users { get; set; }
public DbSet<UserTrack> UserTracks { get; set; }
public DbSet<InviteToken> InviteTokens { get; set; }
@ -79,142 +79,737 @@ namespace Roadie.Library.Data.Context
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
// base.OnModelCreating(builder);
//builder
// .Entity<ScanHistory>()
// .Property(e => e.Status)
// .HasConversion(
// v => v.ToString(),
// v => string.IsNullOrEmpty(v) ? Statuses.Ok : (Statuses)Enum.Parse(typeof(Statuses), v))
// .HasDefaultValue(Statuses.Ok);
builder.Entity<Artist>(entity =>
{
entity
.Property(e => e.BandStatus)
.HasConversion(
v => v.ToString(),
v => string.IsNullOrEmpty(v) ? BandStatus.Unknown : (BandStatus)Enum.Parse(typeof(BandStatus), v))
.HasDefaultValue(BandStatus.Unknown);
//builder
// .Entity<Artist>()
// .Property(e => e.Status)
// .HasConversion(
// v => v.ToString(),
// v => string.IsNullOrEmpty(v) ? Statuses.Incomplete : (Statuses)Enum.Parse(typeof(Statuses), v))
// .HasDefaultValue(Statuses.Incomplete);
entity.HasIndex(e => e.Name)
.HasName("ix_artist_name")
.IsUnique();
builder
.Entity<Release>()
.Property(e => e.ReleaseType)
.HasConversion(
v => v.ToString(),
v => string.IsNullOrEmpty(v)
? ReleaseType.Unknown
: (ReleaseType)Enum.Parse(typeof(ReleaseType), v))
.HasDefaultValue(ReleaseType.Release);
entity.HasIndex(e => e.RoadieId)
.HasName("ix_artist_roadieId");
builder
.Entity<Release>()
.Property(e => e.LibraryStatus)
.HasConversion(
v => v.ToString(),
v => string.IsNullOrEmpty(v)
? LibraryStatus.Incomplete
: (LibraryStatus)Enum.Parse(typeof(LibraryStatus), v))
.HasDefaultValue(LibraryStatus.Incomplete);
entity.HasIndex(e => e.SortName)
.HasName("ix_artist_sortname")
.IsUnique();
});
builder
.Entity<Collection>()
.Property(e => e.CollectionType)
.HasConversion(
v => v.ToString(),
v => string.IsNullOrEmpty(v)
? CollectionType.Unknown
: (CollectionType)Enum.Parse(typeof(CollectionType), v))
.HasDefaultValue(CollectionType.Unknown);
builder.Entity<ArtistAssociation>(entity =>
{
entity.HasIndex(e => e.AssociatedArtistId)
.HasName("ix_associatedArtistId");
builder
.Entity<Artist>()
.Property(e => e.BandStatus)
.HasConversion(
v => v.ToString(),
v => string.IsNullOrEmpty(v) ? BandStatus.Unknown : (BandStatus)Enum.Parse(typeof(BandStatus), v))
.HasDefaultValue(BandStatus.Unknown);
entity.HasIndex(e => new { e.ArtistId, e.AssociatedArtistId })
.HasName("ix__artistAssociation");
//builder
// .Entity<Bookmark>()
// .Property(e => e.BookmarkType)
// .HasConversion(
// v => v.ToString(),
// v => string.IsNullOrEmpty(v) ? BookmarkType.Unknown : (BookmarkType)Enum.Parse(typeof(BookmarkType), v))
// .HasDefaultValue(BookmarkType.Unknown);
entity.HasOne(d => d.Artist)
.WithMany(p => p.AssociatedArtists)
.HasForeignKey(d => d.ArtistId)
.OnDelete(DeleteBehavior.Cascade)
.HasConstraintName("artistAssociation_ibfk_1");
});
builder.Entity<Release>()
.HasOne(d => d.Artist)
.WithMany(p => p.Releases)
.HasForeignKey(d => d.ArtistId)
.OnDelete(DeleteBehavior.Cascade)
.HasConstraintName("release_ibfk_1");
builder.Entity<ArtistGenre>(entity =>
{
entity.HasIndex(e => e.ArtistId)
.HasName("ix_artistGenreTable_artistId");
builder.Entity<ReleaseLabel>()
.HasOne(rl => rl.Release)
.WithMany(r => r.Labels)
.HasForeignKey(rl => rl.ReleaseId);
entity.HasIndex(e => e.GenreId)
.HasName("ix_artistGenre_genreId");
builder.Entity<ReleaseLabel>()
.HasOne(rl => rl.Label)
.WithMany(l => l.ReleaseLabels)
.HasForeignKey(rl => rl.LabelId);
entity.HasIndex(e => new { e.ArtistId, e.GenreId })
.HasName("ix__artistGenreAssociation");
builder.Entity<ReleaseMedia>()
.HasMany(rm => rm.Tracks)
.WithOne(t => t.ReleaseMedia)
.HasForeignKey(rm => rm.ReleaseMediaId);
entity.HasOne(d => d.Artist)
.WithMany(p => p.Genres)
.HasForeignKey(d => d.ArtistId)
.OnDelete(DeleteBehavior.Cascade)
.HasConstraintName("artistGenreTable_ibfk_1");
builder.Entity<ReleaseMedia>()
.HasOne(rm => rm.Release)
.WithMany(r => r.Medias)
.HasForeignKey(r => r.ReleaseId);
entity.HasOne(d => d.Genre)
.WithMany(p => p.Artists)
.HasForeignKey(d => d.GenreId)
.OnDelete(DeleteBehavior.Cascade)
.HasConstraintName("artistGenreTable_ibfk_2");
});
builder.Entity<ReleaseGenre>()
.HasKey(rg => new { rg.ReleaseId, rg.GenreId });
builder.Entity<ArtistSimilar>(entity =>
{
entity.HasIndex(e => e.SimilarArtistId)
.HasName("ix_similarArtistId");
builder.Entity<ReleaseGenre>()
.HasOne(rg => rg.Release)
.WithMany(r => r.Genres)
.HasForeignKey(rg => rg.ReleaseId);
entity.HasIndex(e => new { e.ArtistId, e.SimilarArtistId })
.HasName("ix_artistSimilar");
builder.Entity<ReleaseGenre>()
.HasOne(rg => rg.Genre)
.WithMany(g => g.Releases)
.HasForeignKey(rg => rg.GenreId);
entity.HasOne(d => d.Artist)
.WithMany(p => p.SimilarArtists)
.HasForeignKey(d => d.ArtistId)
.HasConstraintName("artistSimilar_ibfk_1");
});
builder.Entity<ArtistGenre>()
.HasKey(rg => new { rg.ArtistId, rg.GenreId });
builder.Entity<Bookmark>(entity =>
{
entity.HasIndex(e => e.RoadieId)
.HasName("ix_bookmark_roadieId");
builder.Entity<ArtistGenre>()
.HasOne(rg => rg.Artist)
.WithMany(r => r.Genres)
.HasForeignKey(rg => rg.ArtistId);
entity.HasIndex(e => e.UserId)
.HasName("ix_bookmark_userId");
builder.Entity<ArtistGenre>()
.HasOne(rg => rg.Genre)
.WithMany(g => g.Artists)
.HasForeignKey(rg => rg.GenreId);
entity.HasIndex(e => new { e.BookmarkType, e.BookmarkTargetId, e.UserId })
.HasName("ix_bookmark_bookmarkType")
.IsUnique();
builder.Entity<CollectionRelease>()
.HasOne(cr => cr.Release)
.WithMany(r => r.Collections)
.HasForeignKey(cr => cr.ReleaseId);
entity.HasOne(d => d.User)
.WithMany(p => p.Bookmarks)
.HasForeignKey(d => d.UserId)
.OnDelete(DeleteBehavior.Cascade)
.HasConstraintName("bookmark_ibfk_1");
});
builder.Entity<CollectionRelease>()
.HasOne(cr => cr.Collection)
.WithMany(c => c.Releases)
.HasForeignKey(cr => cr.CollectionId);
builder.Entity<ChatMessage>(entity =>
{
entity.HasIndex(e => e.UserId)
.HasName("ix__chatMessage_user");
builder.Entity<Bookmark>()
.HasOne(b => b.User)
.WithMany(u => u.Bookmarks)
.HasForeignKey(b => b.UserId);
entity.HasOne(d => d.User)
.WithMany(p => p.ChatMessages)
.HasForeignKey(d => d.UserId)
.HasConstraintName("chatMessage_ibfk_1");
});
//builder.Entity<Track>()
// .HasOne(t => t.TrackArtist)
// .WithMany(a => a.Tracks)
// .HasForeignKey(t => t.ArtistId);
builder.Entity<Collection>(entity =>
{
entity
.Property(e => e.CollectionType)
.HasConversion(
v => v.ToString(),
v => string.IsNullOrEmpty(v)
? CollectionType.Unknown
: (CollectionType)Enum.Parse(typeof(CollectionType), v))
.HasDefaultValue(CollectionType.Unknown);
entity.HasIndex(e => e.MaintainerId)
.HasName("ix_collection_maintainerId");
entity.HasIndex(e => e.Name)
.HasName("ix_collection_name")
.IsUnique();
entity.HasIndex(e => e.RoadieId)
.HasName("ix_collection_roadieId");
entity.HasOne(d => d.Maintainer)
.WithMany(p => p.Collections)
.HasForeignKey(d => d.MaintainerId)
.OnDelete(DeleteBehavior.SetNull)
.HasConstraintName("collection_ibfk_1");
});
builder.Entity<CollectionMissing>(entity =>
{
entity.HasIndex(e => e.CollectionId)
.HasName("ix_collection_collectionId");
entity.HasOne(d => d.Collection)
.WithMany(p => p.MissingReleases)
.HasForeignKey(d => d.CollectionId)
.OnDelete(DeleteBehavior.Cascade)
.HasConstraintName("collection_missing_ibfk_1");
});
builder.Entity<CollectionRelease>(entity =>
{
entity.HasIndex(e => e.ReleaseId)
.HasName("ix_collectionrelease_releaseId");
entity.HasIndex(e => e.RoadieId)
.HasName("ix_collectionrelease_roadieId");
entity.HasIndex(e => new { e.CollectionId, e.ReleaseId })
.HasName("ix__collection_release");
entity.HasOne(d => d.Collection)
.WithMany(p => p.Releases)
.HasForeignKey(d => d.CollectionId)
.OnDelete(DeleteBehavior.Cascade)
.HasConstraintName("collectionrelease_ibfk_2");
entity.HasOne(d => d.Release)
.WithMany(p => p.Collections)
.HasForeignKey(d => d.ReleaseId)
.OnDelete(DeleteBehavior.Cascade)
.HasConstraintName("collectionrelease_ibfk_1");
});
builder.Entity<Comment>(entity =>
{
entity.HasIndex(e => e.ArtistId)
.HasName("ix_commentartist_ibfk_1");
entity.HasIndex(e => e.CollectionId)
.HasName("ix_commentcollection_ibfk_1");
entity.HasIndex(e => e.GenreId)
.HasName("ix_commentgenre_ibfk_1");
entity.HasIndex(e => e.LabelId)
.HasName("ix_commentlabel_ibfk_1");
entity.HasIndex(e => e.PlaylistId)
.HasName("ix_commentplaylist_ibfk_1");
entity.HasIndex(e => e.ReleaseId)
.HasName("ix_commentrelease_ibfk_1");
entity.HasIndex(e => e.RoadieId)
.HasName("ix_comment_roadieId");
entity.HasIndex(e => e.TrackId)
.HasName("ix_commenttrack_ibfk_1");
entity.HasIndex(e => e.UserId)
.HasName("ix_commentuser_ibfk_1");
entity.HasOne(d => d.Artist)
.WithMany(p => p.Comments)
.HasForeignKey(d => d.ArtistId)
.OnDelete(DeleteBehavior.Cascade)
.HasConstraintName("commentartist_ibfk_1");
entity.HasOne(d => d.Collection)
.WithMany(p => p.Comments)
.HasForeignKey(d => d.CollectionId)
.OnDelete(DeleteBehavior.Cascade)
.HasConstraintName("commentcollection_ibfk_1");
entity.HasOne(d => d.Genre)
.WithMany(p => p.Comments)
.HasForeignKey(d => d.GenreId)
.OnDelete(DeleteBehavior.Cascade)
.HasConstraintName("commentgenre_ibfk_1");
entity.HasOne(d => d.Label)
.WithMany(p => p.Comments)
.HasForeignKey(d => d.LabelId)
.OnDelete(DeleteBehavior.Cascade)
.HasConstraintName("commentlabel_ibfk_1");
entity.HasOne(d => d.Playlist)
.WithMany(p => p.Comments)
.HasForeignKey(d => d.PlaylistId)
.OnDelete(DeleteBehavior.Cascade)
.HasConstraintName("commentplaylist_ibfk_1");
entity.HasOne(d => d.Release)
.WithMany(p => p.Comments)
.HasForeignKey(d => d.ReleaseId)
.OnDelete(DeleteBehavior.Cascade)
.HasConstraintName("commentrelease_ibfk_1");
entity.HasOne(d => d.Track)
.WithMany(p => p.Comments)
.HasForeignKey(d => d.TrackId)
.OnDelete(DeleteBehavior.Cascade)
.HasConstraintName("commenttrack_ibfk_1");
entity.HasOne(d => d.User)
.WithMany(p => p.Comments)
.HasForeignKey(d => d.UserId)
.HasConstraintName("commentuser_ibfk_1");
});
builder.Entity<CommentReaction>(entity =>
{
entity.HasIndex(e => e.CommentId)
.HasName("ix_commentReactioncomment_ibfk_1");
entity.HasIndex(e => e.RoadieId)
.HasName("ix_commentReaction_roadieId");
entity.HasIndex(e => e.UserId)
.HasName("ix_commentReactionuser_ibfk_1");
entity.HasIndex(e => new { e.UserId, e.CommentId })
.HasName("ix_commentReaction_userId")
.IsUnique();
entity.HasOne(d => d.Comment)
.WithMany(p => p.Reactions)
.HasForeignKey(d => d.CommentId)
.HasConstraintName("commentReactioncomment_ibfk_1");
entity.HasOne(d => d.User)
.WithMany(p => p.CommentReactions)
.HasForeignKey(d => d.UserId)
.HasConstraintName("commentReactionuser_ibfk_1");
});
builder.Entity<Credit>(entity =>
{
entity.HasIndex(e => e.ArtistId)
.HasName("ix_credit_artist_ibfk_1");
entity.HasIndex(e => e.CreditCategoryId)
.HasName("ix_credit_category_ibfk_1");
entity.HasIndex(e => e.RoadieId)
.HasName("ix_credit_roadieId");
entity.HasIndex(e => new { e.ReleaseId, e.Id })
.HasName("ix_creditCreditandRelease");
entity.HasIndex(e => new { e.TrackId, e.Id })
.HasName("ix_creditCreditandTrack");
entity.HasOne(d => d.Artist)
.WithMany(p => p.Credits)
.HasForeignKey(d => d.ArtistId)
.OnDelete(DeleteBehavior.Cascade)
.HasConstraintName("credit_artist_ibfk_1");
entity.HasOne(d => d.CreditCategory)
.WithMany(p => p.Credits)
.HasForeignKey(d => d.CreditCategoryId)
.HasConstraintName("credit_category_ibfk_1");
entity.HasOne(d => d.Release)
.WithMany(p => p.Credits)
.HasForeignKey(d => d.ReleaseId)
.OnDelete(DeleteBehavior.Cascade)
.HasConstraintName("credit_release_ibfk_1");
entity.HasOne(d => d.Track)
.WithMany(p => p.Credits)
.HasForeignKey(d => d.TrackId)
.OnDelete(DeleteBehavior.Cascade)
.HasConstraintName("credit_track_ibfk_1");
});
builder.Entity<CreditCategory>(entity =>
{
entity.HasIndex(e => e.RoadieId)
.HasName("ix_creditCategory_roadieId");
});
builder.Entity<Genre>(entity =>
{
entity.HasIndex(e => e.Name)
.HasName("ix_genre_name")
.IsUnique();
entity.HasIndex(e => e.NormalizedName)
.HasName("ix_genre_normalizedName");
entity.HasIndex(e => e.RoadieId)
.HasName("ix_genre_roadieId");
});
builder.Entity<InviteToken>(entity =>
{
entity.HasIndex(e => e.CreatedByUserId)
.HasName("inviteToken_fk_1");
entity.HasIndex(e => e.RoadieId)
.HasName("ix_inviteToken_roadieId");
entity.HasOne(d => d.CreatedByUser)
.WithMany(p => p.InviteTokens)
.HasForeignKey(d => d.CreatedByUserId)
.HasConstraintName("inviteToken_fk_1");
});
builder.Entity<Label>(entity =>
{
entity.HasIndex(e => e.Name)
.HasName("ix_label_name")
.IsUnique();
entity.HasIndex(e => e.RoadieId)
.HasName("ix_label_roadieId");
});
builder.Entity<Playlist>(entity =>
{
entity.HasIndex(e => e.RoadieId)
.HasName("ix_playlist_roadieId");
entity.HasIndex(e => e.UserId)
.HasName("ix_playlist_userId");
entity.HasIndex(e => new { e.Name, e.UserId })
.HasName("ix_playlist_name")
.IsUnique();
entity.HasOne(d => d.User)
.WithMany(p => p.Playlists)
.HasForeignKey(d => d.UserId)
.OnDelete(DeleteBehavior.Cascade)
.HasConstraintName("playlist_ibfk_1");
});
builder.Entity<PlaylistTrack>(entity =>
{
entity.HasIndex(e => e.PlayListId)
.HasName("ix_playListId");
entity.HasIndex(e => e.RoadieId)
.HasName("ix_playlisttrack_roadieId");
entity.HasIndex(e => e.TrackId)
.HasName("trackId");
entity.HasOne(d => d.Playlist)
.WithMany(p => p.Tracks)
.HasForeignKey(d => d.PlayListId)
.OnDelete(DeleteBehavior.Cascade)
.HasConstraintName("playlisttrack_ibfk_2");
entity.HasOne(d => d.Track)
.WithMany(p => p.Playlists)
.HasForeignKey(d => d.TrackId)
.OnDelete(DeleteBehavior.Cascade)
.HasConstraintName("playlisttrack_ibfk_1");
});
builder.Entity<Release>(entity =>
{
entity
.Property(e => e.ReleaseType)
.HasConversion(
v => v.ToString(),
v => string.IsNullOrEmpty(v)
? ReleaseType.Unknown
: (ReleaseType)Enum.Parse(typeof(ReleaseType), v))
.HasDefaultValue(ReleaseType.Release);
entity
.Property(e => e.LibraryStatus)
.HasConversion(
v => v.ToString(),
v => string.IsNullOrEmpty(v)
? LibraryStatus.Incomplete
: (LibraryStatus)Enum.Parse(typeof(LibraryStatus), v))
.HasDefaultValue(LibraryStatus.Incomplete);
entity.HasIndex(e => e.RoadieId)
.HasName("ix_release_roadieId");
entity.HasIndex(e => e.Title)
.HasName("ix_release_title");
entity.HasIndex(e => new { e.ArtistId, e.Title })
.HasName("ix_releaseArtistAndTitle")
.IsUnique();
entity.HasOne(d => d.Artist)
.WithMany(p => p.Releases)
.HasForeignKey(d => d.ArtistId)
.OnDelete(DeleteBehavior.Cascade)
.HasConstraintName("release_ibfk_1");
});
builder.Entity<ReleaseGenre>(entity =>
{
entity.HasIndex(e => e.GenreId)
.HasName("ix_releaseGenre_genreId");
entity.HasIndex(e => new { e.ReleaseId, e.GenreId })
.HasName("ix_releaseGenreTableReleaseAndGenre");
entity.HasOne(d => d.Genre)
.WithMany(p => p.Releases)
.HasForeignKey(d => d.GenreId)
.OnDelete(DeleteBehavior.Cascade)
.HasConstraintName("releaseGenreTable_ibfk_2");
entity.HasOne(d => d.Release)
.WithMany(p => p.Genres)
.HasForeignKey(d => d.ReleaseId)
.OnDelete(DeleteBehavior.Cascade)
.HasConstraintName("releaseGenreTable_ibfk_1");
});
builder.Entity<ReleaseLabel>(entity =>
{
entity.HasIndex(e => e.LabelId)
.HasName("ix_releaselabel_labelId");
entity.HasIndex(e => e.RoadieId)
.HasName("ix_releaselabel_roadieId");
entity.HasIndex(e => new { e.ReleaseId, e.LabelId })
.HasName("ix_release_label");
entity.HasOne(d => d.Label)
.WithMany(p => p.ReleaseLabels)
.HasForeignKey(d => d.LabelId)
.OnDelete(DeleteBehavior.Cascade)
.HasConstraintName("releaselabel_ibfk_2");
entity.HasOne(d => d.Release)
.WithMany(p => p.Labels)
.HasForeignKey(d => d.ReleaseId)
.OnDelete(DeleteBehavior.Cascade)
.HasConstraintName("releaselabel_ibfk_1");
});
builder.Entity<ReleaseMedia>(entity =>
{
entity.HasIndex(e => e.RoadieId)
.HasName("ix_releasemedia_roadieId");
entity.HasIndex(e => new { e.ReleaseId, e.MediaNumber })
.HasName("ix_releasemedia_releaseId");
entity.HasOne(d => d.Release)
.WithMany(p => p.Medias)
.HasForeignKey(d => d.ReleaseId)
.OnDelete(DeleteBehavior.Cascade)
.HasConstraintName("releasemedia_ibfk_1");
});
builder.Entity<Request>(entity =>
{
entity.HasIndex(e => e.RoadieId)
.HasName("ix_request_roadieId");
entity.HasIndex(e => e.UserId)
.HasName("ix_requestartist_ibfk_1");
entity.HasOne(d => d.User)
.WithMany(p => p.Requests)
.HasForeignKey(d => d.UserId)
.OnDelete(DeleteBehavior.Cascade)
.HasConstraintName("requestartist_ibfk_1");
});
builder.Entity<ScanHistory>(entity =>
{
entity.HasIndex(e => e.RoadieId)
.HasName("ix_scanHistory_roadieId");
entity.HasIndex(e => e.UserId)
.HasName("ix_rscanHistoryt_ibfk_1");
});
builder.Entity<Submission>(entity =>
{
entity.HasIndex(e => e.RoadieId)
.HasName("ix_submission_roadieId");
entity.HasIndex(e => e.UserId)
.HasName("ix_submission_ibfk_1");
entity.HasOne(d => d.User)
.WithMany(p => p.Submissions)
.HasForeignKey(d => d.UserId)
.OnDelete(DeleteBehavior.SetNull)
.HasConstraintName("submission_ibfk_1");
});
builder.Entity<Track>(entity =>
{
entity.HasIndex(e => e.ArtistId)
.HasName("ix_track_artistId");
entity.HasIndex(e => e.Hash)
.HasName("ix_track_hash")
.IsUnique();
entity.HasIndex(e => e.ReleaseMediaId)
.HasName("ix_track_releaseMediaId");
entity.HasIndex(e => e.RoadieId)
.HasName("ix_track_roadieId");
entity.HasIndex(e => e.Title)
.HasName("ix_track_title");
entity.HasIndex(e => new { e.ReleaseMediaId, e.TrackNumber })
.HasName("ix_track_unique_to_eleasemedia")
.IsUnique();
entity.HasOne(d => d.TrackArtist)
.WithMany(p => p.Tracks)
.HasForeignKey(d => d.ArtistId)
.OnDelete(DeleteBehavior.SetNull)
.HasConstraintName("track_artist_ibfk_1");
entity.HasOne(d => d.ReleaseMedia)
.WithMany(p => p.Tracks)
.HasForeignKey(d => d.ReleaseMediaId)
.OnDelete(DeleteBehavior.Cascade)
.HasConstraintName("track_ibfk_1");
});
builder.Entity<UserQue>(entity =>
{
entity.HasIndex(e => e.TrackId)
.HasName("ix_userQue_ibfk_2");
entity.HasIndex(e => e.UserId)
.HasName("ix_user");
entity.HasOne(d => d.Track)
.WithMany(p => p.UserQues)
.HasForeignKey(d => d.TrackId)
.HasConstraintName("userQue_ibfk_2");
entity.HasOne(d => d.User)
.WithMany(p => p.UserQues)
.HasForeignKey(d => d.UserId)
.HasConstraintName("userQue_ibfk_1");
});
builder.Entity<UserArtist>(entity =>
{
entity.HasIndex(e => e.ArtistId)
.HasName("ix_userartist_artistId");
entity.HasIndex(e => e.RoadieId)
.HasName("ix_userartist_roadieId");
entity.HasIndex(e => new { e.UserId, e.ArtistId })
.HasName("ix_userartist_userId")
.IsUnique();
entity.HasOne(d => d.Artist)
.WithMany(p => p.UserArtists)
.HasForeignKey(d => d.ArtistId)
.OnDelete(DeleteBehavior.Cascade)
.HasConstraintName("userartist_ibfk_2");
entity.HasOne(d => d.User)
.WithMany(p => p.ArtistRatings)
.HasForeignKey(d => d.UserId)
.OnDelete(DeleteBehavior.Cascade)
.HasConstraintName("userartist_ibfk_1");
});
builder.Entity<UserRelease>(entity =>
{
entity.HasIndex(e => e.ReleaseId)
.HasName("ix_userrelease_releaseId");
entity.HasIndex(e => e.RoadieId)
.HasName("ix_userrelease_roadieId");
entity.HasIndex(e => new { e.UserId, e.ReleaseId })
.HasName("ix_userrelease_userId_ix")
.IsUnique();
entity.HasOne(d => d.Release)
.WithMany(p => p.UserRelases)
.HasForeignKey(d => d.ReleaseId)
.OnDelete(DeleteBehavior.Cascade)
.HasConstraintName("userrelease_ibfk_2");
entity.HasOne(d => d.User)
.WithMany(p => p.UserReleases)
.HasForeignKey(d => d.UserId)
.OnDelete(DeleteBehavior.Cascade)
.HasConstraintName("userrelease_ibfk_1");
});
builder.Entity<UserTrack>(entity =>
{
entity.HasIndex(e => e.RoadieId)
.HasName("ix_usertrack_roadieId");
entity.HasIndex(e => e.TrackId)
.HasName("ix_usertrack_trackId");
entity.HasIndex(e => new { e.UserId, e.TrackId })
.HasName("ix_usertrack_userId_ix")
.IsUnique();
entity.HasOne(d => d.Track)
.WithMany(p => p.UserTracks)
.HasForeignKey(d => d.TrackId)
.OnDelete(DeleteBehavior.Cascade)
.HasConstraintName("usertrack_ibfk_2");
entity.HasOne(d => d.User)
.WithMany(p => p.UserTracks)
.HasForeignKey(d => d.UserId)
.OnDelete(DeleteBehavior.Cascade)
.HasConstraintName("usertrack_ibfk_1");
});
builder.Entity<User>(entity =>
{
entity.HasIndex(e => e.Email)
.HasName("ix_user_email")
.IsUnique();
entity.HasIndex(e => e.RoadieId)
.HasName("ix_user_roadieId");
entity.HasIndex(e => e.UserName)
.HasName("ix_user_username")
.IsUnique();
});
builder.Entity<UserClaims>(entity =>
{
entity.HasIndex(e => e.UserId)
.HasName("ix_userClaims_userId");
entity.HasOne(d => d.User)
.WithMany(p => p.UserClaims)
.HasForeignKey(d => d.UserId)
.HasConstraintName("userClaims_ibfk_1");
});
builder.Entity<UserRoleClaims>(entity =>
{
entity.HasIndex(e => e.RoleId)
.HasName("ix_userRoleClaims_userRoleId");
entity.HasOne(d => d.UserRole)
.WithMany(p => p.RoleClaims)
.HasForeignKey(d => d.RoleId)
.HasConstraintName("userRoleClaims_ibfk_1");
});
builder.Entity<UserRole>(entity =>
{
entity.HasIndex(e => e.Name)
.HasName("ix_userrole_name")
.IsUnique();
entity.HasIndex(e => e.RoadieId)
.HasName("ix_userrole_roadieId");
});
builder.Entity<UsersInRoles>(entity =>
{
entity.HasIndex(e => e.UserId)
.HasName("ix_usersInRoles_userId");
entity.HasIndex(e => e.RoleId)
.HasName("ix_usersInRoles_userRoleId");
entity.HasOne(d => d.User)
.WithMany(p => p.UserRoles)
.HasForeignKey(d => d.UserId)
.OnDelete(DeleteBehavior.Cascade)
.HasConstraintName("usersInRoles_ibfk_1");
entity.HasOne(d => d.Role)
.WithMany(p => p.UserRoles)
.HasForeignKey(d => d.RoleId)
.OnDelete(DeleteBehavior.Cascade)
.HasConstraintName("usersInRoles_ibfk_2");
});
}
Task<EntityEntry> IRoadieDbContext.AddAsync(object entity, CancellationToken cancellationToken) => throw new NotImplementedException();

View file

@ -1,6 +1,4 @@
using Roadie.Library.Enums;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Roadie.Library.Data
@ -39,5 +37,21 @@ namespace Roadie.Library.Data
[NotMapped]
public override string AlternateNames { get; set; }
[ForeignKey(nameof(ArtistId))]
[InverseProperty("Credits")]
public virtual Artist Artist { get; set; }
[ForeignKey(nameof(CreditCategoryId))]
[InverseProperty("Credits")]
public virtual CreditCategory CreditCategory { get; set; }
[ForeignKey(nameof(ReleaseId))]
[InverseProperty("Credits")]
public virtual Release Release { get; set; }
[ForeignKey(nameof(TrackId))]
[InverseProperty("Credits")]
public virtual Track Track { get; set; }
}
}
}

View file

@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Roadie.Library.Data
@ -16,5 +17,13 @@ namespace Roadie.Library.Data
[NotMapped]
public override string SortName { get; set; }
[InverseProperty("CreditCategory")]
public virtual ICollection<Credit> Credits { get; set; }
public CreditCategory()
{
Credits = new HashSet<Credit>();
}
}
}

View file

@ -7,7 +7,9 @@ namespace Roadie.Library.Data
{
public abstract class EntityBase
{
[Column("createdDate")] [Required] public DateTime CreatedDate { get; set; }
[Column("createdDate")]
[Required]
public DateTime CreatedDate { get; set; }
[Column("id")]
[Key]
@ -16,14 +18,14 @@ namespace Roadie.Library.Data
public virtual bool? IsLocked { get; set; }
[Column("lastUpdated")]
[Column("lastUpdated")]
public DateTime? LastUpdated { get; set; }
[Column("RoadieId")]
[Required]
[Column("RoadieId")]
[Required]
public Guid RoadieId { get; set; }
[Column("status")]
[Column("status")]
public Statuses? Status { get; set; }
public EntityBase()

View file

@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
@ -8,12 +7,14 @@ namespace Roadie.Library.Data
[Table("genre")]
public partial class Genre : EntityBase
{
public ICollection<ArtistGenre> Artists { get; set; }
[InverseProperty("Genre")]
public virtual ICollection<ArtistGenre> Artists { get; set; }
public ICollection<Comment> Comments { get; set; }
[InverseProperty("Genre")]
public virtual ICollection<Comment> Comments { get; set; }
[Column("name")]
[MaxLength(100)]
[MaxLength(100)]
[Required]
public string Name { get; set; }
@ -35,14 +36,12 @@ namespace Roadie.Library.Data
[MaxLength(65535)]
public string Tags { get; set; }
[Obsolete("Images moved to file system")]
[Column("thumbnail", TypeName = "blob")]
[MaxLength(65535)]
public byte[] Thumbnail { get; set; }
[Column("normalizedName")]
[MaxLength(100)]
public string NormalizedName { get; set; }
[Column("normalizedName")] [MaxLength(100)] public string NormalizedName { get; set; }
public ICollection<ReleaseGenre> Releases { get; set; }
[InverseProperty("Genre")]
public virtual ICollection<ReleaseGenre> Releases { get; set; }
public Genre()
{

View file

@ -26,23 +26,13 @@ namespace Roadie.Library.Data
public string PathToImage(IRoadieSettings configuration, bool makeFolderIfNotExist = false)
{
var folder = FolderPathHelper.GenrePath(configuration, SortNameValue);
if(!Directory.Exists(folder) && makeFolderIfNotExist)
if (!Directory.Exists(folder) && makeFolderIfNotExist)
{
Directory.CreateDirectory(folder);
}
return Path.Combine(folder, $"{ SortNameValue.ToFileNameFriendly() } [{ Id }].jpg");
}
/// <summary>
/// Returns a full file path to the Label Image
/// </summary>
[Obsolete("This is only here for migration will be removed in future release.")]
public string OldPathToImage(IRoadieSettings configuration)
{
return Path.Combine(configuration.GenreImageFolder, $"{ SortNameValue.ToFileNameFriendly() } [{ Id }].jpg");
}
public static string CacheRegionUrn(Guid Id)
{
return string.Format("urn:genre:{0}", Id);

View file

@ -1,6 +1,5 @@
using Roadie.Library.Identity;
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Roadie.Library.Data
@ -8,6 +7,10 @@ namespace Roadie.Library.Data
[Table("inviteToken")]
public class InviteToken : EntityBase
{
[ForeignKey(nameof(CreatedByUserId))]
[InverseProperty(nameof(User.InviteTokens))]
public virtual User CreatedByUser { get; set; }
[Column("createdByUserId")]
public int CreatedByUserId { get; set; }
@ -17,4 +20,4 @@ namespace Roadie.Library.Data
[NotMapped]
public new bool IsLocked { get; set; }
}
}
}

View file

@ -8,13 +8,19 @@ namespace Roadie.Library.Data
[Table("label")]
public partial class Label : BeginAndEndNamedEntityBase
{
[Column("artistCount")] public int? ArtistCount { get; set; }
[Column("artistCount")]
public int? ArtistCount { get; set; }
public ICollection<Comment> Comments { get; set; }
[InverseProperty("Label")]
public virtual ICollection<Comment> Comments { get; set; }
[Column("discogsId")] [MaxLength(50)] public string DiscogsId { get; set; }
[Column("discogsId")]
[MaxLength(50)]
public string DiscogsId { get; set; }
[Column("imageUrl")] [MaxLength(500)] public string ImageUrl { get; set; }
[Column("imageUrl")]
[MaxLength(500)]
public string ImageUrl { get; set; }
[Column("musicBrainzId")]
[MaxLength(100)]
@ -24,11 +30,14 @@ namespace Roadie.Library.Data
[MaxLength(65535)]
public string Profile { get; set; }
[Column("releaseCount")] public int? ReleaseCount { get; set; }
[Column("releaseCount")]
public int? ReleaseCount { get; set; }
public ICollection<ReleaseLabel> ReleaseLabels { get; set; }
[InverseProperty("Label")]
public virtual ICollection<ReleaseLabel> ReleaseLabels { get; set; }
[Column("trackCount")] public int? TrackCount { get; set; }
[Column("trackCount")]
public int? TrackCount { get; set; }
public Label()
{

View file

@ -2,10 +2,7 @@
using Roadie.Library.Extensions;
using Roadie.Library.Utility;
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
namespace Roadie.Library.Data
{
@ -23,8 +20,6 @@ namespace Roadie.Library.Data
}
}
public string SortNameValue => string.IsNullOrEmpty(SortName) ? Name : SortName;
/// <summary>
/// Returns a full file path to the Label Image
/// </summary>
@ -38,15 +33,6 @@ namespace Roadie.Library.Data
return Path.Combine(folder, $"{ SortNameValue.ToFileNameFriendly() } [{ Id }].jpg");
}
/// <summary>
/// Returns a full file path to the Label Image
/// </summary>
[Obsolete("This is only here for migration will be removed in future release.")]
public string OldPathToImage(IRoadieSettings configuration)
{
return Path.Combine(configuration.LabelImageFolder, $"{ SortNameValue.ToFileNameFriendly() } [{ Id }].jpg");
}
public bool IsValid => !string.IsNullOrEmpty(Name);
public static string CacheRegionUrn(Guid Id)

View file

@ -1,5 +1,4 @@
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Roadie.Library.Data
@ -14,8 +13,8 @@ namespace Roadie.Library.Data
[Column("name")]
public virtual string Name { get; set; }
[Column("sortName")]
[MaxLength(250)]
[Column("sortName")]
[MaxLength(250)]
public virtual string SortName { get; set; }
public virtual string SortNameValue => string.IsNullOrEmpty(SortName) ? Name : SortName;

View file

@ -8,31 +8,42 @@ namespace Roadie.Library.Data
[Table("playlist")]
public partial class Playlist : NamedEntityBase
{
public ICollection<Comment> Comments { get; set; }
[InverseProperty("Playlist")]
public virtual ICollection<Comment> Comments { get; set; }
[Column("Description")]
[MaxLength(1000)]
public string Description { get; set; }
[Column("duration")] public int? Duration { get; set; }
[Column("duration")]
public int? Duration { get; set; }
[Column("isPublic")] public bool IsPublic { get; set; }
[Column("isPublic")]
public bool IsPublic { get; set; }
[Column("releaseCount")] public short ReleaseCount { get; set; }
[Column("releaseCount")]
public short ReleaseCount { get; set; }
[NotMapped] public new string SortName { get; set; }
[NotMapped]
public new string SortName { get; set; }
[Column("trackCount")] public short TrackCount { get; set; }
[Column("trackCount")]
public short TrackCount { get; set; }
public ICollection<PlaylistTrack> Tracks { get; set; }
[InverseProperty("Playlist")]
public virtual ICollection<PlaylistTrack> Tracks { get; set; }
public ApplicationUser User { get; set; }
[ForeignKey(nameof(UserId))]
[InverseProperty("Playlists")]
public virtual User User { get; set; }
[Column("userId")] public int? UserId { get; set; }
[Column("userId")]
public int? UserId { get; set; }
public Playlist()
{
Comments = new HashSet<Comment>();
Tracks = new HashSet<PlaylistTrack>();
}
}
}

View file

@ -1,7 +1,6 @@
using Roadie.Library.Configuration;
using Roadie.Library.Extensions;
using System;
using System.Diagnostics;
using System.IO;
namespace Roadie.Library.Data

View file

@ -6,14 +6,21 @@ namespace Roadie.Library.Data
[Table("playlisttrack")]
public class PlaylistTrack : EntityBase
{
[Column("listNumber")] [Required] public int ListNumber { get; set; }
[Column("listNumber")]
[Required]
public int ListNumber { get; set; }
public Playlist Playlist { get; set; }
[ForeignKey(nameof(PlayListId))]
[InverseProperty("Tracks")]
public virtual Playlist Playlist { get; set; }
[Column("playListId")] public int PlayListId { get; set; }
[Column("playListId")]
public int PlayListId { get; set; }
public Track Track { get; set; }
public virtual Track Track { get; set; }
[Column("trackId")] public int TrackId { get; set; }
[Column("trackId")]
[InverseProperty("PlaylistTracks")]
public int TrackId { get; set; }
}
}

View file

@ -0,0 +1,33 @@
using Roadie.Library.Enums;
using System;
using System.Text.Json.Serialization;
namespace Roadie.Library.Data
{
[Serializable]
public class PositionArtistRelease
{
public string Artist { get; set; }
/// <summary>
/// This is the index (position in the list regardless of the position number)
/// </summary>
[JsonIgnore]
public int Index { get; set; }
/// <summary>
/// This is the position number for the list (can be a year "1984" can be a number "14")
/// </summary>
public int Position { get; set; }
public string Release { get; set; }
[JsonIgnore]
public Statuses Status { get; set; }
[JsonPropertyName("Status")]
public string StatusVerbose => Status.ToString();
public override string ToString() => string.Format("Position [{0}], Artist [{1}], Release [{2}]", Position, Artist, Release);
}
}

View file

@ -14,78 +14,101 @@ namespace Roadie.Library.Data
[MaxLength(65535)]
public string AlternateNames { get; set; }
[Column("amgId")] [MaxLength(50)] public string AmgId { get; set; }
[Column("amgId")]
[MaxLength(50)]
public string AmgId { get; set; }
public Artist Artist { get; set; }
public virtual Artist Artist { get; set; }
[Column("artistId")] [Required] public int ArtistId { get; set; }
[Column("artistId")]
[Required]
public int ArtistId { get; set; }
public ICollection<CollectionRelease> Collections { get; set; }
[InverseProperty("Release")]
public virtual ICollection<CollectionRelease> Collections { get; set; }
public ICollection<Comment> Comments { get; set; }
[InverseProperty("Release")]
public virtual ICollection<Comment> Comments { get; set; }
[Column("discogsId")] [MaxLength(50)] public string DiscogsId { get; set; }
[Column("discogsId")]
[MaxLength(50)]
public string DiscogsId { get; set; }
[Column("duration")] public int? Duration { get; set; }
[Column("duration")]
public int? Duration { get; set; }
public ICollection<ReleaseGenre> Genres { get; set; }
[InverseProperty("Release")]
public virtual ICollection<ReleaseGenre> Genres { get; set; }
[NotMapped]
public IEnumerable<Imaging.IImage> Images { get; set; } = Enumerable.Empty<Imaging.IImage>();
public Imaging.IImage ThumbnailImage => Images.OrderBy(x => x.SortOrder).FirstOrDefault();
[Column("isVirtual")] public bool? IsVirtual { get; set; }
[Column("isVirtual")]
public bool? IsVirtual { get; set; }
[Column("itunesId")] [MaxLength(100)] public string ITunesId { get; set; }
[Column("itunesId")]
[MaxLength(100)]
public string ITunesId { get; set; }
public ICollection<ReleaseLabel> Labels { get; set; }
[InverseProperty("Release")]
public virtual ICollection<ReleaseLabel> Labels { get; set; }
[Column("lastFMId")] [MaxLength(50)] public string LastFMId { get; set; }
[Column("lastFMId")]
[MaxLength(50)]
public string LastFMId { get; set; }
[Column("lastFMSummary", TypeName = "text")]
[MaxLength(65535)]
public string LastFMSummary { get; set; }
[Column("lastPlayed")] public DateTime? LastPlayed { get; set; }
[Column("lastPlayed")]
public DateTime? LastPlayed { get; set; }
[Column("libraryStatus")] public LibraryStatus? LibraryStatus { get; set; }
[Column("libraryStatus")]
public LibraryStatus? LibraryStatus { get; set; }
[Column("mediaCount")] public short? MediaCount { get; set; }
[Column("mediaCount")]
public short? MediaCount { get; set; }
public ICollection<ReleaseMedia> Medias { get; set; }
[InverseProperty("Release")]
public virtual ICollection<ReleaseMedia> Medias { get; set; }
[Column("musicBrainzId")]
[MaxLength(100)]
public string MusicBrainzId { get; set; }
[Column("playedCount")] public int? PlayedCount { get; set; }
[Column("playedCount")]
public int? PlayedCount { get; set; }
[Column("profile", TypeName = "text")]
[MaxLength(65535)]
public string Profile { get; set; }
[Column("rank")] public decimal? Rank { get; set; }
[Column("rank")]
public decimal? Rank { get; set; }
[Column("rating")] public short? Rating { get; set; }
[Column("rating")]
public short? Rating { get; set; }
[Column("releaseDate")] public DateTime? ReleaseDate { get; set; }
[Column("releaseDate")]
public DateTime? ReleaseDate { get; set; }
[Column("releaseType")] public ReleaseType? ReleaseType { get; set; }
[Column("releaseType")]
public ReleaseType? ReleaseType { get; set; }
[Column("spotifyId")] [MaxLength(100)] public string SpotifyId { get; set; }
[Column("spotifyId")]
[MaxLength(100)]
public string SpotifyId { get; set; }
[Column("submissionId")] public int? SubmissionId { get; set; }
[Column("submissionId")]
public int? SubmissionId { get; set; }
[Column("tags", TypeName = "text")]
[MaxLength(65535)]
public string Tags { get; set; }
[Obsolete("Images moved to file system")]
[Column("thumbnail", TypeName = "blob")]
[MaxLength(65535)]
public byte[] Thumbnail { get; set; }
[MaxLength(250)]
[Column("title")]
[Required]
@ -97,21 +120,31 @@ namespace Roadie.Library.Data
public string SortTitleValue => string.IsNullOrEmpty(SortTitle) ? Title : SortTitle;
[Column("trackCount")] public short TrackCount { get; set; }
[Column("trackCount")]
public short TrackCount { get; set; }
[Column("urls", TypeName = "text")]
[MaxLength(65535)]
public string URLs { get; set; }
[InverseProperty("Release")]
public virtual ICollection<Credit> Credits { get; set; }
[InverseProperty("Release")]
public virtual ICollection<UserRelease> UserRelases { get; set; }
public Release()
{
Rating = 0;
ReleaseType = Enums.ReleaseType.Release;
Medias = new HashSet<ReleaseMedia>();
Labels = new HashSet<ReleaseLabel>();
Collections = new HashSet<CollectionRelease>();
Genres = new HashSet<ReleaseGenre>();
Comments = new HashSet<Comment>();
Credits = new HashSet<Credit>();
UserRelases = new HashSet<UserRelease>();
}
}
}

View file

@ -6,17 +6,25 @@ namespace Roadie.Library.Data
[Table("releaseGenreTable")]
public class ReleaseGenre
{
public Genre Genre { get; set; }
[ForeignKey(nameof(ReleaseId))]
[InverseProperty("Genres")]
public virtual Release Release { get; set; }
[Column("genreId")] [Required] public int? GenreId { get; set; }
[Column("releaseId")]
[Required]
public int ReleaseId { get; set; }
[ForeignKey(nameof(GenreId))]
[InverseProperty("Releases")]
public virtual Genre Genre { get; set; }
[Column("genreId")]
[Required]
public int GenreId { get; set; }
[Column("id")]
[Key]
[Column("id")]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public Release Release { get; set; }
[Column("releaseId")] [Required] public int ReleaseId { get; set; }
}
}

View file

@ -5,14 +5,21 @@ namespace Roadie.Library.Data
[Table("releaselabel")]
public class ReleaseLabel : BeginAndEndEntityBase
{
[Column("catalogNumber")] public string CatalogNumber { get; set; }
[Column("catalogNumber")]
public string CatalogNumber { get; set; }
public Label Label { get; set; }
[ForeignKey(nameof(LabelId))]
[InverseProperty("ReleaseLabels")]
public virtual Label Label { get; set; }
[Column("labelId")] public int LabelId { get; set; }
[Column("labelId")]
public int LabelId { get; set; }
public Release Release { get; set; }
[ForeignKey(nameof(ReleaseId))]
[InverseProperty("Labels")]
public virtual Release Release { get; set; }
[Column("releaseId")] public int ReleaseId { get; set; }
[Column("releaseId")]
public int ReleaseId { get; set; }
}
}

View file

@ -7,19 +7,26 @@ namespace Roadie.Library.Data
[Table("releasemedia")]
public class ReleaseMedia : EntityBase
{
[Column("releaseMediaNumber")] public short MediaNumber { get; set; }
[Column("releaseMediaNumber")]
public short MediaNumber { get; set; }
public Release Release { get; set; }
[ForeignKey(nameof(ReleaseId))]
[InverseProperty("Medias")]
public virtual Release Release { get; set; }
[Column("releaseId")] public int ReleaseId { get; set; }
[Column("releaseId")]
public int ReleaseId { get; set; }
[Column("releaseSubTitle")]
[MaxLength(500)]
public string SubTitle { get; set; }
[Column("trackCount")] [Required] public short TrackCount { get; set; }
[Column("trackCount")]
[Required]
public short TrackCount { get; set; }
public ICollection<Track> Tracks { get; set; }
[InverseProperty("ReleaseMedia")]
public virtual ICollection<Track> Tracks { get; set; }
public ReleaseMedia()
{

View file

@ -3,7 +3,6 @@ using Roadie.Library.Utility;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
namespace Roadie.Library.Data
{
@ -106,7 +105,7 @@ namespace Roadie.Library.Data
public override string ToString()
{
return $"Id [{Id}], Status [{ Status }], LibraryStatus [{ LibraryStatus }], Title [{Title}], SortTitle [{ SortTitleValue }], Release Date [{ReleaseYear}]";
return $"Id [{Id}], Status [{ Status }], LibraryStatus [{ LibraryStatus }], Title [{Title}], SortTitle [{ SortTitle }], Release Date [{ReleaseYear}]";
}
}
}

View file

@ -12,9 +12,14 @@ namespace Roadie.Library.Data
[Required]
public string Description { get; set; }
[NotMapped] public new bool? IsLocked { get; set; }
public ApplicationUser User { get; set; }
[NotMapped]
public new bool? IsLocked { get; set; }
[Column("userId")] public int? UserId { get; set; }
[ForeignKey(nameof(UserId))]
[InverseProperty("Requests")]
public virtual User User { get; set; }
[Column("userId")]
public int? UserId { get; set; }
}
}

View file

@ -7,23 +7,31 @@ namespace Roadie.Library.Data
[Table("scanHistory")]
public class ScanHistory : EntityBase
{
[Column("forArtistId")] public int? ForArtistId { get; set; }
[Column("forArtistId")]
public int? ForArtistId { get; set; }
[Column("forReleaseId")] public int? ForReleaseId { get; set; }
[Column("forReleaseId")]
public int? ForReleaseId { get; set; }
[NotMapped] public new bool? IsLocked { get; set; }
[NotMapped]
public new bool? IsLocked { get; set; }
[Column("newArtists")] public int? NewArtists { get; set; }
[Column("newArtists")]
public int? NewArtists { get; set; }
[Column("newReleases")] public int? NewReleases { get; set; }
[Column("newReleases")]
public int? NewReleases { get; set; }
[Column("newTracks")] public int? NewTracks { get; set; }
[Column("newTracks")]
public int? NewTracks { get; set; }
[Column("timeSpanInSeconds")] public int TimeSpanInSeconds { get; set; }
[Column("timeSpanInSeconds")]
public int TimeSpanInSeconds { get; set; }
public ApplicationUser User { get; set; }
public virtual User User { get; set; }
[Column("userId")] public int UserId { get; set; }
[Column("userId")]
public int UserId { get; set; }
public ScanHistory()
{

View file

@ -6,8 +6,11 @@ namespace Roadie.Library.Data
[Table("submission")]
public class Submission : EntityBase
{
public ApplicationUser User { get; set; }
[ForeignKey(nameof(UserId))]
[InverseProperty("Submissions")]
public virtual User User { get; set; }
[Column("userId")] public int UserId { get; set; }
[Column("userId")]
public int UserId { get; set; }
}
}

View file

@ -12,27 +12,48 @@ namespace Roadie.Library.Data
[MaxLength(65535)]
public string AlternateNames { get; set; }
[Column("amgId")] [MaxLength(50)] public string AmgId { get; set; }
[Column("amgId")]
[MaxLength(50)]
public string AmgId { get; set; }
[Column("artistId")] public int? ArtistId { get; set; }
[Column("artistId")]
public int? ArtistId { get; set; }
public ICollection<Comment> Comments { get; set; }
[ForeignKey(nameof(ArtistId))]
[InverseProperty("Tracks")]
public virtual Artist TrackArtist { get; set; }
[Column("duration")] public int? Duration { get; set; }
[InverseProperty("Track")]
public virtual ICollection<Comment> Comments { get; set; }
[Column("fileName")] [MaxLength(500)] public string FileName { get; set; }
[Column("duration")]
public int? Duration { get; set; }
[Column("filePath")] [MaxLength(1000)] public string FilePath { get; set; }
[Column("fileName")]
[MaxLength(500)]
public string FileName { get; set; }
[Column("fileSize")] public int? FileSize { get; set; }
[Column("filePath")]
[MaxLength(1000)]
public string FilePath { get; set; }
[Column("hash")] [MaxLength(32)] public string Hash { get; set; }
[Column("fileSize")]
public int? FileSize { get; set; }
[Column("isrc")] [MaxLength(15)] public string ISRC { get; set; }
[Column("hash")]
[MaxLength(32)]
public string Hash { get; set; }
[Column("lastFMId")] [MaxLength(50)] public string LastFMId { get; set; }
[Column("isrc")]
[MaxLength(15)]
public string ISRC { get; set; }
[Column("lastPlayed")] public DateTime? LastPlayed { get; set; }
[Column("lastFMId")]
[MaxLength(50)]
public string LastFMId { get; set; }
[Column("lastPlayed")]
public DateTime? LastPlayed { get; set; }
[Column("musicBrainzId")]
[MaxLength(100)]
@ -42,34 +63,53 @@ namespace Roadie.Library.Data
[MaxLength(65535)]
public string PartTitles { get; set; }
[Column("playedCount")] public int? PlayedCount { get; set; }
[Column("playedCount")]
public int? PlayedCount { get; set; }
[Column("rating")] public short Rating { get; set; }
[Column("rating")]
public short Rating { get; set; }
public ReleaseMedia ReleaseMedia { get; set; }
public virtual ReleaseMedia ReleaseMedia { get; set; }
[Column("releaseMediaId")] public int ReleaseMediaId { get; set; }
[Column("releaseMediaId")]
public int ReleaseMediaId { get; set; }
[Column("spotifyId")] [MaxLength(100)] public string SpotifyId { get; set; }
[Column("spotifyId")]
[MaxLength(100)]
public string SpotifyId { get; set; }
[Column("tags", TypeName = "text")]
[MaxLength(65535)]
public string Tags { get; set; }
[Obsolete("Images moved to file system")]
[Column("thumbnail", TypeName = "blob")]
public byte[] Thumbnail { get; set; }
[MaxLength(250)]
[Column("title")]
[Required]
public string Title { get; set; }
[Column("trackNumber")] [Required] public short TrackNumber { get; set; }
[Column("trackNumber")]
[Required]
public short TrackNumber { get; set; }
[InverseProperty("Track")]
public virtual ICollection<Credit> Credits { get; set; }
[InverseProperty("Track")]
public virtual ICollection<PlaylistTrack> Playlists { get; set; }
[InverseProperty("Track")]
public virtual ICollection<UserQue> UserQues { get; set; }
[InverseProperty("Track")]
public virtual ICollection<UserTrack> UserTracks { get; set; }
public Track()
{
Comments = new HashSet<Comment>();
Credits = new HashSet<Credit>();
Playlists = new HashSet<PlaylistTrack>();
UserQues = new HashSet<UserQue>();
UserTracks = new HashSet<UserTrack>();
Rating = 0;
}
}

View file

@ -5,8 +5,6 @@ using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
namespace Roadie.Library.Data
{
@ -38,9 +36,11 @@ namespace Roadie.Library.Data
}
}
public Artist TrackArtist { get; set; }
[NotMapped] public IEnumerable<string> TrackArtists { get; set; }
/// <summary>
/// This is used when finding metadata, not storedin the database.
/// </summary>
[NotMapped]
public virtual IEnumerable<string> TrackArtists { get; set; }
public static string CacheRegionUrn(Guid Id)
{
@ -63,7 +63,7 @@ namespace Roadie.Library.Data
public bool DoesFileForTrackExist(IRoadieSettings configuration)
{
var trackPath = PathToTrack(configuration);
if(string.IsNullOrEmpty(trackPath))
if (string.IsNullOrEmpty(trackPath))
{
return false;
}

View file

@ -7,19 +7,30 @@ namespace Roadie.Library.Data
[Table("userartist")]
public class UserArtist : EntityBase
{
public Artist Artist { get; set; }
[ForeignKey(nameof(ArtistId))]
[InverseProperty("UserArtists")]
public virtual Artist Artist { get; set; }
[Column("artistId")] [Required] public int ArtistId { get; set; }
[Column("artistId")]
[Required]
public int ArtistId { get; set; }
[Column("isDisliked")] public bool? IsDisliked { get; set; }
[Column("isDisliked")]
public bool? IsDisliked { get; set; }
[Column("isFavorite")] public bool? IsFavorite { get; set; }
[Column("isFavorite")]
public bool? IsFavorite { get; set; }
[Column("rating")] public short Rating { get; set; }
[Column("rating")]
public short Rating { get; set; }
public ApplicationUser User { get; set; }
[ForeignKey(nameof(UserId))]
[InverseProperty("ArtistRatings")]
public virtual User User { get; set; }
[Column("userId")] [Required] public int UserId { get; set; }
[Column("userId")]
[Required]
public int UserId { get; set; }
public UserArtist()
{

View file

@ -7,13 +7,30 @@ namespace Roadie.Library.Data
[Table("userQue")]
public class UserQue : EntityBase
{
[Column("isCurrent")] public bool? IsCurrent { get; set; }
[Column("position")] public long? Position { get; set; }
[Column("queSortOrder")] [Required] public short QueSortOrder { get; set; }
public Track Track { get; set; }
[Column("trackId")] [Required] public int TrackId { get; set; }
public ApplicationUser User { get; set; }
[Column("isCurrent")]
public bool? IsCurrent { get; set; }
[Column("userId")] [Required] public int UserId { get; set; }
[Column("position")]
public long? Position { get; set; }
[Column("queSortOrder")]
[Required]
public short QueSortOrder { get; set; }
[ForeignKey(nameof(TrackId))]
[InverseProperty("UserQues")]
public virtual Track Track { get; set; }
[Column("trackId")]
[Required]
public int TrackId { get; set; }
[ForeignKey(nameof(UserId))]
[InverseProperty("UserQues")]
public virtual User User { get; set; }
[Column("userId")]
[Required]
public int UserId { get; set; }
}
}

View file

@ -7,19 +7,30 @@ namespace Roadie.Library.Data
[Table("userrelease")]
public class UserRelease : EntityBase
{
[Column("isDisliked")] public bool? IsDisliked { get; set; }
[Column("isDisliked")]
public bool? IsDisliked { get; set; }
[Column("isFavorite")] public bool? IsFavorite { get; set; }
[Column("isFavorite")]
public bool? IsFavorite { get; set; }
[Column("rating")] public short Rating { get; set; }
[Column("rating")]
public short Rating { get; set; }
public Release Release { get; set; }
[ForeignKey(nameof(ReleaseId))]
[InverseProperty("UserRelases")]
public virtual Release Release { get; set; }
[Column("releaseId")] [Required] public int ReleaseId { get; set; }
[Column("releaseId")]
[Required]
public int ReleaseId { get; set; }
public ApplicationUser User { get; set; }
[ForeignKey(nameof(UserId))]
[InverseProperty("UserReleases")]
public virtual User User { get; set; }
[Column("userId")] [Required] public int UserId { get; set; }
[Column("userId")]
[Required]
public int UserId { get; set; }
public UserRelease()
{

View file

@ -8,23 +8,36 @@ namespace Roadie.Library.Data
[Table("usertrack")]
public class UserTrack : EntityBase
{
[Column("isDisliked")] public bool? IsDisliked { get; set; }
[Column("isDisliked")]
public bool? IsDisliked { get; set; }
[Column("isFavorite")] public bool? IsFavorite { get; set; }
[Column("isFavorite")]
public bool? IsFavorite { get; set; }
[Column("lastPlayed")] public DateTime? LastPlayed { get; set; }
[Column("lastPlayed")]
public DateTime? LastPlayed { get; set; }
[Column("playedCount")] public int? PlayedCount { get; set; }
[Column("playedCount")]
public int? PlayedCount { get; set; }
[Column("rating")] public short Rating { get; set; }
[Column("rating")]
public short Rating { get; set; }
public Track Track { get; set; }
[ForeignKey(nameof(TrackId))]
[InverseProperty("UserTracks")]
public virtual Track Track { get; set; }
[Column("trackId")] [Required] public int TrackId { get; set; }
[Column("trackId")]
[Required]
public int TrackId { get; set; }
public ApplicationUser User { get; set; }
[ForeignKey(nameof(UserId))]
[InverseProperty("UserTracks")]
public virtual User User { get; set; }
[Column("userId")] [Required] public int UserId { get; set; }
[Column("userId")]
[Required]
public int UserId { get; set; }
public UserTrack()
{

View file

@ -87,37 +87,38 @@ namespace Roadie.Library.Engines
if (artist.Id < 1 && addArtistResult.Entity.Id > 0) artist.Id = addArtistResult.Entity.Id;
if (inserted > 0 && artist.Id > 0)
{
if (artistGenreTables != null && artistGenreTables.Any(x => x.GenreId == null))
if (artistGenreTables != null)
{
foreach (var artistGenreTable in artistGenreTables)
if (artistGenreTables != null)
{
var genreName = artistGenreTable.Genre?.Name?.ToAlphanumericName();
if (string.IsNullOrEmpty(genreName)) continue;
if (artistGenreTable.Genre.Name.Length > 100)
foreach (var artistGenreTable in artistGenreTables.Select(x => x.Genre?.Name).Distinct())
{
var originalName = artistGenreTable.Genre.Name;
artistGenreTable.Genre.Name = artistGenreTable.Genre.Name.Substring(0, 99);
genreName = genreName.Substring(0, 99);
Logger.LogWarning($"Genre Name Too long was [{originalName}] truncated to [{artistGenreTable.Genre.Name}]");
}
var genre = DbContext.Genres.FirstOrDefault(x => x.NormalizedName == genreName);
if (genre == null)
{
genre = new Genre
var genreName = artistGenreTable.ToAlphanumericName().ToTitleCase();
var normalizedName = genreName.ToUpper();
if (string.IsNullOrEmpty(genreName)) continue;
if (genreName.Length > 100)
{
Name = artistGenreTable.Genre.Name,
NormalizedName = genreName
};
DbContext.Genres.Add(genre);
await DbContext.SaveChangesAsync();
}
if (genre != null && genre.Id > 0)
{
var originalName = genreName;
genreName = genreName.Substring(0, 99);
Logger.LogWarning($"Genre Name Too long was [{originalName}] truncated to [{genreName}]");
}
var genre = DbContext.Genres.FirstOrDefault(x => x.NormalizedName == normalizedName);
if (genre == null)
{
genre = new Genre
{
Name = genreName,
NormalizedName = normalizedName
};
DbContext.Genres.Add(genre);
await DbContext.SaveChangesAsync();
}
DbContext.ArtistGenres.Add(new ArtistGenre
{
ArtistId = artist.Id,
GenreId = genre.Id
});
await DbContext.SaveChangesAsync();
}
}
}
@ -157,7 +158,7 @@ namespace Roadie.Library.Engines
}
catch (Exception ex)
{
Logger.LogError(ex, ex.Serialize());
Logger.LogError(ex, $"Error Adding Artist `{ artist }`, Ex [{ ex.Serialize() }]");
}
return new OperationResult<Artist>
{

View file

@ -110,42 +110,36 @@ namespace Roadie.Library.Engines
if (inserted > 0 && release.Id > 0)
{
_addedReleaseIds.Add(release.Id);
if (releaseGenreTables != null && releaseGenreTables.Any(x => x.GenreId == null))
if (releaseGenreTables != null)
{
var addedGenreIds = new List<int>();
foreach (var releaseGenreTable in releaseGenreTables)
foreach (var releaseGenreTable in releaseGenreTables.Select(x => x.Genre?.Name).Distinct())
{
var genreName = releaseGenreTable.Genre?.Name?.ToAlphanumericName();
var genreName = releaseGenreTable.ToAlphanumericName().ToTitleCase();
var normalizedName = genreName.ToUpper();
if (string.IsNullOrEmpty(genreName)) continue;
if (releaseGenreTable.Genre.Name.Length > 100)
if (genreName.Length > 100)
{
var originalName = releaseGenreTable.Genre.Name;
releaseGenreTable.Genre.Name = releaseGenreTable.Genre.Name.Substring(0, 99);
var originalName = genreName;
genreName = genreName.Substring(0, 99);
Logger.LogWarning($"Genre Name Too long was [{originalName}] truncated to [{releaseGenreTable.Genre.Name}]");
Logger.LogWarning($"Genre Name Too long was [{originalName}] truncated to [{genreName}]");
}
var genre = DbContext.Genres.FirstOrDefault(x => x.NormalizedName == genreName);
var genre = DbContext.Genres.FirstOrDefault(x => x.NormalizedName == normalizedName);
if (genre == null)
{
genre = new Genre
{
Name = releaseGenreTable.Genre.Name,
NormalizedName = genreName
Name = genreName,
NormalizedName = normalizedName
};
DbContext.Genres.Add(genre);
await DbContext.SaveChangesAsync();
}
if (genre != null &&
genre.Id > 0 &&
!addedGenreIds.Any(x => x == genre.Id))
DbContext.ReleaseGenres.Add(new ReleaseGenre
{
DbContext.ReleaseGenres.Add(new ReleaseGenre
{
ReleaseId = release.Id,
GenreId = genre.Id
});
addedGenreIds.Add(genre.Id);
}
ReleaseId = release.Id,
GenreId = genre.Id
});
await DbContext.SaveChangesAsync();
}
}
@ -364,32 +358,6 @@ namespace Roadie.Library.Engines
var release = DatabaseQueryForReleaseTitle(artist, metaData.Release);
//var searchName = metaData.Release.NormalizeName().ToLower();
//var specialSearchName = metaData.Release.ToAlphanumericName();
//var altStart = $"{searchName}|";
//var altIn = $"|{searchName}|";
//var altEnds = $"|{searchName}";
//var altStartSpecial = $"{specialSearchName}|";
//var altInSpecial = $"|{specialSearchName}|";
//var altEndsSpecial = $"|{specialSearchName}";
//var release = (from r in DbContext.Releases
// where r.ArtistId == artist.Id
// where r.Title == searchName ||
// r.Title == specialSearchName ||
// r.AlternateNames == searchName ||
// r.AlternateNames == specialSearchName ||
// r.AlternateNames.Contains(altStart) ||
// r.AlternateNames.Contains(altIn) ||
// r.AlternateNames.Contains(altEnds) ||
// r.AlternateNames.Contains(altStartSpecial) ||
// r.AlternateNames.Contains(altInSpecial) ||
// r.AlternateNames.Contains(altEndsSpecial)
// select r
// ).FirstOrDefault();
sw.Stop();
if (release == null || !release.IsValid)
{

View file

@ -1,41 +0,0 @@
using Microsoft.AspNetCore.Identity;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Roadie.Library.Identity
{
[Table("userrole")]
public class ApplicationRole : IdentityRole<int>
{
[Column("createdDate")] public DateTime? CreatedDate { get; set; }
[Column("description")]
[StringLength(200)]
public string Description { get; set; }
//[Column("id")]
//[Key]
//public override int Id { get; set; }
[Column("isLocked")] public bool? IsLocked { get; set; }
[Column("lastUpdated")] public DateTime? LastUpdated { get; set; }
[Column("name")]
[Required]
[StringLength(80)]
public override string Name { get; set; }
[Column("RoadieId")]
[StringLength(36)]
public string RoadieId { get; set; }
public virtual ICollection<ApplicationRoleClaim> RoleClaims { get; set; }
[Column("status")] public short? Status { get; set; }
public virtual ICollection<ApplicationUserRole> UserRoles { get; set; }
}
}

View file

@ -1,13 +0,0 @@
using Microsoft.AspNetCore.Identity;
using System.ComponentModel.DataAnnotations.Schema;
namespace Roadie.Library.Identity
{
[Table("userRoleClaims")]
public class ApplicationRoleClaim : IdentityRoleClaim<int>
{
public virtual ApplicationRole Role { get; set; }
[Column("userRoleId")] public override int RoleId { get; set; }
}
}

View file

@ -1,135 +0,0 @@
using Microsoft.AspNetCore.Identity;
using Roadie.Library.Data;
using Roadie.Library.Enums;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Roadie.Library.Identity
{
/// <summary>
/// Application User for Identity
/// <remarks>
/// As this is used by UserManager to get for each request in API *do not* lazy load properties as the object
/// is too heavy and requires multiple DB hits to poplate - which is data not needed to authenticate a user.
/// </remarks>
/// </summary>
[Table("user")]
public partial class ApplicationUser : IdentityUser<int>
{
[Column("apiToken")]
[StringLength(100)]
public string ApiToken { get; set; }
public ICollection<UserArtist> ArtistRatings { get; set; }
[Obsolete("Images moved to file system")]
[Column("avatar", TypeName = "blob")]
public byte[] Avatar { get; set; }
public ICollection<Bookmark> Bookmarks { get; set; }
public ICollection<ApplicationUserClaim> Claims { get; set; }
public ICollection<Comment> Comments { get; set; }
[Column("createdDate")] public DateTime? CreatedDate { get; set; }
[Column("doUseHtmlPlayer")] public bool? DoUseHtmlPlayer { get; set; }
[Column("email")]
[Required]
[StringLength(100)]
public override string Email { get; set; }
[Column("ftpDirectory")]
[StringLength(500)]
public string FtpDirectory { get; set; }
[Column("ftpPassword")]
[StringLength(500)]
public string FtpPassword { get; set; }
[Column("ftpUrl")] [StringLength(250)] public string FtpUrl { get; set; }
[Column("ftpUsername")]
[StringLength(50)]
public string FtpUsername { get; set; }
[Column("id")] [Key] public override int Id { get; set; }
[Column("isActive")] public bool? IsActive { get; set; }
[Column("isLocked")] public bool? IsLocked { get; set; }
[Column("isPrivate")] public bool? IsPrivate { get; set; }
/// <summary>
/// This is the last time a user access Roadie via an API (ie Subsonic or Plex or Apache)
/// </summary>
[Column("lastApiAccess")]
public DateTime? LastApiAccess { get; set; }
[Column("lastFMSessionKey")]
[StringLength(50)]
public string LastFMSessionKey { get; set; }
[Column("lastLogin")] public DateTime? LastLogin { get; set; }
[Column("lastUpdated")] public DateTime? LastUpdated { get; set; }
[Column("password")]
[Required]
[StringLength(100)]
public override string PasswordHash { get; set; }
[Column("playerTrackLimit")] public short? PlayerTrackLimit { get; set; }
public ICollection<Playlist> Playlists { get; set; }
[Column("profile", TypeName = "text")]
[StringLength(65535)]
public string Profile { get; set; }
[Column("randomReleaseLimit")] public short? RandomReleaseLimit { get; set; }
[Column("recentlyPlayedLimit")] public short? RecentlyPlayedLimit { get; set; }
[Column("registeredOn")] public DateTime? RegisteredOn { get; set; }
public ICollection<UserRelease> ReleaseRatings { get; set; }
[Column("removeTrackFromQueAfterPlayed")]
public bool? RemoveTrackFromQueAfterPlayed { get; set; }
public ICollection<Request> Requests { get; set; }
[Column("RoadieId")]
[StringLength(36)]
public Guid RoadieId { get; set; }
[Column("status")] public Statuses? Status { get; set; }
public ICollection<Submission> Submissions { get; set; }
[Column("timeformat")]
[StringLength(50)]
public string Timeformat { get; set; }
[Column("timezone")]
[StringLength(50)]
public string Timezone { get; set; }
[Column("defaultRowsPerPage")]
public short? DefaultRowsPerPage { get; set; }
public ICollection<UserTrack> TrackRatings { get; set; }
public ICollection<UserQue> UserQues { get; set; }
public ICollection<ApplicationUserRole> UserRoles { get; set; }
//public ICollection<ChatMessage> ChatMessages { get; set; }
//public ICollection<Collection> Collections { get; set; }
//public ICollection<Submission> Submission { get; set; }
}
}

View file

@ -1,11 +0,0 @@
using Microsoft.AspNetCore.Identity;
using System.ComponentModel.DataAnnotations.Schema;
namespace Roadie.Library.Identity
{
[Table("userClaims")]
public class ApplicationUserClaim : IdentityUserClaim<int>
{
public virtual ApplicationUser User { get; set; }
}
}

View file

@ -5,9 +5,9 @@ using Microsoft.EntityFrameworkCore;
namespace Roadie.Library.Identity
{
public class ApplicationUserDbContext : IdentityDbContext<
ApplicationUser, ApplicationRole, int,
ApplicationUserClaim, ApplicationUserRole, IdentityUserLogin<int>,
ApplicationRoleClaim, IdentityUserToken<int>>
User, UserRole, int,
UserClaims, UsersInRoles, IdentityUserLogin<int>,
UserRoleClaims, IdentityUserToken<int>>
{
public ApplicationUserDbContext(DbContextOptions<ApplicationUserDbContext> options)
: base(options)
@ -18,46 +18,59 @@ namespace Roadie.Library.Identity
{
base.OnModelCreating(builder);
builder.Entity<ApplicationUser>(b =>
// The tables are setup in RoadieDBContext but the table mappings below are necessary for IdentityDbContext to work.
builder.Entity<User>(entity =>
{
b.ToTable("user");
entity.ToTable("user");
// Each User can have many UserClaims
b.HasMany(e => e.Claims)
entity.HasMany(e => e.UserClaims)
.WithOne(e => e.User)
.HasForeignKey(uc => uc.UserId)
.HasForeignKey(uc => uc.Id)
.IsRequired();
// Each User can have many entries in the UserRole join table
b.HasMany(e => e.UserRoles)
entity.HasMany(e => e.UserRoles)
.WithOne(e => e.User)
.HasForeignKey(ur => ur.UserId)
.IsRequired();
});
builder.Entity<ApplicationRole>(b =>
builder.Entity<UserClaims>(entity =>
{
b.ToTable("userrole");
b.HasKey(ar => ar.Id);
entity.ToTable("userClaims");
});
builder.Entity<UserRoleClaims>(entity =>
{
entity.ToTable("userRoleClaims");
});
builder.Entity<UserRole>(entity =>
{
entity.ToTable("userrole");
entity.HasKey(ar => ar.Id);
// Each Role can have many entries in the UserRole join table
b.HasMany(e => e.UserRoles)
entity.HasMany(e => e.UserRoles)
.WithOne(e => e.Role)
.HasForeignKey(ur => ur.RoleId)
.IsRequired();
// Each Role can have many associated RoleClaims
b.HasMany(e => e.RoleClaims)
.WithOne(e => e.Role)
entity.HasMany(e => e.RoleClaims)
.WithOne(e => e.UserRole)
.HasForeignKey(rc => rc.RoleId)
.IsRequired();
});
builder.Entity<ApplicationUserClaim>(b => { b.ToTable("userClaims"); });
builder.Entity<ApplicationUserRole>(b => { b.ToTable("usersInRoles"); });
builder.Entity<ApplicationRoleClaim>(b => { b.ToTable("userRoleClaims"); });
builder.Entity<UsersInRoles>(entity =>
{
entity.ToTable("usersInRoles");
});
}
}
}

View file

@ -1,18 +0,0 @@
using Microsoft.AspNetCore.Identity;
using System.ComponentModel.DataAnnotations.Schema;
namespace Roadie.Library.Identity
{
[Table("usersInRoles")]
public class ApplicationUserRole : IdentityUserRole<int>
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public virtual ApplicationRole Role { get; set; }
[Column("userRoleId")] public override int RoleId { get; set; }
public virtual ApplicationUser User { get; set; }
}
}

View file

@ -0,0 +1,168 @@
using Microsoft.AspNetCore.Identity;
using Roadie.Library.Data;
using Roadie.Library.Enums;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Roadie.Library.Identity
{
/// <summary>
/// Application User for Identity
/// <remarks>
/// As this is used by UserManager to get for each request in API *do not* lazy load properties as the object
/// is too heavy and requires multiple DB hits to poplate - which is data not needed to authenticate a user.
/// </remarks>
/// </summary>
[Table("user")]
public partial class User : IdentityUser<int>
{
[Column("id")]
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public override int Id { get; set; }
[Column("apiToken")]
[StringLength(100)]
public string ApiToken { get; set; }
[InverseProperty("User")]
public virtual ICollection<UserArtist> ArtistRatings { get; set; }
[InverseProperty("User")]
public virtual ICollection<Bookmark> Bookmarks { get; set; }
[InverseProperty("User")]
public virtual ICollection<ChatMessage> ChatMessages { get; set; }
[InverseProperty("User")]
public virtual ICollection<UserClaims> UserClaims { get; set; }
[InverseProperty("Maintainer")]
public virtual ICollection<Collection> Collections { get; set; }
[InverseProperty("User")]
public virtual ICollection<Comment> Comments { get; set; }
[InverseProperty("User")]
public virtual ICollection<Data.CommentReaction> CommentReactions { get; set; }
[Column("createdDate")]
public DateTime? CreatedDate { get; set; }
[Column("doUseHtmlPlayer")]
public bool? DoUseHtmlPlayer { get; set; }
[Column("email")]
[Required]
[StringLength(100)]
public override string Email { get; set; }
[Column("ftpDirectory")]
[StringLength(500)]
public string FtpDirectory { get; set; }
[Column("ftpPassword")]
[StringLength(500)]
public string FtpPassword { get; set; }
[Column("ftpUrl")]
[StringLength(250)]
public string FtpUrl { get; set; }
[Column("ftpUsername")]
[StringLength(50)]
public string FtpUsername { get; set; }
[Column("isActive")]
public bool? IsActive { get; set; }
[Column("isLocked")]
public bool? IsLocked { get; set; }
[Column("isPrivate")]
public bool? IsPrivate { get; set; }
/// <summary>
/// This is the last time a user access Roadie via an API (ie Subsonic or Plex or Apache)
/// </summary>
[Column("lastApiAccess")]
public DateTime? LastApiAccess { get; set; }
[Column("lastFMSessionKey")]
[StringLength(50)]
public string LastFMSessionKey { get; set; }
[Column("lastLogin")]
public DateTime? LastLogin { get; set; }
[Column("lastUpdated")]
public DateTime? LastUpdated { get; set; }
[Column("password")]
[Required]
[StringLength(100)]
public override string PasswordHash { get; set; }
[Column("playerTrackLimit")]
public short? PlayerTrackLimit { get; set; }
public virtual ICollection<Playlist> Playlists { get; set; }
[Column("profile", TypeName = "text")]
[StringLength(65535)]
public string Profile { get; set; }
[Column("randomReleaseLimit")]
public short? RandomReleaseLimit { get; set; }
[Column("recentlyPlayedLimit")]
public short? RecentlyPlayedLimit { get; set; }
[Column("registeredOn")]
public DateTime? RegisteredOn { get; set; }
[InverseProperty("User")]
public virtual ICollection<UserRelease> UserReleases { get; set; }
[Column("removeTrackFromQueAfterPlayed")]
public bool? RemoveTrackFromQueAfterPlayed { get; set; }
[InverseProperty("CreatedByUser")]
public virtual ICollection<InviteToken> InviteTokens { get; set; }
[InverseProperty("User")]
public virtual ICollection<Request> Requests { get; set; }
[Column("RoadieId")]
[StringLength(36)]
public Guid RoadieId { get; set; }
[Column("status")]
public Statuses? Status { get; set; }
[InverseProperty("User")]
public virtual ICollection<Submission> Submissions { get; set; }
[Column("timeformat")]
[StringLength(50)]
public string Timeformat { get; set; }
[Column("timezone")]
[StringLength(50)]
public string Timezone { get; set; }
[Column("defaultRowsPerPage")]
public short? DefaultRowsPerPage { get; set; }
[InverseProperty("User")]
public virtual ICollection<UserTrack> UserTracks { get; set; }
[InverseProperty("User")]
public virtual ICollection<UserQue> UserQues { get; set; }
[InverseProperty("User")]
public virtual ICollection<UsersInRoles> UserRoles { get; set; }
}
}

View file

@ -0,0 +1,33 @@
using Microsoft.AspNetCore.Identity;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Roadie.Library.Identity
{
[Table("userClaims")]
public class UserClaims : IdentityUserClaim<int>
{
[Column("id")]
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public override int Id { get; set; }
[Required]
[Column("userId")]
public override int UserId { get; set; }
[Required]
[Column("claimType")]
[StringLength(200)]
public override string ClaimType { get; set; }
[Required]
[Column("claimValue")]
[StringLength(200)]
public override string ClaimValue { get; set; }
[ForeignKey(nameof(UserId))]
[InverseProperty("UserClaims")]
public virtual User User { get; set; }
}
}

View file

@ -4,12 +4,11 @@ using Roadie.Library.Enums;
using Roadie.Library.Extensions;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
namespace Roadie.Library.Identity
{
public partial class ApplicationUser
public partial class User
{
public string CacheKey => CacheUrn(RoadieId);
@ -30,7 +29,7 @@ namespace Roadie.Library.Identity
return Path.Combine(folder, $"{ UserName.ToFileNameFriendly() } [{ Id }].gif");
}
public ApplicationUser()
public User()
{
RoadieId = Guid.NewGuid();
Status = Statuses.Ok;
@ -45,16 +44,20 @@ namespace Roadie.Library.Identity
RecentlyPlayedLimit = 20;
RandomReleaseLimit = 20;
// Collections = new HashSet<Collection>();
ArtistRatings = new HashSet<UserArtist>();
Bookmarks = new HashSet<Bookmark>();
Collections = new HashSet<Collection>();
Comments = new HashSet<Comment>();
Playlists = new HashSet<Playlist>();
UserRoles = new HashSet<ApplicationUserRole>();
CommentReactions = new HashSet<Data.CommentReaction>();
InviteTokens = new HashSet<InviteToken>();
UserReleases = new HashSet<UserRelease>();
Requests = new HashSet<Request>();
Submissions = new HashSet<Submission>();
UserTracks = new HashSet<UserTrack>();
UserClaims = new HashSet<UserClaims>();
UserQues = new HashSet<UserQue>();
ArtistRatings = new HashSet<UserArtist>();
ReleaseRatings = new HashSet<UserRelease>();
TrackRatings = new HashSet<UserTrack>();
Comments = new HashSet<Comment>();
UserRoles = new HashSet<UsersInRoles>();
}
public static string CacheRegionUrn(Guid Id)

View file

@ -0,0 +1,51 @@
using Microsoft.AspNetCore.Identity;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Roadie.Library.Identity
{
/// <summary>
/// Definition of a User Role
/// </summary>
[Table("userrole")]
public class UserRole : IdentityRole<int>
{
[Column("id")]
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public override int Id { get; set; }
[Column("createdDate")]
public DateTime? CreatedDate { get; set; }
[Column("description")]
[StringLength(200)]
public string Description { get; set; }
[Column("isLocked")]
public bool? IsLocked { get; set; }
[Column("lastUpdated")]
public DateTime? LastUpdated { get; set; }
[Column("name")]
[Required]
[StringLength(80)]
public override string Name { get; set; }
[Column("RoadieId")]
[StringLength(36)]
public string RoadieId { get; set; }
[InverseProperty("UserRole")]
public virtual ICollection<UserRoleClaims> RoleClaims { get; set; }
[Column("status")]
public short? Status { get; set; }
[InverseProperty("Role")]
public virtual ICollection<UsersInRoles> UserRoles { get; set; }
}
}

View file

@ -0,0 +1,30 @@
using Microsoft.AspNetCore.Identity;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Roadie.Library.Identity
{
[Table("userRoleClaims")]
public class UserRoleClaims : IdentityRoleClaim<int>
{
[Key]
[Column("id")]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public override int Id { get; set; }
[Column("userRoleId")]
public override int RoleId { get; set; }
[Required]
[Column("claimType", TypeName = "varchar(200)")]
public new string ClaimType { get; set; }
[Required]
[Column("claimValue", TypeName = "varchar(200)")]
public new string ClaimValue { get; set; }
[ForeignKey(nameof(RoleId))]
[InverseProperty("RoleClaims")]
public virtual UserRole UserRole { get; set; }
}
}

View file

@ -0,0 +1,34 @@
using Microsoft.AspNetCore.Identity;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Roadie.Library.Identity
{
/// <summary>
/// Users In Roles
/// </summary>
[Table("usersInRoles")]
public class UsersInRoles : IdentityUserRole<int>
{
[Column("id")]
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[ForeignKey(nameof(RoleId))]
[InverseProperty("UserRoles")]
public virtual UserRole Role { get; set; }
[Column("userRoleId")]
[Required]
public override int RoleId { get; set; }
[ForeignKey(nameof(UserId))]
[InverseProperty("UserRoles")]
public virtual User User { get; set; }
[Column("userId")]
[Required]
public override int UserId { get; set; }
}
}

View file

@ -1,5 +1,6 @@
using Roadie.Library.Enums;
using System;
using System.Diagnostics;
using System.Linq;
namespace Roadie.Library.Imaging
@ -25,7 +26,15 @@ namespace Roadie.Library.Imaging
{
return null;
}
return ImageHasher.AverageHash(Bytes).ToString();
try
{
return ImageHasher.AverageHash(Bytes).ToString();
}
catch (Exception ex)
{
Trace.WriteLine($"Error Generating Signature Ex [{ ex }]", "Warning");
}
return null;
}
public Image()

View file

@ -49,7 +49,7 @@ namespace Roadie.Library.Imaging
}
catch (Exception ex)
{
Trace.WriteLine($"Error Converting Image to Jpg [{ ex.Message }]");
Trace.WriteLine($"Error Converting Image to Jpg [{ ex.Message }]", "Warning");
}
return null;
}
@ -74,7 +74,7 @@ namespace Roadie.Library.Imaging
}
catch (Exception ex)
{
Trace.WriteLine($"Error Converting Image to Gif [{ ex.Message }]");
Trace.WriteLine($"Error Converting Image to Gif [{ ex.Message }]", "Warning");
}
return null;
}
@ -293,7 +293,7 @@ namespace Roadie.Library.Imaging
}
catch (Exception ex)
{
Trace.WriteLine($"Error Resizing Image [{ex}]");
Trace.WriteLine($"Error Resizing Image [{ex}]", "Warning");
}
return null;
}
@ -312,7 +312,7 @@ namespace Roadie.Library.Imaging
var result = ImageHelper.ResizeImage(ImageHelper.ConvertToJpegFormat(imageBytes), width, height, true)?.Item2;
if (result?.Length >= ImageHelper.MaximumThumbnailByteSize)
{
Trace.WriteLine($"Thumbnail larger than maximum size after resizing to [{configuration.ThumbnailImageSize.Width}x{configuration.ThumbnailImageSize.Height}] Thumbnail Size [{result.Length}]");
Trace.WriteLine($"Thumbnail larger than maximum size after resizing to [{configuration.ThumbnailImageSize.Width}x{configuration.ThumbnailImageSize.Height}] Thumbnail Size [{result.Length}]", "Warning");
result = new byte[0];
}
return result;

View file

@ -86,7 +86,7 @@ namespace Roadie.Library.Models
[MaxLength(65535)] public string Profile { get; set; }
public decimal? Rank { get; set; }
public double? Rank { get; set; }
/// <summary>
/// The Position of this Artist as ranked against other Artists (highest ranking Artist is #1)

View file

@ -1,5 +1,6 @@
using Roadie.Library.Enums;
using Roadie.Library.Models.Users;
using Roadie.Library.Utility;
using System;
using System.Collections.Generic;
using System.Diagnostics;
@ -15,7 +16,7 @@ namespace Roadie.Library.Models
public DateTime? LastPlayed { get; set; }
public IEnumerable<string> MissingReleasesForCollection { get; set; }
public int? PlayedCount { get; set; }
public decimal? Rank { get; set; }
public double? Rank { get; set; }
public short? Rating { get; set; }
public int? ReleaseCount { get; set; }
public Image Thumbnail { get; set; }
@ -37,7 +38,7 @@ namespace Roadie.Library.Models
},
Thumbnail = thumbnail,
Rating = artist.Rating,
Rank = artist.Rank,
Rank = SafeParser.ToNumber<double?>(artist.Rank),
CreatedDate = artist.CreatedDate,
LastUpdated = artist.LastUpdated,
LastPlayed = artist.LastPlayed,

View file

@ -19,7 +19,10 @@ namespace Roadie.Library.Models.Playlists
{
get
{
if (!Duration.HasValue) return "--:--";
if (!Duration.HasValue)
{
return "--:--";
}
return new TimeInfo(Duration.Value).ToFullFormattedString();
}
}

View file

@ -26,7 +26,7 @@ namespace Roadie.Library.Models.Playlists
public DataToken User { get; set; }
public Image UserThumbnail { get; set; }
public static PlaylistList FromDataPlaylist(Data.Playlist playlist, ApplicationUser user, Image playlistThumbnail, Image userThumbnail)
public static PlaylistList FromDataPlaylist(Data.Playlist playlist, User user, Image playlistThumbnail, Image userThumbnail)
{
return new PlaylistList
{

View file

@ -58,7 +58,7 @@ namespace Roadie.Library.Models.Releases
[MaxLength(65535)] public string Profile { get; set; }
public decimal? Rank { get; set; }
public double? Rank { get; set; }
/// <summary>
/// The Position of this Release as ranked against other Releases (highest ranking Release is #1)

View file

@ -50,7 +50,7 @@ namespace Roadie.Library.Models.Releases
public IEnumerable<ReleaseMediaList> Media { get; set; }
public int? MediaCount { get; set; }
public decimal? Rank { get; set; }
public double? Rank { get; set; }
public short? Rating { get; set; }
public DataToken Release { get; set; }
@ -98,7 +98,7 @@ namespace Roadie.Library.Models.Releases
LibraryStatus = release.LibraryStatus,
MediaCount = release.MediaCount,
Rating = release.Rating,
Rank = release.Rank,
Rank = SafeParser.ToNumber<double?>(release.Rank),
ReleaseDateDateTime = release.ReleaseDate,
ReleasePlayUrl = $"{baseUrl}/play/release/{release.RoadieId}",
Status = release.Status,

View file

@ -4,6 +4,6 @@ namespace Roadie.Library.Models.ThirdPartyApi.Subsonic
{
public class SubsonicAuthenticateResponse : Response
{
public ApplicationUser User { get; set; }
public Identity.User SubsonicUser { get; set; }
}
}

View file

@ -20,7 +20,7 @@ namespace Roadie.Library.Models.Users
public Image Thumbnail { get; set; }
public DataToken User { get; set; }
public static UserList FromDataUser(ApplicationUser user, Image thumbnail)
public static UserList FromDataUser(Identity.User user, Image thumbnail)
{
return new UserList
{

View file

@ -13,7 +13,7 @@
<PackageReference Include="EFCore.BulkExtensions" Version="3.0.3" />
<PackageReference Include="FluentFTP" Version="28.0.2" />
<PackageReference Include="Hashids.net" Version="1.3.0" />
<PackageReference Include="HtmlAgilityPack" Version="1.11.16" />
<PackageReference Include="HtmlAgilityPack" Version="1.11.17" />
<PackageReference Include="IdSharp.Common" Version="1.0.1" />
<PackageReference Include="IdSharp.Tagging" Version="1.0.0-rc3" />
<PackageReference Include="Inflatable.Lastfm" Version="1.1.0.339" />
@ -22,13 +22,13 @@
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="3.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="3.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="3.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="3.0.1" />
<PackageReference Include="Microsoft.Extensions.Caching.Redis" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.0.1" />
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="1.3.0" />
<PackageReference Include="Microsoft.Net.Http.Headers" Version="2.2.8" />
<PackageReference Include="Microsoft.PowerShell.SDK" Version="6.2.3" />
<PackageReference Include="MimeMapping" Version="1.0.1.17" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="NodaTime" Version="2.4.7" />
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="3.0.0" />
<PackageReference Include="RestSharp" Version="106.6.10" />
@ -39,7 +39,7 @@
<PackageReference Include="System.Drawing.Common" Version="4.6.1" />
<PackageReference Include="System.IO.FileSystem.AccessControl" Version="4.6.0" />
<PackageReference Include="System.Runtime.Caching" Version="4.6.0" />
<PackageReference Include="z440.atl.core" Version="2.13.0" />
<PackageReference Include="z440.atl.core" Version="2.14.0" />
<PackageReference Include="zlib.net-mutliplatform" Version="1.0.4" />
</ItemGroup>

View file

@ -63,13 +63,13 @@ namespace Roadie.Library.MetaData.MusicBrainz
var response = ex.Response as HttpWebResponse;
if(response?.StatusCode == HttpStatusCode.NotFound)
{
Trace.WriteLine($"GetAsync: 404 Response For url [{ url }]");
Trace.WriteLine($"GetAsync: 404 Response For url [{ url }]", "Warning");
return result;
}
}
catch (Exception ex)
{
Trace.WriteLine($"GetAsync: [{ ex.ToString() }]");
Trace.WriteLine($"GetAsync: [{ ex.ToString() }]", "Warning");
Thread.Sleep(100);
}
finally

View file

@ -33,7 +33,7 @@ namespace Roadie.Library.Utility
}
catch (Exception ex)
{
Trace.WriteLine($"Error Reading Cue [{ cueFilename }] [{ ex }]");
Trace.WriteLine($"Error Reading Cue [{ cueFilename }] [{ ex }]", "Error");
}
return results;
}
@ -70,7 +70,7 @@ namespace Roadie.Library.Utility
}
catch (Exception ex)
{
Trace.WriteLine($"Error Reading Sfv [{ sfvFilename }] [{ ex }]");
Trace.WriteLine($"Error Reading Sfv [{ sfvFilename }] [{ ex }]", "Error");
}
return results;
}
@ -101,7 +101,7 @@ namespace Roadie.Library.Utility
}
catch (Exception ex)
{
Trace.WriteLine($"Error Reading Cue [{ m3uFilename }] [{ ex }]");
Trace.WriteLine($"Error Reading Cue [{ m3uFilename }] [{ ex }]", "Error");
}
return results;
}

View file

@ -169,18 +169,6 @@ namespace Roadie.Library.Utility
return directoryInfo.FullName;
}
[Obsolete("This is only here for migration will be removed in future release.")]
public static string ArtistPathOld(IRoadieSettings configuration, string artistSortName)
{
SimpleContract.Requires<ArgumentException>(!string.IsNullOrEmpty(artistSortName),"Invalid Artist Sort Name");
var artistFolder = artistSortName.ToTitleCase(false);
var directoryInfo = new DirectoryInfo(Path.Combine(configuration.LibraryFolder, artistFolder.ToFolderNameFriendly()));
return directoryInfo.FullName;
}
/// <summary>
/// Full path to Release folder using given full Artist folder
/// </summary>
@ -222,17 +210,6 @@ namespace Roadie.Library.Utility
return directoryInfo.FullName;
}
[Obsolete("This is only here for migration will be removed in future release.")]
public static string ReleasePathOld(string artistFolder, string releaseTitle, DateTime releaseDate)
{
SimpleContract.Requires<ArgumentException>(!string.IsNullOrEmpty(artistFolder), "Invalid Artist Folder");
SimpleContract.Requires<ArgumentException>(!string.IsNullOrEmpty(releaseTitle), "Invalid Release Title");
SimpleContract.Requires<ArgumentException>(releaseDate != DateTime.MinValue, "Invalid Release Date");
var directoryInfo = new DirectoryInfo(Path.Combine(artistFolder, string.Format("{1}{0}", releaseTitle.ToTitleCase(false).ToFolderNameFriendly(), string.Format("[{0}] ", releaseDate.ToString("yyyy")))));
return directoryInfo.FullName;
}
/// <summary>
/// Delete any empty folders in the given folder
/// </summary>
@ -260,7 +237,7 @@ namespace Roadie.Library.Utility
if (!folder.GetFiles("*.*", SearchOption.AllDirectories).Any())
{
folder.Delete(true);
Trace.WriteLine($"Deleting Empty Folder [{folder.FullName}]", "Debug");
Trace.WriteLine($"Deleting Empty Folder [{folder.FullName}]", "Warning");
result = true;
}
}
@ -268,24 +245,24 @@ namespace Roadie.Library.Utility
catch (UnauthorizedAccessException)
{
result = false;
Trace.WriteLine($"UnauthorizedAccessException Deleting Empty Folder [{folder.FullName}]", "Debug");
Trace.WriteLine($"UnauthorizedAccessException Deleting Empty Folder [{folder.FullName}]", "Warning");
}
catch (DirectoryNotFoundException)
{
result = false;
Trace.WriteLine($"DirectoryNotFoundException Deleting Empty Folder [{folder.FullName}]", "Debug");
Trace.WriteLine($"DirectoryNotFoundException Deleting Empty Folder [{folder.FullName}]", "Warning");
}
}
}
catch (UnauthorizedAccessException)
{
result = false;
Trace.WriteLine($"UnauthorizedAccessException Deleting Empty Folder [{processingFolder.FullName}]", "Debug");
Trace.WriteLine($"UnauthorizedAccessException Deleting Empty Folder [{processingFolder.FullName}]", "Warning");
}
catch (DirectoryNotFoundException)
{
result = false;
Trace.WriteLine($"DirectoryNotFoundException Deleting Empty Folder [{processingFolder.FullName}]", "Debug");
Trace.WriteLine($"DirectoryNotFoundException Deleting Empty Folder [{processingFolder.FullName}]", "Warning");
}
return result;
}

View file

@ -52,7 +52,7 @@ namespace Roadie.Library.Utility
}
catch (Exception ex)
{
Trace.WriteLine(string.Format("Error with url [{0}] Exception [{1}]", url, ex));
Trace.WriteLine(string.Format("Error with url [{0}] Exception [{1}]", url, ex), "Warning");
}
return null;
@ -90,7 +90,7 @@ namespace Roadie.Library.Utility
}
catch (Exception ex)
{
Trace.WriteLine($"GetImageFromUrlAsync Url [{ url }], Exception [{ ex.ToString() }");
Trace.WriteLine($"GetImageFromUrlAsync Url [{ url }], Exception [{ ex.ToString() }", "Warning");
}
return null;
}
@ -104,7 +104,7 @@ namespace Roadie.Library.Utility
}
catch (Exception ex)
{
Trace.WriteLine(ex.ToString());
Trace.WriteLine(ex.ToString(), "Error");
}
return false;

View file

@ -1,4 +1,5 @@
using Microsoft.AspNetCore.Identity;
using Mapster;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.SignalR;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
@ -40,6 +41,7 @@ namespace Roadie.Api.Services
private ILabelService LabelService { get; }
private IArtistLookupEngine ArtistLookupEngine { get; }
private IReleaseLookupEngine ReleaseLookupEngine { get; }
private IBookmarkService BookmarkService { get; }
private IReleaseService ReleaseService { get; }
@ -47,7 +49,7 @@ namespace Roadie.Api.Services
IRoadieDbContext context, ICacheManager cacheManager, ILogger<ArtistService> logger,
IHubContext<ScanActivityHub> scanActivityHub, IFileDirectoryProcessorService fileDirectoryProcessorService, IArtistService artistService,
IReleaseService releaseService, IArtistLookupEngine artistLookupEngine, IReleaseLookupEngine releaseLookupEngine,
ILabelService labelService, IGenreService genreService
ILabelService labelService, IGenreService genreService, IBookmarkService bookmarkService
)
: base(configuration, httpEncoder, context, cacheManager, logger, httpContext)
{
@ -62,9 +64,10 @@ namespace Roadie.Api.Services
ArtistLookupEngine = artistLookupEngine;
ReleaseLookupEngine = releaseLookupEngine;
FileDirectoryProcessorService = fileDirectoryProcessorService;
BookmarkService = bookmarkService;
}
public async Task<OperationResult<bool>> DeleteArtist(ApplicationUser user, Guid artistId, bool deleteFolder)
public async Task<OperationResult<bool>> DeleteArtist(User user, Guid artistId, bool deleteFolder)
{
var sw = new Stopwatch();
sw.Start();
@ -105,7 +108,7 @@ namespace Roadie.Api.Services
};
}
public async Task<OperationResult<bool>> DeleteArtistReleases(ApplicationUser user, Guid artistId, bool doDeleteFiles = false)
public async Task<OperationResult<bool>> DeleteArtistReleases(User user, Guid artistId, bool doDeleteFiles = false)
{
var sw = new Stopwatch();
sw.Start();
@ -140,7 +143,7 @@ namespace Roadie.Api.Services
};
}
public async Task<OperationResult<bool>> DeleteArtistSecondaryImage(ApplicationUser user, Guid artistId, int index)
public async Task<OperationResult<bool>> DeleteArtistSecondaryImage(User user, Guid artistId, int index)
{
var sw = new Stopwatch();
sw.Start();
@ -181,7 +184,7 @@ namespace Roadie.Api.Services
};
}
public async Task<OperationResult<bool>> DeleteGenre(ApplicationUser user, Guid genreId)
public async Task<OperationResult<bool>> DeleteGenre(User user, Guid genreId)
{
var sw = new Stopwatch();
sw.Start();
@ -205,7 +208,7 @@ namespace Roadie.Api.Services
errors.Add(ex);
}
sw.Stop();
sw.Stop();
await LogAndPublish($"DeleteGenre `{genre}`, By User `{user}`", LogLevel.Information);
return new OperationResult<bool>
{
@ -216,7 +219,7 @@ namespace Roadie.Api.Services
};
}
public async Task<OperationResult<bool>> DeleteLabel(ApplicationUser user, Guid labelId)
public async Task<OperationResult<bool>> DeleteLabel(User user, Guid labelId)
{
var sw = new Stopwatch();
sw.Start();
@ -251,7 +254,7 @@ namespace Roadie.Api.Services
};
}
public async Task<OperationResult<bool>> DeleteRelease(ApplicationUser user, Guid releaseId, bool? doDeleteFiles)
public async Task<OperationResult<bool>> DeleteRelease(User user, Guid releaseId, bool? doDeleteFiles)
{
var sw = new Stopwatch();
sw.Start();
@ -266,7 +269,6 @@ namespace Roadie.Api.Services
await LogAndPublish($"DeleteRelease Unknown Release [{releaseId}]", LogLevel.Warning);
return new OperationResult<bool>(true, $"Release Not Found [{releaseId}]");
}
await ReleaseService.Delete(user, release, doDeleteFiles ?? false);
}
catch (Exception ex)
@ -288,7 +290,7 @@ namespace Roadie.Api.Services
};
}
public async Task<OperationResult<bool>> DeleteReleaseSecondaryImage(ApplicationUser user, Guid releaseId, int index)
public async Task<OperationResult<bool>> DeleteReleaseSecondaryImage(User user, Guid releaseId, int index)
{
var sw = new Stopwatch();
sw.Start();
@ -329,7 +331,7 @@ namespace Roadie.Api.Services
};
}
public async Task<OperationResult<bool>> DeleteTracks(ApplicationUser user, IEnumerable<Guid> trackIds, bool? doDeleteFile)
public async Task<OperationResult<bool>> DeleteTracks(User user, IEnumerable<Guid> trackIds, bool? doDeleteFile)
{
var sw = new Stopwatch();
sw.Start();
@ -376,8 +378,8 @@ namespace Roadie.Api.Services
Logger.LogError(ex, string.Format("Error Deleting File [{0}] For Track [{1}] Exception [{2}]", trackPath, track.Id, ex.Serialize()));
}
}
await ReleaseService.ScanReleaseFolder(user, track.ReleaseMedia.Release.RoadieId, false, track.ReleaseMedia.Release);
await BookmarkService.RemoveAllBookmarksForItem(BookmarkType.Track, track.Id);
}
catch (Exception ex)
{
@ -399,7 +401,7 @@ namespace Roadie.Api.Services
};
}
public async Task<OperationResult<bool>> DeleteUser(ApplicationUser applicationUser, Guid userId)
public async Task<OperationResult<bool>> DeleteUser(User applicationUser, Guid userId)
{
var sw = new Stopwatch();
sw.Start();
@ -452,20 +454,31 @@ namespace Roadie.Api.Services
/// <summary>
/// This is a very simple way to seed the database or setup configuration when the first (who becomes "Admin") user registers
/// </summary>
public async Task<OperationResult<bool>> DoInitialSetup(ApplicationUser user, UserManager<ApplicationUser> userManager)
public async Task<OperationResult<bool>> DoInitialSetup(User user, UserManager<User> userManager)
{
var sw = new Stopwatch();
sw.Start();
// Create user roles
DbContext.UserRoles.Add(new ApplicationRole
DbContext.UserRoles.Add(new UserRole
{
Id = 1,
Status = (short)Statuses.Ok,
CreatedDate = DateTime.UtcNow,
IsLocked = false,
RoadieId = Guid.NewGuid().ToString(),
Name = "Admin",
Description = "Users with Administrative (full) access",
NormalizedName = "ADMIN"
});
DbContext.UserRoles.Add(new ApplicationRole
DbContext.UserRoles.Add(new UserRole
{
Id = 2,
Status = (short)Statuses.Ok,
CreatedDate = DateTime.UtcNow,
IsLocked = false,
RoadieId = Guid.NewGuid().ToString(),
Name = "Editor",
Description = "Users who have Edit Permissions",
NormalizedName = "EDITOR"
@ -512,7 +525,7 @@ namespace Roadie.Api.Services
};
}
public Task<OperationResult<Dictionary<string, List<string>>>> MissingCollectionReleases(ApplicationUser user)
public Task<OperationResult<Dictionary<string, List<string>>>> MissingCollectionReleases(User user)
{
var sw = Stopwatch.StartNew();
sw.Start();
@ -606,6 +619,14 @@ namespace Roadie.Api.Services
Directory.CreateDirectory(Configuration.LabelImageFolder);
Logger.LogInformation($"Created Label Image Folder [{Configuration.LabelImageFolder}]");
}
if (Configuration.DbContextToUse != DbContexts.MySQL)
{
if (!Directory.Exists(Configuration.FileDatabaseOptions.DatabaseFolder))
{
Directory.CreateDirectory(Configuration.FileDatabaseOptions.DatabaseFolder);
Logger.LogInformation($"Created File Database Folder [{Configuration.FileDatabaseOptions.DatabaseFolder}]");
}
}
}
catch (Exception ex)
{
@ -619,14 +640,14 @@ namespace Roadie.Api.Services
Logger.LogInformation($"Administration startup tasks completed, elapsed time [{ sw.ElapsedMilliseconds }]");
}
public async Task<OperationResult<bool>> ScanAllCollections(ApplicationUser user, bool isReadOnly = false,
public async Task<OperationResult<bool>> ScanAllCollections(User user, bool isReadOnly = false,
bool doPurgeFirst = false)
{
var sw = new Stopwatch();
sw.Start();
var errors = new List<Exception>();
var collections = DbContext.Collections.Where(x => x.IsLocked == false).ToArray();
var collections = await DbContext.Collections.Where(x => x.IsLocked == false).ToArrayAsync();
var updatedReleaseIds = new List<int>();
foreach (var collection in collections)
try
@ -659,7 +680,7 @@ namespace Roadie.Api.Services
};
}
public async Task<OperationResult<bool>> ScanArtist(ApplicationUser user, Guid artistId, bool isReadOnly = false)
public async Task<OperationResult<bool>> ScanArtist(User user, Guid artistId, bool isReadOnly = false)
{
var sw = Stopwatch.StartNew();
@ -702,7 +723,7 @@ namespace Roadie.Api.Services
};
}
public async Task<OperationResult<bool>> ScanArtists(ApplicationUser user, IEnumerable<Guid> artistIds, bool isReadOnly = false)
public async Task<OperationResult<bool>> ScanArtists(User user, IEnumerable<Guid> artistIds, bool isReadOnly = false)
{
var sw = Stopwatch.StartNew();
@ -728,7 +749,7 @@ namespace Roadie.Api.Services
};
}
public async Task<OperationResult<bool>> ScanCollection(ApplicationUser user, Guid collectionId, bool isReadOnly = false, bool doPurgeFirst = false, bool doUpdateRanks = true)
public async Task<OperationResult<bool>> ScanCollection(User user, Guid collectionId, bool isReadOnly = false, bool doPurgeFirst = false, bool doUpdateRanks = true)
{
var sw = new Stopwatch();
sw.Start();
@ -749,7 +770,7 @@ namespace Roadie.Api.Services
if (doPurgeFirst)
{
await LogAndPublish($"ScanCollection Purging Collection [{collectionId}]", LogLevel.Warning);
var crs = DbContext.CollectionReleases.Where(x => x.CollectionId == collection.Id).ToArray();
var crs = await DbContext.CollectionReleases.Where(x => x.CollectionId == collection.Id).ToArrayAsync();
DbContext.CollectionReleases.RemoveRange(crs);
await DbContext.SaveChangesAsync();
}
@ -907,19 +928,19 @@ namespace Roadie.Api.Services
};
}
public async Task<OperationResult<bool>> ScanInboundFolder(ApplicationUser user, bool isReadOnly = false)
public async Task<OperationResult<bool>> ScanInboundFolder(User user, bool isReadOnly = false)
{
var d = new DirectoryInfo(Configuration.InboundFolder);
return await ScanFolder(user, d, isReadOnly);
}
public async Task<OperationResult<bool>> ScanLibraryFolder(ApplicationUser user, bool isReadOnly = false)
public async Task<OperationResult<bool>> ScanLibraryFolder(User user, bool isReadOnly = false)
{
var d = new DirectoryInfo(Configuration.LibraryFolder);
return await ScanFolder(user, d, isReadOnly, false);
}
public async Task<OperationResult<bool>> ScanRelease(ApplicationUser user, Guid releaseId, bool isReadOnly = false, bool wasDoneForInvalidTrackPlay = false)
public async Task<OperationResult<bool>> ScanRelease(User user, Guid releaseId, bool isReadOnly = false, bool wasDoneForInvalidTrackPlay = false)
{
var sw = new Stopwatch();
sw.Start();
@ -964,7 +985,7 @@ namespace Roadie.Api.Services
};
}
public async Task<OperationResult<bool>> ScanReleases(ApplicationUser user, IEnumerable<Guid> releaseIds, bool isReadOnly = false, bool wasDoneForInvalidTrackPlay = false)
public async Task<OperationResult<bool>> ScanReleases(User user, IEnumerable<Guid> releaseIds, bool isReadOnly = false, bool wasDoneForInvalidTrackPlay = false)
{
var sw = Stopwatch.StartNew();
@ -1080,7 +1101,7 @@ namespace Roadie.Api.Services
await ScanActivityHub.Clients.All.SendAsync("SendSystemActivity", message);
}
private async Task<OperationResult<bool>> ScanFolder(ApplicationUser user, DirectoryInfo d, bool isReadOnly, bool doDeleteFiles = true)
private async Task<OperationResult<bool>> ScanFolder(User user, DirectoryInfo d, bool isReadOnly, bool doDeleteFiles = true)
{
var sw = new Stopwatch();
sw.Start();

View file

@ -71,7 +71,7 @@ namespace Roadie.Api.Services
FileDirectoryProcessorService = fileDirectoryProcessorService;
}
public async Task<OperationResult<Artist>> ById(User roadieUser, Guid id, IEnumerable<string> includes)
public async Task<OperationResult<Artist>> ById(Library.Models.Users.User roadieUser, Guid id, IEnumerable<string> includes)
{
var timings = new Dictionary<string, long>();
var tsw = new Stopwatch();
@ -94,11 +94,10 @@ namespace Roadie.Api.Services
tsw.Stop();
timings.Add("getArtist", tsw.ElapsedMilliseconds);
tsw.Restart();
var userBookmarkResult =
await BookmarkService.List(roadieUser, new PagedRequest(), false, BookmarkType.Artist);
var userBookmarkResult = await BookmarkService.List(roadieUser, new PagedRequest(), false, BookmarkType.Artist);
if (userBookmarkResult.IsSuccess)
{
result.Data.UserBookmarked = userBookmarkResult?.Rows?.FirstOrDefault(x => x.Bookmark.Value == artist.RoadieId.ToString()) != null;
result.Data.UserBookmarked = userBookmarkResult?.Rows?.FirstOrDefault(x => x?.Bookmark?.Value == artist?.RoadieId.ToString()) != null;
}
tsw.Stop();
timings.Add("userBookmarkResult", tsw.ElapsedMilliseconds);
@ -148,7 +147,7 @@ namespace Roadie.Api.Services
};
}
public async Task<OperationResult<bool>> Delete(ApplicationUser user, data.Artist artist, bool deleteFolder)
public async Task<OperationResult<bool>> Delete(Library.Identity.User user, data.Artist artist, bool deleteFolder)
{
var isSuccess = false;
try
@ -159,9 +158,25 @@ namespace Roadie.Api.Services
await DbContext.SaveChangesAsync();
if(deleteFolder)
{
// Delete all image files for Artist
foreach (var file in ImageHelper.ImageFilesInFolder(artist.ArtistFileFolder(Configuration), SearchOption.TopDirectoryOnly))
{
try
{
File.Delete(file);
Logger.LogWarning("For Artist [{0}], Deleted File [{1}]", artist.Id, file);
}
catch (Exception ex)
{
Logger.LogError(ex, $"Error Deleting File [{file}] Exception [{ex}]");
}
}
var artistDir = new DirectoryInfo(artist.ArtistFileFolder(Configuration));
FolderPathHelper.DeleteEmptyFolders(artistDir.Parent);
}
await BookmarkService.RemoveAllBookmarksForItem(BookmarkType.Artist, artist.Id);
await UpdatePlaylistCountsForArtist(artist.Id, DateTime.UtcNow);
CacheManager.ClearRegion(artist.CacheRegion);
Logger.LogWarning("User `{0}` deleted Artist `{1}]`", user, artist);
isSuccess = true;
@ -183,7 +198,7 @@ namespace Roadie.Api.Services
};
}
public async Task<Library.Models.Pagination.PagedResult<ArtistList>> List(User roadieUser, PagedRequest request, bool? doRandomize = false, bool? onlyIncludeWithReleases = true)
public async Task<Library.Models.Pagination.PagedResult<ArtistList>> List(Library.Models.Users.User roadieUser, PagedRequest request, bool? doRandomize = false, bool? onlyIncludeWithReleases = true)
{
var sw = new Stopwatch();
sw.Start();
@ -287,7 +302,7 @@ namespace Roadie.Api.Services
},
Thumbnail = ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, a.RoadieId),
Rating = a.Rating,
Rank = a.Rank,
Rank = (double?)a.Rank,
CreatedDate = a.CreatedDate,
LastUpdated = a.LastUpdated,
LastPlayed = a.LastPlayed,
@ -313,7 +328,7 @@ namespace Roadie.Api.Services
else
{
string sortBy;
if (request.ActionValue == User.ActionKeyUserRated)
if (request.ActionValue == Library.Models.Users.User.ActionKeyUserRated)
{
sortBy = string.IsNullOrEmpty(request.Sort)
? request.OrderValue(new Dictionary<string, string> { { "Rating", "DESC" }, { "Artist.Text", "ASC" } })
@ -380,7 +395,7 @@ namespace Roadie.Api.Services
/// <param name="artistToMerge">The Artist to be merged</param>
/// <param name="artistToMergeInto">The Artist to merge into</param>
/// <returns></returns>
public async Task<OperationResult<bool>> MergeArtists(ApplicationUser user, Guid artistToMergeId, Guid artistToMergeIntoId)
public async Task<OperationResult<bool>> MergeArtists(Library.Identity.User user, Guid artistToMergeId, Guid artistToMergeIntoId)
{
var sw = new Stopwatch();
sw.Start();
@ -434,7 +449,7 @@ namespace Roadie.Api.Services
};
}
public async Task<OperationResult<bool>> RefreshArtistMetadata(ApplicationUser user, Guid artistId)
public async Task<OperationResult<bool>> RefreshArtistMetadata(Library.Identity.User user, Guid artistId)
{
SimpleContract.Requires<ArgumentOutOfRangeException>(artistId != Guid.Empty, "Invalid ArtistId");
@ -498,7 +513,7 @@ namespace Roadie.Api.Services
};
}
public async Task<OperationResult<bool>> ScanArtistReleasesFolders(ApplicationUser user, Guid artistId, string destinationFolder, bool doJustInfo)
public async Task<OperationResult<bool>> ScanArtistReleasesFolders(Library.Identity.User user, Guid artistId, string destinationFolder, bool doJustInfo)
{
SimpleContract.Requires<ArgumentOutOfRangeException>(artistId != Guid.Empty, "Invalid ArtistId");
@ -581,12 +596,12 @@ namespace Roadie.Api.Services
};
}
public async Task<OperationResult<Library.Models.Image>> SetReleaseImageByUrl(ApplicationUser user, Guid id, string imageUrl)
public async Task<OperationResult<Library.Models.Image>> SetReleaseImageByUrl(Library.Identity.User user, Guid id, string imageUrl)
{
return await SaveImageBytes(user, id, WebHelper.BytesForImageUrl(imageUrl));
}
public async Task<OperationResult<bool>> UpdateArtist(ApplicationUser user, Artist model)
public async Task<OperationResult<bool>> UpdateArtist(Library.Identity.User user, Artist model)
{
var didRenameArtist = false;
var sw = new Stopwatch();
@ -853,7 +868,7 @@ namespace Roadie.Api.Services
};
}
public async Task<OperationResult<Library.Models.Image>> UploadArtistImage(ApplicationUser user, Guid id, IFormFile file)
public async Task<OperationResult<Library.Models.Image>> UploadArtistImage(Library.Identity.User user, Guid id, IFormFile file)
{
var bytes = new byte[0];
using (var ms = new MemoryStream())
@ -890,7 +905,7 @@ namespace Roadie.Api.Services
? null
: result.BirthDate;
result.RankPosition = result.Rank > 0
? SafeParser.ToNumber<int?>(DbContext.Artists.Count(x => x.Rank > result.Rank) + 1)
? SafeParser.ToNumber<int?>(DbContext.Artists.Count(x => (double?)x.Rank > result.Rank) + 1)
: null;
tsw.Stop();
timings.Add("adapt", tsw.ElapsedMilliseconds);
@ -1044,7 +1059,7 @@ namespace Roadie.Api.Services
},
Thumbnail = ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, a.RoadieId),
Rating = a.Rating,
Rank = a.Rank,
Rank = (double?)a.Rank,
CreatedDate = a.CreatedDate,
LastUpdated = a.LastUpdated,
LastPlayed = a.LastPlayed,
@ -1068,7 +1083,7 @@ namespace Roadie.Api.Services
},
Thumbnail = ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, a.RoadieId),
Rating = a.Rating,
Rank = a.Rank,
Rank = (double?)a.Rank,
CreatedDate = a.CreatedDate,
LastUpdated = a.LastUpdated,
LastPlayed = a.LastPlayed,
@ -1100,7 +1115,7 @@ namespace Roadie.Api.Services
},
Thumbnail = ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, a.RoadieId),
Rating = a.Rating,
Rank = a.Rank,
Rank = (double?)a.Rank,
CreatedDate = a.CreatedDate,
LastUpdated = a.LastUpdated,
LastPlayed = a.LastPlayed,
@ -1124,7 +1139,7 @@ namespace Roadie.Api.Services
},
Thumbnail = ImageHelper.MakeArtistThumbnailImage(Configuration, HttpContext, a.RoadieId),
Rating = a.Rating,
Rank = a.Rank,
Rank = (double?)a.Rank,
CreatedDate = a.CreatedDate,
LastUpdated = a.LastUpdated,
LastPlayed = a.LastPlayed,
@ -1283,7 +1298,7 @@ namespace Roadie.Api.Services
};
}
private async Task<OperationResult<data.Artist>> MergeArtists(ApplicationUser user, data.Artist artistToMerge, data.Artist artistToMergeInto)
private async Task<OperationResult<data.Artist>> MergeArtists(Library.Identity.User user, data.Artist artistToMerge, data.Artist artistToMergeInto)
{
SimpleContract.Requires<ArgumentNullException>(artistToMerge != null, "Invalid Artist");
SimpleContract.Requires<ArgumentNullException>(artistToMergeInto != null, "Invalid Artist");
@ -1437,7 +1452,7 @@ namespace Roadie.Api.Services
};
}
private async Task<OperationResult<Library.Models.Image>> SaveImageBytes(ApplicationUser user, Guid id, byte[] imageBytes)
private async Task<OperationResult<Library.Models.Image>> SaveImageBytes(Library.Identity.User user, Guid id, byte[] imageBytes)
{
var sw = new Stopwatch();
sw.Start();

View file

@ -1,5 +1,7 @@
using Microsoft.EntityFrameworkCore;
using Mapster;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Roadie.Library;
using Roadie.Library.Caching;
using Roadie.Library.Configuration;
using Roadie.Library.Data.Context;
@ -25,14 +27,41 @@ namespace Roadie.Api.Services
{
public class BookmarkService : ServiceBase, IBookmarkService
{
private IUserService UserService { get; }
public BookmarkService(IRoadieSettings configuration,
IHttpEncoder httpEncoder,
IHttpContext httpContext,
IRoadieDbContext context,
ICacheManager cacheManager,
IUserService userService,
ILogger<BookmarkService> logger)
: base(configuration, httpEncoder, context, cacheManager, logger, httpContext)
{
UserService = userService;
}
/// <summary>
/// When a bookmarkable item gets deleted then delete any bookmarks to that item, since its a generic column there is not FK setup.
/// </summary>
public async Task<OperationResult<bool>> RemoveAllBookmarksForItem(BookmarkType type, int id)
{
var bookmarks = await DbContext.Bookmarks.Include(x => x.User)
.Where(x => x.BookmarkType == type && x.BookmarkTargetId == id)
.ToListAsync();
var users = bookmarks.Select(x => x.User).ToList().Distinct();
DbContext.Bookmarks.RemoveRange(bookmarks);
await DbContext.SaveChangesAsync();
foreach(var user in users)
{
CacheManager.ClearRegion(user.CacheRegion);
}
return new OperationResult<bool>
{
IsSuccess = true,
Data = true
};
}
public async Task<Library.Models.Pagination.PagedResult<models.BookmarkList>> List(User roadieUser, PagedRequest request, bool? doRandomize = false, BookmarkType? filterType = null)

View file

@ -77,8 +77,7 @@ namespace Roadie.Api.Services
};
}
public async Task<OperationResult<Collection>> ById(User roadieUser, Guid id,
IEnumerable<string> includes = null)
public async Task<OperationResult<Collection>> ById(User roadieUser, Guid id, IEnumerable<string> includes = null)
{
var sw = Stopwatch.StartNew();
sw.Start();
@ -94,7 +93,7 @@ namespace Roadie.Api.Services
var userBookmarkResult = await BookmarkService.List(roadieUser, new PagedRequest(), false, BookmarkType.Collection);
if (userBookmarkResult.IsSuccess)
{
result.Data.UserBookmarked = userBookmarkResult?.Rows?.FirstOrDefault(x => x.Bookmark.Value == result.Data.Id.ToString()) != null;
result.Data.UserBookmarked = userBookmarkResult?.Rows?.FirstOrDefault(x => x?.Bookmark?.Value == result?.Data?.Id?.ToString()) != null;
}
if (result.Data.Comments.Any())
{
@ -142,6 +141,7 @@ namespace Roadie.Api.Services
{
DbContext.Collections.Remove(collection);
await DbContext.SaveChangesAsync();
await BookmarkService.RemoveAllBookmarksForItem(BookmarkType.Collection, collection.Id);
var collectionImageFilename = collection.PathToImage(Configuration);
if (File.Exists(collectionImageFilename))
{
@ -277,7 +277,7 @@ namespace Roadie.Api.Services
}
collection.IsLocked = model.IsLocked;
var oldPathToImage = collection.PathToImage(Configuration);
var didChangeName = collection.Name != model.Name;
var didChangeName = collection.Name != model.Name && !isNew;
collection.Name = model.Name;
collection.SortName = model.SortName;
collection.Edition = model.Edition;
@ -292,6 +292,21 @@ namespace Roadie.Api.Services
collection.AlternateNames = model.AlternateNamesList.ToDelimitedList();
collection.CollectionCount = model.CollectionCount;
if (model.Maintainer?.Value != null)
{
var maintainer = DbContext.Users.FirstOrDefault(x => x.RoadieId == SafeParser.ToGuid(model.Maintainer.Value));
if (maintainer != null)
{
collection.MaintainerId = maintainer.Id;
}
}
if (isNew)
{
await DbContext.Collections.AddAsync(collection);
await DbContext.SaveChangesAsync();
}
if (didChangeName)
{
if (File.Exists(oldPathToImage))
@ -306,18 +321,12 @@ namespace Roadie.Api.Services
// Save unaltered collection image
File.WriteAllBytes(collection.PathToImage(Configuration, true), ImageHelper.ConvertToJpegFormat(collectionImage));
}
if (model.Maintainer?.Value != null)
{
var maintainer = DbContext.Users.FirstOrDefault(x => x.RoadieId == SafeParser.ToGuid(model.Maintainer.Value));
if (maintainer != null) collection.MaintainerId = maintainer.Id;
}
collection.LastUpdated = now;
if (isNew) await DbContext.Collections.AddAsync(collection);
await DbContext.SaveChangesAsync();
CacheManager.ClearRegion(collection.CacheRegion);
Logger.LogInformation($"UpdateArtist `{collection}` By User `{user}`");
Logger.LogInformation($"UpdateCollection `{collection}` By User `{user}`");
return new OperationResult<bool>
{
IsSuccess = !errors.Any(),

View file

@ -1,5 +1,6 @@
using Microsoft.AspNetCore.Identity.UI.Services;
using Roadie.Library.Configuration;
using System.Diagnostics;
using System.Net;
using System.Net.Mail;
using System.Threading.Tasks;
@ -17,6 +18,11 @@ namespace Roadie.Api.Services
public async Task SendEmailAsync(string email, string subject, string htmlMessage)
{
if(string.IsNullOrEmpty(Configuration.SmtpHost))
{
Trace.WriteLine("Email Server (Configuration.SmtpHost) Not Configured", "Warning");
return;
}
using (var mail = new MailMessage(Configuration.SmtpFromAddress, email))
{
using (var client = new SmtpClient())

View file

@ -76,7 +76,7 @@ namespace Roadie.Api.Services
return result;
}
public async Task<OperationResult<bool>> Process(ApplicationUser user, DirectoryInfo folder, bool doJustInfo, int? submissionId = null, bool doDeleteFiles = true)
public async Task<OperationResult<bool>> Process(User user, DirectoryInfo folder, bool doJustInfo, int? submissionId = null, bool doDeleteFiles = true)
{
var sw = new Stopwatch();
sw.Start();
@ -121,7 +121,7 @@ namespace Roadie.Api.Services
/// <summary>
/// Perform any operations to the given folder and the plugin results after processing
/// </summary>
private async Task<bool> PostProcessFolder(ApplicationUser user, DirectoryInfo inboundFolder, IEnumerable<PluginResultInfo> pluginResults, bool doJustInfo, bool doDeleteFiles = true)
private async Task<bool> PostProcessFolder(User user, DirectoryInfo inboundFolder, IEnumerable<PluginResultInfo> pluginResults, bool doJustInfo, bool doDeleteFiles = true)
{
SimpleContract.Requires<ArgumentNullException>(inboundFolder != null, "Invalid InboundFolder");
if (pluginResults != null)

View file

@ -38,7 +38,7 @@ namespace Roadie.Api.Services
{
}
public async Task<OperationResult<Genre>> ById(User roadieUser, Guid id, IEnumerable<string> includes = null)
public async Task<OperationResult<Genre>> ById(Library.Models.Users.User roadieUser, Guid id, IEnumerable<string> includes = null)
{
var sw = Stopwatch.StartNew();
sw.Start();
@ -58,7 +58,7 @@ namespace Roadie.Api.Services
};
}
public async Task<OperationResult<bool>> Delete(ApplicationUser user, Guid id)
public async Task<OperationResult<bool>> Delete(Library.Identity.User user, Guid id)
{
var sw = new Stopwatch();
sw.Start();
@ -84,7 +84,7 @@ namespace Roadie.Api.Services
};
}
public async Task<Library.Models.Pagination.PagedResult<GenreList>> List(User roadieUser, PagedRequest request, bool? doRandomize = false)
public async Task<Library.Models.Pagination.PagedResult<GenreList>> List(Library.Models.Users.User roadieUser, PagedRequest request, bool? doRandomize = false)
{
var sw = new Stopwatch();
sw.Start();
@ -161,12 +161,12 @@ namespace Roadie.Api.Services
});
}
public async Task<OperationResult<Library.Models.Image>> SetGenreImageByUrl(User user, Guid id, string imageUrl)
public async Task<OperationResult<Library.Models.Image>> SetGenreImageByUrl(Library.Models.Users.User user, Guid id, string imageUrl)
{
return await SaveImageBytes(user, id, WebHelper.BytesForImageUrl(imageUrl));
}
public async Task<OperationResult<bool>> UpdateGenre(User user, Genre model)
public async Task<OperationResult<bool>> UpdateGenre(Library.Models.Users.User user, Genre model)
{
var sw = new Stopwatch();
sw.Start();
@ -243,7 +243,7 @@ namespace Roadie.Api.Services
};
}
public async Task<OperationResult<Library.Models.Image>> UploadGenreImage(User user, Guid id, IFormFile file)
public async Task<OperationResult<Library.Models.Image>> UploadGenreImage(Library.Models.Users.User user, Guid id, IFormFile file)
{
var bytes = new byte[0];
using (var ms = new MemoryStream())
@ -309,7 +309,7 @@ namespace Roadie.Api.Services
});
}
private async Task<OperationResult<Library.Models.Image>> SaveImageBytes(User user, Guid id, byte[] imageBytes)
private async Task<OperationResult<Library.Models.Image>> SaveImageBytes(Library.Models.Users.User user, Guid id, byte[] imageBytes)
{
var sw = new Stopwatch();
sw.Start();

View file

@ -9,45 +9,45 @@ namespace Roadie.Api.Services
{
public interface IAdminService
{
Task<OperationResult<bool>> DeleteArtist(ApplicationUser user, Guid artistId, bool deleteFolder);
Task<OperationResult<bool>> DeleteArtist(User user, Guid artistId, bool deleteFolder);
Task<OperationResult<bool>> DeleteArtistReleases(ApplicationUser user, Guid artistId, bool doDeleteFiles = false);
Task<OperationResult<bool>> DeleteArtistReleases(User user, Guid artistId, bool doDeleteFiles = false);
Task<OperationResult<bool>> DeleteArtistSecondaryImage(ApplicationUser user, Guid artistId, int index);
Task<OperationResult<bool>> DeleteArtistSecondaryImage(User user, Guid artistId, int index);
Task<OperationResult<bool>> DeleteGenre(ApplicationUser user, Guid genreId);
Task<OperationResult<bool>> DeleteGenre(User user, Guid genreId);
Task<OperationResult<bool>> DeleteLabel(ApplicationUser user, Guid labelId);
Task<OperationResult<bool>> DeleteLabel(User user, Guid labelId);
Task<OperationResult<bool>> DeleteRelease(ApplicationUser user, Guid releaseId, bool? doDeleteFiles);
Task<OperationResult<bool>> DeleteRelease(User user, Guid releaseId, bool? doDeleteFiles);
Task<OperationResult<bool>> DeleteReleaseSecondaryImage(ApplicationUser user, Guid releaseId, int index);
Task<OperationResult<bool>> DeleteReleaseSecondaryImage(User user, Guid releaseId, int index);
Task<OperationResult<bool>> DeleteTracks(ApplicationUser user, IEnumerable<Guid> trackIds, bool? doDeleteFile);
Task<OperationResult<bool>> DeleteTracks(User user, IEnumerable<Guid> trackIds, bool? doDeleteFile);
Task<OperationResult<bool>> DeleteUser(ApplicationUser applicationUser, Guid id);
Task<OperationResult<bool>> DeleteUser(User applicationUser, Guid id);
Task<OperationResult<bool>> DoInitialSetup(ApplicationUser user, UserManager<ApplicationUser> userManager);
Task<OperationResult<bool>> DoInitialSetup(User user, UserManager<User> userManager);
Task<OperationResult<Dictionary<string, List<string>>>> MissingCollectionReleases(ApplicationUser user);
Task<OperationResult<Dictionary<string, List<string>>>> MissingCollectionReleases(User user);
void PerformStartUpTasks();
Task<OperationResult<bool>> ScanAllCollections(ApplicationUser user, bool isReadOnly = false, bool doPurgeFirst = false);
Task<OperationResult<bool>> ScanAllCollections(User user, bool isReadOnly = false, bool doPurgeFirst = false);
Task<OperationResult<bool>> ScanArtist(ApplicationUser user, Guid artistId, bool isReadOnly = false);
Task<OperationResult<bool>> ScanArtist(User user, Guid artistId, bool isReadOnly = false);
Task<OperationResult<bool>> ScanArtists(ApplicationUser user, IEnumerable<Guid> artistIds, bool isReadOnly = false);
Task<OperationResult<bool>> ScanArtists(User user, IEnumerable<Guid> artistIds, bool isReadOnly = false);
Task<OperationResult<bool>> ScanCollection(ApplicationUser user, Guid collectionId, bool isReadOnly = false, bool doPurgeFirst = false, bool doUpdateRanks = true);
Task<OperationResult<bool>> ScanCollection(User user, Guid collectionId, bool isReadOnly = false, bool doPurgeFirst = false, bool doUpdateRanks = true);
Task<OperationResult<bool>> ScanInboundFolder(ApplicationUser user, bool isReadOnly = false);
Task<OperationResult<bool>> ScanInboundFolder(User user, bool isReadOnly = false);
Task<OperationResult<bool>> ScanLibraryFolder(ApplicationUser user, bool isReadOnly = false);
Task<OperationResult<bool>> ScanLibraryFolder(User user, bool isReadOnly = false);
Task<OperationResult<bool>> ScanRelease(ApplicationUser user, Guid releaseIds, bool isReadOnly = false, bool wasDoneForInvalidTrackPlay = false);
Task<OperationResult<bool>> ScanRelease(User user, Guid releaseIds, bool isReadOnly = false, bool wasDoneForInvalidTrackPlay = false);
Task<OperationResult<bool>> ScanReleases(ApplicationUser user, IEnumerable<Guid> releaseId, bool isReadOnly = false, bool wasDoneForInvalidTrackPlay = false);
Task<OperationResult<bool>> ScanReleases(User user, IEnumerable<Guid> releaseId, bool isReadOnly = false, bool wasDoneForInvalidTrackPlay = false);
Task<OperationResult<bool>> UpdateInviteTokenUsed(Guid? tokenId);

View file

@ -12,22 +12,22 @@ namespace Roadie.Api.Services
{
public interface IArtistService
{
Task<OperationResult<Artist>> ById(User user, Guid id, IEnumerable<string> includes);
Task<OperationResult<Artist>> ById(Library.Models.Users.User user, Guid id, IEnumerable<string> includes);
Task<OperationResult<bool>> Delete(ApplicationUser user, Library.Data.Artist Artist, bool deleteFolder);
Task<OperationResult<bool>> Delete(Library.Identity.User user, Library.Data.Artist Artist, bool deleteFolder);
Task<PagedResult<ArtistList>> List(User user, PagedRequest request, bool? doRandomize = false, bool? onlyIncludeWithReleases = true);
Task<PagedResult<ArtistList>> List(Library.Models.Users.User user, PagedRequest request, bool? doRandomize = false, bool? onlyIncludeWithReleases = true);
Task<OperationResult<bool>> MergeArtists(ApplicationUser user, Guid artistToMergeId, Guid artistToMergeIntoId);
Task<OperationResult<bool>> MergeArtists(Library.Identity.User user, Guid artistToMergeId, Guid artistToMergeIntoId);
Task<OperationResult<bool>> RefreshArtistMetadata(ApplicationUser user, Guid ArtistId);
Task<OperationResult<bool>> RefreshArtistMetadata(Library.Identity.User user, Guid ArtistId);
Task<OperationResult<bool>> ScanArtistReleasesFolders(ApplicationUser user, Guid artistId, string destinationFolder, bool doJustInfo);
Task<OperationResult<bool>> ScanArtistReleasesFolders(Library.Identity.User user, Guid artistId, string destinationFolder, bool doJustInfo);
Task<OperationResult<Image>> SetReleaseImageByUrl(ApplicationUser user, Guid id, string imageUrl);
Task<OperationResult<Image>> SetReleaseImageByUrl(Library.Identity.User user, Guid id, string imageUrl);
Task<OperationResult<bool>> UpdateArtist(ApplicationUser user, Artist artist);
Task<OperationResult<bool>> UpdateArtist(Library.Identity.User user, Artist artist);
Task<OperationResult<Image>> UploadArtistImage(ApplicationUser user, Guid id, IFormFile file);
Task<OperationResult<Image>> UploadArtistImage(Library.Identity.User user, Guid id, IFormFile file);
}
}

View file

@ -1,4 +1,5 @@
using Roadie.Library.Enums;
using Roadie.Library;
using Roadie.Library.Enums;
using Roadie.Library.Models;
using Roadie.Library.Models.Pagination;
using Roadie.Library.Models.Users;
@ -8,7 +9,7 @@ namespace Roadie.Api.Services
{
public interface IBookmarkService
{
Task<PagedResult<BookmarkList>> List(User roadieUser, PagedRequest request, bool? doRandomize = false,
BookmarkType? filterType = null);
Task<OperationResult<bool>> RemoveAllBookmarksForItem(BookmarkType type, int id);
Task<PagedResult<BookmarkList>> List(User roadieUser, PagedRequest request, bool? doRandomize = false, BookmarkType? filterType = null);
}
}

View file

@ -14,6 +14,6 @@ namespace Roadie.Api.Services
int? ProcessLimit { get; set; }
Task<OperationResult<bool>> Process(ApplicationUser user, DirectoryInfo folder, bool doJustInfo, int? submissionId = null, bool doDeleteFiles = true);
Task<OperationResult<bool>> Process(User user, DirectoryInfo folder, bool doJustInfo, int? submissionId = null, bool doDeleteFiles = true);
}
}

View file

@ -12,16 +12,16 @@ namespace Roadie.Api.Services
{
public interface IGenreService
{
Task<OperationResult<Genre>> ById(User roadieUser, Guid id, IEnumerable<string> includes = null);
Task<OperationResult<Genre>> ById(Library.Models.Users.User roadieUser, Guid id, IEnumerable<string> includes = null);
Task<OperationResult<bool>> Delete(ApplicationUser user, Guid id);
Task<OperationResult<bool>> Delete(Library.Identity.User user, Guid id);
Task<PagedResult<GenreList>> List(User roadieUser, PagedRequest request, bool? doRandomize = false);
Task<PagedResult<GenreList>> List(Library.Models.Users.User roadieUser, PagedRequest request, bool? doRandomize = false);
Task<OperationResult<Image>> SetGenreImageByUrl(User user, Guid id, string imageUrl);
Task<OperationResult<Image>> SetGenreImageByUrl(Library.Models.Users.User user, Guid id, string imageUrl);
Task<OperationResult<bool>> UpdateGenre(User user, Genre model);
Task<OperationResult<bool>> UpdateGenre(Library.Models.Users.User user, Genre model);
Task<OperationResult<Image>> UploadGenreImage(User user, Guid id, IFormFile file);
Task<OperationResult<Image>> UploadGenreImage(Library.Models.Users.User user, Guid id, IFormFile file);
}
}

View file

@ -12,18 +12,18 @@ namespace Roadie.Api.Services
{
public interface ILabelService
{
Task<OperationResult<Label>> ById(User roadieUser, Guid id, IEnumerable<string> includes = null);
Task<OperationResult<Label>> ById(Library.Models.Users.User roadieUser, Guid id, IEnumerable<string> includes = null);
Task<OperationResult<bool>> Delete(ApplicationUser user, Guid id);
Task<OperationResult<bool>> Delete(Library.Identity.User user, Guid id);
Task<PagedResult<LabelList>> List(User roadieUser, PagedRequest request, bool? doRandomize = false);
Task<PagedResult<LabelList>> List(Library.Models.Users.User roadieUser, PagedRequest request, bool? doRandomize = false);
Task<OperationResult<bool>> MergeLabelsIntoLabel(ApplicationUser user, Guid intoLabelId, IEnumerable<Guid> labelIdsToMerge);
Task<OperationResult<bool>> MergeLabelsIntoLabel(Library.Identity.User user, Guid intoLabelId, IEnumerable<Guid> labelIdsToMerge);
Task<OperationResult<Image>> SetLabelImageByUrl(User user, Guid id, string imageUrl);
Task<OperationResult<Image>> SetLabelImageByUrl(Library.Models.Users.User user, Guid id, string imageUrl);
Task<OperationResult<bool>> UpdateLabel(User user, Label label);
Task<OperationResult<bool>> UpdateLabel(Library.Models.Users.User user, Label label);
Task<OperationResult<Image>> UploadLabelImage(User user, Guid id, IFormFile file);
Task<OperationResult<Image>> UploadLabelImage(Library.Models.Users.User user, Guid id, IFormFile file);
}
}

View file

@ -15,26 +15,26 @@ namespace Roadie.Api.Services
{
IEnumerable<int> AddedTrackIds { get; }
Task<OperationResult<Release>> ById(User roadieUser, Guid id, IEnumerable<string> includes = null);
Task<OperationResult<Release>> ById(Library.Models.Users.User roadieUser, Guid id, IEnumerable<string> includes = null);
Task<OperationResult<bool>> Delete(ApplicationUser user, Library.Data.Release release, bool doDeleteFiles = false, bool doUpdateArtistCounts = true);
Task<OperationResult<bool>> Delete(Library.Identity.User user, Library.Data.Release release, bool doDeleteFiles = false, bool doUpdateArtistCounts = true);
Task<OperationResult<bool>> DeleteReleases(ApplicationUser user, IEnumerable<Guid> releaseIds, bool doDeleteFiles = false);
Task<OperationResult<bool>> DeleteReleases(Library.Identity.User user, IEnumerable<Guid> releaseIds, bool doDeleteFiles = false);
Task<PagedResult<ReleaseList>> List(User user, PagedRequest request, bool? doRandomize = false, IEnumerable<string> includes = null);
Task<PagedResult<ReleaseList>> List(Library.Models.Users.User user, PagedRequest request, bool? doRandomize = false, IEnumerable<string> includes = null);
Task<OperationResult<bool>> MergeReleases(ApplicationUser user, Guid releaseToMergeId, Guid releaseToMergeIntoId, bool addAsMedia);
Task<OperationResult<bool>> MergeReleases(Library.Identity.User user, Guid releaseToMergeId, Guid releaseToMergeIntoId, bool addAsMedia);
Task<OperationResult<bool>> MergeReleases(ApplicationUser user, Library.Data.Release releaseToMerge, Library.Data.Release releaseToMergeInto, bool addAsMedia);
Task<OperationResult<bool>> MergeReleases(Library.Identity.User user, Library.Data.Release releaseToMerge, Library.Data.Release releaseToMergeInto, bool addAsMedia);
Task<FileOperationResult<byte[]>> ReleaseZipped(User roadieUser, Guid id);
Task<FileOperationResult<byte[]>> ReleaseZipped(Library.Models.Users.User roadieUser, Guid id);
Task<OperationResult<bool>> ScanReleaseFolder(ApplicationUser user, Guid releaseId, bool doJustInfo, Library.Data.Release releaseToScan = null);
Task<OperationResult<bool>> ScanReleaseFolder(Library.Identity.User user, Guid releaseId, bool doJustInfo, Library.Data.Release releaseToScan = null);
Task<OperationResult<Image>> SetReleaseImageByUrl(ApplicationUser user, Guid id, string imageUrl);
Task<OperationResult<Image>> SetReleaseImageByUrl(Library.Identity.User user, Guid id, string imageUrl);
Task<OperationResult<bool>> UpdateRelease(ApplicationUser user, Release release, string originalReleaseFolder = null);
Task<OperationResult<bool>> UpdateRelease(Library.Identity.User user, Release release, string originalReleaseFolder = null);
Task<OperationResult<Image>> UploadReleaseImage(ApplicationUser user, Guid id, IFormFile file);
Task<OperationResult<Image>> UploadReleaseImage(Library.Identity.User user, Guid id, IFormFile file);
}
}

View file

@ -6,6 +6,6 @@ namespace Roadie.Api.Services
{
public interface ITokenService
{
Task<string> GenerateToken(ApplicationUser user, UserManager<ApplicationUser> userManager);
Task<string> GenerateToken(User user, UserManager<User> userManager);
}
}

View file

@ -178,7 +178,7 @@ namespace Roadie.Api.Services
public async Task<FileOperationResult<IImage>> UserImage(Guid id, int? width, int? height, EntityTagHeaderValue etag = null)
{
return await GetImageFileOperation("UserById",
ApplicationUser.CacheRegionUrn(id),
User.CacheRegionUrn(id),
id,
width,
height,
@ -206,7 +206,7 @@ namespace Roadie.Api.Services
artistFolder = artist.ArtistFileFolder(Configuration);
if (!Directory.Exists(artistFolder))
{
Logger.LogTrace($"Artist Folder [{artistFolder}], Not Found For Artist `{artist}`");
Logger.LogWarning($"Artist Folder [{artistFolder}], Not Found For Artist `{artist}`");
}
else
{
@ -257,7 +257,7 @@ namespace Roadie.Api.Services
artistFolder = artist.ArtistFileFolder(Configuration);
if (!Directory.Exists(artistFolder))
{
Logger.LogTrace($"Artist Folder [{artistFolder}], Not Found For Artist `{artist}`");
Logger.LogWarning($"Artist Folder [{artistFolder}], Not Found For Artist `{artist}`");
}
else
{
@ -545,7 +545,7 @@ namespace Roadie.Api.Services
artistFolder = release.Artist.ArtistFileFolder(Configuration);
if (!Directory.Exists(artistFolder))
{
Logger.LogTrace($"Artist Folder [{artistFolder}], Not Found For Artist `{release.Artist}`");
Logger.LogWarning($"Artist Folder [{artistFolder}], Not Found For Artist `{release.Artist}`");
}
else
{
@ -605,7 +605,7 @@ namespace Roadie.Api.Services
artistFolder = release.Artist.ArtistFileFolder(Configuration);
if (!Directory.Exists(artistFolder))
{
Logger.LogTrace($"Artist Folder [{artistFolder}], Not Found For Artist `{release.Artist}`");
Logger.LogWarning($"Artist Folder [{artistFolder}], Not Found For Artist `{release.Artist}`");
}
else
{

View file

@ -43,7 +43,7 @@ namespace Roadie.Api.Services
BookmarkService = bookmarkService;
}
public async Task<OperationResult<Label>> ById(User roadieUser, Guid id, IEnumerable<string> includes = null)
public async Task<OperationResult<Label>> ById(Library.Models.Users.User roadieUser, Guid id, IEnumerable<string> includes = null)
{
var sw = Stopwatch.StartNew();
sw.Start();
@ -57,7 +57,7 @@ namespace Roadie.Api.Services
var userBookmarkResult = await BookmarkService.List(roadieUser, new PagedRequest(), false, BookmarkType.Label);
if (userBookmarkResult.IsSuccess)
{
result.Data.UserBookmarked = userBookmarkResult?.Rows?.FirstOrDefault(x => x.Bookmark.Value == result.Data.Id.ToString()) != null;
result.Data.UserBookmarked = userBookmarkResult?.Rows?.FirstOrDefault(x => x?.Bookmark?.Value == result?.Data?.Id?.ToString()) != null;
}
if (result.Data.Comments.Any())
{
@ -85,7 +85,7 @@ namespace Roadie.Api.Services
};
}
public async Task<OperationResult<bool>> Delete(ApplicationUser user, Guid id)
public async Task<OperationResult<bool>> Delete(Library.Identity.User user, Guid id)
{
var sw = new Stopwatch();
sw.Start();
@ -99,7 +99,7 @@ namespace Roadie.Api.Services
{
File.Delete(labelImageFilename);
}
await BookmarkService.RemoveAllBookmarksForItem(BookmarkType.Label, label.Id);
Logger.LogWarning("User `{0}` deleted Label `{1}]`", user, label);
CacheManager.ClearRegion(label.CacheRegion);
sw.Stop();
@ -111,7 +111,7 @@ namespace Roadie.Api.Services
};
}
public async Task<Library.Models.Pagination.PagedResult<LabelList>> List(User roadieUser, PagedRequest request,
public async Task<Library.Models.Pagination.PagedResult<LabelList>> List(Library.Models.Users.User roadieUser, PagedRequest request,
bool? doRandomize = false)
{
var sw = new Stopwatch();
@ -198,7 +198,7 @@ namespace Roadie.Api.Services
};
}
public async Task<OperationResult<bool>> MergeLabelsIntoLabel(ApplicationUser user, Guid intoLabelId, IEnumerable<Guid> labelIdsToMerge)
public async Task<OperationResult<bool>> MergeLabelsIntoLabel(Library.Identity.User user, Guid intoLabelId, IEnumerable<Guid> labelIdsToMerge)
{
var sw = new Stopwatch();
sw.Start();
@ -258,12 +258,12 @@ namespace Roadie.Api.Services
};
}
public async Task<OperationResult<Library.Models.Image>> SetLabelImageByUrl(User user, Guid id, string imageUrl)
public async Task<OperationResult<Library.Models.Image>> SetLabelImageByUrl(Library.Models.Users.User user, Guid id, string imageUrl)
{
return await SaveImageBytes(user, id, WebHelper.BytesForImageUrl(imageUrl));
}
public async Task<OperationResult<bool>> UpdateLabel(User user, Label model)
public async Task<OperationResult<bool>> UpdateLabel(Library.Models.Users.User user, Label model)
{
var sw = new Stopwatch();
sw.Start();
@ -344,7 +344,7 @@ namespace Roadie.Api.Services
};
}
public async Task<OperationResult<Library.Models.Image>> UploadLabelImage(User user, Guid id, IFormFile file)
public async Task<OperationResult<Library.Models.Image>> UploadLabelImage(Library.Models.Users.User user, Guid id, IFormFile file)
{
var bytes = new byte[0];
using (var ms = new MemoryStream())
@ -452,7 +452,7 @@ namespace Roadie.Api.Services
};
}
private async Task<OperationResult<Library.Models.Image>> SaveImageBytes(User user, Guid id, byte[] imageBytes)
private async Task<OperationResult<Library.Models.Image>> SaveImageBytes(Library.Models.Users.User user, Guid id, byte[] imageBytes)
{
var sw = new Stopwatch();
sw.Start();

Some files were not shown because too many files have changed in this diff Show more