diff --git a/back/src/Kyoo.Abstractions/Controllers/ILibraryManager.cs b/back/src/Kyoo.Abstractions/Controllers/ILibraryManager.cs index fbe8d1ab..6e84c43a 100644 --- a/back/src/Kyoo.Abstractions/Controllers/ILibraryManager.cs +++ b/back/src/Kyoo.Abstractions/Controllers/ILibraryManager.cs @@ -16,12 +16,7 @@ // You should have received a copy of the GNU General Public License // along with Kyoo. If not, see . -using System; -using System.Collections.Generic; -using System.Linq.Expressions; -using System.Threading.Tasks; using Kyoo.Abstractions.Models; -using Kyoo.Abstractions.Models.Exceptions; namespace Kyoo.Abstractions.Controllers { @@ -30,413 +25,49 @@ namespace Kyoo.Abstractions.Controllers /// public interface ILibraryManager { - /// - /// Get the repository corresponding to the T item. - /// - /// The type you want - /// If the item is not found - /// The repository corresponding - IRepository GetRepository() - where T : class, IResource; - /// /// The repository that handle libraries items (a wrapper around shows and collections). /// - ILibraryItemRepository LibraryItemRepository { get; } + IRepository LibraryItems { get; } /// /// The repository that handle collections. /// - ICollectionRepository CollectionRepository { get; } + IRepository Collections { get; } /// /// The repository that handle shows. /// - IMovieRepository MovieRepository { get; } + IRepository Movies { get; } /// /// The repository that handle shows. /// - IShowRepository ShowRepository { get; } + IRepository Shows { get; } /// /// The repository that handle seasons. /// - ISeasonRepository SeasonRepository { get; } + IRepository Seasons { get; } /// /// The repository that handle episodes. /// - IEpisodeRepository EpisodeRepository { get; } + IRepository Episodes { get; } /// /// The repository that handle people. /// - IPeopleRepository PeopleRepository { get; } + IRepository People { get; } /// /// The repository that handle studios. /// - IStudioRepository StudioRepository { get; } + IRepository Studios { get; } /// /// The repository that handle users. /// - IUserRepository UserRepository { get; } - - /// - /// Get the resource by it's ID - /// - /// The id of the resource - /// The type of the resource - /// If the item is not found - /// The resource found - Task Get(int id) - where T : class, IResource; - - /// - /// Get the resource by it's slug - /// - /// The slug of the resource - /// The type of the resource - /// If the item is not found - /// The resource found - Task Get(string slug) - where T : class, IResource; - - /// - /// Get the resource by a filter function. - /// - /// The filter function. - /// The type of the resource - /// If the item is not found - /// The first resource found that match the where function - Task Get(Expression> where) - where T : class, IResource; - - /// - /// Get a season from it's showID and it's seasonNumber - /// - /// The id of the show - /// The season's number - /// If the item is not found - /// The season found - Task Get(int showID, int seasonNumber); - - /// - /// Get a season from it's show slug and it's seasonNumber - /// - /// The slug of the show - /// The season's number - /// If the item is not found - /// The season found - Task Get(string showSlug, int seasonNumber); - - /// - /// Get a episode from it's showID, it's seasonNumber and it's episode number. - /// - /// The id of the show - /// The season's number - /// The episode's number - /// If the item is not found - /// The episode found - Task Get(int showID, int seasonNumber, int episodeNumber); - - /// - /// Get a episode from it's show slug, it's seasonNumber and it's episode number. - /// - /// The slug of the show - /// The season's number - /// The episode's number - /// If the item is not found - /// The episode found - Task Get(string showSlug, int seasonNumber, int episodeNumber); - - /// - /// Get the resource by it's ID or null if it is not found. - /// - /// The id of the resource - /// The type of the resource - /// The resource found - Task GetOrDefault(int id) - where T : class, IResource; - - /// - /// Get the resource by it's slug or null if it is not found. - /// - /// The slug of the resource - /// The type of the resource - /// The resource found - Task GetOrDefault(string slug) - where T : class, IResource; - - /// - /// Get the resource by a filter function or null if it is not found. - /// - /// The filter function. - /// A custom sort method to handle cases where multiples items match the filters. - /// The type of the resource - /// The first resource found that match the where function - Task GetOrDefault(Expression> where, Sort? sortBy = default) - where T : class, IResource; - - /// - /// Get a season from it's showID and it's seasonNumber or null if it is not found. - /// - /// The id of the show - /// The season's number - /// The season found - Task GetOrDefault(int showID, int seasonNumber); - - /// - /// Get a season from it's show slug and it's seasonNumber or null if it is not found. - /// - /// The slug of the show - /// The season's number - /// The season found - Task GetOrDefault(string showSlug, int seasonNumber); - - /// - /// Get a episode from it's showID, it's seasonNumber and it's episode number or null if it is not found. - /// - /// The id of the show - /// The season's number - /// The episode's number - /// The episode found - Task GetOrDefault(int showID, int seasonNumber, int episodeNumber); - - /// - /// Get a episode from it's show slug, it's seasonNumber and it's episode number or null if it is not found. - /// - /// The slug of the show - /// The season's number - /// The episode's number - /// The episode found - Task GetOrDefault(string showSlug, int seasonNumber, int episodeNumber); - - /// - /// Load a related resource - /// - /// The source object. - /// A getter function for the member to load - /// - /// true if you want to load the relation even if it is not null, false otherwise. - /// - /// The type of the source object - /// The related resource's type - /// The param - /// - /// - /// - Task Load(T obj, Expression> member, bool force = false) - where T : class, IResource - where T2 : class, IResource; - - /// - /// Load a collection of related resource - /// - /// The source object. - /// A getter function for the member to load - /// - /// true if you want to load the relation even if it is not null, false otherwise. - /// - /// The type of the source object - /// The related resource's type - /// The param - /// - /// - /// - Task Load(T obj, Expression>> member, bool force = false) - where T : class, IResource - where T2 : class; - - /// - /// Load a related resource by it's name - /// - /// The source object. - /// The name of the resource to load (case sensitive) - /// - /// true if you want to load the relation even if it is not null, false otherwise. - /// - /// The type of the source object - /// The param - /// - /// - /// - Task Load(T obj, string memberName, bool force = false) - where T : class, IResource; - - /// - /// Load a related resource without specifying it's type. - /// - /// The source object. - /// The name of the resource to load (case sensitive) - /// - /// true if you want to load the relation even if it is not null, false otherwise. - /// - /// - /// - /// - /// A representing the asynchronous operation. - Task Load(IResource obj, string memberName, bool force = false); - - /// - /// Get people's roles from a show. - /// - /// The ID of the show - /// A filter function - /// Sort information (sort order and sort by) - /// How many items to return and where to start - /// No exist with the given ID. - /// A list of items that match every filters - Task> GetPeopleFromShow(int showID, - Expression>? where = null, - Sort? sort = default, - Pagination? limit = default); - - /// - /// Get people's roles from a show. - /// - /// The slug of the show - /// A filter function - /// Sort information (sort order and sort by) - /// How many items to return and where to start - /// No exist with the given slug. - /// A list of items that match every filters - Task> GetPeopleFromShow(string showSlug, - Expression>? where = null, - Sort? sort = default, - Pagination? limit = default); - - /// - /// Get people's roles from a person. - /// - /// The id of the person - /// A filter function - /// Sort information (sort order and sort by) - /// How many items to return and where to start - /// No exist with the given ID. - /// A list of items that match every filters - Task> GetRolesFromPeople(int id, - Expression>? where = null, - Sort? sort = default, - Pagination? limit = default); - - /// - /// Get people's roles from a person. - /// - /// The slug of the person - /// A filter function - /// Sort information (sort order and sort by) - /// How many items to return and where to start - /// No exist with the given slug. - /// A list of items that match every filters - Task> GetRolesFromPeople(string slug, - Expression>? where = null, - Sort? sort = default, - Pagination? limit = default); - - /// - /// Get all resources with filters - /// - /// A filter function - /// Sort information (sort order and sort by) - /// How many items to return and where to start - /// The type of resources to load - /// A list of resources that match every filters - Task> GetAll(Expression>? where = null, - Sort? sort = default, - Pagination? limit = default) - where T : class, IResource; - - /// - /// Get the count of resources that match the filter - /// - /// A filter function - /// The type of resources to load - /// A list of resources that match every filters - Task GetCount(Expression>? where = null) - where T : class, IResource; - - /// - /// Search for a resource - /// - /// The search query - /// The type of resources - /// A list of 20 items that match the search query - Task> Search(string query) - where T : class, IResource; - - /// - /// Create a new resource. - /// - /// The item to register - /// The type of resource - /// The resource registers and completed by database's information (related items and so on) - Task Create(T item) - where T : class, IResource; - - /// - /// Create a new resource if it does not exist already. If it does, the existing value is returned instead. - /// - /// The item to register - /// The type of resource - /// The newly created item or the existing value if it existed. - Task CreateIfNotExists(T item) - where T : class, IResource; - - /// - /// Edit a resource - /// - /// The resource to edit, it's ID can't change. - /// The type of resources - /// If the item is not found - /// The resource edited and completed by database's information (related items and so on) - Task Edit(T item) - where T : class, IResource; - - /// - /// Edit only specific properties of a resource - /// - /// The id of the resource to edit - /// - /// A method that will be called when you need to update every properties that you want to - /// persist. It can return false to abort the process via an ArgumentException - /// - /// The type of resources - /// If the item is not found - /// The resource edited and completed by database's information (related items and so on) - Task Patch(int id, Func> patch) - where T : class, IResource; - - /// - /// Delete a resource. - /// - /// The resource to delete - /// The type of resource to delete - /// If the item is not found - /// A representing the asynchronous operation. - Task Delete(T item) - where T : class, IResource; - - /// - /// Delete a resource by it's ID. - /// - /// The id of the resource to delete - /// The type of resource to delete - /// If the item is not found - /// A representing the asynchronous operation. - Task Delete(int id) - where T : class, IResource; - - /// - /// Delete a resource by it's slug. - /// - /// The slug of the resource to delete - /// The type of resource to delete - /// If the item is not found - /// A representing the asynchronous operation. - Task Delete(string slug) - where T : class, IResource; + IRepository Users { get; } } } diff --git a/back/src/Kyoo.Abstractions/Controllers/IRepository.cs b/back/src/Kyoo.Abstractions/Controllers/IRepository.cs index df64bbd7..a13fcd10 100644 --- a/back/src/Kyoo.Abstractions/Controllers/IRepository.cs +++ b/back/src/Kyoo.Abstractions/Controllers/IRepository.cs @@ -22,6 +22,7 @@ using System.Linq.Expressions; using System.Threading.Tasks; using Kyoo.Abstractions.Models; using Kyoo.Abstractions.Models.Exceptions; +using Kyoo.Abstractions.Models.Utils; namespace Kyoo.Abstractions.Controllers { @@ -42,47 +43,55 @@ namespace Kyoo.Abstractions.Controllers /// Get a resource from it's ID. /// /// The id of the resource + /// The related fields to include. /// If the item could not be found. /// The resource found - Task Get(int id); + Task Get(int id, Include? include = default); /// /// Get a resource from it's slug. /// /// The slug of the resource + /// The related fields to include. /// If the item could not be found. /// The resource found - Task Get(string slug); + Task Get(string slug, Include? include = default); /// /// Get the first resource that match the predicate. /// /// A predicate to filter the resource. + /// The related fields to include. /// If the item could not be found. /// The resource found - Task Get(Expression> where); + Task Get(Expression> where, Include? include = default); /// /// Get a resource from it's ID or null if it is not found. /// /// The id of the resource + /// The related fields to include. /// The resource found - Task GetOrDefault(int id); + Task GetOrDefault(int id, Include? include = default); /// /// Get a resource from it's slug or null if it is not found. /// /// The slug of the resource + /// The related fields to include. /// The resource found - Task GetOrDefault(string slug); + Task GetOrDefault(string slug, Include? include = default); /// /// Get the first resource that match the predicate or null if it is not found. /// /// A predicate to filter the resource. + /// The related fields to include. /// A custom sort method to handle cases where multiples items match the filters. /// The resource found - Task GetOrDefault(Expression> where, Sort? sortBy = default); + Task GetOrDefault(Expression> where, + Include? include = default, + Sort? sortBy = default); /// /// Search for resources. @@ -97,10 +106,12 @@ namespace Kyoo.Abstractions.Controllers /// A filter predicate /// Sort information about the query (sort by, sort order) /// How pagination should be done (where to start and how many to return) + /// The related fields to include. /// A list of resources that match every filters Task> GetAll(Expression>? where = null, Sort? sort = default, - Pagination? limit = default); + Pagination? limit = default, + Include? include = default); /// /// Get the number of resources that match the filter's predicate. @@ -200,209 +211,4 @@ namespace Kyoo.Abstractions.Controllers /// Type RepositoryType { get; } } - - /// - /// A repository to handle shows. - /// - public interface IMovieRepository : IRepository { } - - /// - /// A repository to handle shows. - /// - public interface IShowRepository : IRepository - { - /// - /// Get a show's slug from it's ID. - /// - /// The ID of the show - /// If a show with the given ID is not found. - /// The show's slug - Task GetSlug(int showID); - } - - /// - /// A repository to handle seasons. - /// - public interface ISeasonRepository : IRepository - { - /// - /// Get a season from it's showID and it's seasonNumber - /// - /// The id of the show - /// The season's number - /// If the item is not found - /// The season found - Task Get(int showID, int seasonNumber); - - /// - /// Get a season from it's show slug and it's seasonNumber - /// - /// The slug of the show - /// The season's number - /// If the item is not found - /// The season found - Task Get(string showSlug, int seasonNumber); - - /// - /// Get a season from it's showID and it's seasonNumber or null if it is not found. - /// - /// The id of the show - /// The season's number - /// The season found - Task GetOrDefault(int showID, int seasonNumber); - - /// - /// Get a season from it's show slug and it's seasonNumber or null if it is not found. - /// - /// The slug of the show - /// The season's number - /// The season found - Task GetOrDefault(string showSlug, int seasonNumber); - } - - /// - /// The repository to handle episodes - /// - public interface IEpisodeRepository : IRepository - { - // TODO replace the next methods with extension methods. - - /// - /// Get a episode from it's showID, it's seasonNumber and it's episode number. - /// - /// The id of the show - /// The season's number - /// The episode's number - /// If the item is not found - /// The episode found - Task Get(int showID, int seasonNumber, int episodeNumber); - - /// - /// Get a episode from it's show slug, it's seasonNumber and it's episode number. - /// - /// The slug of the show - /// The season's number - /// The episode's number - /// If the item is not found - /// The episode found - Task Get(string showSlug, int seasonNumber, int episodeNumber); - - /// - /// Get a episode from it's showID, it's seasonNumber and it's episode number or null if it is not found. - /// - /// The id of the show - /// The season's number - /// The episode's number - /// The episode found - Task GetOrDefault(int showID, int seasonNumber, int episodeNumber); - - /// - /// Get a episode from it's show slug, it's seasonNumber and it's episode number or null if it is not found. - /// - /// The slug of the show - /// The season's number - /// The episode's number - /// The episode found - Task GetOrDefault(string showSlug, int seasonNumber, int episodeNumber); - - /// - /// Get a episode from it's showID and it's absolute number. - /// - /// The id of the show - /// The episode's absolute number (The episode number does not reset to 1 after the end of a season. - /// If the item is not found - /// The episode found - Task GetAbsolute(int showID, int absoluteNumber); - - /// - /// Get a episode from it's showID and it's absolute number. - /// - /// The slug of the show - /// The episode's absolute number (The episode number does not reset to 1 after the end of a season. - /// If the item is not found - /// The episode found - Task GetAbsolute(string showSlug, int absoluteNumber); - } - - /// - /// A repository to handle library items (A wrapper around shows and collections). - /// - public interface ILibraryItemRepository : IRepository { } - - /// - /// A repository for collections - /// - public interface ICollectionRepository : IRepository { } - - /// - /// A repository for studios. - /// - public interface IStudioRepository : IRepository { } - - /// - /// A repository for people. - /// - public interface IPeopleRepository : IRepository - { - /// - /// Get people's roles from a show. - /// - /// The ID of the show - /// A filter function - /// Sort information (sort order and sort by) - /// How many items to return and where to start - /// No exist with the given ID. - /// A list of items that match every filters - Task> GetFromShow(int showID, - Expression>? where = null, - Sort? sort = default, - Pagination? limit = default); - - /// - /// Get people's roles from a show. - /// - /// The slug of the show - /// A filter function - /// Sort information (sort order and sort by) - /// How many items to return and where to start - /// No exist with the given slug. - /// A list of items that match every filters - Task> GetFromShow(string showSlug, - Expression>? where = null, - Sort? sort = default, - Pagination? limit = default); - - /// - /// Get people's roles from a person. - /// - /// The id of the person - /// A filter function - /// Sort information (sort order and sort by) - /// How many items to return and where to start - /// No exist with the given ID. - /// A list of items that match every filters - Task> GetFromPeople(int id, - Expression>? where = null, - Sort? sort = default, - Pagination? limit = default); - - /// - /// Get people's roles from a person. - /// - /// The slug of the person - /// A filter function - /// Sort information (sort order and sort by) - /// How many items to return and where to start - /// No exist with the given slug. - /// A list of items that match every filters - Task> GetFromPeople(string slug, - Expression>? where = null, - Sort? sort = default, - Pagination? limit = default); - } - - /// - /// A repository to handle users. - /// - public interface IUserRepository : IRepository { } } diff --git a/back/src/Kyoo.Abstractions/Models/Utils/Include.cs b/back/src/Kyoo.Abstractions/Models/Utils/Include.cs new file mode 100644 index 00000000..6cedf16c --- /dev/null +++ b/back/src/Kyoo.Abstractions/Models/Utils/Include.cs @@ -0,0 +1,48 @@ +// Kyoo - A portable and vast media library solution. +// Copyright (c) Kyoo. +// +// See AUTHORS.md and LICENSE file in the project root for full license information. +// +// Kyoo is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// any later version. +// +// Kyoo is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Kyoo. If not, see . + +using System.ComponentModel.DataAnnotations; +using System.Reflection; +using Kyoo.Abstractions.Models.Attributes; + +namespace Kyoo.Abstractions.Models.Utils; + +public class Include + where T : IResource +{ + public string[] Fields { get; private init; } + + public static Include From(string fields) + { + if (string.IsNullOrEmpty(fields)) + return new(); + + string[] values = fields.Split(','); + foreach (string field in values) + { + PropertyInfo? prop = typeof(T).GetProperty(field, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance); + if (prop?.GetCustomAttribute() == null) + throw new ValidationException($"No loadable relation with the name {field}."); + } + + return new() + { + Fields = values, + }; + } +} diff --git a/back/src/Kyoo.Authentication/Views/AuthApi.cs b/back/src/Kyoo.Authentication/Views/AuthApi.cs index 2040ac13..5effe83d 100644 --- a/back/src/Kyoo.Authentication/Views/AuthApi.cs +++ b/back/src/Kyoo.Authentication/Views/AuthApi.cs @@ -47,7 +47,7 @@ namespace Kyoo.Authentication.Views /// /// The repository to handle users. /// - private readonly IUserRepository _users; + private readonly IRepository _users; /// /// The token generator. @@ -65,7 +65,7 @@ namespace Kyoo.Authentication.Views /// The repository used to check if the user exists. /// The token generator. /// The permission opitons. - public AuthApi(IUserRepository users, ITokenController token, PermissionOption permissions) + public AuthApi(IRepository users, ITokenController token, PermissionOption permissions) { _users = users; _token = token; diff --git a/back/src/Kyoo.Core/Controllers/LibraryManager.cs b/back/src/Kyoo.Core/Controllers/LibraryManager.cs index 664f56bb..bceab8f8 100644 --- a/back/src/Kyoo.Core/Controllers/LibraryManager.cs +++ b/back/src/Kyoo.Core/Controllers/LibraryManager.cs @@ -16,16 +16,8 @@ // You should have received a copy of the GNU General Public License // along with Kyoo. If not, see . -using System; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Linq.Expressions; -using System.Threading.Tasks; using Kyoo.Abstractions.Controllers; using Kyoo.Abstractions.Models; -using Kyoo.Abstractions.Models.Exceptions; -using Kyoo.Utils; namespace Kyoo.Core.Controllers { @@ -34,438 +26,53 @@ namespace Kyoo.Core.Controllers /// public class LibraryManager : ILibraryManager { - /// - /// The list of repositories - /// - private readonly IBaseRepository[] _repositories; - - /// - public ILibraryItemRepository LibraryItemRepository { get; } - - /// - public ICollectionRepository CollectionRepository { get; } - - /// - public IMovieRepository MovieRepository { get; } - - /// - public IShowRepository ShowRepository { get; } - - /// - public ISeasonRepository SeasonRepository { get; } - - /// - public IEpisodeRepository EpisodeRepository { get; } - - /// - public IPeopleRepository PeopleRepository { get; } - - /// - public IStudioRepository StudioRepository { get; } - - /// - public IUserRepository UserRepository { get; } - - /// - /// Create a new instance with every repository available. - /// - /// The list of repositories that this library manager should manage. - /// If a repository for every base type is not available, this instance won't be stable. - public LibraryManager(IEnumerable repositories) + public LibraryManager( + IRepository libraryItemRepository, + IRepository collectionRepository, + IRepository movieRepository, + IRepository showRepository, + IRepository seasonRepository, + IRepository episodeRepository, + IRepository peopleRepository, + IRepository studioRepository, + IRepository userRepository) { - _repositories = repositories.ToArray(); - LibraryItemRepository = (ILibraryItemRepository)GetRepository(); - CollectionRepository = (ICollectionRepository)GetRepository(); - MovieRepository = (IMovieRepository)GetRepository(); - ShowRepository = (IShowRepository)GetRepository(); - SeasonRepository = (ISeasonRepository)GetRepository(); - EpisodeRepository = (IEpisodeRepository)GetRepository(); - PeopleRepository = (IPeopleRepository)GetRepository(); - StudioRepository = (IStudioRepository)GetRepository(); - UserRepository = (IUserRepository)GetRepository(); + LibraryItems = libraryItemRepository; + Collections = collectionRepository; + Movies = movieRepository; + Shows = showRepository; + Seasons = seasonRepository; + Episodes = episodeRepository; + People = peopleRepository; + Studios = studioRepository; + Users = userRepository; } /// - public IRepository GetRepository() - where T : class, IResource - { - if (_repositories.FirstOrDefault(x => x.RepositoryType == typeof(T)) is IRepository ret) - return ret; - throw new ItemNotFoundException($"No repository found for the type {typeof(T).Name}."); - } + public IRepository LibraryItems { get; } /// - public Task Get(int id) - where T : class, IResource - { - return GetRepository().Get(id); - } + public IRepository Collections { get; } /// - public Task Get(string slug) - where T : class, IResource - { - return GetRepository().Get(slug); - } + public IRepository Movies { get; } /// - public Task Get(Expression> where) - where T : class, IResource - { - return GetRepository().Get(where); - } + public IRepository Shows { get; } /// - public Task Get(int showID, int seasonNumber) - { - return SeasonRepository.Get(showID, seasonNumber); - } + public IRepository Seasons { get; } /// - public Task Get(string showSlug, int seasonNumber) - { - return SeasonRepository.Get(showSlug, seasonNumber); - } + public IRepository Episodes { get; } /// - public Task Get(int showID, int seasonNumber, int episodeNumber) - { - return EpisodeRepository.Get(showID, seasonNumber, episodeNumber); - } + public IRepository People { get; } /// - public Task Get(string showSlug, int seasonNumber, int episodeNumber) - { - return EpisodeRepository.Get(showSlug, seasonNumber, episodeNumber); - } + public IRepository Studios { get; } /// - public async Task GetOrDefault(int id) - where T : class, IResource - { - return await GetRepository().GetOrDefault(id); - } - - /// - public async Task GetOrDefault(string slug) - where T : class, IResource - { - return await GetRepository().GetOrDefault(slug); - } - - /// - public async Task GetOrDefault(Expression> where, Sort? sortBy) - where T : class, IResource - { - return await GetRepository().GetOrDefault(where, sortBy); - } - - /// - public async Task GetOrDefault(int showID, int seasonNumber) - { - return await SeasonRepository.GetOrDefault(showID, seasonNumber); - } - - /// - public async Task GetOrDefault(string showSlug, int seasonNumber) - { - return await SeasonRepository.GetOrDefault(showSlug, seasonNumber); - } - - /// - public async Task GetOrDefault(int showID, int seasonNumber, int episodeNumber) - { - return await EpisodeRepository.GetOrDefault(showID, seasonNumber, episodeNumber); - } - - /// - public async Task GetOrDefault(string showSlug, int seasonNumber, int episodeNumber) - { - return await EpisodeRepository.GetOrDefault(showSlug, seasonNumber, episodeNumber); - } - - /// - /// Set relations between to objects. - /// - /// The owner object - /// A Task to load a collection of related objects - /// A setter function to store the collection of related objects - /// A setter function to store the owner of a releated object loaded - /// The type of the owner object - /// The type of the related object - private static async Task _SetRelation(T1 obj, - Task> loader, - Action> setter, - Action inverse) - { - ICollection loaded = await loader; - setter(obj, loaded); - foreach (T2 item in loaded) - inverse(item, obj); - } - - /// - public Task Load(T obj, Expression> member, bool force = false) - where T : class, IResource - where T2 : class, IResource - { - return Load(obj, Utility.GetPropertyName(member), force); - } - - /// - public Task Load(T obj, Expression>> member, bool force = false) - where T : class, IResource - where T2 : class - { - return Load(obj, Utility.GetPropertyName(member), force); - } - - /// - public async Task Load(T obj, string memberName, bool force = false) - where T : class, IResource - { - await Load(obj as IResource, memberName, force); - return obj; - } - - /// - [SuppressMessage("StyleCop.CSharp.LayoutRules", "SA1507:CodeMustNotContainMultipleBlankLinesInARow", - Justification = "Separate the code by semantics and simplify the code read.")] - [SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1107:Code should not contain multiple statements on one line", - Justification = "Assing IDs and Values in the same line.")] - public Task Load(IResource obj, string memberName, bool force = false) - { - if (obj == null) - throw new ArgumentNullException(nameof(obj)); - - object? existingValue = obj.GetType() - .GetProperties() - .FirstOrDefault(x => string.Equals(x.Name, memberName, StringComparison.InvariantCultureIgnoreCase)) - ?.GetValue(obj); - if (existingValue != null && !force) - return Task.CompletedTask; - - return (obj, member: memberName) switch - { - (Collection c, nameof(Collection.Shows)) => ShowRepository - .GetAll(x => x.Collections!.Any(y => y.Id == obj.Id)) - .Then(x => c.Shows = x), - - (Collection c, nameof(Collection.Movies)) => MovieRepository - .GetAll(x => x.Collections!.Any(y => y.Id == obj.Id)) - .Then(x => c.Movies = x), - - - (Movie m, nameof(Movie.People)) => PeopleRepository - .GetFromShow(obj.Id) - .Then(x => m.People = x), - - (Movie m, nameof(Movie.Collections)) => CollectionRepository - .GetAll(x => x.Movies!.Any(y => y.Id == obj.Id)) - .Then(x => m.Collections = x), - - (Movie m, nameof(Movie.Studio)) => StudioRepository - .GetOrDefault(x => x.Movies!.Any(y => y.Id == obj.Id)) - .Then(x => - { - m.Studio = x; - m.StudioID = x?.Id ?? 0; - }), - - - (Show s, nameof(Show.People)) => PeopleRepository - .GetFromShow(obj.Id) - .Then(x => s.People = x), - - (Show s, nameof(Show.Seasons)) => _SetRelation(s, - SeasonRepository.GetAll(x => x.Show!.Id == obj.Id), - (x, y) => x.Seasons = y, - (x, y) => { x.Show = y; x.ShowId = y.Id; }), - - (Show s, nameof(Show.Episodes)) => _SetRelation(s, - EpisodeRepository.GetAll(x => x.Show!.Id == obj.Id), - (x, y) => x.Episodes = y, - (x, y) => { x.Show = y; x.ShowId = y.Id; }), - - (Show s, nameof(Show.Collections)) => CollectionRepository - .GetAll(x => x.Shows!.Any(y => y.Id == obj.Id)) - .Then(x => s.Collections = x), - - (Show s, nameof(Show.Studio)) => StudioRepository - .GetOrDefault(x => x.Shows!.Any(y => y.Id == obj.Id)) - .Then(x => - { - s.Studio = x; - s.StudioId = x?.Id ?? 0; - }), - - - (Season s, nameof(Season.Episodes)) => _SetRelation(s, - EpisodeRepository.GetAll(x => x.Season!.Id == obj.Id), - (x, y) => x.Episodes = y, - (x, y) => { x.Season = y; x.SeasonId = y.Id; }), - - (Season s, nameof(Season.Show)) => ShowRepository - .GetOrDefault(x => x.Seasons!.Any(y => y.Id == obj.Id)) - .Then(x => - { - s.Show = x; - s.ShowId = x?.Id ?? 0; - }), - - - (Episode e, nameof(Episode.Show)) => ShowRepository - .GetOrDefault(x => x.Episodes!.Any(y => y.Id == obj.Id)) - .Then(x => - { - e.Show = x; - e.ShowId = x?.Id ?? 0; - }), - - (Episode e, nameof(Episode.Season)) => SeasonRepository - .GetOrDefault(x => x.Episodes!.Any(y => y.Id == e.Id)) - .Then(x => - { - e.Season = x; - e.SeasonId = x?.Id ?? 0; - }), - - (Episode e, nameof(Episode.PreviousEpisode)) => EpisodeRepository - .GetAll( - where: x => x.ShowId == e.ShowId, - limit: new Pagination(1, e.Id, true) - ).Then(x => e.PreviousEpisode = x.FirstOrDefault()), - - (Episode e, nameof(Episode.NextEpisode)) => EpisodeRepository - .GetAll( - where: x => x.ShowId == e.ShowId, - limit: new Pagination(1, e.Id) - ).Then(x => e.NextEpisode = x.FirstOrDefault()), - - - (Studio s, nameof(Studio.Shows)) => ShowRepository - .GetAll(x => x.Studio!.Id == obj.Id) - .Then(x => s.Shows = x), - - (Studio s, nameof(Studio.Movies)) => MovieRepository - .GetAll(x => x.Studio!.Id == obj.Id) - .Then(x => s.Movies = x), - - - (People p, nameof(People.Roles)) => PeopleRepository - .GetFromPeople(obj.Id) - .Then(x => p.Roles = x), - - _ => throw new ArgumentException($"Couldn't find a way to load {memberName} of {obj.Slug}.") - }; - } - - /// - public Task> GetPeopleFromShow(int showID, - Expression>? where = null, - Sort? sort = default, - Pagination? limit = default) - { - return PeopleRepository.GetFromShow(showID, where, sort, limit); - } - - /// - public Task> GetPeopleFromShow(string showSlug, - Expression>? where = null, - Sort? sort = default, - Pagination? limit = default) - { - return PeopleRepository.GetFromShow(showSlug, where, sort, limit); - } - - /// - public Task> GetRolesFromPeople(int id, - Expression>? where = null, - Sort? sort = default, - Pagination? limit = default) - { - return PeopleRepository.GetFromPeople(id, where, sort, limit); - } - - /// - public Task> GetRolesFromPeople(string slug, - Expression>? where = null, - Sort? sort = default, - Pagination? limit = default) - { - return PeopleRepository.GetFromPeople(slug, where, sort, limit); - } - - /// - public Task> GetAll(Expression>? where = null, - Sort? sort = default, - Pagination? limit = default) - where T : class, IResource - { - return GetRepository().GetAll(where, sort, limit); - } - - /// - public Task GetCount(Expression>? where = null) - where T : class, IResource - { - return GetRepository().GetCount(where); - } - - /// - public Task> Search(string query) - where T : class, IResource - { - return GetRepository().Search(query); - } - - /// - public Task Create(T item) - where T : class, IResource - { - return GetRepository().Create(item); - } - - /// - public Task CreateIfNotExists(T item) - where T : class, IResource - { - return GetRepository().CreateIfNotExists(item); - } - - /// - public Task Edit(T item) - where T : class, IResource - { - return GetRepository().Edit(item); - } - - /// - public Task Patch(int id, Func> patch) - where T : class, IResource - { - return GetRepository().Patch(id, patch); - } - - /// - public Task Delete(T item) - where T : class, IResource - { - return GetRepository().Delete(item); - } - - /// - public Task Delete(int id) - where T : class, IResource - { - return GetRepository().Delete(id); - } - - /// - public Task Delete(string slug) - where T : class, IResource - { - return GetRepository().Delete(slug); - } + public IRepository Users { get; } } } diff --git a/back/src/Kyoo.Core/Controllers/Repositories/CollectionRepository.cs b/back/src/Kyoo.Core/Controllers/Repositories/CollectionRepository.cs index 7b7a1388..df4e0205 100644 --- a/back/src/Kyoo.Core/Controllers/Repositories/CollectionRepository.cs +++ b/back/src/Kyoo.Core/Controllers/Repositories/CollectionRepository.cs @@ -30,7 +30,7 @@ namespace Kyoo.Core.Controllers /// /// A local repository to handle collections /// - public class CollectionRepository : LocalRepository, ICollectionRepository + public class CollectionRepository : LocalRepository { /// /// The database handle diff --git a/back/src/Kyoo.Core/Controllers/Repositories/EpisodeRepository.cs b/back/src/Kyoo.Core/Controllers/Repositories/EpisodeRepository.cs index c9ef4a82..15d9904a 100644 --- a/back/src/Kyoo.Core/Controllers/Repositories/EpisodeRepository.cs +++ b/back/src/Kyoo.Core/Controllers/Repositories/EpisodeRepository.cs @@ -22,9 +22,7 @@ using System.Linq; using System.Threading.Tasks; using Kyoo.Abstractions.Controllers; using Kyoo.Abstractions.Models; -using Kyoo.Abstractions.Models.Exceptions; using Kyoo.Postgresql; -using Kyoo.Utils; using Microsoft.EntityFrameworkCore; namespace Kyoo.Core.Controllers @@ -32,14 +30,14 @@ namespace Kyoo.Core.Controllers /// /// A local repository to handle episodes. /// - public class EpisodeRepository : LocalRepository, IEpisodeRepository + public class EpisodeRepository : LocalRepository { /// /// The database handle /// private readonly DatabaseContext _database; - private readonly IShowRepository _shows; + private readonly IRepository _shows; /// // Use absolute numbers by default and fallback to season/episodes if it does not exists. @@ -56,7 +54,7 @@ namespace Kyoo.Core.Controllers /// A show repository /// The thumbnail manager used to store images. public EpisodeRepository(DatabaseContext database, - IShowRepository shows, + IRepository shows, IThumbnailsManager thumbs) : base(database, thumbs) { @@ -76,60 +74,6 @@ namespace Kyoo.Core.Controllers }; } - /// - public Task GetOrDefault(int showID, int seasonNumber, int episodeNumber) - { - return _database.Episodes.FirstOrDefaultAsync(x => x.ShowId == showID - && x.SeasonNumber == seasonNumber - && x.EpisodeNumber == episodeNumber).Then(SetBackingImage); - } - - /// - public Task GetOrDefault(string showSlug, int seasonNumber, int episodeNumber) - { - return _database.Episodes.FirstOrDefaultAsync(x => x.Show!.Slug == showSlug - && x.SeasonNumber == seasonNumber - && x.EpisodeNumber == episodeNumber).Then(SetBackingImage); - } - - /// - public async Task Get(int showID, int seasonNumber, int episodeNumber) - { - Episode? ret = await GetOrDefault(showID, seasonNumber, episodeNumber); - if (ret == null) - throw new ItemNotFoundException($"No episode S{seasonNumber}E{episodeNumber} found on the show {showID}."); - return ret; - } - - /// - public async Task Get(string showSlug, int seasonNumber, int episodeNumber) - { - Episode? ret = await GetOrDefault(showSlug, seasonNumber, episodeNumber); - if (ret == null) - throw new ItemNotFoundException($"No episode S{seasonNumber}E{episodeNumber} found on the show {showSlug}."); - return ret; - } - - /// - public async Task GetAbsolute(int showID, int absoluteNumber) - { - Episode? ret = await _database.Episodes.FirstOrDefaultAsync(x => x.ShowId == showID - && x.AbsoluteNumber == absoluteNumber).Then(SetBackingImage); - if (ret == null) - throw new ItemNotFoundException(); - return ret; - } - - /// - public async Task GetAbsolute(string showSlug, int absoluteNumber) - { - Episode? ret = await _database.Episodes.FirstOrDefaultAsync(x => x.Show!.Slug == showSlug - && x.AbsoluteNumber == absoluteNumber).Then(SetBackingImage); - if (ret == null) - throw new ItemNotFoundException(); - return ret; - } - /// public override async Task> Search(string query) { @@ -156,9 +100,9 @@ namespace Kyoo.Core.Controllers await base.Create(obj); _database.Entry(obj).State = EntityState.Added; await _database.SaveChangesAsync(() => - obj.SeasonNumber != null && obj.EpisodeNumber != null - ? Get(obj.ShowId, obj.SeasonNumber.Value, obj.EpisodeNumber.Value) - : GetAbsolute(obj.ShowId, obj.AbsoluteNumber!.Value)); + obj is { SeasonNumber: not null, EpisodeNumber: not null } + ? Get(x => x.ShowId == obj.ShowId && x.SeasonNumber == obj.SeasonNumber && x.EpisodeNumber == obj.EpisodeNumber) + : Get(x => x.ShowId == obj.ShowId && x.AbsoluteNumber == obj.AbsoluteNumber)); OnResourceCreated(obj); return obj; } diff --git a/back/src/Kyoo.Core/Controllers/Repositories/LibraryItemRepository.cs b/back/src/Kyoo.Core/Controllers/Repositories/LibraryItemRepository.cs index 045de09d..c3495fcc 100644 --- a/back/src/Kyoo.Core/Controllers/Repositories/LibraryItemRepository.cs +++ b/back/src/Kyoo.Core/Controllers/Repositories/LibraryItemRepository.cs @@ -30,7 +30,7 @@ namespace Kyoo.Core.Controllers /// /// A local repository to handle library items. /// - public class LibraryItemRepository : LocalRepository, ILibraryItemRepository + public class LibraryItemRepository : LocalRepository { /// /// The database handle @@ -41,7 +41,7 @@ namespace Kyoo.Core.Controllers protected override Sort DefaultSort => new Sort.By(x => x.Name); /// - /// Create a new . + /// Create a new . /// /// The database instance /// The thumbnail manager used to store images. diff --git a/back/src/Kyoo.Core/Controllers/Repositories/LocalRepository.cs b/back/src/Kyoo.Core/Controllers/Repositories/LocalRepository.cs index a8b50d66..7133bb63 100644 --- a/back/src/Kyoo.Core/Controllers/Repositories/LocalRepository.cs +++ b/back/src/Kyoo.Core/Controllers/Repositories/LocalRepository.cs @@ -27,6 +27,7 @@ using Kyoo.Abstractions.Controllers; using Kyoo.Abstractions.Models; using Kyoo.Abstractions.Models.Attributes; using Kyoo.Abstractions.Models.Exceptions; +using Kyoo.Abstractions.Models.Utils; using Kyoo.Core.Api; using Kyoo.Postgresql; using Kyoo.Utils; @@ -83,7 +84,7 @@ namespace Kyoo.Core.Controllers /// Sort the given query. /// /// The query to sort. - /// How to sort the query + /// How to sort the query. /// The newly sorted query. protected IOrderedQueryable Sort(IQueryable query, Sort? sortBy = null) { @@ -268,6 +269,15 @@ namespace Kyoo.Core.Controllers return Expression.Lambda>(filter!, x); } + protected IQueryable AddIncludes(IQueryable query, Include? include) + { + if (include == null) + return query; + foreach (string field in include.Fields) + query = query.Include(field); + return query; + } + protected void SetBackingImage(T? obj) { if (obj is not IThumbnails thumbs) @@ -306,50 +316,66 @@ namespace Kyoo.Core.Controllers } /// - public virtual async Task Get(int id) + public virtual async Task Get(int id, Include? include = default) { - T? ret = await GetOrDefault(id); + T? ret = await GetOrDefault(id, include); if (ret == null) throw new ItemNotFoundException($"No {typeof(T).Name} found with the id {id}"); return ret; } /// - public virtual async Task Get(string slug) + public virtual async Task Get(string slug, Include? include = default) { - T? ret = await GetOrDefault(slug); + T? ret = await GetOrDefault(slug, include); if (ret == null) throw new ItemNotFoundException($"No {typeof(T).Name} found with the slug {slug}"); return ret; } /// - public virtual async Task Get(Expression> where) + public virtual async Task Get(Expression> where, Include? include = default) { - T? ret = await GetOrDefault(where); + T? ret = await GetOrDefault(where, include: include); if (ret == null) throw new ItemNotFoundException($"No {typeof(T).Name} found with the given predicate."); return ret; } /// - public virtual Task GetOrDefault(int id) + public virtual Task GetOrDefault(int id, Include? include = default) { - return Database.Set().FirstOrDefaultAsync(x => x.Id == id).Then(SetBackingImage); + return AddIncludes(Database.Set(), include) + .FirstOrDefaultAsync(x => x.Id == id) + .Then(SetBackingImage); } /// - public virtual Task GetOrDefault(string slug) + public virtual Task GetOrDefault(string slug, Include? include = default) { if (slug == "random") - return Database.Set().OrderBy(x => EF.Functions.Random()).FirstOrDefaultAsync().Then(SetBackingImage); - return Database.Set().FirstOrDefaultAsync(x => x.Slug == slug).Then(SetBackingImage); + { + return AddIncludes(Database.Set(), include) + .OrderBy(x => EF.Functions.Random()) + .FirstOrDefaultAsync() + .Then(SetBackingImage); + } + return AddIncludes(Database.Set(), include) + .FirstOrDefaultAsync(x => x.Slug == slug) + .Then(SetBackingImage); } /// - public virtual Task GetOrDefault(Expression> where, Sort? sortBy = default) + public virtual Task GetOrDefault(Expression> where, + Include? include = default, + Sort? sortBy = default) { - return Sort(Database.Set(), sortBy).FirstOrDefaultAsync(where).Then(SetBackingImage); + return Sort( + AddIncludes(Database.Set(), include), + sortBy + ) + .FirstOrDefaultAsync(where) + .Then(SetBackingImage); } /// @@ -358,9 +384,10 @@ namespace Kyoo.Core.Controllers /// public virtual async Task> GetAll(Expression>? where = null, Sort? sort = default, - Pagination? limit = default) + Pagination? limit = default, + Include? include = default) { - return (await ApplyFilters(Database.Set(), where, sort, limit)) + return (await ApplyFilters(Database.Set(), where, sort, limit, include)) .Select(SetBackingImageSelf).ToList(); } @@ -371,12 +398,15 @@ namespace Kyoo.Core.Controllers /// An expression to filter based on arbitrary conditions /// The sort settings (sort order and sort by) /// Pagination information (where to start and how many to get) + /// Related fields to also load with this query. /// The filtered query protected async Task> ApplyFilters(IQueryable query, Expression>? where = null, Sort? sort = default, - Pagination? limit = default) + Pagination? limit = default, + Include? include = default) { + query = AddIncludes(query, include); query = Sort(query, sort); if (where != null) query = query.Where(where); diff --git a/back/src/Kyoo.Core/Controllers/Repositories/MovieRepository.cs b/back/src/Kyoo.Core/Controllers/Repositories/MovieRepository.cs index 328c3cd8..4daf2b7d 100644 --- a/back/src/Kyoo.Core/Controllers/Repositories/MovieRepository.cs +++ b/back/src/Kyoo.Core/Controllers/Repositories/MovieRepository.cs @@ -29,7 +29,7 @@ namespace Kyoo.Core.Controllers /// /// A local repository to handle shows /// - public class MovieRepository : LocalRepository, IMovieRepository + public class MovieRepository : LocalRepository { /// /// The database handle @@ -39,12 +39,12 @@ namespace Kyoo.Core.Controllers /// /// A studio repository to handle creation/validation of related studios. /// - private readonly IStudioRepository _studios; + private readonly IRepository _studios; /// /// A people repository to handle creation/validation of related people. /// - private readonly IPeopleRepository _people; + private readonly IRepository _people; /// protected override Sort DefaultSort => new Sort.By(x => x.Name); @@ -57,8 +57,8 @@ namespace Kyoo.Core.Controllers /// A people repository /// The thumbnail manager used to store images. public MovieRepository(DatabaseContext database, - IStudioRepository studios, - IPeopleRepository people, + IRepository studios, + IRepository people, IThumbnailsManager thumbs) : base(database, thumbs) { diff --git a/back/src/Kyoo.Core/Controllers/Repositories/PeopleRepository.cs b/back/src/Kyoo.Core/Controllers/Repositories/PeopleRepository.cs index deee3aaf..004d6e9f 100644 --- a/back/src/Kyoo.Core/Controllers/Repositories/PeopleRepository.cs +++ b/back/src/Kyoo.Core/Controllers/Repositories/PeopleRepository.cs @@ -32,7 +32,7 @@ namespace Kyoo.Core.Controllers /// /// A local repository to handle people. /// - public class PeopleRepository : LocalRepository, IPeopleRepository + public class PeopleRepository : LocalRepository { /// /// The database handle @@ -42,7 +42,7 @@ namespace Kyoo.Core.Controllers /// /// A lazy loaded show repository to validate requests from shows. /// - private readonly Lazy _shows; + private readonly Lazy> _shows; /// protected override Sort DefaultSort => new Sort.By(x => x.Name); @@ -54,7 +54,7 @@ namespace Kyoo.Core.Controllers /// A lazy loaded show repository /// The thumbnail manager used to store images. public PeopleRepository(DatabaseContext database, - Lazy shows, + Lazy> shows, IThumbnailsManager thumbs) : base(database, thumbs) { @@ -123,13 +123,12 @@ namespace Kyoo.Core.Controllers await base.Delete(obj); } - /// - public Task> GetFromShow(int showID, - Expression>? where = null, - Sort? sort = default, - Pagination? limit = default) - { - return Task.FromResult>(new List()); + // /// + // public Task> GetFromShow(int showID, + // Expression>? where = null, + // Sort? sort = default, + // Pagination? limit = default) + // { // ICollection people = await ApplyFilters(_database.PeopleRoles // .Where(x => x.ShowID == showID) // .Include(x => x.People), @@ -142,69 +141,66 @@ namespace Kyoo.Core.Controllers // foreach (PeopleRole role in people) // role.ForPeople = true; // return people; - } + // } - /// - public Task> GetFromShow(string showSlug, - Expression>? where = null, - Sort? sort = default, - Pagination? limit = default) - { - return Task.FromResult>(new List()); - // ICollection people = await ApplyFilters(_database.PeopleRoles - // .Where(x => x.Show.Slug == showSlug) - // .Include(x => x.People) - // .Include(x => x.Show), - // id => _database.PeopleRoles.FirstOrDefaultAsync(x => x.ID == id), - // x => x.People.Name, - // where, - // sort, - // limit); - // if (!people.Any() && await _shows.Value.GetOrDefault(showSlug) == null) - // throw new ItemNotFoundException(); - // foreach (PeopleRole role in people) - // role.ForPeople = true; - // return people; - } + // /// + // public Task> GetFromShow(string showSlug, + // Expression>? where = null, + // Sort? sort = default, + // Pagination? limit = default) + // { + // ICollection people = await ApplyFilters(_database.PeopleRoles + // .Where(x => x.Show.Slug == showSlug) + // .Include(x => x.People) + // .Include(x => x.Show), + // id => _database.PeopleRoles.FirstOrDefaultAsync(x => x.ID == id), + // x => x.People.Name, + // where, + // sort, + // limit); + // if (!people.Any() && await _shows.Value.GetOrDefault(showSlug) == null) + // throw new ItemNotFoundException(); + // foreach (PeopleRole role in people) + // role.ForPeople = true; + // return people; + // } - /// - public Task> GetFromPeople(int id, - Expression>? where = null, - Sort? sort = default, - Pagination? limit = default) - { - return Task.FromResult>(new List()); - // ICollection roles = await ApplyFilters(_database.PeopleRoles - // .Where(x => x.PeopleID == id) - // .Include(x => x.Show), - // y => _database.PeopleRoles.FirstOrDefaultAsync(x => x.ID == y), - // x => x.Show.Title, - // where, - // sort, - // limit); - // if (!roles.Any() && await GetOrDefault(id) == null) - // throw new ItemNotFoundException(); - // return roles; - } + // /// + // public Task> GetFromPeople(int id, + // Expression>? where = null, + // Sort? sort = default, + // Pagination? limit = default) + // { + // ICollection roles = await ApplyFilters(_database.PeopleRoles + // .Where(x => x.PeopleID == id) + // .Include(x => x.Show), + // y => _database.PeopleRoles.FirstOrDefaultAsync(x => x.ID == y), + // x => x.Show.Title, + // where, + // sort, + // limit); + // if (!roles.Any() && await GetOrDefault(id) == null) + // throw new ItemNotFoundException(); + // return roles; + // } - /// - public Task> GetFromPeople(string slug, - Expression>? where = null, - Sort? sort = default, - Pagination? limit = default) - { - return Task.FromResult>(new List()); - // ICollection roles = await ApplyFilters(_database.PeopleRoles - // .Where(x => x.People.Slug == slug) - // .Include(x => x.Show), - // id => _database.PeopleRoles.FirstOrDefaultAsync(x => x.ID == id), - // x => x.Show.Title, - // where, - // sort, - // limit); - // if (!roles.Any() && await GetOrDefault(slug) == null) - // throw new ItemNotFoundException(); - // return roles; - } + // /// + // public Task> GetFromPeople(string slug, + // Expression>? where = null, + // Sort? sort = default, + // Pagination? limit = default) + // { + // ICollection roles = await ApplyFilters(_database.PeopleRoles + // .Where(x => x.People.Slug == slug) + // .Include(x => x.Show), + // id => _database.PeopleRoles.FirstOrDefaultAsync(x => x.ID == id), + // x => x.Show.Title, + // where, + // sort, + // limit); + // if (!roles.Any() && await GetOrDefault(slug) == null) + // throw new ItemNotFoundException(); + // return roles; + // } } } diff --git a/back/src/Kyoo.Core/Controllers/Repositories/SeasonRepository.cs b/back/src/Kyoo.Core/Controllers/Repositories/SeasonRepository.cs index 417539cc..6fa81f7d 100644 --- a/back/src/Kyoo.Core/Controllers/Repositories/SeasonRepository.cs +++ b/back/src/Kyoo.Core/Controllers/Repositories/SeasonRepository.cs @@ -32,7 +32,7 @@ namespace Kyoo.Core.Controllers /// /// A local repository to handle seasons. /// - public class SeasonRepository : LocalRepository, ISeasonRepository + public class SeasonRepository : LocalRepository { /// /// The database handle @@ -49,7 +49,7 @@ namespace Kyoo.Core.Controllers /// A shows repository /// The thumbnail manager used to store images. public SeasonRepository(DatabaseContext database, - IShowRepository shows, + IRepository shows, IThumbnailsManager thumbs) : base(database, thumbs) { @@ -68,38 +68,6 @@ namespace Kyoo.Core.Controllers }; } - /// - public async Task Get(int showID, int seasonNumber) - { - Season? ret = await GetOrDefault(showID, seasonNumber); - if (ret == null) - throw new ItemNotFoundException($"No season {seasonNumber} found for the show {showID}"); - return ret; - } - - /// - public async Task Get(string showSlug, int seasonNumber) - { - Season? ret = await GetOrDefault(showSlug, seasonNumber); - if (ret == null) - throw new ItemNotFoundException($"No season {seasonNumber} found for the show {showSlug}"); - return ret; - } - - /// - public Task GetOrDefault(int showID, int seasonNumber) - { - return _database.Seasons.FirstOrDefaultAsync(x => x.ShowId == showID - && x.SeasonNumber == seasonNumber).Then(SetBackingImage); - } - - /// - public Task GetOrDefault(string showSlug, int seasonNumber) - { - return _database.Seasons.FirstOrDefaultAsync(x => x.Show!.Slug == showSlug - && x.SeasonNumber == seasonNumber).Then(SetBackingImage); - } - /// public override async Task> Search(string query) { @@ -119,7 +87,7 @@ namespace Kyoo.Core.Controllers await base.Create(obj); obj.ShowSlug = _database.Shows.First(x => x.Id == obj.ShowId).Slug; _database.Entry(obj).State = EntityState.Added; - await _database.SaveChangesAsync(() => Get(obj.ShowId, obj.SeasonNumber)); + await _database.SaveChangesAsync(() => Get(x => x.ShowId == obj.ShowId && x.SeasonNumber == obj.SeasonNumber)); OnResourceCreated(obj); return obj; } diff --git a/back/src/Kyoo.Core/Controllers/Repositories/ShowRepository.cs b/back/src/Kyoo.Core/Controllers/Repositories/ShowRepository.cs index f52f0ce1..1090b744 100644 --- a/back/src/Kyoo.Core/Controllers/Repositories/ShowRepository.cs +++ b/back/src/Kyoo.Core/Controllers/Repositories/ShowRepository.cs @@ -21,7 +21,6 @@ using System.Linq; using System.Threading.Tasks; using Kyoo.Abstractions.Controllers; using Kyoo.Abstractions.Models; -using Kyoo.Abstractions.Models.Exceptions; using Kyoo.Postgresql; using Kyoo.Utils; using Microsoft.EntityFrameworkCore; @@ -31,7 +30,7 @@ namespace Kyoo.Core.Controllers /// /// A local repository to handle shows /// - public class ShowRepository : LocalRepository, IShowRepository + public class ShowRepository : LocalRepository { /// /// The database handle @@ -41,12 +40,12 @@ namespace Kyoo.Core.Controllers /// /// A studio repository to handle creation/validation of related studios. /// - private readonly IStudioRepository _studios; + private readonly IRepository _studios; /// /// A people repository to handle creation/validation of related people. /// - private readonly IPeopleRepository _people; + private readonly IRepository _people; /// protected override Sort DefaultSort => new Sort.By(x => x.Name); @@ -59,8 +58,8 @@ namespace Kyoo.Core.Controllers /// A people repository /// The thumbnail manager used to store images. public ShowRepository(DatabaseContext database, - IStudioRepository studios, - IPeopleRepository people, + IRepository studios, + IRepository people, IThumbnailsManager thumbs) : base(database, thumbs) { @@ -135,17 +134,6 @@ namespace Kyoo.Core.Controllers } } - /// - public async Task GetSlug(int showID) - { - string? ret = await _database.Shows.Where(x => x.Id == showID) - .Select(x => x.Slug) - .FirstOrDefaultAsync(); - if (ret == null) - throw new ItemNotFoundException(); - return ret; - } - /// public override async Task Delete(Show obj) { diff --git a/back/src/Kyoo.Core/Controllers/Repositories/StudioRepository.cs b/back/src/Kyoo.Core/Controllers/Repositories/StudioRepository.cs index 21b16576..aad3a591 100644 --- a/back/src/Kyoo.Core/Controllers/Repositories/StudioRepository.cs +++ b/back/src/Kyoo.Core/Controllers/Repositories/StudioRepository.cs @@ -30,7 +30,7 @@ namespace Kyoo.Core.Controllers /// /// A local repository to handle studios /// - public class StudioRepository : LocalRepository, IStudioRepository + public class StudioRepository : LocalRepository { /// /// The database handle diff --git a/back/src/Kyoo.Core/Controllers/Repositories/UserRepository.cs b/back/src/Kyoo.Core/Controllers/Repositories/UserRepository.cs index 8e40646e..6f050b9e 100644 --- a/back/src/Kyoo.Core/Controllers/Repositories/UserRepository.cs +++ b/back/src/Kyoo.Core/Controllers/Repositories/UserRepository.cs @@ -29,7 +29,7 @@ namespace Kyoo.Core.Controllers /// /// A repository for users. /// - public class UserRepository : LocalRepository, IUserRepository + public class UserRepository : LocalRepository { /// /// The database handle diff --git a/back/src/Kyoo.Core/CoreModule.cs b/back/src/Kyoo.Core/CoreModule.cs index 13a0e5a7..7748c1c9 100644 --- a/back/src/Kyoo.Core/CoreModule.cs +++ b/back/src/Kyoo.Core/CoreModule.cs @@ -50,15 +50,15 @@ namespace Kyoo.Core builder.RegisterType().As().InstancePerLifetimeScope(); builder.RegisterType().As().InstancePerLifetimeScope(); - builder.RegisterRepository(); - builder.RegisterRepository(); - builder.RegisterRepository(); - builder.RegisterRepository(); - builder.RegisterRepository(); - builder.RegisterRepository(); - builder.RegisterRepository(); - builder.RegisterRepository(); - builder.RegisterRepository(); + builder.RegisterRepository(); + builder.RegisterRepository(); + builder.RegisterRepository(); + builder.RegisterRepository(); + builder.RegisterRepository(); + builder.RegisterRepository(); + builder.RegisterRepository(); + builder.RegisterRepository(); + builder.RegisterRepository(); } /// diff --git a/back/src/Kyoo.Core/Views/Helper/CrudApi.cs b/back/src/Kyoo.Core/Views/Helper/CrudApi.cs index 488eb44b..d3cc5fca 100644 --- a/back/src/Kyoo.Core/Views/Helper/CrudApi.cs +++ b/back/src/Kyoo.Core/Views/Helper/CrudApi.cs @@ -62,17 +62,18 @@ namespace Kyoo.Core.Api /// Get a specific resource via it's ID or it's slug. /// /// The ID or slug of the resource to retrieve. + /// The aditional fields to include in the result. /// The retrieved resource. /// A resource with the given ID or slug does not exist. [HttpGet("{identifier:id}")] [PartialPermission(Kind.Read)] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] - public async Task> Get(Identifier identifier) + public async Task> Get(Identifier identifier, [FromQuery] Include? fields) { T? ret = await identifier.Match( - id => Repository.GetOrDefault(id), - slug => Repository.GetOrDefault(slug) + id => Repository.GetOrDefault(id, fields), + slug => Repository.GetOrDefault(slug, fields) ); if (ret == null) return NotFound(); @@ -106,6 +107,7 @@ namespace Kyoo.Core.Api /// Sort information about the query (sort by, sort order). /// Filter the returned items. /// How many items per page should be returned, where should the page start... + /// The aditional fields to include in the result. /// A list of resources that match every filters. /// Invalid filters or sort information. [HttpGet] @@ -115,12 +117,14 @@ namespace Kyoo.Core.Api public async Task>> GetAll( [FromQuery] Sort sortBy, [FromQuery] Dictionary where, - [FromQuery] Pagination pagination) + [FromQuery] Pagination pagination, + [FromQuery] Include? fields) { ICollection resources = await Repository.GetAll( ApiHelper.ParseWhere(where), sortBy, - pagination + pagination, + fields ); return Page(resources, pagination.Limit); diff --git a/back/src/Kyoo.Core/Views/Helper/ResourceViewAttribute.cs b/back/src/Kyoo.Core/Views/Helper/ResourceViewAttribute.cs index c95e51af..aa896e31 100644 --- a/back/src/Kyoo.Core/Views/Helper/ResourceViewAttribute.cs +++ b/back/src/Kyoo.Core/Views/Helper/ResourceViewAttribute.cs @@ -18,18 +18,7 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Threading.Tasks; -using Kyoo.Abstractions.Controllers; -using Kyoo.Abstractions.Models; -using Kyoo.Abstractions.Models.Attributes; -using Kyoo.Abstractions.Models.Utils; -using Kyoo.Utils; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.Controllers; using Microsoft.AspNetCore.Mvc.Filters; -using Microsoft.Extensions.DependencyInjection; namespace Kyoo.Core.Api { @@ -54,80 +43,7 @@ namespace Kyoo.Core.Api context.ActionArguments["where"] = nWhere; } - List fields = context.HttpContext.Request.Query["fields"] - .SelectMany(x => x!.Split(',')) - .ToList(); - - if (context.ActionDescriptor is ControllerActionDescriptor descriptor) - { - Type type = descriptor.MethodInfo.ReturnType; - type = Utility.GetGenericDefinition(type, typeof(Task<>))?.GetGenericArguments()[0] ?? type; - type = Utility.GetGenericDefinition(type, typeof(ActionResult<>))?.GetGenericArguments()[0] ?? type; - type = Utility.GetGenericDefinition(type, typeof(Page<>))?.GetGenericArguments()[0] ?? type; - - context.HttpContext.Items["ResourceType"] = type.Name; - - PropertyInfo[] properties = type.GetProperties() - .Where(x => x.GetCustomAttribute() != null) - .ToArray(); - if (fields.Count == 1 && fields.Contains("all")) - fields = properties.Select(x => x.Name).ToList(); - else - { - fields = fields - .Select(x => - { - string? property = properties - .FirstOrDefault(y - => string.Equals(x, y.Name, StringComparison.InvariantCultureIgnoreCase)) - ?.Name; - if (property != null) - return property; - context.Result = new BadRequestObjectResult( - new RequestError($"{x} does not exist on {type.Name}.") - ); - return null; - }) - .OfType() - .ToList(); - if (context.Result != null) - return; - } - } - context.HttpContext.Items["fields"] = fields; base.OnActionExecuting(context); } - - /// - public override async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next) - { - if (context.Result is ObjectResult result) - await _LoadResultRelations(context, result); - await base.OnResultExecutionAsync(context, next); - } - - private static async Task _LoadResultRelations(ActionContext context, ObjectResult result) - { - if (result.DeclaredType == null) - return; - - ILibraryManager library = context.HttpContext.RequestServices.GetRequiredService(); - ICollection fields = (ICollection)context.HttpContext.Items["fields"]!; - Type? pageType = Utility.GetGenericDefinition(result.DeclaredType, typeof(Page<>)); - - if (pageType != null) - { - foreach (IResource resource in ((dynamic)result.Value!).Items) - { - foreach (string field in fields!) - await library.Load(resource, field); - } - } - else if (result.DeclaredType.IsAssignableTo(typeof(IResource))) - { - foreach (string field in fields!) - await library.Load((IResource)result.Value!, field); - } - } } } diff --git a/back/src/Kyoo.Core/Views/Metadata/StaffApi.cs b/back/src/Kyoo.Core/Views/Metadata/StaffApi.cs index fdce01a1..01aa3983 100644 --- a/back/src/Kyoo.Core/Views/Metadata/StaffApi.cs +++ b/back/src/Kyoo.Core/Views/Metadata/StaffApi.cs @@ -56,43 +56,43 @@ namespace Kyoo.Core.Api /// The thumbnail manager used to retrieve images paths. public StaffApi(ILibraryManager libraryManager, IThumbnailsManager thumbs) - : base(libraryManager.PeopleRepository, thumbs) + : base(libraryManager.People, thumbs) { _libraryManager = libraryManager; } - /// - /// Get roles - /// - /// - /// List the roles in witch this person has played, written or worked in a way. - /// - /// The ID or slug of the person. - /// A key to sort roles by. - /// An optional list of filters. - /// The number of roles to return. - /// A page of roles. - /// The filters or the sort parameters are invalid. - /// No person with the given ID or slug could be found. - [HttpGet("{identifier:id}/roles")] - [HttpGet("{identifier:id}/role", Order = AlternativeRoute)] - [PartialPermission(Kind.Read)] - [ProducesResponseType(StatusCodes.Status200OK)] - [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(RequestError))] - [ProducesResponseType(StatusCodes.Status404NotFound)] - public async Task>> GetRoles(Identifier identifier, - [FromQuery] Sort sortBy, - [FromQuery] Dictionary where, - [FromQuery] Pagination pagination) - { - Expression>? whereQuery = ApiHelper.ParseWhere(where); - - ICollection resources = await identifier.Match( - id => _libraryManager.GetRolesFromPeople(id, whereQuery, sortBy, pagination), - slug => _libraryManager.GetRolesFromPeople(slug, whereQuery, sortBy, pagination) - ); - - return Page(resources, pagination.Limit); - } + // /// + // /// Get roles + // /// + // /// + // /// List the roles in witch this person has played, written or worked in a way. + // /// + // /// The ID or slug of the person. + // /// A key to sort roles by. + // /// An optional list of filters. + // /// The number of roles to return. + // /// A page of roles. + // /// The filters or the sort parameters are invalid. + // /// No person with the given ID or slug could be found. + // [HttpGet("{identifier:id}/roles")] + // [HttpGet("{identifier:id}/role", Order = AlternativeRoute)] + // [PartialPermission(Kind.Read)] + // [ProducesResponseType(StatusCodes.Status200OK)] + // [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(RequestError))] + // [ProducesResponseType(StatusCodes.Status404NotFound)] + // public async Task>> GetRoles(Identifier identifier, + // [FromQuery] Sort sortBy, + // [FromQuery] Dictionary where, + // [FromQuery] Pagination pagination) + // { + // Expression>? whereQuery = ApiHelper.ParseWhere(where); + // + // ICollection resources = await identifier.Match( + // id => _libraryManager.GetRolesFromPeople(id, whereQuery, sortBy, pagination), + // slug => _libraryManager.GetRolesFromPeople(slug, whereQuery, sortBy, pagination) + // ); + // + // return Page(resources, pagination.Limit); + // } } } diff --git a/back/src/Kyoo.Core/Views/Metadata/StudioApi.cs b/back/src/Kyoo.Core/Views/Metadata/StudioApi.cs index 95871123..7439af0f 100644 --- a/back/src/Kyoo.Core/Views/Metadata/StudioApi.cs +++ b/back/src/Kyoo.Core/Views/Metadata/StudioApi.cs @@ -16,7 +16,6 @@ // You should have received a copy of the GNU General Public License // along with Kyoo. If not, see . -using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; @@ -53,7 +52,7 @@ namespace Kyoo.Core.Api /// The library manager used to modify or retrieve information in the data store. /// public StudioApi(ILibraryManager libraryManager) - : base(libraryManager.StudioRepository) + : base(libraryManager.Studios) { _libraryManager = libraryManager; } @@ -68,6 +67,7 @@ namespace Kyoo.Core.Api /// A key to sort shows by. /// An optional list of filters. /// The number of shows to return. + /// The aditional fields to include in the result. /// A page of shows. /// The filters or the sort parameters are invalid. /// No studio with the given ID or slug could be found. @@ -80,15 +80,17 @@ namespace Kyoo.Core.Api public async Task>> GetShows(Identifier identifier, [FromQuery] Sort sortBy, [FromQuery] Dictionary where, - [FromQuery] Pagination pagination) + [FromQuery] Pagination pagination, + [FromQuery] Include fields) { - ICollection resources = await _libraryManager.GetAll( + ICollection resources = await _libraryManager.Shows.GetAll( ApiHelper.ParseWhere(where, identifier.Matcher(x => x.StudioId, x => x.Studio!.Slug)), sortBy, - pagination + pagination, + fields ); - if (!resources.Any() && await _libraryManager.GetOrDefault(identifier.IsSame()) == null) + if (!resources.Any() && await _libraryManager.Studios.GetOrDefault(identifier.IsSame()) == null) return NotFound(); return Page(resources, pagination.Limit); } diff --git a/back/src/Kyoo.Core/Views/Resources/CollectionApi.cs b/back/src/Kyoo.Core/Views/Resources/CollectionApi.cs index 9e8a5e7b..137a5797 100644 --- a/back/src/Kyoo.Core/Views/Resources/CollectionApi.cs +++ b/back/src/Kyoo.Core/Views/Resources/CollectionApi.cs @@ -54,7 +54,7 @@ namespace Kyoo.Core.Api /// The thumbnail manager used to retrieve images paths. public CollectionApi(ILibraryManager libraryManager, IThumbnailsManager thumbs) - : base(libraryManager.CollectionRepository, thumbs) + : base(libraryManager.Collections, thumbs) { _libraryManager = libraryManager; } @@ -69,6 +69,7 @@ namespace Kyoo.Core.Api /// A key to sort shows by. /// An optional list of filters. /// The number of shows to return. + /// The aditional fields to include in the result. /// A page of shows. /// The filters or the sort parameters are invalid. /// No collection with the given ID could be found. @@ -81,15 +82,17 @@ namespace Kyoo.Core.Api public async Task>> GetShows(Identifier identifier, [FromQuery] Sort sortBy, [FromQuery] Dictionary where, - [FromQuery] Pagination pagination) + [FromQuery] Pagination pagination, + [FromQuery] Include fields) { - ICollection resources = await _libraryManager.GetAll( + ICollection resources = await _libraryManager.Shows.GetAll( ApiHelper.ParseWhere(where, identifier.IsContainedIn(x => x.Collections!)), sortBy, - pagination + pagination, + fields ); - if (!resources.Any() && await _libraryManager.GetOrDefault(identifier.IsSame()) == null) + if (!resources.Any() && await _libraryManager.Collections.GetOrDefault(identifier.IsSame()) == null) return NotFound(); return Page(resources, pagination.Limit); } diff --git a/back/src/Kyoo.Core/Views/Resources/EpisodeApi.cs b/back/src/Kyoo.Core/Views/Resources/EpisodeApi.cs index 18c77ba8..7be18dc7 100644 --- a/back/src/Kyoo.Core/Views/Resources/EpisodeApi.cs +++ b/back/src/Kyoo.Core/Views/Resources/EpisodeApi.cs @@ -53,7 +53,7 @@ namespace Kyoo.Core.Api /// The thumbnail manager used to retrieve images paths. public EpisodeApi(ILibraryManager libraryManager, IThumbnailsManager thumbnails) - : base(libraryManager.EpisodeRepository, thumbnails) + : base(libraryManager.Episodes, thumbnails) { _libraryManager = libraryManager; } @@ -65,15 +65,16 @@ namespace Kyoo.Core.Api /// Get the show that this episode is part of. /// /// The ID or slug of the . + /// The aditional fields to include in the result. /// The show that contains this episode. /// No episode with the given ID or slug could be found. [HttpGet("{identifier:id}/show")] [PartialPermission(Kind.Read)] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] - public async Task> GetShow(Identifier identifier) + public async Task> GetShow(Identifier identifier, [FromQuery] Include fields) { - return await _libraryManager.Get(identifier.IsContainedIn(x => x.Episodes!)); + return await _libraryManager.Shows.Get(identifier.IsContainedIn(x => x.Episodes!), fields); } /// @@ -83,6 +84,7 @@ namespace Kyoo.Core.Api /// Get the season that this episode is part of. /// /// The ID or slug of the . + /// The aditional fields to include in the result. /// The season that contains this episode. /// The episode is not part of a season. /// No episode with the given ID or slug could be found. @@ -91,14 +93,17 @@ namespace Kyoo.Core.Api [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status404NotFound)] - public async Task> GetSeason(Identifier identifier) + public async Task> GetSeason(Identifier identifier, [FromQuery] Include fields) { - Season? ret = await _libraryManager.GetOrDefault(identifier.IsContainedIn(x => x.Episodes!)); + Season? ret = await _libraryManager.Seasons.GetOrDefault( + identifier.IsContainedIn(x => x.Episodes!), + fields + ); if (ret != null) return ret; Episode? episode = await identifier.Match( - id => _libraryManager.GetOrDefault(id), - slug => _libraryManager.GetOrDefault(slug) + id => _libraryManager.Episodes.GetOrDefault(id), + slug => _libraryManager.Episodes.GetOrDefault(slug) ); return episode == null ? NotFound() diff --git a/back/src/Kyoo.Core/Views/Resources/LibraryItemApi.cs b/back/src/Kyoo.Core/Views/Resources/LibraryItemApi.cs index 7f2f22b6..79ef417f 100644 --- a/back/src/Kyoo.Core/Views/Resources/LibraryItemApi.cs +++ b/back/src/Kyoo.Core/Views/Resources/LibraryItemApi.cs @@ -16,14 +16,10 @@ // You should have received a copy of the GNU General Public License // along with Kyoo. If not, see . -using System.Collections.Generic; -using System.Threading.Tasks; using Kyoo.Abstractions.Controllers; using Kyoo.Abstractions.Models; using Kyoo.Abstractions.Models.Attributes; using Kyoo.Abstractions.Models.Permissions; -using Kyoo.Abstractions.Models.Utils; -using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using static Kyoo.Abstractions.Models.Utils.Constants; @@ -44,7 +40,7 @@ namespace Kyoo.Core.Api /// /// The library item repository used to modify or retrieve information in the data store. /// - private readonly ILibraryItemRepository _libraryItems; + private readonly IRepository _libraryItems; /// /// Create a new . @@ -53,7 +49,7 @@ namespace Kyoo.Core.Api /// The library item repository used to modify or retrieve information in the data store. /// /// Thumbnail manager to retrieve images. - public LibraryItemApi(ILibraryItemRepository libraryItems, IThumbnailsManager thumbs) + public LibraryItemApi(IRepository libraryItems, IThumbnailsManager thumbs) : base(libraryItems, thumbs) { _libraryItems = libraryItems; diff --git a/back/src/Kyoo.Core/Views/Resources/MovieApi.cs b/back/src/Kyoo.Core/Views/Resources/MovieApi.cs index 8b3058ae..da0ae654 100644 --- a/back/src/Kyoo.Core/Views/Resources/MovieApi.cs +++ b/back/src/Kyoo.Core/Views/Resources/MovieApi.cs @@ -54,7 +54,7 @@ namespace Kyoo.Core.Api /// The thumbnail manager used to retrieve images paths. public MovieApi(ILibraryManager libraryManager, IThumbnailsManager thumbs) - : base(libraryManager.MovieRepository, thumbs) + : base(libraryManager.Movies, thumbs) { _libraryManager = libraryManager; } @@ -100,15 +100,16 @@ namespace Kyoo.Core.Api /// Get the studio that made the show. /// /// The ID or slug of the . + /// The aditional fields to include in the result. /// The studio that made the show. /// No show with the given ID or slug could be found. [HttpGet("{identifier:id}/studio")] [PartialPermission(Kind.Read)] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] - public async Task> GetStudio(Identifier identifier) + public async Task> GetStudio(Identifier identifier, [FromQuery] Include fields) { - return await _libraryManager.Get(identifier.IsContainedIn(x => x.Movies!)); + return await _libraryManager.Studios.Get(identifier.IsContainedIn(x => x.Movies!), fields); } /// @@ -121,6 +122,7 @@ namespace Kyoo.Core.Api /// A key to sort collections by. /// An optional list of filters. /// The number of collections to return. + /// The aditional fields to include in the result. /// A page of collections. /// The filters or the sort parameters are invalid. /// No show with the given ID or slug could be found. @@ -133,15 +135,17 @@ namespace Kyoo.Core.Api public async Task>> GetCollections(Identifier identifier, [FromQuery] Sort sortBy, [FromQuery] Dictionary where, - [FromQuery] Pagination pagination) + [FromQuery] Pagination pagination, + [FromQuery] Include fields) { - ICollection resources = await _libraryManager.GetAll( + ICollection resources = await _libraryManager.Collections.GetAll( ApiHelper.ParseWhere(where, identifier.IsContainedIn(x => x.Movies!)), sortBy, - pagination + pagination, + fields ); - if (!resources.Any() && await _libraryManager.GetOrDefault(identifier.IsSame()) == null) + if (!resources.Any() && await _libraryManager.Movies.GetOrDefault(identifier.IsSame()) == null) return NotFound(); return Page(resources, pagination.Limit); } diff --git a/back/src/Kyoo.Core/Views/Resources/SearchApi.cs b/back/src/Kyoo.Core/Views/Resources/SearchApi.cs index fb6fcbc9..35e45de2 100644 --- a/back/src/Kyoo.Core/Views/Resources/SearchApi.cs +++ b/back/src/Kyoo.Core/Views/Resources/SearchApi.cs @@ -22,6 +22,7 @@ using Kyoo.Abstractions.Controllers; using Kyoo.Abstractions.Models; using Kyoo.Abstractions.Models.Attributes; using Kyoo.Abstractions.Models.Permissions; +using Kyoo.Abstractions.Models.Utils; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using static Kyoo.Abstractions.Models.Utils.Constants; @@ -52,39 +53,6 @@ namespace Kyoo.Core.Api _libraryManager = libraryManager; } - /// - /// Global search - /// - /// - /// Search for collections, shows, episodes, staff, genre and studios at the same time - /// - /// The query to search for. - /// A list of every resources found for the specified query. - [HttpGet] - [Permission(nameof(Collection), Kind.Read)] - [Permission(nameof(Show), Kind.Read)] - [Permission(nameof(Episode), Kind.Read)] - [Permission(nameof(People), Kind.Read)] - [Permission(nameof(Genre), Kind.Read)] - [Permission(nameof(Studio), Kind.Read)] - [ProducesResponseType(StatusCodes.Status200OK)] - public async Task> Search(string query) - { - HttpContext.Items["ResourceType"] = nameof(Episode); - HttpContext.Items["fields"] = new[] { nameof(Episode.Show) }; - return new SearchResult - { - Query = query, - Collections = await _libraryManager.Search(query), - Items = await _libraryManager.Search(query), - Movies = await _libraryManager.Search(query), - Shows = await _libraryManager.Search(query), - Episodes = await _libraryManager.Search(query), - People = await _libraryManager.Search(query), - Studios = await _libraryManager.Search(query) - }; - } - /// /// Search collections /// @@ -92,15 +60,16 @@ namespace Kyoo.Core.Api /// Search for collections /// /// The query to search for. + /// The aditional fields to include in the result. /// A list of collections found for the specified query. [HttpGet("collections")] [HttpGet("collection", Order = AlternativeRoute)] [Permission(nameof(Collection), Kind.Read)] [ApiDefinition("Collections")] [ProducesResponseType(StatusCodes.Status200OK)] - public Task> SearchCollections(string query) + public Task> SearchCollections(string query, [FromQuery] Include fields) { - return _libraryManager.Search(query); + return _libraryManager.Collections.Search(query); } /// @@ -110,15 +79,16 @@ namespace Kyoo.Core.Api /// Search for shows /// /// The query to search for. + /// The aditional fields to include in the result. /// A list of shows found for the specified query. [HttpGet("shows")] [HttpGet("show", Order = AlternativeRoute)] [Permission(nameof(Show), Kind.Read)] [ApiDefinition("Shows")] [ProducesResponseType(StatusCodes.Status200OK)] - public Task> SearchShows(string query) + public Task> SearchShows(string query, [FromQuery] Include fields) { - return _libraryManager.Search(query); + return _libraryManager.Shows.Search(query); } /// @@ -128,15 +98,16 @@ namespace Kyoo.Core.Api /// Search for items /// /// The query to search for. + /// The aditional fields to include in the result. /// A list of items found for the specified query. [HttpGet("items")] [HttpGet("item", Order = AlternativeRoute)] [Permission(nameof(Show), Kind.Read)] [ApiDefinition("Items")] [ProducesResponseType(StatusCodes.Status200OK)] - public Task> SearchItems(string query) + public Task> SearchItems(string query, [FromQuery] Include fields) { - return _libraryManager.Search(query); + return _libraryManager.LibraryItems.Search(query); } /// @@ -146,15 +117,16 @@ namespace Kyoo.Core.Api /// Search for episodes /// /// The query to search for. + /// The aditional fields to include in the result. /// A list of episodes found for the specified query. [HttpGet("episodes")] [HttpGet("episode", Order = AlternativeRoute)] [Permission(nameof(Episode), Kind.Read)] [ApiDefinition("Episodes")] [ProducesResponseType(StatusCodes.Status200OK)] - public Task> SearchEpisodes(string query) + public Task> SearchEpisodes(string query, [FromQuery] Include fields) { - return _libraryManager.Search(query); + return _libraryManager.Episodes.Search(query); } /// @@ -164,6 +136,7 @@ namespace Kyoo.Core.Api /// Search for staff /// /// The query to search for. + /// The aditional fields to include in the result. /// A list of staff members found for the specified query. [HttpGet("staff")] [HttpGet("person", Order = AlternativeRoute)] @@ -171,9 +144,9 @@ namespace Kyoo.Core.Api [Permission(nameof(People), Kind.Read)] [ApiDefinition("Staff")] [ProducesResponseType(StatusCodes.Status200OK)] - public Task> SearchPeople(string query) + public Task> SearchPeople(string query, [FromQuery] Include fields) { - return _libraryManager.Search(query); + return _libraryManager.People.Search(query); } /// @@ -183,15 +156,16 @@ namespace Kyoo.Core.Api /// Search for studios /// /// The query to search for. + /// The aditional fields to include in the result. /// A list of studios found for the specified query. [HttpGet("studios")] [HttpGet("studio", Order = AlternativeRoute)] [Permission(nameof(Studio), Kind.Read)] [ApiDefinition("Studios")] [ProducesResponseType(StatusCodes.Status200OK)] - public Task> SearchStudios(string query) + public Task> SearchStudios(string query, [FromQuery] Include fields) { - return _libraryManager.Search(query); + return _libraryManager.Studios.Search(query); } } } diff --git a/back/src/Kyoo.Core/Views/Resources/SeasonApi.cs b/back/src/Kyoo.Core/Views/Resources/SeasonApi.cs index f00fa9b9..a878acc1 100644 --- a/back/src/Kyoo.Core/Views/Resources/SeasonApi.cs +++ b/back/src/Kyoo.Core/Views/Resources/SeasonApi.cs @@ -54,7 +54,7 @@ namespace Kyoo.Core.Api /// The thumbnail manager used to retrieve images paths. public SeasonApi(ILibraryManager libraryManager, IThumbnailsManager thumbs) - : base(libraryManager.SeasonRepository, thumbs) + : base(libraryManager.Seasons, thumbs) { _libraryManager = libraryManager; } @@ -69,6 +69,7 @@ namespace Kyoo.Core.Api /// A key to sort episodes by. /// An optional list of filters. /// The number of episodes to return. + /// The aditional fields to include in the result. /// A page of episodes. /// The filters or the sort parameters are invalid. /// No season with the given ID or slug could be found. @@ -81,15 +82,17 @@ namespace Kyoo.Core.Api public async Task>> GetEpisode(Identifier identifier, [FromQuery] Sort sortBy, [FromQuery] Dictionary where, - [FromQuery] Pagination pagination) + [FromQuery] Pagination pagination, + [FromQuery] Include fields) { - ICollection resources = await _libraryManager.GetAll( + ICollection resources = await _libraryManager.Episodes.GetAll( ApiHelper.ParseWhere(where, identifier.Matcher(x => x.SeasonId, x => x.Season!.Slug)), sortBy, - pagination + pagination, + fields ); - if (!resources.Any() && await _libraryManager.GetOrDefault(identifier.IsSame()) == null) + if (!resources.Any() && await _libraryManager.Seasons.GetOrDefault(identifier.IsSame()) == null) return NotFound(); return Page(resources, pagination.Limit); } @@ -101,15 +104,19 @@ namespace Kyoo.Core.Api /// Get the show that this season is part of. /// /// The ID or slug of the . + /// The aditional fields to include in the result. /// The show that contains this season. /// No season with the given ID or slug could be found. [HttpGet("{identifier:id}/show")] [PartialPermission(Kind.Read)] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] - public async Task> GetShow(Identifier identifier) + public async Task> GetShow(Identifier identifier, [FromQuery] Include fields) { - Show? ret = await _libraryManager.GetOrDefault(identifier.IsContainedIn(x => x.Seasons!)); + Show? ret = await _libraryManager.Shows.GetOrDefault( + identifier.IsContainedIn(x => x.Seasons!), + fields + ); if (ret == null) return NotFound(); return ret; diff --git a/back/src/Kyoo.Core/Views/Resources/ShowApi.cs b/back/src/Kyoo.Core/Views/Resources/ShowApi.cs index eaa0913d..861bce7f 100644 --- a/back/src/Kyoo.Core/Views/Resources/ShowApi.cs +++ b/back/src/Kyoo.Core/Views/Resources/ShowApi.cs @@ -16,10 +16,8 @@ // You should have received a copy of the GNU General Public License // along with Kyoo. If not, see . -using System; using System.Collections.Generic; using System.Linq; -using System.Linq.Expressions; using System.Threading.Tasks; using Kyoo.Abstractions.Controllers; using Kyoo.Abstractions.Models; @@ -56,7 +54,7 @@ namespace Kyoo.Core.Api /// The thumbnail manager used to retrieve images paths. public ShowApi(ILibraryManager libraryManager, IThumbnailsManager thumbs) - : base(libraryManager.ShowRepository, thumbs) + : base(libraryManager.Shows, thumbs) { _libraryManager = libraryManager; } @@ -71,6 +69,7 @@ namespace Kyoo.Core.Api /// A key to sort seasons by. /// An optional list of filters. /// The number of seasons to return. + /// The aditional fields to include in the result. /// A page of seasons. /// The filters or the sort parameters are invalid. /// No show with the given ID or slug could be found. @@ -83,15 +82,17 @@ namespace Kyoo.Core.Api public async Task>> GetSeasons(Identifier identifier, [FromQuery] Sort sortBy, [FromQuery] Dictionary where, - [FromQuery] Pagination pagination) + [FromQuery] Pagination pagination, + [FromQuery] Include fields) { - ICollection resources = await _libraryManager.GetAll( + ICollection resources = await _libraryManager.Seasons.GetAll( ApiHelper.ParseWhere(where, identifier.Matcher(x => x.ShowId, x => x.Show!.Slug)), sortBy, - pagination + pagination, + fields ); - if (!resources.Any() && await _libraryManager.GetOrDefault(identifier.IsSame()) == null) + if (!resources.Any() && await _libraryManager.Shows.GetOrDefault(identifier.IsSame()) == null) return NotFound(); return Page(resources, pagination.Limit); } @@ -106,6 +107,7 @@ namespace Kyoo.Core.Api /// A key to sort episodes by. /// An optional list of filters. /// The number of episodes to return. + /// The aditional fields to include in the result. /// A page of episodes. /// The filters or the sort parameters are invalid. /// No show with the given ID or slug could be found. @@ -118,51 +120,55 @@ namespace Kyoo.Core.Api public async Task>> GetEpisodes(Identifier identifier, [FromQuery] Sort sortBy, [FromQuery] Dictionary where, - [FromQuery] Pagination pagination) + [FromQuery] Pagination pagination, + [FromQuery] Include fields) { - ICollection resources = await _libraryManager.GetAll( + ICollection resources = await _libraryManager.Episodes.GetAll( ApiHelper.ParseWhere(where, identifier.Matcher(x => x.ShowId, x => x.Show!.Slug)), sortBy, - pagination + pagination, + fields ); - if (!resources.Any() && await _libraryManager.GetOrDefault(identifier.IsSame()) == null) + if (!resources.Any() && await _libraryManager.Shows.GetOrDefault(identifier.IsSame()) == null) return NotFound(); return Page(resources, pagination.Limit); } - /// - /// Get staff - /// - /// - /// List staff members that made this show. - /// - /// The ID or slug of the . - /// A key to sort staff members by. - /// An optional list of filters. - /// The number of people to return. - /// A page of people. - /// The filters or the sort parameters are invalid. - /// No show with the given ID or slug could be found. - [HttpGet("{identifier:id}/staff")] - [HttpGet("{identifier:id}/people", Order = AlternativeRoute)] - [PartialPermission(Kind.Read)] - [ProducesResponseType(StatusCodes.Status200OK)] - [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(RequestError))] - [ProducesResponseType(StatusCodes.Status404NotFound)] - public async Task>> GetPeople(Identifier identifier, - [FromQuery] Sort sortBy, - [FromQuery] Dictionary where, - [FromQuery] Pagination pagination) - { - Expression>? whereQuery = ApiHelper.ParseWhere(where); - - ICollection resources = await identifier.Match( - id => _libraryManager.GetPeopleFromShow(id, whereQuery, sortBy, pagination), - slug => _libraryManager.GetPeopleFromShow(slug, whereQuery, sortBy, pagination) - ); - return Page(resources, pagination.Limit); - } + // /// + // /// Get staff + // /// + // /// + // /// List staff members that made this show. + // /// + // /// The ID or slug of the . + // /// A key to sort staff members by. + // /// An optional list of filters. + // /// The number of people to return. + // /// The aditional fields to include in the result. + // /// A page of people. + // /// The filters or the sort parameters are invalid. + // /// No show with the given ID or slug could be found. + // [HttpGet("{identifier:id}/staff")] + // [HttpGet("{identifier:id}/people", Order = AlternativeRoute)] + // [PartialPermission(Kind.Read)] + // [ProducesResponseType(StatusCodes.Status200OK)] + // [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(RequestError))] + // [ProducesResponseType(StatusCodes.Status404NotFound)] + // public async Task>> GetPeople(Identifier identifier, + // [FromQuery] Sort sortBy, + // [FromQuery] Dictionary where, + // [FromQuery] Pagination pagination, + // [FromQuery] Include fields) + // { + // Expression>? whereQuery = ApiHelper.ParseWhere(where); + // + // ICollection resources = await identifier.Match( + // id => _libraryManager.GetPeopleFromShow(id, whereQuery, sortBy, pagination), + // slug => _libraryManager.GetPeopleFromShow(slug, whereQuery, sortBy, pagination) + // ); + // return Page(resources, pagination.Limit); + // } /// /// Get studio that made the show @@ -171,15 +177,16 @@ namespace Kyoo.Core.Api /// Get the studio that made the show. /// /// The ID or slug of the . + /// The aditional fields to include in the result. /// The studio that made the show. /// No show with the given ID or slug could be found. [HttpGet("{identifier:id}/studio")] [PartialPermission(Kind.Read)] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] - public async Task> GetStudio(Identifier identifier) + public async Task> GetStudio(Identifier identifier, [FromQuery] Include fields) { - return await _libraryManager.Get(identifier.IsContainedIn(x => x.Shows!)); + return await _libraryManager.Studios.Get(identifier.IsContainedIn(x => x.Shows!), fields); } /// @@ -192,6 +199,7 @@ namespace Kyoo.Core.Api /// A key to sort collections by. /// An optional list of filters. /// The number of collections to return. + /// The aditional fields to include in the result. /// A page of collections. /// The filters or the sort parameters are invalid. /// No show with the given ID or slug could be found. @@ -204,15 +212,17 @@ namespace Kyoo.Core.Api public async Task>> GetCollections(Identifier identifier, [FromQuery] Sort sortBy, [FromQuery] Dictionary where, - [FromQuery] Pagination pagination) + [FromQuery] Pagination pagination, + [FromQuery] Include fields) { - ICollection resources = await _libraryManager.GetAll( + ICollection resources = await _libraryManager.Collections.GetAll( ApiHelper.ParseWhere(where, identifier.IsContainedIn(x => x.Shows!)), sortBy, - pagination + pagination, + fields ); - if (!resources.Any() && await _libraryManager.GetOrDefault(identifier.IsSame()) == null) + if (!resources.Any() && await _libraryManager.Shows.GetOrDefault(identifier.IsSame()) == null) return NotFound(); return Page(resources, pagination.Limit); } diff --git a/back/tests/Kyoo.Tests/Database/RepositoryActivator.cs b/back/tests/Kyoo.Tests/Database/RepositoryActivator.cs index 99fd8dcc..0504aeea 100644 --- a/back/tests/Kyoo.Tests/Database/RepositoryActivator.cs +++ b/back/tests/Kyoo.Tests/Database/RepositoryActivator.cs @@ -18,8 +18,10 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using Kyoo.Abstractions.Controllers; +using Kyoo.Abstractions.Models; using Kyoo.Core.Controllers; using Kyoo.Postgresql; using Moq; @@ -34,6 +36,8 @@ namespace Kyoo.Tests.Database private readonly List _databases = new(); + private readonly IBaseRepository[] _repositories; + public RepositoryActivator(ITestOutputHelper output, PostgresFixture postgres = null) { Context = new PostgresTestContext(postgres, output); @@ -42,7 +46,7 @@ namespace Kyoo.Tests.Database CollectionRepository collection = new(_NewContext(), thumbs.Object); StudioRepository studio = new(_NewContext(), thumbs.Object); PeopleRepository people = new(_NewContext(), - new Lazy(() => LibraryManager.ShowRepository), + new Lazy>(() => LibraryManager.Shows), thumbs.Object); MovieRepository movies = new(_NewContext(), studio, people, thumbs.Object); ShowRepository show = new(_NewContext(), studio, people, thumbs.Object); @@ -51,7 +55,8 @@ namespace Kyoo.Tests.Database EpisodeRepository episode = new(_NewContext(), show, thumbs.Object); UserRepository user = new(_NewContext(), thumbs.Object); - LibraryManager = new LibraryManager(new IBaseRepository[] { + _repositories = new IBaseRepository[] + { libraryItem, collection, movies, @@ -61,7 +66,25 @@ namespace Kyoo.Tests.Database people, studio, user - }); + }; + + LibraryManager = new LibraryManager( + libraryItem, + collection, + movies, + show, + season, + episode, + people, + studio, + user + ); + } + + public IRepository GetRepository() + where T: class, IResource + { + return _repositories.First(x => x.RepositoryType == typeof(T)) as IRepository; } private DatabaseContext _NewContext() diff --git a/back/tests/Kyoo.Tests/Database/RepositoryTests.cs b/back/tests/Kyoo.Tests/Database/RepositoryTests.cs index eada621e..ae4b10d3 100644 --- a/back/tests/Kyoo.Tests/Database/RepositoryTests.cs +++ b/back/tests/Kyoo.Tests/Database/RepositoryTests.cs @@ -37,7 +37,7 @@ namespace Kyoo.Tests.Database protected RepositoryTests(RepositoryActivator repositories) { Repositories = repositories; - _repository = Repositories.LibraryManager.GetRepository(); + _repository = Repositories.GetRepository(); } public void Dispose() diff --git a/back/tests/Kyoo.Tests/Database/SpecificTests/CollectionsTests.cs b/back/tests/Kyoo.Tests/Database/SpecificTests/CollectionsTests.cs index 31fb2b3d..696f4ee2 100644 --- a/back/tests/Kyoo.Tests/Database/SpecificTests/CollectionsTests.cs +++ b/back/tests/Kyoo.Tests/Database/SpecificTests/CollectionsTests.cs @@ -41,12 +41,12 @@ namespace Kyoo.Tests.Database public abstract class ACollectionTests : RepositoryTests { - private readonly ICollectionRepository _repository; + private readonly IRepository _repository; protected ACollectionTests(RepositoryActivator repositories) : base(repositories) { - _repository = Repositories.LibraryManager.CollectionRepository; + _repository = Repositories.LibraryManager.Collections; } [Fact] diff --git a/back/tests/Kyoo.Tests/Database/SpecificTests/EpisodeTests.cs b/back/tests/Kyoo.Tests/Database/SpecificTests/EpisodeTests.cs index c6f5d51e..54435781 100644 --- a/back/tests/Kyoo.Tests/Database/SpecificTests/EpisodeTests.cs +++ b/back/tests/Kyoo.Tests/Database/SpecificTests/EpisodeTests.cs @@ -42,13 +42,13 @@ namespace Kyoo.Tests.Database public abstract class AEpisodeTests : RepositoryTests { - private readonly IEpisodeRepository _repository; + private readonly IRepository _repository; protected AEpisodeTests(RepositoryActivator repositories) : base(repositories) { - _repository = repositories.LibraryManager.EpisodeRepository; + _repository = repositories.LibraryManager.Episodes; } [Fact] @@ -56,7 +56,7 @@ namespace Kyoo.Tests.Database { Episode episode = await _repository.Get(1); Assert.Equal($"{TestSample.Get().Slug}-s1e1", episode.Slug); - await Repositories.LibraryManager.ShowRepository.Patch(episode.ShowId, (x) => + await Repositories.LibraryManager.Shows.Patch(episode.ShowId, (x) => { x.Slug = "new-slug"; return Task.FromResult(true); @@ -85,7 +85,7 @@ namespace Kyoo.Tests.Database { Episode episode = await _repository.Get(1); Assert.Equal($"{TestSample.Get().Slug}-s1e1", episode.Slug); - episode = await Repositories.LibraryManager.Patch(episode.Id, (x) => + episode = await Repositories.LibraryManager.Episodes.Patch(episode.Id, (x) => { x.EpisodeNumber = 2; return Task.FromResult(true); @@ -125,7 +125,7 @@ namespace Kyoo.Tests.Database public async Task SlugEditAbsoluteTest() { Episode episode = await _repository.Create(TestSample.GetAbsoluteEpisode()); - await Repositories.LibraryManager.ShowRepository.Patch(episode.ShowId, (x) => + await Repositories.LibraryManager.Shows.Patch(episode.ShowId, (x) => { x.Slug = "new-slug"; return Task.FromResult(true); @@ -298,8 +298,8 @@ namespace Kyoo.Tests.Database Episode expected = TestSample.Get(); expected.Id = 0; - expected.ShowId = (await Repositories.LibraryManager.ShowRepository.Create(TestSample.Get())).Id; - expected.SeasonId = (await Repositories.LibraryManager.SeasonRepository.Create(TestSample.Get())).Id; + expected.ShowId = (await Repositories.LibraryManager.Shows.Create(TestSample.Get())).Id; + expected.SeasonId = (await Repositories.LibraryManager.Seasons.Create(TestSample.Get())).Id; await _repository.Create(expected); KAssert.DeepEqual(expected, await _repository.Get(expected.Slug)); } @@ -310,8 +310,8 @@ namespace Kyoo.Tests.Database Episode expected = TestSample.Get(); KAssert.DeepEqual(expected, await _repository.CreateIfNotExists(TestSample.Get())); await _repository.Delete(TestSample.Get()); - expected.ShowId = (await Repositories.LibraryManager.ShowRepository.Create(TestSample.Get())).Id; - expected.SeasonId = (await Repositories.LibraryManager.SeasonRepository.Create(TestSample.Get())).Id; + expected.ShowId = (await Repositories.LibraryManager.Shows.Create(TestSample.Get())).Id; + expected.SeasonId = (await Repositories.LibraryManager.Seasons.Create(TestSample.Get())).Id; KAssert.DeepEqual(expected, await _repository.CreateIfNotExists(expected)); } } diff --git a/back/tests/Kyoo.Tests/Database/SpecificTests/PeopleTests.cs b/back/tests/Kyoo.Tests/Database/SpecificTests/PeopleTests.cs index 8bf3b9da..ff01d205 100644 --- a/back/tests/Kyoo.Tests/Database/SpecificTests/PeopleTests.cs +++ b/back/tests/Kyoo.Tests/Database/SpecificTests/PeopleTests.cs @@ -40,12 +40,12 @@ namespace Kyoo.Tests.Database public abstract class APeopleTests : RepositoryTests { - private readonly IPeopleRepository _repository; + private readonly IRepository _repository; protected APeopleTests(RepositoryActivator repositories) : base(repositories) { - _repository = Repositories.LibraryManager.PeopleRepository; + _repository = Repositories.LibraryManager.People; } [Fact] diff --git a/back/tests/Kyoo.Tests/Database/SpecificTests/SeasonTests.cs b/back/tests/Kyoo.Tests/Database/SpecificTests/SeasonTests.cs index e67fd367..24289012 100644 --- a/back/tests/Kyoo.Tests/Database/SpecificTests/SeasonTests.cs +++ b/back/tests/Kyoo.Tests/Database/SpecificTests/SeasonTests.cs @@ -40,12 +40,12 @@ namespace Kyoo.Tests.Database public abstract class ASeasonTests : RepositoryTests { - private readonly ISeasonRepository _repository; + private readonly IRepository _repository; protected ASeasonTests(RepositoryActivator repositories) : base(repositories) { - _repository = Repositories.LibraryManager.SeasonRepository; + _repository = Repositories.LibraryManager.Seasons; } [Fact] @@ -53,7 +53,7 @@ namespace Kyoo.Tests.Database { Season season = await _repository.Get(1); Assert.Equal("anohana-s1", season.Slug); - await Repositories.LibraryManager.ShowRepository.Patch(season.ShowId, (x) => + await Repositories.LibraryManager.Shows.Patch(season.ShowId, (x) => { x.Slug = "new-slug"; return Task.FromResult(true); diff --git a/back/tests/Kyoo.Tests/Database/SpecificTests/ShowTests.cs b/back/tests/Kyoo.Tests/Database/SpecificTests/ShowTests.cs index ca537106..a6f93e8b 100644 --- a/back/tests/Kyoo.Tests/Database/SpecificTests/ShowTests.cs +++ b/back/tests/Kyoo.Tests/Database/SpecificTests/ShowTests.cs @@ -42,12 +42,12 @@ namespace Kyoo.Tests.Database public abstract class AShowTests : RepositoryTests { - private readonly IShowRepository _repository; + private readonly IRepository _repository; protected AShowTests(RepositoryActivator repositories) : base(repositories) { - _repository = Repositories.LibraryManager.ShowRepository; + _repository = Repositories.LibraryManager.Shows; } [Fact] @@ -278,13 +278,6 @@ namespace Kyoo.Tests.Database Assert.Equal("300!", created.Slug); } - [Fact] - public async Task GetSlugTest() - { - Show reference = TestSample.Get(); - Assert.Equal(reference.Slug, await _repository.GetSlug(reference.Id)); - } - [Theory] [InlineData("test")] [InlineData("super")] @@ -307,15 +300,11 @@ namespace Kyoo.Tests.Database public async Task DeleteShowWithEpisodeAndSeason() { Show show = TestSample.Get(); - await Repositories.LibraryManager.Load(show, x => x.Seasons); - await Repositories.LibraryManager.Load(show, x => x.Episodes); Assert.Equal(1, await _repository.GetCount()); - Assert.Single(show.Seasons!); - Assert.Single(show.Episodes!); await _repository.Delete(show); - Assert.Equal(0, await Repositories.LibraryManager.ShowRepository.GetCount()); - Assert.Equal(0, await Repositories.LibraryManager.SeasonRepository.GetCount()); - Assert.Equal(0, await Repositories.LibraryManager.EpisodeRepository.GetCount()); + Assert.Equal(0, await Repositories.LibraryManager.Shows.GetCount()); + Assert.Equal(0, await Repositories.LibraryManager.Seasons.GetCount()); + Assert.Equal(0, await Repositories.LibraryManager.Episodes.GetCount()); } } } diff --git a/back/tests/Kyoo.Tests/Database/SpecificTests/StudioTests.cs b/back/tests/Kyoo.Tests/Database/SpecificTests/StudioTests.cs index b95f3bed..678d4202 100644 --- a/back/tests/Kyoo.Tests/Database/SpecificTests/StudioTests.cs +++ b/back/tests/Kyoo.Tests/Database/SpecificTests/StudioTests.cs @@ -37,12 +37,12 @@ namespace Kyoo.Tests.Database public abstract class AStudioTests : RepositoryTests { [SuppressMessage("ReSharper", "NotAccessedField.Local")] - private readonly IStudioRepository _repository; + private readonly IRepository _repository; protected AStudioTests(RepositoryActivator repositories) : base(repositories) { - _repository = Repositories.LibraryManager.StudioRepository; + _repository = Repositories.LibraryManager.Studios; } } } diff --git a/back/tests/Kyoo.Tests/Database/SpecificTests/UserTests.cs b/back/tests/Kyoo.Tests/Database/SpecificTests/UserTests.cs index 3ab32722..5fe797dd 100644 --- a/back/tests/Kyoo.Tests/Database/SpecificTests/UserTests.cs +++ b/back/tests/Kyoo.Tests/Database/SpecificTests/UserTests.cs @@ -37,12 +37,12 @@ namespace Kyoo.Tests.Database public abstract class AUserTests : RepositoryTests { [SuppressMessage("ReSharper", "NotAccessedField.Local")] - private readonly IUserRepository _repository; + private readonly IRepository _repository; protected AUserTests(RepositoryActivator repositories) : base(repositories) { - _repository = Repositories.LibraryManager.UserRepository; + _repository = Repositories.LibraryManager.Users; } } }