mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-05-24 02:02:36 -04:00
Add include as a first class param and remove library manager thing
This commit is contained in:
parent
c621c45695
commit
d3fbec1a9d
@ -16,12 +16,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
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
|
||||
/// </summary>
|
||||
public interface ILibraryManager
|
||||
{
|
||||
/// <summary>
|
||||
/// Get the repository corresponding to the T item.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type you want</typeparam>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>The repository corresponding</returns>
|
||||
IRepository<T> GetRepository<T>()
|
||||
where T : class, IResource;
|
||||
|
||||
/// <summary>
|
||||
/// The repository that handle libraries items (a wrapper around shows and collections).
|
||||
/// </summary>
|
||||
ILibraryItemRepository LibraryItemRepository { get; }
|
||||
IRepository<LibraryItem> LibraryItems { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The repository that handle collections.
|
||||
/// </summary>
|
||||
ICollectionRepository CollectionRepository { get; }
|
||||
IRepository<Collection> Collections { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The repository that handle shows.
|
||||
/// </summary>
|
||||
IMovieRepository MovieRepository { get; }
|
||||
IRepository<Movie> Movies { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The repository that handle shows.
|
||||
/// </summary>
|
||||
IShowRepository ShowRepository { get; }
|
||||
IRepository<Show> Shows { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The repository that handle seasons.
|
||||
/// </summary>
|
||||
ISeasonRepository SeasonRepository { get; }
|
||||
IRepository<Season> Seasons { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The repository that handle episodes.
|
||||
/// </summary>
|
||||
IEpisodeRepository EpisodeRepository { get; }
|
||||
IRepository<Episode> Episodes { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The repository that handle people.
|
||||
/// </summary>
|
||||
IPeopleRepository PeopleRepository { get; }
|
||||
IRepository<People> People { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The repository that handle studios.
|
||||
/// </summary>
|
||||
IStudioRepository StudioRepository { get; }
|
||||
IRepository<Studio> Studios { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The repository that handle users.
|
||||
/// </summary>
|
||||
IUserRepository UserRepository { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Get the resource by it's ID
|
||||
/// </summary>
|
||||
/// <param name="id">The id of the resource</param>
|
||||
/// <typeparam name="T">The type of the resource</typeparam>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>The resource found</returns>
|
||||
Task<T> Get<T>(int id)
|
||||
where T : class, IResource;
|
||||
|
||||
/// <summary>
|
||||
/// Get the resource by it's slug
|
||||
/// </summary>
|
||||
/// <param name="slug">The slug of the resource</param>
|
||||
/// <typeparam name="T">The type of the resource</typeparam>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>The resource found</returns>
|
||||
Task<T> Get<T>(string slug)
|
||||
where T : class, IResource;
|
||||
|
||||
/// <summary>
|
||||
/// Get the resource by a filter function.
|
||||
/// </summary>
|
||||
/// <param name="where">The filter function.</param>
|
||||
/// <typeparam name="T">The type of the resource</typeparam>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>The first resource found that match the where function</returns>
|
||||
Task<T> Get<T>(Expression<Func<T, bool>> where)
|
||||
where T : class, IResource;
|
||||
|
||||
/// <summary>
|
||||
/// Get a season from it's showID and it's seasonNumber
|
||||
/// </summary>
|
||||
/// <param name="showID">The id of the show</param>
|
||||
/// <param name="seasonNumber">The season's number</param>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>The season found</returns>
|
||||
Task<Season> Get(int showID, int seasonNumber);
|
||||
|
||||
/// <summary>
|
||||
/// Get a season from it's show slug and it's seasonNumber
|
||||
/// </summary>
|
||||
/// <param name="showSlug">The slug of the show</param>
|
||||
/// <param name="seasonNumber">The season's number</param>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>The season found</returns>
|
||||
Task<Season> Get(string showSlug, int seasonNumber);
|
||||
|
||||
/// <summary>
|
||||
/// Get a episode from it's showID, it's seasonNumber and it's episode number.
|
||||
/// </summary>
|
||||
/// <param name="showID">The id of the show</param>
|
||||
/// <param name="seasonNumber">The season's number</param>
|
||||
/// <param name="episodeNumber">The episode's number</param>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>The episode found</returns>
|
||||
Task<Episode> Get(int showID, int seasonNumber, int episodeNumber);
|
||||
|
||||
/// <summary>
|
||||
/// Get a episode from it's show slug, it's seasonNumber and it's episode number.
|
||||
/// </summary>
|
||||
/// <param name="showSlug">The slug of the show</param>
|
||||
/// <param name="seasonNumber">The season's number</param>
|
||||
/// <param name="episodeNumber">The episode's number</param>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>The episode found</returns>
|
||||
Task<Episode> Get(string showSlug, int seasonNumber, int episodeNumber);
|
||||
|
||||
/// <summary>
|
||||
/// Get the resource by it's ID or null if it is not found.
|
||||
/// </summary>
|
||||
/// <param name="id">The id of the resource</param>
|
||||
/// <typeparam name="T">The type of the resource</typeparam>
|
||||
/// <returns>The resource found</returns>
|
||||
Task<T?> GetOrDefault<T>(int id)
|
||||
where T : class, IResource;
|
||||
|
||||
/// <summary>
|
||||
/// Get the resource by it's slug or null if it is not found.
|
||||
/// </summary>
|
||||
/// <param name="slug">The slug of the resource</param>
|
||||
/// <typeparam name="T">The type of the resource</typeparam>
|
||||
/// <returns>The resource found</returns>
|
||||
Task<T?> GetOrDefault<T>(string slug)
|
||||
where T : class, IResource;
|
||||
|
||||
/// <summary>
|
||||
/// Get the resource by a filter function or null if it is not found.
|
||||
/// </summary>
|
||||
/// <param name="where">The filter function.</param>
|
||||
/// <param name="sortBy">A custom sort method to handle cases where multiples items match the filters.</param>
|
||||
/// <typeparam name="T">The type of the resource</typeparam>
|
||||
/// <returns>The first resource found that match the where function</returns>
|
||||
Task<T?> GetOrDefault<T>(Expression<Func<T, bool>> where, Sort<T>? sortBy = default)
|
||||
where T : class, IResource;
|
||||
|
||||
/// <summary>
|
||||
/// Get a season from it's showID and it's seasonNumber or null if it is not found.
|
||||
/// </summary>
|
||||
/// <param name="showID">The id of the show</param>
|
||||
/// <param name="seasonNumber">The season's number</param>
|
||||
/// <returns>The season found</returns>
|
||||
Task<Season?> GetOrDefault(int showID, int seasonNumber);
|
||||
|
||||
/// <summary>
|
||||
/// Get a season from it's show slug and it's seasonNumber or null if it is not found.
|
||||
/// </summary>
|
||||
/// <param name="showSlug">The slug of the show</param>
|
||||
/// <param name="seasonNumber">The season's number</param>
|
||||
/// <returns>The season found</returns>
|
||||
Task<Season?> GetOrDefault(string showSlug, int seasonNumber);
|
||||
|
||||
/// <summary>
|
||||
/// Get a episode from it's showID, it's seasonNumber and it's episode number or null if it is not found.
|
||||
/// </summary>
|
||||
/// <param name="showID">The id of the show</param>
|
||||
/// <param name="seasonNumber">The season's number</param>
|
||||
/// <param name="episodeNumber">The episode's number</param>
|
||||
/// <returns>The episode found</returns>
|
||||
Task<Episode?> GetOrDefault(int showID, int seasonNumber, int episodeNumber);
|
||||
|
||||
/// <summary>
|
||||
/// Get a episode from it's show slug, it's seasonNumber and it's episode number or null if it is not found.
|
||||
/// </summary>
|
||||
/// <param name="showSlug">The slug of the show</param>
|
||||
/// <param name="seasonNumber">The season's number</param>
|
||||
/// <param name="episodeNumber">The episode's number</param>
|
||||
/// <returns>The episode found</returns>
|
||||
Task<Episode?> GetOrDefault(string showSlug, int seasonNumber, int episodeNumber);
|
||||
|
||||
/// <summary>
|
||||
/// Load a related resource
|
||||
/// </summary>
|
||||
/// <param name="obj">The source object.</param>
|
||||
/// <param name="member">A getter function for the member to load</param>
|
||||
/// <param name="force">
|
||||
/// <c>true</c> if you want to load the relation even if it is not null, <c>false</c> otherwise.
|
||||
/// </param>
|
||||
/// <typeparam name="T">The type of the source object</typeparam>
|
||||
/// <typeparam name="T2">The related resource's type</typeparam>
|
||||
/// <returns>The param <paramref name="obj"/></returns>
|
||||
/// <seealso cref="Load{T,T2}(T, Expression{Func{T,ICollection{T2}}}, bool)"/>
|
||||
/// <seealso cref="Load{T}(T, string, bool)"/>
|
||||
/// <seealso cref="Load(IResource, string, bool)"/>
|
||||
Task<T> Load<T, T2>(T obj, Expression<Func<T, T2>> member, bool force = false)
|
||||
where T : class, IResource
|
||||
where T2 : class, IResource;
|
||||
|
||||
/// <summary>
|
||||
/// Load a collection of related resource
|
||||
/// </summary>
|
||||
/// <param name="obj">The source object.</param>
|
||||
/// <param name="member">A getter function for the member to load</param>
|
||||
/// <param name="force">
|
||||
/// <c>true</c> if you want to load the relation even if it is not null, <c>false</c> otherwise.
|
||||
/// </param>
|
||||
/// <typeparam name="T">The type of the source object</typeparam>
|
||||
/// <typeparam name="T2">The related resource's type</typeparam>
|
||||
/// <returns>The param <paramref name="obj"/></returns>
|
||||
/// <seealso cref="Load{T,T2}(T, Expression{Func{T,T2}}, bool)"/>
|
||||
/// <seealso cref="Load{T}(T, string, bool)"/>
|
||||
/// <seealso cref="Load(IResource, string, bool)"/>
|
||||
Task<T> Load<T, T2>(T obj, Expression<Func<T, ICollection<T2>>> member, bool force = false)
|
||||
where T : class, IResource
|
||||
where T2 : class;
|
||||
|
||||
/// <summary>
|
||||
/// Load a related resource by it's name
|
||||
/// </summary>
|
||||
/// <param name="obj">The source object.</param>
|
||||
/// <param name="memberName">The name of the resource to load (case sensitive)</param>
|
||||
/// <param name="force">
|
||||
/// <c>true</c> if you want to load the relation even if it is not null, <c>false</c> otherwise.
|
||||
/// </param>
|
||||
/// <typeparam name="T">The type of the source object</typeparam>
|
||||
/// <returns>The param <paramref name="obj"/></returns>
|
||||
/// <seealso cref="Load{T,T2}(T, Expression{Func{T,T2}}, bool)"/>
|
||||
/// <seealso cref="Load{T,T2}(T, Expression{Func{T,ICollection{T2}}}, bool)"/>
|
||||
/// <seealso cref="Load(IResource, string, bool)"/>
|
||||
Task<T> Load<T>(T obj, string memberName, bool force = false)
|
||||
where T : class, IResource;
|
||||
|
||||
/// <summary>
|
||||
/// Load a related resource without specifying it's type.
|
||||
/// </summary>
|
||||
/// <param name="obj">The source object.</param>
|
||||
/// <param name="memberName">The name of the resource to load (case sensitive)</param>
|
||||
/// <param name="force">
|
||||
/// <c>true</c> if you want to load the relation even if it is not null, <c>false</c> otherwise.
|
||||
/// </param>
|
||||
/// <seealso cref="Load{T,T2}(T, Expression{Func{T,T2}}, bool)"/>
|
||||
/// <seealso cref="Load{T,T2}(T, Expression{Func{T,ICollection{T2}}}, bool)"/>
|
||||
/// <seealso cref="Load{T}(T, string, bool)"/>
|
||||
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
|
||||
Task Load(IResource obj, string memberName, bool force = false);
|
||||
|
||||
/// <summary>
|
||||
/// Get people's roles from a show.
|
||||
/// </summary>
|
||||
/// <param name="showID">The ID of the show</param>
|
||||
/// <param name="where">A filter function</param>
|
||||
/// <param name="sort">Sort information (sort order and sort by)</param>
|
||||
/// <param name="limit">How many items to return and where to start</param>
|
||||
/// <exception cref="ItemNotFoundException">No <see cref="Show"/> exist with the given ID.</exception>
|
||||
/// <returns>A list of items that match every filters</returns>
|
||||
Task<ICollection<PeopleRole>> GetPeopleFromShow(int showID,
|
||||
Expression<Func<PeopleRole, bool>>? where = null,
|
||||
Sort<PeopleRole>? sort = default,
|
||||
Pagination? limit = default);
|
||||
|
||||
/// <summary>
|
||||
/// Get people's roles from a show.
|
||||
/// </summary>
|
||||
/// <param name="showSlug">The slug of the show</param>
|
||||
/// <param name="where">A filter function</param>
|
||||
/// <param name="sort">Sort information (sort order and sort by)</param>
|
||||
/// <param name="limit">How many items to return and where to start</param>
|
||||
/// <exception cref="ItemNotFoundException">No <see cref="Show"/> exist with the given slug.</exception>
|
||||
/// <returns>A list of items that match every filters</returns>
|
||||
Task<ICollection<PeopleRole>> GetPeopleFromShow(string showSlug,
|
||||
Expression<Func<PeopleRole, bool>>? where = null,
|
||||
Sort<PeopleRole>? sort = default,
|
||||
Pagination? limit = default);
|
||||
|
||||
/// <summary>
|
||||
/// Get people's roles from a person.
|
||||
/// </summary>
|
||||
/// <param name="id">The id of the person</param>
|
||||
/// <param name="where">A filter function</param>
|
||||
/// <param name="sort">Sort information (sort order and sort by)</param>
|
||||
/// <param name="limit">How many items to return and where to start</param>
|
||||
/// <exception cref="ItemNotFoundException">No <see cref="People"/> exist with the given ID.</exception>
|
||||
/// <returns>A list of items that match every filters</returns>
|
||||
Task<ICollection<PeopleRole>> GetRolesFromPeople(int id,
|
||||
Expression<Func<PeopleRole, bool>>? where = null,
|
||||
Sort<PeopleRole>? sort = default,
|
||||
Pagination? limit = default);
|
||||
|
||||
/// <summary>
|
||||
/// Get people's roles from a person.
|
||||
/// </summary>
|
||||
/// <param name="slug">The slug of the person</param>
|
||||
/// <param name="where">A filter function</param>
|
||||
/// <param name="sort">Sort information (sort order and sort by)</param>
|
||||
/// <param name="limit">How many items to return and where to start</param>
|
||||
/// <exception cref="ItemNotFoundException">No <see cref="People"/> exist with the given slug.</exception>
|
||||
/// <returns>A list of items that match every filters</returns>
|
||||
Task<ICollection<PeopleRole>> GetRolesFromPeople(string slug,
|
||||
Expression<Func<PeopleRole, bool>>? where = null,
|
||||
Sort<PeopleRole>? sort = default,
|
||||
Pagination? limit = default);
|
||||
|
||||
/// <summary>
|
||||
/// Get all resources with filters
|
||||
/// </summary>
|
||||
/// <param name="where">A filter function</param>
|
||||
/// <param name="sort">Sort information (sort order and sort by)</param>
|
||||
/// <param name="limit">How many items to return and where to start</param>
|
||||
/// <typeparam name="T">The type of resources to load</typeparam>
|
||||
/// <returns>A list of resources that match every filters</returns>
|
||||
Task<ICollection<T>> GetAll<T>(Expression<Func<T, bool>>? where = null,
|
||||
Sort<T>? sort = default,
|
||||
Pagination? limit = default)
|
||||
where T : class, IResource;
|
||||
|
||||
/// <summary>
|
||||
/// Get the count of resources that match the filter
|
||||
/// </summary>
|
||||
/// <param name="where">A filter function</param>
|
||||
/// <typeparam name="T">The type of resources to load</typeparam>
|
||||
/// <returns>A list of resources that match every filters</returns>
|
||||
Task<int> GetCount<T>(Expression<Func<T, bool>>? where = null)
|
||||
where T : class, IResource;
|
||||
|
||||
/// <summary>
|
||||
/// Search for a resource
|
||||
/// </summary>
|
||||
/// <param name="query">The search query</param>
|
||||
/// <typeparam name="T">The type of resources</typeparam>
|
||||
/// <returns>A list of 20 items that match the search query</returns>
|
||||
Task<ICollection<T>> Search<T>(string query)
|
||||
where T : class, IResource;
|
||||
|
||||
/// <summary>
|
||||
/// Create a new resource.
|
||||
/// </summary>
|
||||
/// <param name="item">The item to register</param>
|
||||
/// <typeparam name="T">The type of resource</typeparam>
|
||||
/// <returns>The resource registers and completed by database's information (related items and so on)</returns>
|
||||
Task<T> Create<T>(T item)
|
||||
where T : class, IResource;
|
||||
|
||||
/// <summary>
|
||||
/// Create a new resource if it does not exist already. If it does, the existing value is returned instead.
|
||||
/// </summary>
|
||||
/// <param name="item">The item to register</param>
|
||||
/// <typeparam name="T">The type of resource</typeparam>
|
||||
/// <returns>The newly created item or the existing value if it existed.</returns>
|
||||
Task<T> CreateIfNotExists<T>(T item)
|
||||
where T : class, IResource;
|
||||
|
||||
/// <summary>
|
||||
/// Edit a resource
|
||||
/// </summary>
|
||||
/// <param name="item">The resource to edit, it's ID can't change.</param>
|
||||
/// <typeparam name="T">The type of resources</typeparam>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>The resource edited and completed by database's information (related items and so on)</returns>
|
||||
Task<T> Edit<T>(T item)
|
||||
where T : class, IResource;
|
||||
|
||||
/// <summary>
|
||||
/// Edit only specific properties of a resource
|
||||
/// </summary>
|
||||
/// <param name="id">The id of the resource to edit</param>
|
||||
/// <param name="patch">
|
||||
/// 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
|
||||
/// </param>
|
||||
/// <typeparam name="T">The type of resources</typeparam>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>The resource edited and completed by database's information (related items and so on)</returns>
|
||||
Task<T> Patch<T>(int id, Func<T, Task<bool>> patch)
|
||||
where T : class, IResource;
|
||||
|
||||
/// <summary>
|
||||
/// Delete a resource.
|
||||
/// </summary>
|
||||
/// <param name="item">The resource to delete</param>
|
||||
/// <typeparam name="T">The type of resource to delete</typeparam>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
|
||||
Task Delete<T>(T item)
|
||||
where T : class, IResource;
|
||||
|
||||
/// <summary>
|
||||
/// Delete a resource by it's ID.
|
||||
/// </summary>
|
||||
/// <param name="id">The id of the resource to delete</param>
|
||||
/// <typeparam name="T">The type of resource to delete</typeparam>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
|
||||
Task Delete<T>(int id)
|
||||
where T : class, IResource;
|
||||
|
||||
/// <summary>
|
||||
/// Delete a resource by it's slug.
|
||||
/// </summary>
|
||||
/// <param name="slug">The slug of the resource to delete</param>
|
||||
/// <typeparam name="T">The type of resource to delete</typeparam>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
|
||||
Task Delete<T>(string slug)
|
||||
where T : class, IResource;
|
||||
IRepository<User> Users { get; }
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
/// </summary>
|
||||
/// <param name="id">The id of the resource</param>
|
||||
/// <param name="include">The related fields to include.</param>
|
||||
/// <exception cref="ItemNotFoundException">If the item could not be found.</exception>
|
||||
/// <returns>The resource found</returns>
|
||||
Task<T> Get(int id);
|
||||
Task<T> Get(int id, Include<T>? include = default);
|
||||
|
||||
/// <summary>
|
||||
/// Get a resource from it's slug.
|
||||
/// </summary>
|
||||
/// <param name="slug">The slug of the resource</param>
|
||||
/// <param name="include">The related fields to include.</param>
|
||||
/// <exception cref="ItemNotFoundException">If the item could not be found.</exception>
|
||||
/// <returns>The resource found</returns>
|
||||
Task<T> Get(string slug);
|
||||
Task<T> Get(string slug, Include<T>? include = default);
|
||||
|
||||
/// <summary>
|
||||
/// Get the first resource that match the predicate.
|
||||
/// </summary>
|
||||
/// <param name="where">A predicate to filter the resource.</param>
|
||||
/// <param name="include">The related fields to include.</param>
|
||||
/// <exception cref="ItemNotFoundException">If the item could not be found.</exception>
|
||||
/// <returns>The resource found</returns>
|
||||
Task<T> Get(Expression<Func<T, bool>> where);
|
||||
Task<T> Get(Expression<Func<T, bool>> where, Include<T>? include = default);
|
||||
|
||||
/// <summary>
|
||||
/// Get a resource from it's ID or null if it is not found.
|
||||
/// </summary>
|
||||
/// <param name="id">The id of the resource</param>
|
||||
/// <param name="include">The related fields to include.</param>
|
||||
/// <returns>The resource found</returns>
|
||||
Task<T?> GetOrDefault(int id);
|
||||
Task<T?> GetOrDefault(int id, Include<T>? include = default);
|
||||
|
||||
/// <summary>
|
||||
/// Get a resource from it's slug or null if it is not found.
|
||||
/// </summary>
|
||||
/// <param name="slug">The slug of the resource</param>
|
||||
/// <param name="include">The related fields to include.</param>
|
||||
/// <returns>The resource found</returns>
|
||||
Task<T?> GetOrDefault(string slug);
|
||||
Task<T?> GetOrDefault(string slug, Include<T>? include = default);
|
||||
|
||||
/// <summary>
|
||||
/// Get the first resource that match the predicate or null if it is not found.
|
||||
/// </summary>
|
||||
/// <param name="where">A predicate to filter the resource.</param>
|
||||
/// <param name="include">The related fields to include.</param>
|
||||
/// <param name="sortBy">A custom sort method to handle cases where multiples items match the filters.</param>
|
||||
/// <returns>The resource found</returns>
|
||||
Task<T?> GetOrDefault(Expression<Func<T, bool>> where, Sort<T>? sortBy = default);
|
||||
Task<T?> GetOrDefault(Expression<Func<T, bool>> where,
|
||||
Include<T>? include = default,
|
||||
Sort<T>? sortBy = default);
|
||||
|
||||
/// <summary>
|
||||
/// Search for resources.
|
||||
@ -97,10 +106,12 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// <param name="where">A filter predicate</param>
|
||||
/// <param name="sort">Sort information about the query (sort by, sort order)</param>
|
||||
/// <param name="limit">How pagination should be done (where to start and how many to return)</param>
|
||||
/// <param name="include">The related fields to include.</param>
|
||||
/// <returns>A list of resources that match every filters</returns>
|
||||
Task<ICollection<T>> GetAll(Expression<Func<T, bool>>? where = null,
|
||||
Sort<T>? sort = default,
|
||||
Pagination? limit = default);
|
||||
Pagination? limit = default,
|
||||
Include<T>? include = default);
|
||||
|
||||
/// <summary>
|
||||
/// Get the number of resources that match the filter's predicate.
|
||||
@ -200,209 +211,4 @@ namespace Kyoo.Abstractions.Controllers
|
||||
/// </summary>
|
||||
Type RepositoryType { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A repository to handle shows.
|
||||
/// </summary>
|
||||
public interface IMovieRepository : IRepository<Movie> { }
|
||||
|
||||
/// <summary>
|
||||
/// A repository to handle shows.
|
||||
/// </summary>
|
||||
public interface IShowRepository : IRepository<Show>
|
||||
{
|
||||
/// <summary>
|
||||
/// Get a show's slug from it's ID.
|
||||
/// </summary>
|
||||
/// <param name="showID">The ID of the show</param>
|
||||
/// <exception cref="ItemNotFoundException">If a show with the given ID is not found.</exception>
|
||||
/// <returns>The show's slug</returns>
|
||||
Task<string> GetSlug(int showID);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A repository to handle seasons.
|
||||
/// </summary>
|
||||
public interface ISeasonRepository : IRepository<Season>
|
||||
{
|
||||
/// <summary>
|
||||
/// Get a season from it's showID and it's seasonNumber
|
||||
/// </summary>
|
||||
/// <param name="showID">The id of the show</param>
|
||||
/// <param name="seasonNumber">The season's number</param>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>The season found</returns>
|
||||
Task<Season> Get(int showID, int seasonNumber);
|
||||
|
||||
/// <summary>
|
||||
/// Get a season from it's show slug and it's seasonNumber
|
||||
/// </summary>
|
||||
/// <param name="showSlug">The slug of the show</param>
|
||||
/// <param name="seasonNumber">The season's number</param>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>The season found</returns>
|
||||
Task<Season> Get(string showSlug, int seasonNumber);
|
||||
|
||||
/// <summary>
|
||||
/// Get a season from it's showID and it's seasonNumber or null if it is not found.
|
||||
/// </summary>
|
||||
/// <param name="showID">The id of the show</param>
|
||||
/// <param name="seasonNumber">The season's number</param>
|
||||
/// <returns>The season found</returns>
|
||||
Task<Season?> GetOrDefault(int showID, int seasonNumber);
|
||||
|
||||
/// <summary>
|
||||
/// Get a season from it's show slug and it's seasonNumber or null if it is not found.
|
||||
/// </summary>
|
||||
/// <param name="showSlug">The slug of the show</param>
|
||||
/// <param name="seasonNumber">The season's number</param>
|
||||
/// <returns>The season found</returns>
|
||||
Task<Season?> GetOrDefault(string showSlug, int seasonNumber);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The repository to handle episodes
|
||||
/// </summary>
|
||||
public interface IEpisodeRepository : IRepository<Episode>
|
||||
{
|
||||
// TODO replace the next methods with extension methods.
|
||||
|
||||
/// <summary>
|
||||
/// Get a episode from it's showID, it's seasonNumber and it's episode number.
|
||||
/// </summary>
|
||||
/// <param name="showID">The id of the show</param>
|
||||
/// <param name="seasonNumber">The season's number</param>
|
||||
/// <param name="episodeNumber">The episode's number</param>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>The episode found</returns>
|
||||
Task<Episode> Get(int showID, int seasonNumber, int episodeNumber);
|
||||
|
||||
/// <summary>
|
||||
/// Get a episode from it's show slug, it's seasonNumber and it's episode number.
|
||||
/// </summary>
|
||||
/// <param name="showSlug">The slug of the show</param>
|
||||
/// <param name="seasonNumber">The season's number</param>
|
||||
/// <param name="episodeNumber">The episode's number</param>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>The episode found</returns>
|
||||
Task<Episode> Get(string showSlug, int seasonNumber, int episodeNumber);
|
||||
|
||||
/// <summary>
|
||||
/// Get a episode from it's showID, it's seasonNumber and it's episode number or null if it is not found.
|
||||
/// </summary>
|
||||
/// <param name="showID">The id of the show</param>
|
||||
/// <param name="seasonNumber">The season's number</param>
|
||||
/// <param name="episodeNumber">The episode's number</param>
|
||||
/// <returns>The episode found</returns>
|
||||
Task<Episode?> GetOrDefault(int showID, int seasonNumber, int episodeNumber);
|
||||
|
||||
/// <summary>
|
||||
/// Get a episode from it's show slug, it's seasonNumber and it's episode number or null if it is not found.
|
||||
/// </summary>
|
||||
/// <param name="showSlug">The slug of the show</param>
|
||||
/// <param name="seasonNumber">The season's number</param>
|
||||
/// <param name="episodeNumber">The episode's number</param>
|
||||
/// <returns>The episode found</returns>
|
||||
Task<Episode?> GetOrDefault(string showSlug, int seasonNumber, int episodeNumber);
|
||||
|
||||
/// <summary>
|
||||
/// Get a episode from it's showID and it's absolute number.
|
||||
/// </summary>
|
||||
/// <param name="showID">The id of the show</param>
|
||||
/// <param name="absoluteNumber">The episode's absolute number (The episode number does not reset to 1 after the end of a season.</param>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>The episode found</returns>
|
||||
Task<Episode> GetAbsolute(int showID, int absoluteNumber);
|
||||
|
||||
/// <summary>
|
||||
/// Get a episode from it's showID and it's absolute number.
|
||||
/// </summary>
|
||||
/// <param name="showSlug">The slug of the show</param>
|
||||
/// <param name="absoluteNumber">The episode's absolute number (The episode number does not reset to 1 after the end of a season.</param>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>The episode found</returns>
|
||||
Task<Episode> GetAbsolute(string showSlug, int absoluteNumber);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A repository to handle library items (A wrapper around shows and collections).
|
||||
/// </summary>
|
||||
public interface ILibraryItemRepository : IRepository<LibraryItem> { }
|
||||
|
||||
/// <summary>
|
||||
/// A repository for collections
|
||||
/// </summary>
|
||||
public interface ICollectionRepository : IRepository<Collection> { }
|
||||
|
||||
/// <summary>
|
||||
/// A repository for studios.
|
||||
/// </summary>
|
||||
public interface IStudioRepository : IRepository<Studio> { }
|
||||
|
||||
/// <summary>
|
||||
/// A repository for people.
|
||||
/// </summary>
|
||||
public interface IPeopleRepository : IRepository<People>
|
||||
{
|
||||
/// <summary>
|
||||
/// Get people's roles from a show.
|
||||
/// </summary>
|
||||
/// <param name="showID">The ID of the show</param>
|
||||
/// <param name="where">A filter function</param>
|
||||
/// <param name="sort">Sort information (sort order and sort by)</param>
|
||||
/// <param name="limit">How many items to return and where to start</param>
|
||||
/// <exception cref="ItemNotFoundException">No <see cref="Show"/> exist with the given ID.</exception>
|
||||
/// <returns>A list of items that match every filters</returns>
|
||||
Task<ICollection<PeopleRole>> GetFromShow(int showID,
|
||||
Expression<Func<PeopleRole, bool>>? where = null,
|
||||
Sort<PeopleRole>? sort = default,
|
||||
Pagination? limit = default);
|
||||
|
||||
/// <summary>
|
||||
/// Get people's roles from a show.
|
||||
/// </summary>
|
||||
/// <param name="showSlug">The slug of the show</param>
|
||||
/// <param name="where">A filter function</param>
|
||||
/// <param name="sort">Sort information (sort order and sort by)</param>
|
||||
/// <param name="limit">How many items to return and where to start</param>
|
||||
/// <exception cref="ItemNotFoundException">No <see cref="Show"/> exist with the given slug.</exception>
|
||||
/// <returns>A list of items that match every filters</returns>
|
||||
Task<ICollection<PeopleRole>> GetFromShow(string showSlug,
|
||||
Expression<Func<PeopleRole, bool>>? where = null,
|
||||
Sort<PeopleRole>? sort = default,
|
||||
Pagination? limit = default);
|
||||
|
||||
/// <summary>
|
||||
/// Get people's roles from a person.
|
||||
/// </summary>
|
||||
/// <param name="id">The id of the person</param>
|
||||
/// <param name="where">A filter function</param>
|
||||
/// <param name="sort">Sort information (sort order and sort by)</param>
|
||||
/// <param name="limit">How many items to return and where to start</param>
|
||||
/// <exception cref="ItemNotFoundException">No <see cref="People"/> exist with the given ID.</exception>
|
||||
/// <returns>A list of items that match every filters</returns>
|
||||
Task<ICollection<PeopleRole>> GetFromPeople(int id,
|
||||
Expression<Func<PeopleRole, bool>>? where = null,
|
||||
Sort<PeopleRole>? sort = default,
|
||||
Pagination? limit = default);
|
||||
|
||||
/// <summary>
|
||||
/// Get people's roles from a person.
|
||||
/// </summary>
|
||||
/// <param name="slug">The slug of the person</param>
|
||||
/// <param name="where">A filter function</param>
|
||||
/// <param name="sort">Sort information (sort order and sort by)</param>
|
||||
/// <param name="limit">How many items to return and where to start</param>
|
||||
/// <exception cref="ItemNotFoundException">No <see cref="People"/> exist with the given slug.</exception>
|
||||
/// <returns>A list of items that match every filters</returns>
|
||||
Task<ICollection<PeopleRole>> GetFromPeople(string slug,
|
||||
Expression<Func<PeopleRole, bool>>? where = null,
|
||||
Sort<PeopleRole>? sort = default,
|
||||
Pagination? limit = default);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A repository to handle users.
|
||||
/// </summary>
|
||||
public interface IUserRepository : IRepository<User> { }
|
||||
}
|
||||
|
48
back/src/Kyoo.Abstractions/Models/Utils/Include.cs
Normal file
48
back/src/Kyoo.Abstractions/Models/Utils/Include.cs
Normal file
@ -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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Reflection;
|
||||
using Kyoo.Abstractions.Models.Attributes;
|
||||
|
||||
namespace Kyoo.Abstractions.Models.Utils;
|
||||
|
||||
public class Include<T>
|
||||
where T : IResource
|
||||
{
|
||||
public string[] Fields { get; private init; }
|
||||
|
||||
public static Include<T> 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<LoadableRelationAttribute>() == null)
|
||||
throw new ValidationException($"No loadable relation with the name {field}.");
|
||||
}
|
||||
|
||||
return new()
|
||||
{
|
||||
Fields = values,
|
||||
};
|
||||
}
|
||||
}
|
@ -47,7 +47,7 @@ namespace Kyoo.Authentication.Views
|
||||
/// <summary>
|
||||
/// The repository to handle users.
|
||||
/// </summary>
|
||||
private readonly IUserRepository _users;
|
||||
private readonly IRepository<User> _users;
|
||||
|
||||
/// <summary>
|
||||
/// The token generator.
|
||||
@ -65,7 +65,7 @@ namespace Kyoo.Authentication.Views
|
||||
/// <param name="users">The repository used to check if the user exists.</param>
|
||||
/// <param name="token">The token generator.</param>
|
||||
/// <param name="permissions">The permission opitons.</param>
|
||||
public AuthApi(IUserRepository users, ITokenController token, PermissionOption permissions)
|
||||
public AuthApi(IRepository<User> users, ITokenController token, PermissionOption permissions)
|
||||
{
|
||||
_users = users;
|
||||
_token = token;
|
||||
|
@ -16,16 +16,8 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
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
|
||||
/// </summary>
|
||||
public class LibraryManager : ILibraryManager
|
||||
{
|
||||
/// <summary>
|
||||
/// The list of repositories
|
||||
/// </summary>
|
||||
private readonly IBaseRepository[] _repositories;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ILibraryItemRepository LibraryItemRepository { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public ICollectionRepository CollectionRepository { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public IMovieRepository MovieRepository { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public IShowRepository ShowRepository { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public ISeasonRepository SeasonRepository { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEpisodeRepository EpisodeRepository { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public IPeopleRepository PeopleRepository { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public IStudioRepository StudioRepository { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public IUserRepository UserRepository { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="LibraryManager"/> instance with every repository available.
|
||||
/// </summary>
|
||||
/// <param name="repositories">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.</param>
|
||||
public LibraryManager(IEnumerable<IBaseRepository> repositories)
|
||||
public LibraryManager(
|
||||
IRepository<LibraryItem> libraryItemRepository,
|
||||
IRepository<Collection> collectionRepository,
|
||||
IRepository<Movie> movieRepository,
|
||||
IRepository<Show> showRepository,
|
||||
IRepository<Season> seasonRepository,
|
||||
IRepository<Episode> episodeRepository,
|
||||
IRepository<People> peopleRepository,
|
||||
IRepository<Studio> studioRepository,
|
||||
IRepository<User> userRepository)
|
||||
{
|
||||
_repositories = repositories.ToArray();
|
||||
LibraryItemRepository = (ILibraryItemRepository)GetRepository<LibraryItem>();
|
||||
CollectionRepository = (ICollectionRepository)GetRepository<Collection>();
|
||||
MovieRepository = (IMovieRepository)GetRepository<Movie>();
|
||||
ShowRepository = (IShowRepository)GetRepository<Show>();
|
||||
SeasonRepository = (ISeasonRepository)GetRepository<Season>();
|
||||
EpisodeRepository = (IEpisodeRepository)GetRepository<Episode>();
|
||||
PeopleRepository = (IPeopleRepository)GetRepository<People>();
|
||||
StudioRepository = (IStudioRepository)GetRepository<Studio>();
|
||||
UserRepository = (IUserRepository)GetRepository<User>();
|
||||
LibraryItems = libraryItemRepository;
|
||||
Collections = collectionRepository;
|
||||
Movies = movieRepository;
|
||||
Shows = showRepository;
|
||||
Seasons = seasonRepository;
|
||||
Episodes = episodeRepository;
|
||||
People = peopleRepository;
|
||||
Studios = studioRepository;
|
||||
Users = userRepository;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IRepository<T> GetRepository<T>()
|
||||
where T : class, IResource
|
||||
{
|
||||
if (_repositories.FirstOrDefault(x => x.RepositoryType == typeof(T)) is IRepository<T> ret)
|
||||
return ret;
|
||||
throw new ItemNotFoundException($"No repository found for the type {typeof(T).Name}.");
|
||||
}
|
||||
public IRepository<LibraryItem> LibraryItems { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<T> Get<T>(int id)
|
||||
where T : class, IResource
|
||||
{
|
||||
return GetRepository<T>().Get(id);
|
||||
}
|
||||
public IRepository<Collection> Collections { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<T> Get<T>(string slug)
|
||||
where T : class, IResource
|
||||
{
|
||||
return GetRepository<T>().Get(slug);
|
||||
}
|
||||
public IRepository<Movie> Movies { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<T> Get<T>(Expression<Func<T, bool>> where)
|
||||
where T : class, IResource
|
||||
{
|
||||
return GetRepository<T>().Get(where);
|
||||
}
|
||||
public IRepository<Show> Shows { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<Season> Get(int showID, int seasonNumber)
|
||||
{
|
||||
return SeasonRepository.Get(showID, seasonNumber);
|
||||
}
|
||||
public IRepository<Season> Seasons { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<Season> Get(string showSlug, int seasonNumber)
|
||||
{
|
||||
return SeasonRepository.Get(showSlug, seasonNumber);
|
||||
}
|
||||
public IRepository<Episode> Episodes { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<Episode> Get(int showID, int seasonNumber, int episodeNumber)
|
||||
{
|
||||
return EpisodeRepository.Get(showID, seasonNumber, episodeNumber);
|
||||
}
|
||||
public IRepository<People> People { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<Episode> Get(string showSlug, int seasonNumber, int episodeNumber)
|
||||
{
|
||||
return EpisodeRepository.Get(showSlug, seasonNumber, episodeNumber);
|
||||
}
|
||||
public IRepository<Studio> Studios { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<T?> GetOrDefault<T>(int id)
|
||||
where T : class, IResource
|
||||
{
|
||||
return await GetRepository<T>().GetOrDefault(id);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<T?> GetOrDefault<T>(string slug)
|
||||
where T : class, IResource
|
||||
{
|
||||
return await GetRepository<T>().GetOrDefault(slug);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<T?> GetOrDefault<T>(Expression<Func<T, bool>> where, Sort<T>? sortBy)
|
||||
where T : class, IResource
|
||||
{
|
||||
return await GetRepository<T>().GetOrDefault(where, sortBy);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<Season?> GetOrDefault(int showID, int seasonNumber)
|
||||
{
|
||||
return await SeasonRepository.GetOrDefault(showID, seasonNumber);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<Season?> GetOrDefault(string showSlug, int seasonNumber)
|
||||
{
|
||||
return await SeasonRepository.GetOrDefault(showSlug, seasonNumber);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<Episode?> GetOrDefault(int showID, int seasonNumber, int episodeNumber)
|
||||
{
|
||||
return await EpisodeRepository.GetOrDefault(showID, seasonNumber, episodeNumber);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<Episode?> GetOrDefault(string showSlug, int seasonNumber, int episodeNumber)
|
||||
{
|
||||
return await EpisodeRepository.GetOrDefault(showSlug, seasonNumber, episodeNumber);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set relations between to objects.
|
||||
/// </summary>
|
||||
/// <param name="obj">The owner object</param>
|
||||
/// <param name="loader">A Task to load a collection of related objects</param>
|
||||
/// <param name="setter">A setter function to store the collection of related objects</param>
|
||||
/// <param name="inverse">A setter function to store the owner of a releated object loaded</param>
|
||||
/// <typeparam name="T1">The type of the owner object</typeparam>
|
||||
/// <typeparam name="T2">The type of the related object</typeparam>
|
||||
private static async Task _SetRelation<T1, T2>(T1 obj,
|
||||
Task<ICollection<T2>> loader,
|
||||
Action<T1, ICollection<T2>> setter,
|
||||
Action<T2, T1> inverse)
|
||||
{
|
||||
ICollection<T2> loaded = await loader;
|
||||
setter(obj, loaded);
|
||||
foreach (T2 item in loaded)
|
||||
inverse(item, obj);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<T> Load<T, T2>(T obj, Expression<Func<T, T2>> member, bool force = false)
|
||||
where T : class, IResource
|
||||
where T2 : class, IResource
|
||||
{
|
||||
return Load(obj, Utility.GetPropertyName(member), force);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<T> Load<T, T2>(T obj, Expression<Func<T, ICollection<T2>>> member, bool force = false)
|
||||
where T : class, IResource
|
||||
where T2 : class
|
||||
{
|
||||
return Load(obj, Utility.GetPropertyName(member), force);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<T> Load<T>(T obj, string memberName, bool force = false)
|
||||
where T : class, IResource
|
||||
{
|
||||
await Load(obj as IResource, memberName, force);
|
||||
return obj;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
[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}.")
|
||||
};
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<ICollection<PeopleRole>> GetPeopleFromShow(int showID,
|
||||
Expression<Func<PeopleRole, bool>>? where = null,
|
||||
Sort<PeopleRole>? sort = default,
|
||||
Pagination? limit = default)
|
||||
{
|
||||
return PeopleRepository.GetFromShow(showID, where, sort, limit);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<ICollection<PeopleRole>> GetPeopleFromShow(string showSlug,
|
||||
Expression<Func<PeopleRole, bool>>? where = null,
|
||||
Sort<PeopleRole>? sort = default,
|
||||
Pagination? limit = default)
|
||||
{
|
||||
return PeopleRepository.GetFromShow(showSlug, where, sort, limit);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<ICollection<PeopleRole>> GetRolesFromPeople(int id,
|
||||
Expression<Func<PeopleRole, bool>>? where = null,
|
||||
Sort<PeopleRole>? sort = default,
|
||||
Pagination? limit = default)
|
||||
{
|
||||
return PeopleRepository.GetFromPeople(id, where, sort, limit);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<ICollection<PeopleRole>> GetRolesFromPeople(string slug,
|
||||
Expression<Func<PeopleRole, bool>>? where = null,
|
||||
Sort<PeopleRole>? sort = default,
|
||||
Pagination? limit = default)
|
||||
{
|
||||
return PeopleRepository.GetFromPeople(slug, where, sort, limit);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<ICollection<T>> GetAll<T>(Expression<Func<T, bool>>? where = null,
|
||||
Sort<T>? sort = default,
|
||||
Pagination? limit = default)
|
||||
where T : class, IResource
|
||||
{
|
||||
return GetRepository<T>().GetAll(where, sort, limit);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<int> GetCount<T>(Expression<Func<T, bool>>? where = null)
|
||||
where T : class, IResource
|
||||
{
|
||||
return GetRepository<T>().GetCount(where);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<ICollection<T>> Search<T>(string query)
|
||||
where T : class, IResource
|
||||
{
|
||||
return GetRepository<T>().Search(query);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<T> Create<T>(T item)
|
||||
where T : class, IResource
|
||||
{
|
||||
return GetRepository<T>().Create(item);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<T> CreateIfNotExists<T>(T item)
|
||||
where T : class, IResource
|
||||
{
|
||||
return GetRepository<T>().CreateIfNotExists(item);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<T> Edit<T>(T item)
|
||||
where T : class, IResource
|
||||
{
|
||||
return GetRepository<T>().Edit(item);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<T> Patch<T>(int id, Func<T, Task<bool>> patch)
|
||||
where T : class, IResource
|
||||
{
|
||||
return GetRepository<T>().Patch(id, patch);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task Delete<T>(T item)
|
||||
where T : class, IResource
|
||||
{
|
||||
return GetRepository<T>().Delete(item);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task Delete<T>(int id)
|
||||
where T : class, IResource
|
||||
{
|
||||
return GetRepository<T>().Delete(id);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task Delete<T>(string slug)
|
||||
where T : class, IResource
|
||||
{
|
||||
return GetRepository<T>().Delete(slug);
|
||||
}
|
||||
public IRepository<User> Users { get; }
|
||||
}
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ namespace Kyoo.Core.Controllers
|
||||
/// <summary>
|
||||
/// A local repository to handle collections
|
||||
/// </summary>
|
||||
public class CollectionRepository : LocalRepository<Collection>, ICollectionRepository
|
||||
public class CollectionRepository : LocalRepository<Collection>
|
||||
{
|
||||
/// <summary>
|
||||
/// The database handle
|
||||
|
@ -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
|
||||
/// <summary>
|
||||
/// A local repository to handle episodes.
|
||||
/// </summary>
|
||||
public class EpisodeRepository : LocalRepository<Episode>, IEpisodeRepository
|
||||
public class EpisodeRepository : LocalRepository<Episode>
|
||||
{
|
||||
/// <summary>
|
||||
/// The database handle
|
||||
/// </summary>
|
||||
private readonly DatabaseContext _database;
|
||||
|
||||
private readonly IShowRepository _shows;
|
||||
private readonly IRepository<Show> _shows;
|
||||
|
||||
/// <inheritdoc />
|
||||
// Use absolute numbers by default and fallback to season/episodes if it does not exists.
|
||||
@ -56,7 +54,7 @@ namespace Kyoo.Core.Controllers
|
||||
/// <param name="shows">A show repository</param>
|
||||
/// <param name="thumbs">The thumbnail manager used to store images.</param>
|
||||
public EpisodeRepository(DatabaseContext database,
|
||||
IShowRepository shows,
|
||||
IRepository<Show> shows,
|
||||
IThumbnailsManager thumbs)
|
||||
: base(database, thumbs)
|
||||
{
|
||||
@ -76,60 +74,6 @@ namespace Kyoo.Core.Controllers
|
||||
};
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<Episode?> GetOrDefault(int showID, int seasonNumber, int episodeNumber)
|
||||
{
|
||||
return _database.Episodes.FirstOrDefaultAsync(x => x.ShowId == showID
|
||||
&& x.SeasonNumber == seasonNumber
|
||||
&& x.EpisodeNumber == episodeNumber).Then(SetBackingImage);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<Episode?> GetOrDefault(string showSlug, int seasonNumber, int episodeNumber)
|
||||
{
|
||||
return _database.Episodes.FirstOrDefaultAsync(x => x.Show!.Slug == showSlug
|
||||
&& x.SeasonNumber == seasonNumber
|
||||
&& x.EpisodeNumber == episodeNumber).Then(SetBackingImage);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<Episode> 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;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<Episode> 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;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<Episode> 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;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<Episode> 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;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task<ICollection<Episode>> 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;
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ namespace Kyoo.Core.Controllers
|
||||
/// <summary>
|
||||
/// A local repository to handle library items.
|
||||
/// </summary>
|
||||
public class LibraryItemRepository : LocalRepository<LibraryItem>, ILibraryItemRepository
|
||||
public class LibraryItemRepository : LocalRepository<LibraryItem>
|
||||
{
|
||||
/// <summary>
|
||||
/// The database handle
|
||||
@ -41,7 +41,7 @@ namespace Kyoo.Core.Controllers
|
||||
protected override Sort<LibraryItem> DefaultSort => new Sort<LibraryItem>.By(x => x.Name);
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="ILibraryItemRepository"/>.
|
||||
/// Create a new <see cref="LibraryItemRepository"/>.
|
||||
/// </summary>
|
||||
/// <param name="database">The database instance</param>
|
||||
/// <param name="thumbs">The thumbnail manager used to store images.</param>
|
||||
|
@ -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.
|
||||
/// </summary>
|
||||
/// <param name="query">The query to sort.</param>
|
||||
/// <param name="sortBy">How to sort the query</param>
|
||||
/// <param name="sortBy">How to sort the query.</param>
|
||||
/// <returns>The newly sorted query.</returns>
|
||||
protected IOrderedQueryable<T> Sort(IQueryable<T> query, Sort<T>? sortBy = null)
|
||||
{
|
||||
@ -268,6 +269,15 @@ namespace Kyoo.Core.Controllers
|
||||
return Expression.Lambda<Func<T, bool>>(filter!, x);
|
||||
}
|
||||
|
||||
protected IQueryable<T> AddIncludes(IQueryable<T> query, Include<T>? 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
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual async Task<T> Get(int id)
|
||||
public virtual async Task<T> Get(int id, Include<T>? 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;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual async Task<T> Get(string slug)
|
||||
public virtual async Task<T> Get(string slug, Include<T>? 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;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual async Task<T> Get(Expression<Func<T, bool>> where)
|
||||
public virtual async Task<T> Get(Expression<Func<T, bool>> where, Include<T>? 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;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual Task<T?> GetOrDefault(int id)
|
||||
public virtual Task<T?> GetOrDefault(int id, Include<T>? include = default)
|
||||
{
|
||||
return Database.Set<T>().FirstOrDefaultAsync(x => x.Id == id).Then(SetBackingImage);
|
||||
return AddIncludes(Database.Set<T>(), include)
|
||||
.FirstOrDefaultAsync(x => x.Id == id)
|
||||
.Then(SetBackingImage);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual Task<T?> GetOrDefault(string slug)
|
||||
public virtual Task<T?> GetOrDefault(string slug, Include<T>? include = default)
|
||||
{
|
||||
if (slug == "random")
|
||||
return Database.Set<T>().OrderBy(x => EF.Functions.Random()).FirstOrDefaultAsync().Then(SetBackingImage);
|
||||
return Database.Set<T>().FirstOrDefaultAsync(x => x.Slug == slug).Then(SetBackingImage);
|
||||
{
|
||||
return AddIncludes(Database.Set<T>(), include)
|
||||
.OrderBy(x => EF.Functions.Random())
|
||||
.FirstOrDefaultAsync()
|
||||
.Then(SetBackingImage);
|
||||
}
|
||||
return AddIncludes(Database.Set<T>(), include)
|
||||
.FirstOrDefaultAsync(x => x.Slug == slug)
|
||||
.Then(SetBackingImage);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual Task<T?> GetOrDefault(Expression<Func<T, bool>> where, Sort<T>? sortBy = default)
|
||||
public virtual Task<T?> GetOrDefault(Expression<Func<T, bool>> where,
|
||||
Include<T>? include = default,
|
||||
Sort<T>? sortBy = default)
|
||||
{
|
||||
return Sort(Database.Set<T>(), sortBy).FirstOrDefaultAsync(where).Then(SetBackingImage);
|
||||
return Sort(
|
||||
AddIncludes(Database.Set<T>(), include),
|
||||
sortBy
|
||||
)
|
||||
.FirstOrDefaultAsync(where)
|
||||
.Then(SetBackingImage);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
@ -358,9 +384,10 @@ namespace Kyoo.Core.Controllers
|
||||
/// <inheritdoc/>
|
||||
public virtual async Task<ICollection<T>> GetAll(Expression<Func<T, bool>>? where = null,
|
||||
Sort<T>? sort = default,
|
||||
Pagination? limit = default)
|
||||
Pagination? limit = default,
|
||||
Include<T>? include = default)
|
||||
{
|
||||
return (await ApplyFilters(Database.Set<T>(), where, sort, limit))
|
||||
return (await ApplyFilters(Database.Set<T>(), where, sort, limit, include))
|
||||
.Select(SetBackingImageSelf).ToList();
|
||||
}
|
||||
|
||||
@ -371,12 +398,15 @@ namespace Kyoo.Core.Controllers
|
||||
/// <param name="where">An expression to filter based on arbitrary conditions</param>
|
||||
/// <param name="sort">The sort settings (sort order and sort by)</param>
|
||||
/// <param name="limit">Pagination information (where to start and how many to get)</param>
|
||||
/// <param name="include">Related fields to also load with this query.</param>
|
||||
/// <returns>The filtered query</returns>
|
||||
protected async Task<ICollection<T>> ApplyFilters(IQueryable<T> query,
|
||||
Expression<Func<T, bool>>? where = null,
|
||||
Sort<T>? sort = default,
|
||||
Pagination? limit = default)
|
||||
Pagination? limit = default,
|
||||
Include<T>? include = default)
|
||||
{
|
||||
query = AddIncludes(query, include);
|
||||
query = Sort(query, sort);
|
||||
if (where != null)
|
||||
query = query.Where(where);
|
||||
|
@ -29,7 +29,7 @@ namespace Kyoo.Core.Controllers
|
||||
/// <summary>
|
||||
/// A local repository to handle shows
|
||||
/// </summary>
|
||||
public class MovieRepository : LocalRepository<Movie>, IMovieRepository
|
||||
public class MovieRepository : LocalRepository<Movie>
|
||||
{
|
||||
/// <summary>
|
||||
/// The database handle
|
||||
@ -39,12 +39,12 @@ namespace Kyoo.Core.Controllers
|
||||
/// <summary>
|
||||
/// A studio repository to handle creation/validation of related studios.
|
||||
/// </summary>
|
||||
private readonly IStudioRepository _studios;
|
||||
private readonly IRepository<Studio> _studios;
|
||||
|
||||
/// <summary>
|
||||
/// A people repository to handle creation/validation of related people.
|
||||
/// </summary>
|
||||
private readonly IPeopleRepository _people;
|
||||
private readonly IRepository<People> _people;
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override Sort<Movie> DefaultSort => new Sort<Movie>.By(x => x.Name);
|
||||
@ -57,8 +57,8 @@ namespace Kyoo.Core.Controllers
|
||||
/// <param name="people">A people repository</param>
|
||||
/// <param name="thumbs">The thumbnail manager used to store images.</param>
|
||||
public MovieRepository(DatabaseContext database,
|
||||
IStudioRepository studios,
|
||||
IPeopleRepository people,
|
||||
IRepository<Studio> studios,
|
||||
IRepository<People> people,
|
||||
IThumbnailsManager thumbs)
|
||||
: base(database, thumbs)
|
||||
{
|
||||
|
@ -32,7 +32,7 @@ namespace Kyoo.Core.Controllers
|
||||
/// <summary>
|
||||
/// A local repository to handle people.
|
||||
/// </summary>
|
||||
public class PeopleRepository : LocalRepository<People>, IPeopleRepository
|
||||
public class PeopleRepository : LocalRepository<People>
|
||||
{
|
||||
/// <summary>
|
||||
/// The database handle
|
||||
@ -42,7 +42,7 @@ namespace Kyoo.Core.Controllers
|
||||
/// <summary>
|
||||
/// A lazy loaded show repository to validate requests from shows.
|
||||
/// </summary>
|
||||
private readonly Lazy<IShowRepository> _shows;
|
||||
private readonly Lazy<IRepository<Show>> _shows;
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override Sort<People> DefaultSort => new Sort<People>.By(x => x.Name);
|
||||
@ -54,7 +54,7 @@ namespace Kyoo.Core.Controllers
|
||||
/// <param name="shows">A lazy loaded show repository</param>
|
||||
/// <param name="thumbs">The thumbnail manager used to store images.</param>
|
||||
public PeopleRepository(DatabaseContext database,
|
||||
Lazy<IShowRepository> shows,
|
||||
Lazy<IRepository<Show>> shows,
|
||||
IThumbnailsManager thumbs)
|
||||
: base(database, thumbs)
|
||||
{
|
||||
@ -123,13 +123,12 @@ namespace Kyoo.Core.Controllers
|
||||
await base.Delete(obj);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<ICollection<PeopleRole>> GetFromShow(int showID,
|
||||
Expression<Func<PeopleRole, bool>>? where = null,
|
||||
Sort<PeopleRole>? sort = default,
|
||||
Pagination? limit = default)
|
||||
{
|
||||
return Task.FromResult<ICollection<PeopleRole>>(new List<PeopleRole>());
|
||||
// /// <inheritdoc />
|
||||
// public Task<ICollection<PeopleRole>> GetFromShow(int showID,
|
||||
// Expression<Func<PeopleRole, bool>>? where = null,
|
||||
// Sort<PeopleRole>? sort = default,
|
||||
// Pagination? limit = default)
|
||||
// {
|
||||
// ICollection<PeopleRole> 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;
|
||||
}
|
||||
// }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<ICollection<PeopleRole>> GetFromShow(string showSlug,
|
||||
Expression<Func<PeopleRole, bool>>? where = null,
|
||||
Sort<PeopleRole>? sort = default,
|
||||
Pagination? limit = default)
|
||||
{
|
||||
return Task.FromResult<ICollection<PeopleRole>>(new List<PeopleRole>());
|
||||
// ICollection<PeopleRole> 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;
|
||||
}
|
||||
// /// <inheritdoc />
|
||||
// public Task<ICollection<PeopleRole>> GetFromShow(string showSlug,
|
||||
// Expression<Func<PeopleRole, bool>>? where = null,
|
||||
// Sort<PeopleRole>? sort = default,
|
||||
// Pagination? limit = default)
|
||||
// {
|
||||
// ICollection<PeopleRole> 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;
|
||||
// }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<ICollection<PeopleRole>> GetFromPeople(int id,
|
||||
Expression<Func<PeopleRole, bool>>? where = null,
|
||||
Sort<PeopleRole>? sort = default,
|
||||
Pagination? limit = default)
|
||||
{
|
||||
return Task.FromResult<ICollection<PeopleRole>>(new List<PeopleRole>());
|
||||
// ICollection<PeopleRole> 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;
|
||||
}
|
||||
// /// <inheritdoc />
|
||||
// public Task<ICollection<PeopleRole>> GetFromPeople(int id,
|
||||
// Expression<Func<PeopleRole, bool>>? where = null,
|
||||
// Sort<PeopleRole>? sort = default,
|
||||
// Pagination? limit = default)
|
||||
// {
|
||||
// ICollection<PeopleRole> 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;
|
||||
// }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<ICollection<PeopleRole>> GetFromPeople(string slug,
|
||||
Expression<Func<PeopleRole, bool>>? where = null,
|
||||
Sort<PeopleRole>? sort = default,
|
||||
Pagination? limit = default)
|
||||
{
|
||||
return Task.FromResult<ICollection<PeopleRole>>(new List<PeopleRole>());
|
||||
// ICollection<PeopleRole> 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;
|
||||
}
|
||||
// /// <inheritdoc />
|
||||
// public Task<ICollection<PeopleRole>> GetFromPeople(string slug,
|
||||
// Expression<Func<PeopleRole, bool>>? where = null,
|
||||
// Sort<PeopleRole>? sort = default,
|
||||
// Pagination? limit = default)
|
||||
// {
|
||||
// ICollection<PeopleRole> 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;
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ namespace Kyoo.Core.Controllers
|
||||
/// <summary>
|
||||
/// A local repository to handle seasons.
|
||||
/// </summary>
|
||||
public class SeasonRepository : LocalRepository<Season>, ISeasonRepository
|
||||
public class SeasonRepository : LocalRepository<Season>
|
||||
{
|
||||
/// <summary>
|
||||
/// The database handle
|
||||
@ -49,7 +49,7 @@ namespace Kyoo.Core.Controllers
|
||||
/// <param name="shows">A shows repository</param>
|
||||
/// <param name="thumbs">The thumbnail manager used to store images.</param>
|
||||
public SeasonRepository(DatabaseContext database,
|
||||
IShowRepository shows,
|
||||
IRepository<Show> shows,
|
||||
IThumbnailsManager thumbs)
|
||||
: base(database, thumbs)
|
||||
{
|
||||
@ -68,38 +68,6 @@ namespace Kyoo.Core.Controllers
|
||||
};
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<Season> 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;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task<Season> 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;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Task<Season?> GetOrDefault(int showID, int seasonNumber)
|
||||
{
|
||||
return _database.Seasons.FirstOrDefaultAsync(x => x.ShowId == showID
|
||||
&& x.SeasonNumber == seasonNumber).Then(SetBackingImage);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Task<Season?> GetOrDefault(string showSlug, int seasonNumber)
|
||||
{
|
||||
return _database.Seasons.FirstOrDefaultAsync(x => x.Show!.Slug == showSlug
|
||||
&& x.SeasonNumber == seasonNumber).Then(SetBackingImage);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override async Task<ICollection<Season>> 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;
|
||||
}
|
||||
|
@ -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
|
||||
/// <summary>
|
||||
/// A local repository to handle shows
|
||||
/// </summary>
|
||||
public class ShowRepository : LocalRepository<Show>, IShowRepository
|
||||
public class ShowRepository : LocalRepository<Show>
|
||||
{
|
||||
/// <summary>
|
||||
/// The database handle
|
||||
@ -41,12 +40,12 @@ namespace Kyoo.Core.Controllers
|
||||
/// <summary>
|
||||
/// A studio repository to handle creation/validation of related studios.
|
||||
/// </summary>
|
||||
private readonly IStudioRepository _studios;
|
||||
private readonly IRepository<Studio> _studios;
|
||||
|
||||
/// <summary>
|
||||
/// A people repository to handle creation/validation of related people.
|
||||
/// </summary>
|
||||
private readonly IPeopleRepository _people;
|
||||
private readonly IRepository<People> _people;
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override Sort<Show> DefaultSort => new Sort<Show>.By(x => x.Name);
|
||||
@ -59,8 +58,8 @@ namespace Kyoo.Core.Controllers
|
||||
/// <param name="people">A people repository</param>
|
||||
/// <param name="thumbs">The thumbnail manager used to store images.</param>
|
||||
public ShowRepository(DatabaseContext database,
|
||||
IStudioRepository studios,
|
||||
IPeopleRepository people,
|
||||
IRepository<Studio> studios,
|
||||
IRepository<People> people,
|
||||
IThumbnailsManager thumbs)
|
||||
: base(database, thumbs)
|
||||
{
|
||||
@ -135,17 +134,6 @@ namespace Kyoo.Core.Controllers
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<string> 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;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task Delete(Show obj)
|
||||
{
|
||||
|
@ -30,7 +30,7 @@ namespace Kyoo.Core.Controllers
|
||||
/// <summary>
|
||||
/// A local repository to handle studios
|
||||
/// </summary>
|
||||
public class StudioRepository : LocalRepository<Studio>, IStudioRepository
|
||||
public class StudioRepository : LocalRepository<Studio>
|
||||
{
|
||||
/// <summary>
|
||||
/// The database handle
|
||||
|
@ -29,7 +29,7 @@ namespace Kyoo.Core.Controllers
|
||||
/// <summary>
|
||||
/// A repository for users.
|
||||
/// </summary>
|
||||
public class UserRepository : LocalRepository<User>, IUserRepository
|
||||
public class UserRepository : LocalRepository<User>
|
||||
{
|
||||
/// <summary>
|
||||
/// The database handle
|
||||
|
@ -50,15 +50,15 @@ namespace Kyoo.Core
|
||||
builder.RegisterType<ThumbnailsManager>().As<IThumbnailsManager>().InstancePerLifetimeScope();
|
||||
builder.RegisterType<LibraryManager>().As<ILibraryManager>().InstancePerLifetimeScope();
|
||||
|
||||
builder.RegisterRepository<ILibraryItemRepository, LibraryItemRepository>();
|
||||
builder.RegisterRepository<ICollectionRepository, CollectionRepository>();
|
||||
builder.RegisterRepository<IMovieRepository, MovieRepository>();
|
||||
builder.RegisterRepository<IShowRepository, ShowRepository>();
|
||||
builder.RegisterRepository<ISeasonRepository, SeasonRepository>();
|
||||
builder.RegisterRepository<IEpisodeRepository, EpisodeRepository>();
|
||||
builder.RegisterRepository<IPeopleRepository, PeopleRepository>();
|
||||
builder.RegisterRepository<IStudioRepository, StudioRepository>();
|
||||
builder.RegisterRepository<IUserRepository, UserRepository>();
|
||||
builder.RegisterRepository<LibraryItemRepository>();
|
||||
builder.RegisterRepository<CollectionRepository>();
|
||||
builder.RegisterRepository<MovieRepository>();
|
||||
builder.RegisterRepository<ShowRepository>();
|
||||
builder.RegisterRepository<SeasonRepository>();
|
||||
builder.RegisterRepository<EpisodeRepository>();
|
||||
builder.RegisterRepository<PeopleRepository>();
|
||||
builder.RegisterRepository<StudioRepository>();
|
||||
builder.RegisterRepository<UserRepository>();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
@ -62,17 +62,18 @@ namespace Kyoo.Core.Api
|
||||
/// Get a specific resource via it's ID or it's slug.
|
||||
/// </remarks>
|
||||
/// <param name="identifier">The ID or slug of the resource to retrieve.</param>
|
||||
/// <param name="fields">The aditional fields to include in the result.</param>
|
||||
/// <returns>The retrieved resource.</returns>
|
||||
/// <response code="404">A resource with the given ID or slug does not exist.</response>
|
||||
[HttpGet("{identifier:id}")]
|
||||
[PartialPermission(Kind.Read)]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public async Task<ActionResult<T>> Get(Identifier identifier)
|
||||
public async Task<ActionResult<T>> Get(Identifier identifier, [FromQuery] Include<T>? 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
|
||||
/// <param name="sortBy">Sort information about the query (sort by, sort order).</param>
|
||||
/// <param name="where">Filter the returned items.</param>
|
||||
/// <param name="pagination">How many items per page should be returned, where should the page start...</param>
|
||||
/// <param name="fields">The aditional fields to include in the result.</param>
|
||||
/// <returns>A list of resources that match every filters.</returns>
|
||||
/// <response code="400">Invalid filters or sort information.</response>
|
||||
[HttpGet]
|
||||
@ -115,12 +117,14 @@ namespace Kyoo.Core.Api
|
||||
public async Task<ActionResult<Page<T>>> GetAll(
|
||||
[FromQuery] Sort<T> sortBy,
|
||||
[FromQuery] Dictionary<string, string> where,
|
||||
[FromQuery] Pagination pagination)
|
||||
[FromQuery] Pagination pagination,
|
||||
[FromQuery] Include<T>? fields)
|
||||
{
|
||||
ICollection<T> resources = await Repository.GetAll(
|
||||
ApiHelper.ParseWhere<T>(where),
|
||||
sortBy,
|
||||
pagination
|
||||
pagination,
|
||||
fields
|
||||
);
|
||||
|
||||
return Page(resources, pagination.Limit);
|
||||
|
@ -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<string> 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<LoadableRelationAttribute>() != 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<string>()
|
||||
.ToList();
|
||||
if (context.Result != null)
|
||||
return;
|
||||
}
|
||||
}
|
||||
context.HttpContext.Items["fields"] = fields;
|
||||
base.OnActionExecuting(context);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
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<ILibraryManager>();
|
||||
ICollection<string> fields = (ICollection<string>)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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -56,43 +56,43 @@ namespace Kyoo.Core.Api
|
||||
/// <param name="thumbs">The thumbnail manager used to retrieve images paths.</param>
|
||||
public StaffApi(ILibraryManager libraryManager,
|
||||
IThumbnailsManager thumbs)
|
||||
: base(libraryManager.PeopleRepository, thumbs)
|
||||
: base(libraryManager.People, thumbs)
|
||||
{
|
||||
_libraryManager = libraryManager;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get roles
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// List the roles in witch this person has played, written or worked in a way.
|
||||
/// </remarks>
|
||||
/// <param name="identifier">The ID or slug of the person.</param>
|
||||
/// <param name="sortBy">A key to sort roles by.</param>
|
||||
/// <param name="where">An optional list of filters.</param>
|
||||
/// <param name="pagination">The number of roles to return.</param>
|
||||
/// <returns>A page of roles.</returns>
|
||||
/// <response code="400">The filters or the sort parameters are invalid.</response>
|
||||
/// <response code="404">No person with the given ID or slug could be found.</response>
|
||||
[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<ActionResult<Page<PeopleRole>>> GetRoles(Identifier identifier,
|
||||
[FromQuery] Sort<PeopleRole> sortBy,
|
||||
[FromQuery] Dictionary<string, string> where,
|
||||
[FromQuery] Pagination pagination)
|
||||
{
|
||||
Expression<Func<PeopleRole, bool>>? whereQuery = ApiHelper.ParseWhere<PeopleRole>(where);
|
||||
|
||||
ICollection<PeopleRole> resources = await identifier.Match(
|
||||
id => _libraryManager.GetRolesFromPeople(id, whereQuery, sortBy, pagination),
|
||||
slug => _libraryManager.GetRolesFromPeople(slug, whereQuery, sortBy, pagination)
|
||||
);
|
||||
|
||||
return Page(resources, pagination.Limit);
|
||||
}
|
||||
// /// <summary>
|
||||
// /// Get roles
|
||||
// /// </summary>
|
||||
// /// <remarks>
|
||||
// /// List the roles in witch this person has played, written or worked in a way.
|
||||
// /// </remarks>
|
||||
// /// <param name="identifier">The ID or slug of the person.</param>
|
||||
// /// <param name="sortBy">A key to sort roles by.</param>
|
||||
// /// <param name="where">An optional list of filters.</param>
|
||||
// /// <param name="pagination">The number of roles to return.</param>
|
||||
// /// <returns>A page of roles.</returns>
|
||||
// /// <response code="400">The filters or the sort parameters are invalid.</response>
|
||||
// /// <response code="404">No person with the given ID or slug could be found.</response>
|
||||
// [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<ActionResult<Page<PeopleRole>>> GetRoles(Identifier identifier,
|
||||
// [FromQuery] Sort<PeopleRole> sortBy,
|
||||
// [FromQuery] Dictionary<string, string> where,
|
||||
// [FromQuery] Pagination pagination)
|
||||
// {
|
||||
// Expression<Func<PeopleRole, bool>>? whereQuery = ApiHelper.ParseWhere<PeopleRole>(where);
|
||||
//
|
||||
// ICollection<PeopleRole> resources = await identifier.Match(
|
||||
// id => _libraryManager.GetRolesFromPeople(id, whereQuery, sortBy, pagination),
|
||||
// slug => _libraryManager.GetRolesFromPeople(slug, whereQuery, sortBy, pagination)
|
||||
// );
|
||||
//
|
||||
// return Page(resources, pagination.Limit);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,6 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
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.
|
||||
/// </param>
|
||||
public StudioApi(ILibraryManager libraryManager)
|
||||
: base(libraryManager.StudioRepository)
|
||||
: base(libraryManager.Studios)
|
||||
{
|
||||
_libraryManager = libraryManager;
|
||||
}
|
||||
@ -68,6 +67,7 @@ namespace Kyoo.Core.Api
|
||||
/// <param name="sortBy">A key to sort shows by.</param>
|
||||
/// <param name="where">An optional list of filters.</param>
|
||||
/// <param name="pagination">The number of shows to return.</param>
|
||||
/// <param name="fields">The aditional fields to include in the result.</param>
|
||||
/// <returns>A page of shows.</returns>
|
||||
/// <response code="400">The filters or the sort parameters are invalid.</response>
|
||||
/// <response code="404">No studio with the given ID or slug could be found.</response>
|
||||
@ -80,15 +80,17 @@ namespace Kyoo.Core.Api
|
||||
public async Task<ActionResult<Page<Show>>> GetShows(Identifier identifier,
|
||||
[FromQuery] Sort<Show> sortBy,
|
||||
[FromQuery] Dictionary<string, string> where,
|
||||
[FromQuery] Pagination pagination)
|
||||
[FromQuery] Pagination pagination,
|
||||
[FromQuery] Include<Show> fields)
|
||||
{
|
||||
ICollection<Show> resources = await _libraryManager.GetAll(
|
||||
ICollection<Show> resources = await _libraryManager.Shows.GetAll(
|
||||
ApiHelper.ParseWhere(where, identifier.Matcher<Show>(x => x.StudioId, x => x.Studio!.Slug)),
|
||||
sortBy,
|
||||
pagination
|
||||
pagination,
|
||||
fields
|
||||
);
|
||||
|
||||
if (!resources.Any() && await _libraryManager.GetOrDefault(identifier.IsSame<Studio>()) == null)
|
||||
if (!resources.Any() && await _libraryManager.Studios.GetOrDefault(identifier.IsSame<Studio>()) == null)
|
||||
return NotFound();
|
||||
return Page(resources, pagination.Limit);
|
||||
}
|
||||
|
@ -54,7 +54,7 @@ namespace Kyoo.Core.Api
|
||||
/// <param name="thumbs">The thumbnail manager used to retrieve images paths.</param>
|
||||
public CollectionApi(ILibraryManager libraryManager,
|
||||
IThumbnailsManager thumbs)
|
||||
: base(libraryManager.CollectionRepository, thumbs)
|
||||
: base(libraryManager.Collections, thumbs)
|
||||
{
|
||||
_libraryManager = libraryManager;
|
||||
}
|
||||
@ -69,6 +69,7 @@ namespace Kyoo.Core.Api
|
||||
/// <param name="sortBy">A key to sort shows by.</param>
|
||||
/// <param name="where">An optional list of filters.</param>
|
||||
/// <param name="pagination">The number of shows to return.</param>
|
||||
/// <param name="fields">The aditional fields to include in the result.</param>
|
||||
/// <returns>A page of shows.</returns>
|
||||
/// <response code="400">The filters or the sort parameters are invalid.</response>
|
||||
/// <response code="404">No collection with the given ID could be found.</response>
|
||||
@ -81,15 +82,17 @@ namespace Kyoo.Core.Api
|
||||
public async Task<ActionResult<Page<Show>>> GetShows(Identifier identifier,
|
||||
[FromQuery] Sort<Show> sortBy,
|
||||
[FromQuery] Dictionary<string, string> where,
|
||||
[FromQuery] Pagination pagination)
|
||||
[FromQuery] Pagination pagination,
|
||||
[FromQuery] Include<Show> fields)
|
||||
{
|
||||
ICollection<Show> resources = await _libraryManager.GetAll(
|
||||
ICollection<Show> resources = await _libraryManager.Shows.GetAll(
|
||||
ApiHelper.ParseWhere(where, identifier.IsContainedIn<Show, Collection>(x => x.Collections!)),
|
||||
sortBy,
|
||||
pagination
|
||||
pagination,
|
||||
fields
|
||||
);
|
||||
|
||||
if (!resources.Any() && await _libraryManager.GetOrDefault(identifier.IsSame<Collection>()) == null)
|
||||
if (!resources.Any() && await _libraryManager.Collections.GetOrDefault(identifier.IsSame<Collection>()) == null)
|
||||
return NotFound();
|
||||
return Page(resources, pagination.Limit);
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ namespace Kyoo.Core.Api
|
||||
/// <param name="thumbnails">The thumbnail manager used to retrieve images paths.</param>
|
||||
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.
|
||||
/// </remarks>
|
||||
/// <param name="identifier">The ID or slug of the <see cref="Episode"/>.</param>
|
||||
/// <param name="fields">The aditional fields to include in the result.</param>
|
||||
/// <returns>The show that contains this episode.</returns>
|
||||
/// <response code="404">No episode with the given ID or slug could be found.</response>
|
||||
[HttpGet("{identifier:id}/show")]
|
||||
[PartialPermission(Kind.Read)]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public async Task<ActionResult<Show>> GetShow(Identifier identifier)
|
||||
public async Task<ActionResult<Show>> GetShow(Identifier identifier, [FromQuery] Include<Show> fields)
|
||||
{
|
||||
return await _libraryManager.Get(identifier.IsContainedIn<Show, Episode>(x => x.Episodes!));
|
||||
return await _libraryManager.Shows.Get(identifier.IsContainedIn<Show, Episode>(x => x.Episodes!), fields);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -83,6 +84,7 @@ namespace Kyoo.Core.Api
|
||||
/// Get the season that this episode is part of.
|
||||
/// </remarks>
|
||||
/// <param name="identifier">The ID or slug of the <see cref="Episode"/>.</param>
|
||||
/// <param name="fields">The aditional fields to include in the result.</param>
|
||||
/// <returns>The season that contains this episode.</returns>
|
||||
/// <response code="204">The episode is not part of a season.</response>
|
||||
/// <response code="404">No episode with the given ID or slug could be found.</response>
|
||||
@ -91,14 +93,17 @@ namespace Kyoo.Core.Api
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public async Task<ActionResult<Season>> GetSeason(Identifier identifier)
|
||||
public async Task<ActionResult<Season>> GetSeason(Identifier identifier, [FromQuery] Include<Season> fields)
|
||||
{
|
||||
Season? ret = await _libraryManager.GetOrDefault(identifier.IsContainedIn<Season, Episode>(x => x.Episodes!));
|
||||
Season? ret = await _libraryManager.Seasons.GetOrDefault(
|
||||
identifier.IsContainedIn<Season, Episode>(x => x.Episodes!),
|
||||
fields
|
||||
);
|
||||
if (ret != null)
|
||||
return ret;
|
||||
Episode? episode = await identifier.Match(
|
||||
id => _libraryManager.GetOrDefault<Episode>(id),
|
||||
slug => _libraryManager.GetOrDefault<Episode>(slug)
|
||||
id => _libraryManager.Episodes.GetOrDefault(id),
|
||||
slug => _libraryManager.Episodes.GetOrDefault(slug)
|
||||
);
|
||||
return episode == null
|
||||
? NotFound()
|
||||
|
@ -16,14 +16,10 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
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
|
||||
/// <summary>
|
||||
/// The library item repository used to modify or retrieve information in the data store.
|
||||
/// </summary>
|
||||
private readonly ILibraryItemRepository _libraryItems;
|
||||
private readonly IRepository<LibraryItem> _libraryItems;
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="LibraryItemApi"/>.
|
||||
@ -53,7 +49,7 @@ namespace Kyoo.Core.Api
|
||||
/// The library item repository used to modify or retrieve information in the data store.
|
||||
/// </param>
|
||||
/// <param name="thumbs">Thumbnail manager to retrieve images.</param>
|
||||
public LibraryItemApi(ILibraryItemRepository libraryItems, IThumbnailsManager thumbs)
|
||||
public LibraryItemApi(IRepository<LibraryItem> libraryItems, IThumbnailsManager thumbs)
|
||||
: base(libraryItems, thumbs)
|
||||
{
|
||||
_libraryItems = libraryItems;
|
||||
|
@ -54,7 +54,7 @@ namespace Kyoo.Core.Api
|
||||
/// <param name="thumbs">The thumbnail manager used to retrieve images paths.</param>
|
||||
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.
|
||||
/// </remarks>
|
||||
/// <param name="identifier">The ID or slug of the <see cref="Show"/>.</param>
|
||||
/// <param name="fields">The aditional fields to include in the result.</param>
|
||||
/// <returns>The studio that made the show.</returns>
|
||||
/// <response code="404">No show with the given ID or slug could be found.</response>
|
||||
[HttpGet("{identifier:id}/studio")]
|
||||
[PartialPermission(Kind.Read)]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public async Task<ActionResult<Studio>> GetStudio(Identifier identifier)
|
||||
public async Task<ActionResult<Studio>> GetStudio(Identifier identifier, [FromQuery] Include<Studio> fields)
|
||||
{
|
||||
return await _libraryManager.Get(identifier.IsContainedIn<Studio, Movie>(x => x.Movies!));
|
||||
return await _libraryManager.Studios.Get(identifier.IsContainedIn<Studio, Movie>(x => x.Movies!), fields);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -121,6 +122,7 @@ namespace Kyoo.Core.Api
|
||||
/// <param name="sortBy">A key to sort collections by.</param>
|
||||
/// <param name="where">An optional list of filters.</param>
|
||||
/// <param name="pagination">The number of collections to return.</param>
|
||||
/// <param name="fields">The aditional fields to include in the result.</param>
|
||||
/// <returns>A page of collections.</returns>
|
||||
/// <response code="400">The filters or the sort parameters are invalid.</response>
|
||||
/// <response code="404">No show with the given ID or slug could be found.</response>
|
||||
@ -133,15 +135,17 @@ namespace Kyoo.Core.Api
|
||||
public async Task<ActionResult<Page<Collection>>> GetCollections(Identifier identifier,
|
||||
[FromQuery] Sort<Collection> sortBy,
|
||||
[FromQuery] Dictionary<string, string> where,
|
||||
[FromQuery] Pagination pagination)
|
||||
[FromQuery] Pagination pagination,
|
||||
[FromQuery] Include<Collection> fields)
|
||||
{
|
||||
ICollection<Collection> resources = await _libraryManager.GetAll(
|
||||
ICollection<Collection> resources = await _libraryManager.Collections.GetAll(
|
||||
ApiHelper.ParseWhere(where, identifier.IsContainedIn<Collection, Movie>(x => x.Movies!)),
|
||||
sortBy,
|
||||
pagination
|
||||
pagination,
|
||||
fields
|
||||
);
|
||||
|
||||
if (!resources.Any() && await _libraryManager.GetOrDefault(identifier.IsSame<Movie>()) == null)
|
||||
if (!resources.Any() && await _libraryManager.Movies.GetOrDefault(identifier.IsSame<Movie>()) == null)
|
||||
return NotFound();
|
||||
return Page(resources, pagination.Limit);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Global search
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Search for collections, shows, episodes, staff, genre and studios at the same time
|
||||
/// </remarks>
|
||||
/// <param name="query">The query to search for.</param>
|
||||
/// <returns>A list of every resources found for the specified query.</returns>
|
||||
[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<ActionResult<SearchResult>> Search(string query)
|
||||
{
|
||||
HttpContext.Items["ResourceType"] = nameof(Episode);
|
||||
HttpContext.Items["fields"] = new[] { nameof(Episode.Show) };
|
||||
return new SearchResult
|
||||
{
|
||||
Query = query,
|
||||
Collections = await _libraryManager.Search<Collection>(query),
|
||||
Items = await _libraryManager.Search<LibraryItem>(query),
|
||||
Movies = await _libraryManager.Search<Movie>(query),
|
||||
Shows = await _libraryManager.Search<Show>(query),
|
||||
Episodes = await _libraryManager.Search<Episode>(query),
|
||||
People = await _libraryManager.Search<People>(query),
|
||||
Studios = await _libraryManager.Search<Studio>(query)
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Search collections
|
||||
/// </summary>
|
||||
@ -92,15 +60,16 @@ namespace Kyoo.Core.Api
|
||||
/// Search for collections
|
||||
/// </remarks>
|
||||
/// <param name="query">The query to search for.</param>
|
||||
/// <param name="fields">The aditional fields to include in the result.</param>
|
||||
/// <returns>A list of collections found for the specified query.</returns>
|
||||
[HttpGet("collections")]
|
||||
[HttpGet("collection", Order = AlternativeRoute)]
|
||||
[Permission(nameof(Collection), Kind.Read)]
|
||||
[ApiDefinition("Collections")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
public Task<ICollection<Collection>> SearchCollections(string query)
|
||||
public Task<ICollection<Collection>> SearchCollections(string query, [FromQuery] Include<Collection> fields)
|
||||
{
|
||||
return _libraryManager.Search<Collection>(query);
|
||||
return _libraryManager.Collections.Search(query);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -110,15 +79,16 @@ namespace Kyoo.Core.Api
|
||||
/// Search for shows
|
||||
/// </remarks>
|
||||
/// <param name="query">The query to search for.</param>
|
||||
/// <param name="fields">The aditional fields to include in the result.</param>
|
||||
/// <returns>A list of shows found for the specified query.</returns>
|
||||
[HttpGet("shows")]
|
||||
[HttpGet("show", Order = AlternativeRoute)]
|
||||
[Permission(nameof(Show), Kind.Read)]
|
||||
[ApiDefinition("Shows")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
public Task<ICollection<Show>> SearchShows(string query)
|
||||
public Task<ICollection<Show>> SearchShows(string query, [FromQuery] Include<Show> fields)
|
||||
{
|
||||
return _libraryManager.Search<Show>(query);
|
||||
return _libraryManager.Shows.Search(query);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -128,15 +98,16 @@ namespace Kyoo.Core.Api
|
||||
/// Search for items
|
||||
/// </remarks>
|
||||
/// <param name="query">The query to search for.</param>
|
||||
/// <param name="fields">The aditional fields to include in the result.</param>
|
||||
/// <returns>A list of items found for the specified query.</returns>
|
||||
[HttpGet("items")]
|
||||
[HttpGet("item", Order = AlternativeRoute)]
|
||||
[Permission(nameof(Show), Kind.Read)]
|
||||
[ApiDefinition("Items")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
public Task<ICollection<LibraryItem>> SearchItems(string query)
|
||||
public Task<ICollection<LibraryItem>> SearchItems(string query, [FromQuery] Include<LibraryItem> fields)
|
||||
{
|
||||
return _libraryManager.Search<LibraryItem>(query);
|
||||
return _libraryManager.LibraryItems.Search(query);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -146,15 +117,16 @@ namespace Kyoo.Core.Api
|
||||
/// Search for episodes
|
||||
/// </remarks>
|
||||
/// <param name="query">The query to search for.</param>
|
||||
/// <param name="fields">The aditional fields to include in the result.</param>
|
||||
/// <returns>A list of episodes found for the specified query.</returns>
|
||||
[HttpGet("episodes")]
|
||||
[HttpGet("episode", Order = AlternativeRoute)]
|
||||
[Permission(nameof(Episode), Kind.Read)]
|
||||
[ApiDefinition("Episodes")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
public Task<ICollection<Episode>> SearchEpisodes(string query)
|
||||
public Task<ICollection<Episode>> SearchEpisodes(string query, [FromQuery] Include<Episode> fields)
|
||||
{
|
||||
return _libraryManager.Search<Episode>(query);
|
||||
return _libraryManager.Episodes.Search(query);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -164,6 +136,7 @@ namespace Kyoo.Core.Api
|
||||
/// Search for staff
|
||||
/// </remarks>
|
||||
/// <param name="query">The query to search for.</param>
|
||||
/// <param name="fields">The aditional fields to include in the result.</param>
|
||||
/// <returns>A list of staff members found for the specified query.</returns>
|
||||
[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<ICollection<People>> SearchPeople(string query)
|
||||
public Task<ICollection<People>> SearchPeople(string query, [FromQuery] Include<People> fields)
|
||||
{
|
||||
return _libraryManager.Search<People>(query);
|
||||
return _libraryManager.People.Search(query);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -183,15 +156,16 @@ namespace Kyoo.Core.Api
|
||||
/// Search for studios
|
||||
/// </remarks>
|
||||
/// <param name="query">The query to search for.</param>
|
||||
/// <param name="fields">The aditional fields to include in the result.</param>
|
||||
/// <returns>A list of studios found for the specified query.</returns>
|
||||
[HttpGet("studios")]
|
||||
[HttpGet("studio", Order = AlternativeRoute)]
|
||||
[Permission(nameof(Studio), Kind.Read)]
|
||||
[ApiDefinition("Studios")]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
public Task<ICollection<Studio>> SearchStudios(string query)
|
||||
public Task<ICollection<Studio>> SearchStudios(string query, [FromQuery] Include<Studio> fields)
|
||||
{
|
||||
return _libraryManager.Search<Studio>(query);
|
||||
return _libraryManager.Studios.Search(query);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -54,7 +54,7 @@ namespace Kyoo.Core.Api
|
||||
/// <param name="thumbs">The thumbnail manager used to retrieve images paths.</param>
|
||||
public SeasonApi(ILibraryManager libraryManager,
|
||||
IThumbnailsManager thumbs)
|
||||
: base(libraryManager.SeasonRepository, thumbs)
|
||||
: base(libraryManager.Seasons, thumbs)
|
||||
{
|
||||
_libraryManager = libraryManager;
|
||||
}
|
||||
@ -69,6 +69,7 @@ namespace Kyoo.Core.Api
|
||||
/// <param name="sortBy">A key to sort episodes by.</param>
|
||||
/// <param name="where">An optional list of filters.</param>
|
||||
/// <param name="pagination">The number of episodes to return.</param>
|
||||
/// <param name="fields">The aditional fields to include in the result.</param>
|
||||
/// <returns>A page of episodes.</returns>
|
||||
/// <response code="400">The filters or the sort parameters are invalid.</response>
|
||||
/// <response code="404">No season with the given ID or slug could be found.</response>
|
||||
@ -81,15 +82,17 @@ namespace Kyoo.Core.Api
|
||||
public async Task<ActionResult<Page<Episode>>> GetEpisode(Identifier identifier,
|
||||
[FromQuery] Sort<Episode> sortBy,
|
||||
[FromQuery] Dictionary<string, string> where,
|
||||
[FromQuery] Pagination pagination)
|
||||
[FromQuery] Pagination pagination,
|
||||
[FromQuery] Include<Episode> fields)
|
||||
{
|
||||
ICollection<Episode> resources = await _libraryManager.GetAll(
|
||||
ICollection<Episode> resources = await _libraryManager.Episodes.GetAll(
|
||||
ApiHelper.ParseWhere(where, identifier.Matcher<Episode>(x => x.SeasonId, x => x.Season!.Slug)),
|
||||
sortBy,
|
||||
pagination
|
||||
pagination,
|
||||
fields
|
||||
);
|
||||
|
||||
if (!resources.Any() && await _libraryManager.GetOrDefault(identifier.IsSame<Season>()) == null)
|
||||
if (!resources.Any() && await _libraryManager.Seasons.GetOrDefault(identifier.IsSame<Season>()) == 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.
|
||||
/// </remarks>
|
||||
/// <param name="identifier">The ID or slug of the <see cref="Season"/>.</param>
|
||||
/// <param name="fields">The aditional fields to include in the result.</param>
|
||||
/// <returns>The show that contains this season.</returns>
|
||||
/// <response code="404">No season with the given ID or slug could be found.</response>
|
||||
[HttpGet("{identifier:id}/show")]
|
||||
[PartialPermission(Kind.Read)]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public async Task<ActionResult<Show>> GetShow(Identifier identifier)
|
||||
public async Task<ActionResult<Show>> GetShow(Identifier identifier, [FromQuery] Include<Show> fields)
|
||||
{
|
||||
Show? ret = await _libraryManager.GetOrDefault(identifier.IsContainedIn<Show, Season>(x => x.Seasons!));
|
||||
Show? ret = await _libraryManager.Shows.GetOrDefault(
|
||||
identifier.IsContainedIn<Show, Season>(x => x.Seasons!),
|
||||
fields
|
||||
);
|
||||
if (ret == null)
|
||||
return NotFound();
|
||||
return ret;
|
||||
|
@ -16,10 +16,8 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
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
|
||||
/// <param name="thumbs">The thumbnail manager used to retrieve images paths.</param>
|
||||
public ShowApi(ILibraryManager libraryManager,
|
||||
IThumbnailsManager thumbs)
|
||||
: base(libraryManager.ShowRepository, thumbs)
|
||||
: base(libraryManager.Shows, thumbs)
|
||||
{
|
||||
_libraryManager = libraryManager;
|
||||
}
|
||||
@ -71,6 +69,7 @@ namespace Kyoo.Core.Api
|
||||
/// <param name="sortBy">A key to sort seasons by.</param>
|
||||
/// <param name="where">An optional list of filters.</param>
|
||||
/// <param name="pagination">The number of seasons to return.</param>
|
||||
/// <param name="fields">The aditional fields to include in the result.</param>
|
||||
/// <returns>A page of seasons.</returns>
|
||||
/// <response code="400">The filters or the sort parameters are invalid.</response>
|
||||
/// <response code="404">No show with the given ID or slug could be found.</response>
|
||||
@ -83,15 +82,17 @@ namespace Kyoo.Core.Api
|
||||
public async Task<ActionResult<Page<Season>>> GetSeasons(Identifier identifier,
|
||||
[FromQuery] Sort<Season> sortBy,
|
||||
[FromQuery] Dictionary<string, string> where,
|
||||
[FromQuery] Pagination pagination)
|
||||
[FromQuery] Pagination pagination,
|
||||
[FromQuery] Include<Season> fields)
|
||||
{
|
||||
ICollection<Season> resources = await _libraryManager.GetAll(
|
||||
ICollection<Season> resources = await _libraryManager.Seasons.GetAll(
|
||||
ApiHelper.ParseWhere(where, identifier.Matcher<Season>(x => x.ShowId, x => x.Show!.Slug)),
|
||||
sortBy,
|
||||
pagination
|
||||
pagination,
|
||||
fields
|
||||
);
|
||||
|
||||
if (!resources.Any() && await _libraryManager.GetOrDefault(identifier.IsSame<Show>()) == null)
|
||||
if (!resources.Any() && await _libraryManager.Shows.GetOrDefault(identifier.IsSame<Show>()) == null)
|
||||
return NotFound();
|
||||
return Page(resources, pagination.Limit);
|
||||
}
|
||||
@ -106,6 +107,7 @@ namespace Kyoo.Core.Api
|
||||
/// <param name="sortBy">A key to sort episodes by.</param>
|
||||
/// <param name="where">An optional list of filters.</param>
|
||||
/// <param name="pagination">The number of episodes to return.</param>
|
||||
/// <param name="fields">The aditional fields to include in the result.</param>
|
||||
/// <returns>A page of episodes.</returns>
|
||||
/// <response code="400">The filters or the sort parameters are invalid.</response>
|
||||
/// <response code="404">No show with the given ID or slug could be found.</response>
|
||||
@ -118,51 +120,55 @@ namespace Kyoo.Core.Api
|
||||
public async Task<ActionResult<Page<Episode>>> GetEpisodes(Identifier identifier,
|
||||
[FromQuery] Sort<Episode> sortBy,
|
||||
[FromQuery] Dictionary<string, string> where,
|
||||
[FromQuery] Pagination pagination)
|
||||
[FromQuery] Pagination pagination,
|
||||
[FromQuery] Include<Episode> fields)
|
||||
{
|
||||
ICollection<Episode> resources = await _libraryManager.GetAll(
|
||||
ICollection<Episode> resources = await _libraryManager.Episodes.GetAll(
|
||||
ApiHelper.ParseWhere(where, identifier.Matcher<Episode>(x => x.ShowId, x => x.Show!.Slug)),
|
||||
sortBy,
|
||||
pagination
|
||||
pagination,
|
||||
fields
|
||||
);
|
||||
|
||||
if (!resources.Any() && await _libraryManager.GetOrDefault(identifier.IsSame<Show>()) == null)
|
||||
if (!resources.Any() && await _libraryManager.Shows.GetOrDefault(identifier.IsSame<Show>()) == null)
|
||||
return NotFound();
|
||||
return Page(resources, pagination.Limit);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get staff
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// List staff members that made this show.
|
||||
/// </remarks>
|
||||
/// <param name="identifier">The ID or slug of the <see cref="Show"/>.</param>
|
||||
/// <param name="sortBy">A key to sort staff members by.</param>
|
||||
/// <param name="where">An optional list of filters.</param>
|
||||
/// <param name="pagination">The number of people to return.</param>
|
||||
/// <returns>A page of people.</returns>
|
||||
/// <response code="400">The filters or the sort parameters are invalid.</response>
|
||||
/// <response code="404">No show with the given ID or slug could be found.</response>
|
||||
[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<ActionResult<Page<PeopleRole>>> GetPeople(Identifier identifier,
|
||||
[FromQuery] Sort<PeopleRole> sortBy,
|
||||
[FromQuery] Dictionary<string, string> where,
|
||||
[FromQuery] Pagination pagination)
|
||||
{
|
||||
Expression<Func<PeopleRole, bool>>? whereQuery = ApiHelper.ParseWhere<PeopleRole>(where);
|
||||
|
||||
ICollection<PeopleRole> resources = await identifier.Match(
|
||||
id => _libraryManager.GetPeopleFromShow(id, whereQuery, sortBy, pagination),
|
||||
slug => _libraryManager.GetPeopleFromShow(slug, whereQuery, sortBy, pagination)
|
||||
);
|
||||
return Page(resources, pagination.Limit);
|
||||
}
|
||||
// /// <summary>
|
||||
// /// Get staff
|
||||
// /// </summary>
|
||||
// /// <remarks>
|
||||
// /// List staff members that made this show.
|
||||
// /// </remarks>
|
||||
// /// <param name="identifier">The ID or slug of the <see cref="Show"/>.</param>
|
||||
// /// <param name="sortBy">A key to sort staff members by.</param>
|
||||
// /// <param name="where">An optional list of filters.</param>
|
||||
// /// <param name="pagination">The number of people to return.</param>
|
||||
// /// <param name="fields">The aditional fields to include in the result.</param>
|
||||
// /// <returns>A page of people.</returns>
|
||||
// /// <response code="400">The filters or the sort parameters are invalid.</response>
|
||||
// /// <response code="404">No show with the given ID or slug could be found.</response>
|
||||
// [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<ActionResult<Page<PeopleRole>>> GetPeople(Identifier identifier,
|
||||
// [FromQuery] Sort<PeopleRole> sortBy,
|
||||
// [FromQuery] Dictionary<string, string> where,
|
||||
// [FromQuery] Pagination pagination,
|
||||
// [FromQuery] Include<PeopleRole> fields)
|
||||
// {
|
||||
// Expression<Func<PeopleRole, bool>>? whereQuery = ApiHelper.ParseWhere<PeopleRole>(where);
|
||||
//
|
||||
// ICollection<PeopleRole> resources = await identifier.Match(
|
||||
// id => _libraryManager.GetPeopleFromShow(id, whereQuery, sortBy, pagination),
|
||||
// slug => _libraryManager.GetPeopleFromShow(slug, whereQuery, sortBy, pagination)
|
||||
// );
|
||||
// return Page(resources, pagination.Limit);
|
||||
// }
|
||||
|
||||
/// <summary>
|
||||
/// Get studio that made the show
|
||||
@ -171,15 +177,16 @@ namespace Kyoo.Core.Api
|
||||
/// Get the studio that made the show.
|
||||
/// </remarks>
|
||||
/// <param name="identifier">The ID or slug of the <see cref="Show"/>.</param>
|
||||
/// <param name="fields">The aditional fields to include in the result.</param>
|
||||
/// <returns>The studio that made the show.</returns>
|
||||
/// <response code="404">No show with the given ID or slug could be found.</response>
|
||||
[HttpGet("{identifier:id}/studio")]
|
||||
[PartialPermission(Kind.Read)]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public async Task<ActionResult<Studio>> GetStudio(Identifier identifier)
|
||||
public async Task<ActionResult<Studio>> GetStudio(Identifier identifier, [FromQuery] Include<Studio> fields)
|
||||
{
|
||||
return await _libraryManager.Get(identifier.IsContainedIn<Studio, Show>(x => x.Shows!));
|
||||
return await _libraryManager.Studios.Get(identifier.IsContainedIn<Studio, Show>(x => x.Shows!), fields);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -192,6 +199,7 @@ namespace Kyoo.Core.Api
|
||||
/// <param name="sortBy">A key to sort collections by.</param>
|
||||
/// <param name="where">An optional list of filters.</param>
|
||||
/// <param name="pagination">The number of collections to return.</param>
|
||||
/// <param name="fields">The aditional fields to include in the result.</param>
|
||||
/// <returns>A page of collections.</returns>
|
||||
/// <response code="400">The filters or the sort parameters are invalid.</response>
|
||||
/// <response code="404">No show with the given ID or slug could be found.</response>
|
||||
@ -204,15 +212,17 @@ namespace Kyoo.Core.Api
|
||||
public async Task<ActionResult<Page<Collection>>> GetCollections(Identifier identifier,
|
||||
[FromQuery] Sort<Collection> sortBy,
|
||||
[FromQuery] Dictionary<string, string> where,
|
||||
[FromQuery] Pagination pagination)
|
||||
[FromQuery] Pagination pagination,
|
||||
[FromQuery] Include<Collection> fields)
|
||||
{
|
||||
ICollection<Collection> resources = await _libraryManager.GetAll(
|
||||
ICollection<Collection> resources = await _libraryManager.Collections.GetAll(
|
||||
ApiHelper.ParseWhere(where, identifier.IsContainedIn<Collection, Show>(x => x.Shows!)),
|
||||
sortBy,
|
||||
pagination
|
||||
pagination,
|
||||
fields
|
||||
);
|
||||
|
||||
if (!resources.Any() && await _libraryManager.GetOrDefault(identifier.IsSame<Show>()) == null)
|
||||
if (!resources.Any() && await _libraryManager.Shows.GetOrDefault(identifier.IsSame<Show>()) == null)
|
||||
return NotFound();
|
||||
return Page(resources, pagination.Limit);
|
||||
}
|
||||
|
@ -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<DatabaseContext> _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<IShowRepository>(() => LibraryManager.ShowRepository),
|
||||
new Lazy<IRepository<Show>>(() => 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<T> GetRepository<T>()
|
||||
where T: class, IResource
|
||||
{
|
||||
return _repositories.First(x => x.RepositoryType == typeof(T)) as IRepository<T>;
|
||||
}
|
||||
|
||||
private DatabaseContext _NewContext()
|
||||
|
@ -37,7 +37,7 @@ namespace Kyoo.Tests.Database
|
||||
protected RepositoryTests(RepositoryActivator repositories)
|
||||
{
|
||||
Repositories = repositories;
|
||||
_repository = Repositories.LibraryManager.GetRepository<T>();
|
||||
_repository = Repositories.GetRepository<T>();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
@ -41,12 +41,12 @@ namespace Kyoo.Tests.Database
|
||||
|
||||
public abstract class ACollectionTests : RepositoryTests<Collection>
|
||||
{
|
||||
private readonly ICollectionRepository _repository;
|
||||
private readonly IRepository<Collection> _repository;
|
||||
|
||||
protected ACollectionTests(RepositoryActivator repositories)
|
||||
: base(repositories)
|
||||
{
|
||||
_repository = Repositories.LibraryManager.CollectionRepository;
|
||||
_repository = Repositories.LibraryManager.Collections;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -42,13 +42,13 @@ namespace Kyoo.Tests.Database
|
||||
|
||||
public abstract class AEpisodeTests : RepositoryTests<Episode>
|
||||
{
|
||||
private readonly IEpisodeRepository _repository;
|
||||
private readonly IRepository<Episode> _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<Show>().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<Show>().Slug}-s1e1", episode.Slug);
|
||||
episode = await Repositories.LibraryManager.Patch<Episode>(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<Episode>();
|
||||
expected.Id = 0;
|
||||
expected.ShowId = (await Repositories.LibraryManager.ShowRepository.Create(TestSample.Get<Show>())).Id;
|
||||
expected.SeasonId = (await Repositories.LibraryManager.SeasonRepository.Create(TestSample.Get<Season>())).Id;
|
||||
expected.ShowId = (await Repositories.LibraryManager.Shows.Create(TestSample.Get<Show>())).Id;
|
||||
expected.SeasonId = (await Repositories.LibraryManager.Seasons.Create(TestSample.Get<Season>())).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<Episode>();
|
||||
KAssert.DeepEqual(expected, await _repository.CreateIfNotExists(TestSample.Get<Episode>()));
|
||||
await _repository.Delete(TestSample.Get<Episode>());
|
||||
expected.ShowId = (await Repositories.LibraryManager.ShowRepository.Create(TestSample.Get<Show>())).Id;
|
||||
expected.SeasonId = (await Repositories.LibraryManager.SeasonRepository.Create(TestSample.Get<Season>())).Id;
|
||||
expected.ShowId = (await Repositories.LibraryManager.Shows.Create(TestSample.Get<Show>())).Id;
|
||||
expected.SeasonId = (await Repositories.LibraryManager.Seasons.Create(TestSample.Get<Season>())).Id;
|
||||
KAssert.DeepEqual(expected, await _repository.CreateIfNotExists(expected));
|
||||
}
|
||||
}
|
||||
|
@ -40,12 +40,12 @@ namespace Kyoo.Tests.Database
|
||||
|
||||
public abstract class APeopleTests : RepositoryTests<People>
|
||||
{
|
||||
private readonly IPeopleRepository _repository;
|
||||
private readonly IRepository<People> _repository;
|
||||
|
||||
protected APeopleTests(RepositoryActivator repositories)
|
||||
: base(repositories)
|
||||
{
|
||||
_repository = Repositories.LibraryManager.PeopleRepository;
|
||||
_repository = Repositories.LibraryManager.People;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -40,12 +40,12 @@ namespace Kyoo.Tests.Database
|
||||
|
||||
public abstract class ASeasonTests : RepositoryTests<Season>
|
||||
{
|
||||
private readonly ISeasonRepository _repository;
|
||||
private readonly IRepository<Season> _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);
|
||||
|
@ -42,12 +42,12 @@ namespace Kyoo.Tests.Database
|
||||
|
||||
public abstract class AShowTests : RepositoryTests<Show>
|
||||
{
|
||||
private readonly IShowRepository _repository;
|
||||
private readonly IRepository<Show> _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<Show>();
|
||||
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<Show>();
|
||||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -37,12 +37,12 @@ namespace Kyoo.Tests.Database
|
||||
public abstract class AStudioTests : RepositoryTests<Studio>
|
||||
{
|
||||
[SuppressMessage("ReSharper", "NotAccessedField.Local")]
|
||||
private readonly IStudioRepository _repository;
|
||||
private readonly IRepository<Studio> _repository;
|
||||
|
||||
protected AStudioTests(RepositoryActivator repositories)
|
||||
: base(repositories)
|
||||
{
|
||||
_repository = Repositories.LibraryManager.StudioRepository;
|
||||
_repository = Repositories.LibraryManager.Studios;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -37,12 +37,12 @@ namespace Kyoo.Tests.Database
|
||||
public abstract class AUserTests : RepositoryTests<User>
|
||||
{
|
||||
[SuppressMessage("ReSharper", "NotAccessedField.Local")]
|
||||
private readonly IUserRepository _repository;
|
||||
private readonly IRepository<User> _repository;
|
||||
|
||||
protected AUserTests(RepositoryActivator repositories)
|
||||
: base(repositories)
|
||||
{
|
||||
_repository = Repositories.LibraryManager.UserRepository;
|
||||
_repository = Repositories.LibraryManager.Users;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user