diff --git a/back/src/Kyoo.Abstractions/Models/LibraryItem.cs b/back/src/Kyoo.Abstractions/Models/LibraryItem.cs index 61e0867f..80678aa7 100644 --- a/back/src/Kyoo.Abstractions/Models/LibraryItem.cs +++ b/back/src/Kyoo.Abstractions/Models/LibraryItem.cs @@ -20,6 +20,7 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Text.Json.Serialization; +using Kyoo.Abstractions.Models.Attributes; using Kyoo.Utils; namespace Kyoo.Abstractions.Models diff --git a/back/src/Kyoo.Core/Controllers/Repositories/LibraryItemRepository.cs b/back/src/Kyoo.Core/Controllers/Repositories/LibraryItemRepository.cs index 09bf6432..3085ae1b 100644 --- a/back/src/Kyoo.Core/Controllers/Repositories/LibraryItemRepository.cs +++ b/back/src/Kyoo.Core/Controllers/Repositories/LibraryItemRepository.cs @@ -19,6 +19,7 @@ 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; @@ -63,6 +64,29 @@ namespace Kyoo.Core.Controllers .ToListAsync(); } + public async Task> GetAllOfCollection( + Expression> selector, + Expression>? where = null, + Sort? sort = default, + Pagination? limit = default, + Include? include = default) + { + return await ApplyFilters( + _database.LibraryItems + .Where(item => + _database.Movies + .Where(x => x.Id == -item.Id) + .Any(x => x.Collections!.AsQueryable().Any(selector)) + || _database.Shows + .Where(x => x.Id == item.Id) + .Any(x => x.Collections!.AsQueryable().Any(selector)) + ), + where, + sort, + limit, + include); + } + /// public override Task Create(LibraryItem obj) => throw new InvalidOperationException(); diff --git a/back/src/Kyoo.Core/Views/Resources/CollectionApi.cs b/back/src/Kyoo.Core/Views/Resources/CollectionApi.cs index 497df34a..ef7bbf10 100644 --- a/back/src/Kyoo.Core/Views/Resources/CollectionApi.cs +++ b/back/src/Kyoo.Core/Views/Resources/CollectionApi.cs @@ -43,14 +43,17 @@ namespace Kyoo.Core.Api { private readonly ILibraryManager _libraryManager; private readonly CollectionRepository _collections; + private readonly LibraryItemRepository _items; public CollectionApi(ILibraryManager libraryManager, CollectionRepository collections, + LibraryItemRepository items, IThumbnailsManager thumbs) : base(libraryManager.Collections, thumbs) { _libraryManager = libraryManager; _collections = collections; + _items = items; } /// @@ -115,6 +118,45 @@ namespace Kyoo.Core.Api return NoContent(); } + /// + /// Get items in collection + /// + /// + /// Lists the items that are contained in the collection with the given id or slug. + /// + /// The ID or slug of the . + /// A key to sort items by. + /// An optional list of filters. + /// The number of items to return. + /// The aditional fields to include in the result. + /// A page of items. + /// The filters or the sort parameters are invalid. + /// No collection with the given ID could be found. + [HttpGet("{identifier:id}/items")] + [HttpGet("{identifier:id}/item", Order = AlternativeRoute)] + [PartialPermission(Kind.Read)] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(RequestError))] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public async Task>> GetItems(Identifier identifier, + [FromQuery] Sort sortBy, + [FromQuery] Dictionary where, + [FromQuery] Pagination pagination, + [FromQuery] Include? fields) + { + ICollection resources = await _items.GetAllOfCollection( + identifier.IsSame(), + ApiHelper.ParseWhere(where), + sortBy == new Sort.Default() ? new Sort.By(x => x.AirDate) : sortBy, + pagination, + fields + ); + + if (!resources.Any() && await _libraryManager.Collections.GetOrDefault(identifier.IsSame()) == null) + return NotFound(); + return Page(resources, pagination.Limit); + } + /// /// Get shows in collection /// @@ -143,7 +185,45 @@ namespace Kyoo.Core.Api { ICollection resources = await _libraryManager.Shows.GetAll( ApiHelper.ParseWhere(where, identifier.IsContainedIn(x => x.Collections!)), - sortBy ?? new Sort.By(x => x.StartAir), + sortBy == new Sort.Default() ? new Sort.By(x => x.AirDate) : sortBy, + pagination, + fields + ); + + if (!resources.Any() && await _libraryManager.Collections.GetOrDefault(identifier.IsSame()) == null) + return NotFound(); + return Page(resources, pagination.Limit); + } + + /// + /// Get movies in collection + /// + /// + /// Lists the movies that are contained in the collection with the given id or slug. + /// + /// The ID or slug of the . + /// A key to sort movies by. + /// An optional list of filters. + /// The number of movies to return. + /// The aditional fields to include in the result. + /// A page of movies. + /// The filters or the sort parameters are invalid. + /// No collection with the given ID could be found. + [HttpGet("{identifier:id}/movies")] + [HttpGet("{identifier:id}/movie", Order = AlternativeRoute)] + [PartialPermission(Kind.Read)] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(RequestError))] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public async Task>> GetMovies(Identifier identifier, + [FromQuery] Sort sortBy, + [FromQuery] Dictionary where, + [FromQuery] Pagination pagination, + [FromQuery] Include? fields) + { + ICollection resources = await _libraryManager.Movies.GetAll( + ApiHelper.ParseWhere(where, identifier.IsContainedIn(x => x.Collections!)), + sortBy == new Sort.Default() ? new Sort.By(x => x.AirDate) : sortBy, pagination, fields );