diff --git a/Kyoo.Common/Controllers/IRepository.cs b/Kyoo.Common/Controllers/IRepository.cs index f8c534b7..62bf0250 100644 --- a/Kyoo.Common/Controllers/IRepository.cs +++ b/Kyoo.Common/Controllers/IRepository.cs @@ -78,7 +78,7 @@ namespace Kyoo.Controllers { Task Get(int id); Task Get(string slug); - async Task Get(Expression> where) => (await GetAll(where, limit: 1)).FirstOrDefault(); + Task Get(Expression> where); Task> Search(string query); Task> GetAll(Expression> where = null, diff --git a/Kyoo.Common/Models/Resources/Studio.cs b/Kyoo.Common/Models/Resources/Studio.cs index 8936bf66..a101c394 100644 --- a/Kyoo.Common/Models/Resources/Studio.cs +++ b/Kyoo.Common/Models/Resources/Studio.cs @@ -27,7 +27,7 @@ namespace Kyoo.Models public static Studio Default() { - return new Studio("unknow", "Unknow Studio"); + return new Studio("unknown", "Unknown Studio"); } } } diff --git a/Kyoo.Common/Utility.cs b/Kyoo.Common/Utility.cs index 97f96e95..baeab0f2 100644 --- a/Kyoo.Common/Utility.cs +++ b/Kyoo.Common/Utility.cs @@ -5,6 +5,7 @@ using System.Globalization; using System.Linq; using System.Linq.Expressions; using System.Reflection; +using System.Runtime.ExceptionServices; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; @@ -259,13 +260,21 @@ namespace Kyoo return string.Empty; return "?" + string.Join('&', query.Select(x => $"{x.Key}={x.Value}")); } + + [System.Diagnostics.CodeAnalysis.DoesNotReturn] + public static void ReThrow([NotNull] this Exception ex) + { + if (ex == null) + throw new ArgumentNullException(nameof(ex)); + ExceptionDispatchInfo.Capture(ex).Throw(); + } public static Task Then(this Task task, Action map) { return task.ContinueWith(x => { if (x.IsFaulted) - throw x.Exception!.InnerException!; + x.Exception!.InnerException!.ReThrow(); if (x.IsCanceled) throw new TaskCanceledException(); map(x.Result); @@ -278,7 +287,7 @@ namespace Kyoo return task.ContinueWith(x => { if (x.IsFaulted) - throw x.Exception!.InnerException!; + x.Exception!.InnerException!.ReThrow(); if (x.IsCanceled) throw new TaskCanceledException(); return map(x.Result); @@ -290,7 +299,7 @@ namespace Kyoo return task.ContinueWith(x => { if (x.IsFaulted) - throw x.Exception!.InnerException!; + x.Exception!.InnerException!.ReThrow(); if (x.IsCanceled) throw new TaskCanceledException(); return (T)((dynamic)x).Result; diff --git a/Kyoo.CommonAPI/LocalRepository.cs b/Kyoo.CommonAPI/LocalRepository.cs index c8ed3c4b..7cad6a9d 100644 --- a/Kyoo.CommonAPI/LocalRepository.cs +++ b/Kyoo.CommonAPI/LocalRepository.cs @@ -45,6 +45,11 @@ namespace Kyoo.Controllers { return Database.Set().FirstOrDefaultAsync(x => x.Slug == slug); } + + public virtual Task Get(Expression> predicate) + { + return Database.Set().FirstOrDefaultAsync(predicate); + } public virtual Task> GetAll(Expression> where = null, Sort sort = default, @@ -95,8 +100,14 @@ namespace Kyoo.Controllers return await query.ToListAsync(); } - - public abstract Task Create([NotNull] T obj); + + public virtual async Task Create([NotNull] T obj) + { + if (obj == null) + throw new ArgumentNullException(nameof(obj)); + await Validate(obj); + return obj; + } public virtual async Task CreateIfNotExists(T obj) { @@ -139,6 +150,9 @@ namespace Kyoo.Controllers protected virtual Task Validate(T ressource) { + if (ressource.Slug == null) + throw new ArgumentException("Ressource can't have null as a slug."); + foreach (PropertyInfo property in typeof(T).GetProperties() .Where(x => typeof(IEnumerable).IsAssignableFrom(x.PropertyType) && !typeof(string).IsAssignableFrom(x.PropertyType))) @@ -201,6 +215,11 @@ namespace Kyoo.Controllers return base.Get(slug).Cast(); } + public Task Get(Expression> predicate) + { + return Get(predicate.Convert>()).Cast(); + } + public abstract Task> Search(string query); public virtual Task> GetAll(Expression> where = null, @@ -224,8 +243,6 @@ namespace Kyoo.Controllers return items.ToList(); } - - public abstract override Task Create(TInternal obj); Task IRepository.Create(T item) { diff --git a/Kyoo/Controllers/Repositories/CollectionRepository.cs b/Kyoo/Controllers/Repositories/CollectionRepository.cs index 8d8b6175..d76cad51 100644 --- a/Kyoo/Controllers/Repositories/CollectionRepository.cs +++ b/Kyoo/Controllers/Repositories/CollectionRepository.cs @@ -52,9 +52,7 @@ namespace Kyoo.Controllers public override async Task Create(CollectionDE obj) { - if (obj == null) - throw new ArgumentNullException(nameof(obj)); - + await base.Create(obj); _database.Entry(obj).State = EntityState.Added; await _database.SaveChangesAsync($"Trying to insert a duplicated collection (slug {obj.Slug} already exists)."); return obj; @@ -82,7 +80,7 @@ namespace Kyoo.Controllers { ICollection collections = await ApplyFilters(_database.CollectionLinks .Where(x => x.ShowID == showID) - .Select(x => x.Collection as CollectionDE), + .Select(x => (CollectionDE)x.Collection), where, sort, limit); @@ -98,7 +96,7 @@ namespace Kyoo.Controllers { ICollection collections = await ApplyFilters(_database.CollectionLinks .Where(x => x.Show.Slug == showSlug) - .Select(x => x.Collection as CollectionDE), + .Select(x => (CollectionDE)x.Collection), where, sort, limit); @@ -114,7 +112,7 @@ namespace Kyoo.Controllers { ICollection collections = await ApplyFilters(_database.LibraryLinks .Where(x => x.LibraryID == id && x.CollectionID != null) - .Select(x => x.Collection as CollectionDE), + .Select(x => (CollectionDE)x.Collection), where, sort, limit); @@ -130,7 +128,7 @@ namespace Kyoo.Controllers { ICollection collections = await ApplyFilters(_database.LibraryLinks .Where(x => x.Library.Slug == slug && x.CollectionID != null) - .Select(x => x.Collection as CollectionDE), + .Select(x => (CollectionDE)x.Collection), where, sort, limit); diff --git a/Kyoo/Controllers/Repositories/EpisodeRepository.cs b/Kyoo/Controllers/Repositories/EpisodeRepository.cs index 8c9e5be8..277dda98 100644 --- a/Kyoo/Controllers/Repositories/EpisodeRepository.cs +++ b/Kyoo/Controllers/Repositories/EpisodeRepository.cs @@ -97,10 +97,7 @@ namespace Kyoo.Controllers public override async Task Create(Episode obj) { - if (obj == null) - throw new ArgumentNullException(nameof(obj)); - - await Validate(obj); + await base.Create(obj); _database.Entry(obj).State = EntityState.Added; if (obj.ExternalIDs != null) foreach (MetadataID entry in obj.ExternalIDs) diff --git a/Kyoo/Controllers/Repositories/GenreRepository.cs b/Kyoo/Controllers/Repositories/GenreRepository.cs index 5a33204b..607c2da9 100644 --- a/Kyoo/Controllers/Repositories/GenreRepository.cs +++ b/Kyoo/Controllers/Repositories/GenreRepository.cs @@ -47,9 +47,7 @@ namespace Kyoo.Controllers public override async Task Create(GenreDE obj) { - if (obj == null) - throw new ArgumentNullException(nameof(obj)); - + await base.Create(obj); _database.Entry(obj).State = EntityState.Added; await _database.SaveChangesAsync($"Trying to insert a duplicated genre (slug {obj.Slug} already exists)."); return obj; @@ -73,7 +71,7 @@ namespace Kyoo.Controllers Pagination limit = default) { ICollection genres = await ApplyFilters(_database.GenreLinks.Where(x => x.ShowID == showID) - .Select(x => x.Genre as GenreDE), + .Select(x => (GenreDE)x.Genre), where, sort, limit); @@ -89,7 +87,7 @@ namespace Kyoo.Controllers { ICollection genres = await ApplyFilters(_database.GenreLinks .Where(x => x.Show.Slug == showSlug) - .Select(x => x.Genre as GenreDE), + .Select(x => (GenreDE)x.Genre), where, sort, limit); diff --git a/Kyoo/Controllers/Repositories/LibraryRepository.cs b/Kyoo/Controllers/Repositories/LibraryRepository.cs index a2b9dd10..66e402c6 100644 --- a/Kyoo/Controllers/Repositories/LibraryRepository.cs +++ b/Kyoo/Controllers/Repositories/LibraryRepository.cs @@ -52,10 +52,7 @@ namespace Kyoo.Controllers public override async Task Create(LibraryDE obj) { - if (obj == null) - throw new ArgumentNullException(nameof(obj)); - - await Validate(obj); + await base.Create(obj); _database.Entry(obj).State = EntityState.Added; if (obj.ProviderLinks != null) foreach (ProviderLink entry in obj.ProviderLinks) @@ -103,7 +100,7 @@ namespace Kyoo.Controllers { ICollection libraries = await ApplyFilters(_database.LibraryLinks .Where(x => x.ShowID == showID) - .Select(x => x.Library as LibraryDE), + .Select(x => (LibraryDE)x.Library), where, sort, limit); @@ -119,7 +116,7 @@ namespace Kyoo.Controllers { ICollection libraries = await ApplyFilters(_database.LibraryLinks .Where(x => x.Show.Slug == showSlug) - .Select(x => x.Library as LibraryDE), + .Select(x => (LibraryDE)x.Library), where, sort, limit); @@ -135,7 +132,7 @@ namespace Kyoo.Controllers { ICollection libraries = await ApplyFilters(_database.LibraryLinks .Where(x => x.CollectionID == id) - .Select(x => x.Library as LibraryDE), + .Select(x => (LibraryDE)x.Library), where, sort, limit); @@ -151,7 +148,7 @@ namespace Kyoo.Controllers { ICollection libraries = await ApplyFilters(_database.LibraryLinks .Where(x => x.Collection.Slug == slug) - .Select(x => x.Library as LibraryDE), + .Select(x => (LibraryDE)x.Library), where, sort, limit); diff --git a/Kyoo/Controllers/Repositories/PeopleRepository.cs b/Kyoo/Controllers/Repositories/PeopleRepository.cs index 3dc863fd..5a36b292 100644 --- a/Kyoo/Controllers/Repositories/PeopleRepository.cs +++ b/Kyoo/Controllers/Repositories/PeopleRepository.cs @@ -52,10 +52,7 @@ namespace Kyoo.Controllers public override async Task Create(People obj) { - if (obj == null) - throw new ArgumentNullException(nameof(obj)); - - await Validate(obj); + await base.Create(obj); _database.Entry(obj).State = EntityState.Added; if (obj.ExternalIDs != null) foreach (MetadataID entry in obj.ExternalIDs) diff --git a/Kyoo/Controllers/Repositories/ProviderRepository.cs b/Kyoo/Controllers/Repositories/ProviderRepository.cs index a86960ce..6219a919 100644 --- a/Kyoo/Controllers/Repositories/ProviderRepository.cs +++ b/Kyoo/Controllers/Repositories/ProviderRepository.cs @@ -29,11 +29,7 @@ namespace Kyoo.Controllers public override async Task Create(ProviderID obj) { - if (obj == null) - throw new ArgumentNullException(nameof(obj)); - if (obj.Slug == null) - throw new ArgumentException($"Provider's slug can't be null (name: {obj.Name})."); - + await base.Create(obj); _database.Entry(obj).State = EntityState.Added; await _database.SaveChangesAsync($"Trying to insert a duplicated provider (slug {obj.Slug} already exists)."); diff --git a/Kyoo/Controllers/Repositories/SeasonRepository.cs b/Kyoo/Controllers/Repositories/SeasonRepository.cs index 4d61d34a..5d0a56d9 100644 --- a/Kyoo/Controllers/Repositories/SeasonRepository.cs +++ b/Kyoo/Controllers/Repositories/SeasonRepository.cs @@ -80,10 +80,7 @@ namespace Kyoo.Controllers public override async Task Create(Season obj) { - if (obj == null) - throw new ArgumentNullException(nameof(obj)); - - await Validate(obj); + await base.Create(obj); _database.Entry(obj).State = EntityState.Added; if (obj.ExternalIDs != null) foreach (MetadataID entry in obj.ExternalIDs) diff --git a/Kyoo/Controllers/Repositories/ShowRepository.cs b/Kyoo/Controllers/Repositories/ShowRepository.cs index 2810d641..b54e12ca 100644 --- a/Kyoo/Controllers/Repositories/ShowRepository.cs +++ b/Kyoo/Controllers/Repositories/ShowRepository.cs @@ -88,10 +88,7 @@ namespace Kyoo.Controllers public override async Task Create(ShowDE obj) { - if (obj == null) - throw new ArgumentNullException(nameof(obj)); - - await Validate(obj); + await base.Create(obj); _database.Entry(obj).State = EntityState.Added; if (obj.GenreLinks != null) foreach (GenreLink entry in obj.GenreLinks) @@ -190,7 +187,7 @@ namespace Kyoo.Controllers { ICollection shows = await ApplyFilters(_database.LibraryLinks .Where(x => x.LibraryID == id && x.ShowID != null) - .Select(x => x.Show as ShowDE), + .Select(x => (ShowDE)x.Show), where, sort, limit); @@ -206,7 +203,7 @@ namespace Kyoo.Controllers { ICollection shows = await ApplyFilters(_database.LibraryLinks .Where(x => x.Library.Slug == slug && x.ShowID != null) - .Select(x => x.Show as ShowDE), + .Select(x => (ShowDE)x.Show), where, sort, limit); @@ -222,7 +219,7 @@ namespace Kyoo.Controllers { ICollection shows = await ApplyFilters(_database.CollectionLinks .Where(x => x.CollectionID== id) - .Select(x => x.Show as ShowDE), + .Select(x => (ShowDE)x.Show), where, sort, limit); @@ -238,7 +235,7 @@ namespace Kyoo.Controllers { ICollection shows = await ApplyFilters(_database.CollectionLinks .Where(x => x.Collection.Slug == slug) - .Select(x => x.Show as ShowDE), + .Select(x => (ShowDE)x.Show), where, sort, limit); diff --git a/Kyoo/Controllers/Repositories/StudioRepository.cs b/Kyoo/Controllers/Repositories/StudioRepository.cs index f9329d89..a8922f90 100644 --- a/Kyoo/Controllers/Repositories/StudioRepository.cs +++ b/Kyoo/Controllers/Repositories/StudioRepository.cs @@ -30,9 +30,7 @@ namespace Kyoo.Controllers public override async Task Create(Studio obj) { - if (obj == null) - throw new ArgumentNullException(nameof(obj)); - + await base.Create(obj); _database.Entry(obj).State = EntityState.Added; await _database.SaveChangesAsync($"Trying to insert a duplicated studio (slug {obj.Slug} already exists)."); return obj; diff --git a/Kyoo/Controllers/Repositories/TrackRepository.cs b/Kyoo/Controllers/Repositories/TrackRepository.cs index 60c25fe7..6765309e 100644 --- a/Kyoo/Controllers/Repositories/TrackRepository.cs +++ b/Kyoo/Controllers/Repositories/TrackRepository.cs @@ -68,14 +68,11 @@ namespace Kyoo.Controllers public override async Task Create(Track obj) { - if (obj == null) - throw new ArgumentNullException(nameof(obj)); - if (obj.EpisodeID <= 0) throw new InvalidOperationException($"Can't store a track not related to any episode (episodeID: {obj.EpisodeID})."); + await base.Create(obj); _database.Entry(obj).State = EntityState.Added; - await _database.SaveChangesAsync($"Trying to insert a duplicated track (slug {obj.Slug} already exists)."); return obj; } diff --git a/Kyoo/Startup.cs b/Kyoo/Startup.cs index 673431da..d6ff4004 100644 --- a/Kyoo/Startup.cs +++ b/Kyoo/Startup.cs @@ -46,9 +46,9 @@ namespace Kyoo services.AddDbContext(options => { options.UseLazyLoadingProxies() - .UseNpgsql(_configuration.GetConnectionString("Database")) - .EnableSensitiveDataLogging() - .UseLoggerFactory(LoggerFactory.Create(builder => builder.AddConsole())); + .UseNpgsql(_configuration.GetConnectionString("Database")); + // .EnableSensitiveDataLogging() + // .UseLoggerFactory(LoggerFactory.Create(builder => builder.AddConsole())); }, ServiceLifetime.Transient); services.AddDbContext(options =>