Finishing the library's items route

This commit is contained in:
Zoe Roux 2020-07-29 00:33:58 +02:00
parent e69eda8df3
commit 5b0b2fbb7b
10 changed files with 240 additions and 78 deletions

View File

@ -12,6 +12,7 @@ namespace Kyoo.Controllers
{
// Repositories
ILibraryRepository LibraryRepository { get; }
ILibraryItemRepository LibraryItemRepository { get; }
ICollectionRepository CollectionRepository { get; }
IShowRepository ShowRepository { get; }
ISeasonRepository SeasonRepository { get; }
@ -231,6 +232,28 @@ namespace Kyoo.Controllers
Expression<Func<Collection, object>> sort,
Pagination limit = default
) => GetCollectionsFromLibrary(showSlug, where, new Sort<Collection>(sort), limit);
Task<ICollection<LibraryItem>> GetItemsFromLibrary(int id,
Expression<Func<LibraryItem, bool>> where = null,
Sort<LibraryItem> sort = default,
Pagination limit = default);
Task<ICollection<LibraryItem>> GetItemsFromLibrary(int id,
[Optional] Expression<Func<LibraryItem, bool>> where,
Expression<Func<LibraryItem, object>> sort,
Pagination limit = default
) => GetItemsFromLibrary(id, where, new Sort<LibraryItem>(sort), limit);
Task<ICollection<LibraryItem>> GetItemsFromLibrary(string librarySlug,
Expression<Func<LibraryItem, bool>> where = null,
Sort<LibraryItem> sort = default,
Pagination limit = default);
Task<ICollection<LibraryItem>> GetItemsFromLibrary(string librarySlug,
[Optional] Expression<Func<LibraryItem, bool>> where,
Expression<Func<LibraryItem, object>> sort,
Pagination limit = default
) => GetItemsFromLibrary(librarySlug, where, new Sort<LibraryItem>(sort), limit);
// Helpers

View File

@ -257,6 +257,31 @@ namespace Kyoo.Controllers
) => GetFromShow(showSlug, where, new Sort<Library>(sort), limit);
}
public interface ILibraryItemRepository : IRepository<LibraryItem>
{
public Task<ICollection<LibraryItem>> GetFromLibrary(int id,
Expression<Func<LibraryItem, bool>> where = null,
Sort<LibraryItem> sort = default,
Pagination limit = default);
public Task<ICollection<LibraryItem>> GetFromLibrary(int id,
[Optional] Expression<Func<LibraryItem, bool>> where,
Expression<Func<LibraryItem, object>> sort,
Pagination limit = default
) => GetFromLibrary(id, where, new Sort<LibraryItem>(sort), limit);
public Task<ICollection<LibraryItem>> GetFromLibrary(string librarySlug,
Expression<Func<LibraryItem, bool>> where = null,
Sort<LibraryItem> sort = default,
Pagination limit = default);
public Task<ICollection<LibraryItem>> GetFromLibrary(string librarySlug,
[Optional] Expression<Func<LibraryItem, bool>> where,
Expression<Func<LibraryItem, object>> sort,
Pagination limit = default
) => GetFromLibrary(librarySlug, where, new Sort<LibraryItem>(sort), limit);
}
public interface ICollectionRepository : IRepository<Collection>
{
Task<ICollection<Collection>> GetFromShow(int showID,

View File

@ -9,6 +9,7 @@ namespace Kyoo.Controllers
public class LibraryManager : ILibraryManager
{
public ILibraryRepository LibraryRepository { get; }
public ILibraryItemRepository LibraryItemRepository { get; }
public ICollectionRepository CollectionRepository { get; }
public IShowRepository ShowRepository { get; }
public ISeasonRepository SeasonRepository { get; }
@ -20,6 +21,7 @@ namespace Kyoo.Controllers
public IProviderRepository ProviderRepository { get; }
public LibraryManager(ILibraryRepository libraryRepository,
ILibraryItemRepository libraryItemRepository,
ICollectionRepository collectionRepository,
IShowRepository showRepository,
ISeasonRepository seasonRepository,
@ -31,6 +33,7 @@ namespace Kyoo.Controllers
IPeopleRepository peopleRepository)
{
LibraryRepository = libraryRepository;
LibraryItemRepository = libraryItemRepository;
CollectionRepository = collectionRepository;
ShowRepository = showRepository;
SeasonRepository = seasonRepository;
@ -361,6 +364,22 @@ namespace Kyoo.Controllers
return CollectionRepository.GetFromLibrary(slug, where, sort, limit);
}
public Task<ICollection<LibraryItem>> GetItemsFromLibrary(int id,
Expression<Func<LibraryItem, bool>> where = null,
Sort<LibraryItem> sort = default,
Pagination limit = default)
{
return LibraryItemRepository.GetFromLibrary(id, where, sort, limit);
}
public Task<ICollection<LibraryItem>> GetItemsFromLibrary(string librarySlug,
Expression<Func<LibraryItem, bool>> where = null,
Sort<LibraryItem> sort = default,
Pagination limit = default)
{
return LibraryItemRepository.GetFromLibrary(librarySlug, where, sort, limit);
}
public Task AddShowLink(int showID, int? libraryID, int? collectionID)
{
return ShowRepository.AddShowLink(showID, libraryID, collectionID);

View File

@ -45,7 +45,7 @@ namespace Kyoo.Controllers
public abstract Task<ICollection<T>> Search(string query);
public Task<ICollection<T>> GetAll(Expression<Func<T, bool>> where = null,
public virtual Task<ICollection<T>> GetAll(Expression<Func<T, bool>> where = null,
Sort<T> sort = default,
Pagination limit = default)
{

View File

@ -0,0 +1,136 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
using Kyoo.Models;
using Kyoo.Models.Exceptions;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
namespace Kyoo.Controllers
{
public class LibraryItemRepository : LocalRepository<LibraryItem>, ILibraryItemRepository
{
private readonly DatabaseContext _database;
private readonly IProviderRepository _providers;
private readonly Lazy<ILibraryRepository> _libraries;
private readonly Lazy<IShowRepository> _shows;
private readonly Lazy<ICollectionRepository> _collections;
protected override Expression<Func<LibraryItem, object>> DefaultSort => x => x.Title;
public LibraryItemRepository(DatabaseContext database, IProviderRepository providers, IServiceProvider services)
: base(database)
{
_database = database;
_providers = providers;
_libraries = new Lazy<ILibraryRepository>(services.GetRequiredService<ILibraryRepository>);
_shows = new Lazy<IShowRepository>(services.GetRequiredService<IShowRepository>);
_collections = new Lazy<ICollectionRepository>(services.GetRequiredService<ICollectionRepository>);
}
public override void Dispose()
{
_database.Dispose();
_providers.Dispose();
if (_shows.IsValueCreated)
_shows.Value.Dispose();
if (_collections.IsValueCreated)
_collections.Value.Dispose();
}
public override async ValueTask DisposeAsync()
{
await _database.DisposeAsync();
await _providers.DisposeAsync();
if (_shows.IsValueCreated)
await _shows.Value.DisposeAsync();
if (_collections.IsValueCreated)
await _collections.Value.DisposeAsync();
}
public override async Task<LibraryItem> Get(int id)
{
return id > 0
? new LibraryItem(await _shows.Value.Get(id))
: new LibraryItem(await _collections.Value.Get(-id));
}
public override Task<LibraryItem> Get(string slug)
{
throw new InvalidOperationException();
}
private IQueryable<LibraryItem> ItemsQuery
=> _database.Shows
.Where(x => !_database.CollectionLinks.Any(y => y.ShowID == x.ID))
.Select(LibraryItem.FromShow)
.Concat(_database.Collections
.Select(LibraryItem.FromCollection));
public override Task<ICollection<LibraryItem>> GetAll(Expression<Func<LibraryItem, bool>> where = null,
Sort<LibraryItem> sort = default,
Pagination limit = default)
{
return ApplyFilters(ItemsQuery, where, sort, limit);
}
public override async Task<ICollection<LibraryItem>> Search(string query)
{
return await ItemsQuery
.Where(x => EF.Functions.ILike(x.Title, $"%{query}%"))
.Take(20)
.ToListAsync();
}
public override Task<LibraryItem> Create(LibraryItem obj) => throw new InvalidOperationException();
public override Task<LibraryItem> CreateIfNotExists(LibraryItem obj) => throw new InvalidOperationException();
public override Task<LibraryItem> Edit(LibraryItem obj, bool reset) => throw new InvalidOperationException();
protected override Task Validate(LibraryItem obj) => throw new InvalidOperationException();
public override Task Delete(int id) => throw new InvalidOperationException();
public override Task Delete(string slug) => throw new InvalidOperationException();
public override Task Delete(LibraryItem obj) => throw new InvalidOperationException();
private IQueryable<LibraryItem> LibraryRelatedQuery(Expression<Func<LibraryLink, bool>> selector)
=> _database.LibraryLinks
.Where(selector)
.Select(x => x.Show)
.Where(x => x != null)
.Where(x => !_database.CollectionLinks.Any(y => y.ShowID == x.ID))
.Select(LibraryItem.FromShow)
.Concat(_database.LibraryLinks
.Where(selector)
.Select(x => x.Collection)
.Where(x => x != null)
.Select(LibraryItem.FromCollection));
public async Task<ICollection<LibraryItem>> GetFromLibrary(int id,
Expression<Func<LibraryItem, bool>> where = null,
Sort<LibraryItem> sort = default,
Pagination limit = default)
{
ICollection<LibraryItem> items = await ApplyFilters(LibraryRelatedQuery(x => x.LibraryID == id),
where,
sort,
limit);
if (!items.Any() && await _libraries.Value.Get(id) == null)
throw new ItemNotFound();
return items;
}
public async Task<ICollection<LibraryItem>> GetFromLibrary(string slug,
Expression<Func<LibraryItem, bool>> where = null,
Sort<LibraryItem> sort = default,
Pagination limit = default)
{
ICollection<LibraryItem> items = await ApplyFilters(LibraryRelatedQuery(x => x.Library.Slug == slug),
where,
sort,
limit);
if (!items.Any() && await _libraries.Value.Get(slug) == null)
throw new ItemNotFound();
return items;
}
}
}

View File

@ -136,29 +136,5 @@ namespace Kyoo.Controllers
throw new ItemNotFound();
return libraries;
}
public async Task<ICollection<LibraryItem>> GetItems(string librarySlug,
Expression<Func<LibraryItem, bool>> where = null,
Sort<LibraryItem> sort = default,
Pagination limit = default)
{
IQueryable<LibraryItem> query = _database.Shows
.Where(x => !_database.CollectionLinks.Any(y => y.ShowID == x.ID))
.Select(LibraryItem.FromShow)
.Concat(_database.Collections
.Select(LibraryItem.FromCollection));
ICollection<LibraryItem> items = await ApplyFilters(query,
async id => id > 0
? new LibraryItem(await _database.Shows.FirstOrDefaultAsync(x => x.ID == id))
: new LibraryItem(await _database.Collections.FirstOrDefaultAsync(x => x.ID == -id)),
x => x.Slug,
where,
sort,
limit);
if (!items.Any() && await Get(librarySlug) == null)
throw new ItemNotFound();
return items;
}
}
}

View File

@ -47,8 +47,8 @@ namespace Kyoo
{
options.UseLazyLoadingProxies()
.UseNpgsql(_configuration.GetConnectionString("Database"))
.EnableSensitiveDataLogging()
.UseLoggerFactory(LoggerFactory.Create(builder => builder.AddConsole()));
.EnableSensitiveDataLogging()
.UseLoggerFactory(LoggerFactory.Create(builder => builder.AddConsole()));
}, ServiceLifetime.Transient);
services.AddDbContext<IdentityDatabase>(options =>
@ -134,6 +134,7 @@ namespace Kyoo
services.AddScoped<ILibraryRepository, LibraryRepository>();
services.AddScoped<ILibraryItemRepository, LibraryItemRepository>();
services.AddScoped<ICollectionRepository, CollectionRepository>();
services.AddScoped<IShowRepository, ShowRepository>();
services.AddScoped<ISeasonRepository, SeasonRepository>();

View File

@ -44,7 +44,6 @@ namespace Kyoo.Api
[FromQuery] Dictionary<string, string> where,
[FromQuery] int limit = 50)
{
where.Remove("id");
where.Remove("sortBy");
where.Remove("limit");
where.Remove("afterID");
@ -77,7 +76,6 @@ namespace Kyoo.Api
[FromQuery] Dictionary<string, string> where,
[FromQuery] int limit = 20)
{
where.Remove("slug");
where.Remove("sortBy");
where.Remove("limit");
where.Remove("afterID");
@ -110,7 +108,6 @@ namespace Kyoo.Api
[FromQuery] Dictionary<string, string> where,
[FromQuery] int limit = 50)
{
where.Remove("id");
where.Remove("sortBy");
where.Remove("limit");
where.Remove("afterID");
@ -143,7 +140,6 @@ namespace Kyoo.Api
[FromQuery] Dictionary<string, string> where,
[FromQuery] int limit = 20)
{
where.Remove("slug");
where.Remove("sortBy");
where.Remove("limit");
where.Remove("afterID");
@ -176,14 +172,45 @@ namespace Kyoo.Api
[FromQuery] Dictionary<string, string> where,
[FromQuery] int limit = 50)
{
where.Remove("id");
where.Remove("sortBy");
where.Remove("limit");
where.Remove("afterID");
try
{
ICollection<LibraryItem> ressources = await ((LibraryRepository)_libraryManager.LibraryRepository).GetItems("",
ICollection<LibraryItem> ressources = await _libraryManager.GetItemsFromLibrary(id,
ApiHelper.ParseWhere<LibraryItem>(where),
new Sort<LibraryItem>(sortBy),
new Pagination(limit, afterID));
return Page(ressources, limit);
}
catch (ItemNotFound)
{
return NotFound();
}
catch (ArgumentException ex)
{
return BadRequest(new {Error = ex.Message});
}
}
[HttpGet("{slug}/item")]
[HttpGet("{slug}/items")]
[Authorize(Policy = "Read")]
public async Task<ActionResult<Page<LibraryItem>>> GetItems(string slug,
[FromQuery] string sortBy,
[FromQuery] int afterID,
[FromQuery] Dictionary<string, string> where,
[FromQuery] int limit = 50)
{
where.Remove("sortBy");
where.Remove("limit");
where.Remove("afterID");
try
{
ICollection<LibraryItem> ressources = await _libraryManager.GetItemsFromLibrary(slug,
ApiHelper.ParseWhere<LibraryItem>(where),
new Sort<LibraryItem>(sortBy),
new Pagination(limit, afterID));
@ -199,38 +226,5 @@ namespace Kyoo.Api
return BadRequest(new {Error = ex.Message});
}
}
//
// [HttpGet("{slug}/collection")]
// [HttpGet("{slug}/collections")]
// [Authorize(Policy = "Read")]
// public async Task<ActionResult<Page<Collection>>> GetCollections(string slug,
// [FromQuery] string sortBy,
// [FromQuery] int afterID,
// [FromQuery] Dictionary<string, string> where,
// [FromQuery] int limit = 20)
// {
// where.Remove("slug");
// where.Remove("sortBy");
// where.Remove("limit");
// where.Remove("afterID");
//
// try
// {
// ICollection<Collection> ressources = await _libraryManager.GetCollectionsFromLibrary(slug,
// ApiHelper.ParseWhere<Collection>(where),
// new Sort<Collection>(sortBy),
// new Pagination(limit, afterID));
//
// return Page(ressources, limit);
// }
// catch (ItemNotFound)
// {
// return NotFound();
// }
// catch (ArgumentException ex)
// {
// return BadRequest(new {Error = ex.Message});
// }
// }
}
}

View File

@ -33,7 +33,6 @@ namespace Kyoo.Api
[FromQuery] Dictionary<string, string> where,
[FromQuery] int limit = 20)
{
where.Remove("showID");
where.Remove("sortBy");
where.Remove("limit");
where.Remove("afterID");
@ -66,7 +65,6 @@ namespace Kyoo.Api
[FromQuery] Dictionary<string, string> where,
[FromQuery] int limit = 20)
{
where.Remove("slug");
where.Remove("sortBy");
where.Remove("limit");
where.Remove("afterID");
@ -99,7 +97,6 @@ namespace Kyoo.Api
[FromQuery] Dictionary<string, string> where,
[FromQuery] int limit = 50)
{
where.Remove("showID");
where.Remove("sortBy");
where.Remove("limit");
where.Remove("afterID");
@ -132,7 +129,6 @@ namespace Kyoo.Api
[FromQuery] Dictionary<string, string> where,
[FromQuery] int limit = 50)
{
where.Remove("slug");
where.Remove("sortBy");
where.Remove("limit");
where.Remove("afterID");
@ -164,7 +160,6 @@ namespace Kyoo.Api
[FromQuery] Dictionary<string, string> where,
[FromQuery] int limit = 30)
{
where.Remove("showID");
where.Remove("sortBy");
where.Remove("limit");
where.Remove("afterID");
@ -196,7 +191,6 @@ namespace Kyoo.Api
[FromQuery] Dictionary<string, string> where,
[FromQuery] int limit = 30)
{
where.Remove("slug");
where.Remove("sortBy");
where.Remove("limit");
where.Remove("afterID");
@ -229,7 +223,6 @@ namespace Kyoo.Api
[FromQuery] Dictionary<string, string> where,
[FromQuery] int limit = 30)
{
where.Remove("showID");
where.Remove("sortBy");
where.Remove("limit");
where.Remove("afterID");
@ -262,7 +255,6 @@ namespace Kyoo.Api
[FromQuery] Dictionary<string, string> where,
[FromQuery] int limit = 30)
{
where.Remove("slug");
where.Remove("sortBy");
where.Remove("limit");
where.Remove("afterID");
@ -323,7 +315,6 @@ namespace Kyoo.Api
[FromQuery] Dictionary<string, string> where,
[FromQuery] int limit = 30)
{
where.Remove("showID");
where.Remove("sortBy");
where.Remove("limit");
where.Remove("afterID");
@ -356,7 +347,6 @@ namespace Kyoo.Api
[FromQuery] Dictionary<string, string> where,
[FromQuery] int limit = 30)
{
where.Remove("slug");
where.Remove("sortBy");
where.Remove("limit");
where.Remove("afterID");
@ -389,7 +379,6 @@ namespace Kyoo.Api
[FromQuery] Dictionary<string, string> where,
[FromQuery] int limit = 30)
{
where.Remove("showID");
where.Remove("sortBy");
where.Remove("limit");
where.Remove("afterID");
@ -422,7 +411,6 @@ namespace Kyoo.Api
[FromQuery] Dictionary<string, string> where,
[FromQuery] int limit = 30)
{
where.Remove("slug");
where.Remove("sortBy");
where.Remove("limit");
where.Remove("afterID");