Add PUT /collections/id/movie/id route to link movies/shows to colletions

This commit is contained in:
Zoe Roux 2023-11-01 16:34:40 +01:00
parent b2f4933a5f
commit 88eb325079
4 changed files with 86 additions and 17 deletions

View File

@ -42,6 +42,7 @@ namespace Kyoo.Abstractions
where T : IBaseRepository
{
return builder.RegisterType<T>()
.AsSelf()
.As<IBaseRepository>()
.As(Utility.GetGenericDefinition(typeof(T), typeof(IRepository<>))!)
.InstancePerLifetimeScope();
@ -62,7 +63,7 @@ namespace Kyoo.Abstractions
where T : notnull
where T2 : IBaseRepository, T
{
return builder.RegisterRepository<T2>().As<T>();
return builder.RegisterRepository<T2>().AsSelf().As<T>();
}
}
}

View File

@ -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;
@ -81,6 +82,18 @@ namespace Kyoo.Core.Controllers
throw new ArgumentException("The collection's name must be set and not empty");
}
public async Task AddMovie(int id, int movieId)
{
_database.AddLinks<Collection, Movie>(id, movieId);
await _database.SaveChangesAsync();
}
public async Task AddShow(int id, int showId)
{
_database.AddLinks<Collection, Show>(id, showId);
await _database.SaveChangesAsync();
}
/// <inheritdoc />
public override async Task Delete(Collection obj)
{

View File

@ -24,6 +24,7 @@ using Kyoo.Abstractions.Models;
using Kyoo.Abstractions.Models.Attributes;
using Kyoo.Abstractions.Models.Permissions;
using Kyoo.Abstractions.Models.Utils;
using Kyoo.Core.Controllers;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using static Kyoo.Abstractions.Models.Utils.Constants;
@ -40,23 +41,78 @@ namespace Kyoo.Core.Api
[ApiDefinition("Collections", Group = ResourcesGroup)]
public class CollectionApi : CrudThumbsApi<Collection>
{
/// <summary>
/// The library manager used to modify or retrieve information about the data store.
/// </summary>
private readonly ILibraryManager _libraryManager;
private readonly CollectionRepository _collections;
/// <summary>
/// Create a new <see cref="CollectionApi"/>.
/// </summary>
/// <param name="libraryManager">
/// The library manager used to modify or retrieve information about the data store.
/// </param>
/// <param name="thumbs">The thumbnail manager used to retrieve images paths.</param>
public CollectionApi(ILibraryManager libraryManager,
CollectionRepository collections,
IThumbnailsManager thumbs)
: base(libraryManager.Collections, thumbs)
{
_libraryManager = libraryManager;
_collections = collections;
}
/// <summary>
/// Add a movie
/// </summary>
/// <remarks>
/// Add a movie in the collection.
/// </remarks>
/// <param name="identifier">The ID or slug of the <see cref="Collection"/>.</param>
/// <param name="movie">The ID or slug of the <see cref="Movie"/> to add.</param>
/// <returns>Nothing if successful.</returns>
/// <response code="404">No collection or movie with the given ID could be found.</response>
/// <response code="409">The specified movie is already in this collection.</response>
[HttpPut("{identifier:id}/movies/{movie:id}")]
[HttpPut("{identifier:id}/movie/{movie:id}", Order = AlternativeRoute)]
[PartialPermission(Kind.Write)]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status409Conflict)]
public async Task<ActionResult> AddMovie(Identifier identifier, Identifier movie)
{
int collectionId = await identifier.Match(
async id => (await _libraryManager.Collections.Get(id)).Id,
async slug => (await _libraryManager.Collections.Get(slug)).Id
);
int movieId = await movie.Match(
async id => (await _libraryManager.Movies.Get(id)).Id,
async slug => (await _libraryManager.Movies.Get(slug)).Id
);
await _collections.AddMovie(collectionId, movieId);
return NoContent();
}
/// <summary>
/// Add a show
/// </summary>
/// <remarks>
/// Add a show in the collection.
/// </remarks>
/// <param name="identifier">The ID or slug of the <see cref="Collection"/>.</param>
/// <param name="show">The ID or slug of the <see cref="Show"/> to add.</param>
/// <returns>Nothing if successful.</returns>
/// <response code="404">No collection or show with the given ID could be found.</response>
/// <response code="409">The specified show is already in this collection.</response>
[HttpPut("{identifier:id}/shows/{show:id}")]
[HttpPut("{identifier:id}/show/{show:id}", Order = AlternativeRoute)]
[PartialPermission(Kind.Write)]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status409Conflict)]
public async Task<ActionResult> AddShow(Identifier identifier, Identifier show)
{
int collectionId = await identifier.Match(
async id => (await _libraryManager.Collections.Get(id)).Id,
async slug => (await _libraryManager.Collections.Get(slug)).Id
);
int showId = await show.Match(
async id => (await _libraryManager.Shows.Get(id)).Id,
async slug => (await _libraryManager.Shows.Get(slug)).Id
);
await _collections.AddShow(collectionId, showId);
return NoContent();
}
/// <summary>
@ -83,11 +139,11 @@ namespace Kyoo.Core.Api
[FromQuery] Sort<Show> sortBy,
[FromQuery] Dictionary<string, string> where,
[FromQuery] Pagination pagination,
[FromQuery] Include<Show> fields)
[FromQuery] Include<Show>? fields)
{
ICollection<Show> resources = await _libraryManager.Shows.GetAll(
ApiHelper.ParseWhere(where, identifier.IsContainedIn<Show, Collection>(x => x.Collections!)),
sortBy,
sortBy ?? new Sort<Show>.By(x => x.StartAir),
pagination,
fields
);

View File

@ -116,13 +116,12 @@ namespace Kyoo.Postgresql
/// <param name="second">The ID of the second resource.</param>
/// <typeparam name="T1">The first resource type of the relation. It is the owner of the second</typeparam>
/// <typeparam name="T2">The second resource type of the relation. It is the contained resource.</typeparam>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
public async Task AddLinks<T1, T2>(int first, int second)
public void AddLinks<T1, T2>(int first, int second)
where T1 : class, IResource
where T2 : class, IResource
{
await Set<Dictionary<string, object>>(LinkName<T1, T2>())
.AddAsync(new Dictionary<string, object>
Set<Dictionary<string, object>>(LinkName<T1, T2>())
.Add(new Dictionary<string, object>
{
[LinkNameFk<T1>()] = first,
[LinkNameFk<T2>()] = second