@@ -0,0 +1,105 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using ErsatzTV.Application.MediaCollections;
|
||||
using ErsatzTV.Controllers.Api.Requests;
|
||||
using ErsatzTV.Core;
|
||||
using ErsatzTV.Extensions;
|
||||
using ErsatzTV.Filters;
|
||||
using MediatR;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace ErsatzTV.Controllers.Api;
|
||||
|
||||
[ApiController]
|
||||
[ServiceFilter(typeof(ApiKeyAuthorizationFilter))]
|
||||
public class CollectionController(IMediator mediator) : ControllerBase
|
||||
{
|
||||
[HttpGet("/api/collections")]
|
||||
[Tags("Collections")]
|
||||
[EndpointSummary("Get all collections")]
|
||||
[EndpointGroupName("general")]
|
||||
public async Task<List<MediaCollectionViewModel>> GetAll(CancellationToken cancellationToken) =>
|
||||
await mediator.Send(new GetAllCollections(), cancellationToken);
|
||||
|
||||
[HttpGet("/api/collections/{id:int}", Name = "GetCollectionById")]
|
||||
[Tags("Collections")]
|
||||
[EndpointSummary("Get a collection by id")]
|
||||
[EndpointGroupName("general")]
|
||||
public async Task<IActionResult> GetById(int id, CancellationToken cancellationToken)
|
||||
{
|
||||
Option<MediaCollectionViewModel> result = await mediator.Send(new GetCollectionById(id), cancellationToken);
|
||||
return result.ToGetResult();
|
||||
}
|
||||
|
||||
[HttpPost("/api/collections")]
|
||||
[Tags("Collections")]
|
||||
[EndpointSummary("Create a collection")]
|
||||
[EndpointGroupName("general")]
|
||||
public async Task<IActionResult> Create(
|
||||
[Required] [FromBody] CreateCollectionRequest request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
Either<BaseError, MediaCollectionViewModel> result =
|
||||
await mediator.Send(request.ToCommand(), cancellationToken);
|
||||
return result.ToCreatedResult(vm => $"/api/collections/{vm.Id}", vm => vm);
|
||||
}
|
||||
|
||||
[HttpPut("/api/collections/{id:int}")]
|
||||
[Tags("Collections")]
|
||||
[EndpointSummary("Update a collection")]
|
||||
[EndpointGroupName("general")]
|
||||
public async Task<IActionResult> Update(
|
||||
int id,
|
||||
[Required] [FromBody] UpdateCollectionRequest request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
Either<BaseError, Unit> result = await mediator.Send(request.ToCommand(id), cancellationToken);
|
||||
return await result.Match(
|
||||
Left: error => Task.FromResult(error.ToErrorResult()),
|
||||
Right: async _ =>
|
||||
{
|
||||
Option<MediaCollectionViewModel> collection =
|
||||
await mediator.Send(new GetCollectionById(id), cancellationToken);
|
||||
return collection.Match(
|
||||
Some: vm => (IActionResult)new OkObjectResult(vm),
|
||||
None: () => new NotFoundResult());
|
||||
});
|
||||
}
|
||||
|
||||
[HttpDelete("/api/collections/{id:int}")]
|
||||
[Tags("Collections")]
|
||||
[EndpointSummary("Delete a collection")]
|
||||
[EndpointGroupName("general")]
|
||||
public async Task<IActionResult> Delete(int id, CancellationToken cancellationToken)
|
||||
{
|
||||
Either<BaseError, Unit> result = await mediator.Send(new DeleteCollection(id), cancellationToken);
|
||||
return result.ToDeletedResult();
|
||||
}
|
||||
|
||||
[HttpPost("/api/collections/{id:int}/items")]
|
||||
[Tags("Collections")]
|
||||
[EndpointSummary("Add items to a collection")]
|
||||
[EndpointGroupName("general")]
|
||||
public async Task<IActionResult> AddItems(
|
||||
int id,
|
||||
[Required] [FromBody] AddItemsToCollectionRequest request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
Either<BaseError, Unit> result = await mediator.Send(request.ToCommand(id), cancellationToken);
|
||||
return result.ToDeletedResult();
|
||||
}
|
||||
|
||||
[HttpDelete("/api/collections/{id:int}/items/{mediaItemId:int}")]
|
||||
[Tags("Collections")]
|
||||
[EndpointSummary("Remove an item from a collection")]
|
||||
[EndpointGroupName("general")]
|
||||
public async Task<IActionResult> RemoveItem(int id, int mediaItemId, CancellationToken cancellationToken)
|
||||
{
|
||||
Either<BaseError, Unit> result = await mediator.Send(
|
||||
new RemoveItemsFromCollection(id)
|
||||
{
|
||||
MediaItemIds = [mediaItemId]
|
||||
},
|
||||
cancellationToken);
|
||||
return result.ToDeletedResult();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using ErsatzTV.Application.MediaCollections;
|
||||
|
||||
namespace ErsatzTV.Controllers.Api.Requests;
|
||||
|
||||
public record AddItemsToCollectionRequest(
|
||||
List<int> MovieIds,
|
||||
List<int> ShowIds,
|
||||
List<int> SeasonIds,
|
||||
List<int> EpisodeIds,
|
||||
List<int> ArtistIds,
|
||||
List<int> MusicVideoIds,
|
||||
List<int> OtherVideoIds,
|
||||
List<int> SongIds,
|
||||
List<int> ImageIds,
|
||||
List<int> RemoteStreamIds)
|
||||
{
|
||||
public AddItemsToCollection ToCommand(int collectionId) =>
|
||||
new(
|
||||
collectionId,
|
||||
MovieIds ?? [],
|
||||
ShowIds ?? [],
|
||||
SeasonIds ?? [],
|
||||
EpisodeIds ?? [],
|
||||
ArtistIds ?? [],
|
||||
MusicVideoIds ?? [],
|
||||
OtherVideoIds ?? [],
|
||||
SongIds ?? [],
|
||||
ImageIds ?? [],
|
||||
RemoteStreamIds ?? []);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using ErsatzTV.Application.MediaCollections;
|
||||
|
||||
namespace ErsatzTV.Controllers.Api.Requests;
|
||||
|
||||
public record CreateCollectionRequest(string Name)
|
||||
{
|
||||
public CreateCollection ToCommand() => new(Name);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using ErsatzTV.Application.MediaCollections;
|
||||
|
||||
namespace ErsatzTV.Controllers.Api.Requests;
|
||||
|
||||
public record CreateSmartCollectionRequest(string Name, string Query)
|
||||
{
|
||||
public CreateSmartCollection ToCommand() => new(Query, Name);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using ErsatzTV.Application.MediaCollections;
|
||||
|
||||
namespace ErsatzTV.Controllers.Api.Requests;
|
||||
|
||||
public record UpdateCollectionRequest(string Name, bool? UseCustomPlaybackOrder)
|
||||
{
|
||||
public UpdateCollection ToCommand(int id) =>
|
||||
new(id, Name)
|
||||
{
|
||||
UseCustomPlaybackOrder = Optional(UseCustomPlaybackOrder)
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using ErsatzTV.Application.MediaCollections;
|
||||
|
||||
namespace ErsatzTV.Controllers.Api.Requests;
|
||||
|
||||
public record UpdateSmartCollectionRequest(string Name, string Query)
|
||||
{
|
||||
public UpdateSmartCollection ToCommand(int id) => new(id, Name, Query);
|
||||
}
|
||||
@@ -1,43 +1,80 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using ErsatzTV.Application.MediaCollections;
|
||||
using ErsatzTV.Controllers.Api.Requests;
|
||||
using ErsatzTV.Core;
|
||||
using ErsatzTV.Core.Api.SmartCollections;
|
||||
using ErsatzTV.Extensions;
|
||||
using ErsatzTV.Filters;
|
||||
using MediatR;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace ErsatzTV.Controllers.Api;
|
||||
|
||||
[ApiController]
|
||||
[EndpointGroupName("general")]
|
||||
[ServiceFilter(typeof(ApiKeyAuthorizationFilter))]
|
||||
public class SmartCollectionController(IMediator mediator) : ControllerBase
|
||||
{
|
||||
[HttpGet("/api/collections/smart", Name="GetSmartCollections")]
|
||||
public async Task<List<SmartCollectionResponseModel>> GetAll() =>
|
||||
await mediator.Send(new GetAllSmartCollectionsForApi());
|
||||
[HttpGet("/api/smart-collections")]
|
||||
[Tags("Smart Collections")]
|
||||
[EndpointSummary("Get all smart collections")]
|
||||
[EndpointGroupName("general")]
|
||||
public async Task<List<SmartCollectionResponseModel>> GetAll(CancellationToken cancellationToken) =>
|
||||
await mediator.Send(new GetAllSmartCollectionsForApi(), cancellationToken);
|
||||
|
||||
[HttpPost("/api/collections/smart/new", Name = "CreateSmartCollection")]
|
||||
public async Task<IActionResult> AddOne(
|
||||
[Required] [FromBody]
|
||||
CreateSmartCollection request)
|
||||
[HttpGet("/api/smart-collections/{id:int}", Name = "GetSmartCollectionById")]
|
||||
[Tags("Smart Collections")]
|
||||
[EndpointSummary("Get a smart collection by id")]
|
||||
[EndpointGroupName("general")]
|
||||
public async Task<IActionResult> GetById(int id, CancellationToken cancellationToken)
|
||||
{
|
||||
Either<BaseError, CreateSmartCollectionResult> result =
|
||||
await mediator.Send(request).MapT(r => new CreateSmartCollectionResult(r.Id));
|
||||
return result.Match<IActionResult>(Ok, error => Problem(error.ToString()));
|
||||
Option<SmartCollectionViewModel> result =
|
||||
await mediator.Send(new GetSmartCollectionById(id), cancellationToken);
|
||||
return result.ToGetResult();
|
||||
}
|
||||
|
||||
[HttpPut("/api/collections/smart/update", Name="UpdateSmartCollection")]
|
||||
public async Task<IActionResult> UpdateOne(
|
||||
[Required] [FromBody]
|
||||
UpdateSmartCollection request)
|
||||
[HttpPost("/api/smart-collections")]
|
||||
[Tags("Smart Collections")]
|
||||
[EndpointSummary("Create a smart collection")]
|
||||
[EndpointGroupName("general")]
|
||||
public async Task<IActionResult> Create(
|
||||
[Required] [FromBody] CreateSmartCollectionRequest request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
Either<BaseError, UpdateSmartCollectionResult> result = await mediator.Send(request);
|
||||
return result.Match<IActionResult>(Ok, error => Problem(error.ToString()));
|
||||
Either<BaseError, SmartCollectionViewModel> result =
|
||||
await mediator.Send(request.ToCommand(), cancellationToken);
|
||||
return result.ToCreatedResult(vm => $"/api/smart-collections/{vm.Id}", vm => vm);
|
||||
}
|
||||
|
||||
[HttpDelete("/api/collections/smart/delete/{id:int}", Name="DeleteSmartCollection")]
|
||||
public async Task<IActionResult> DeleteSmartCollection(int id)
|
||||
[HttpPut("/api/smart-collections/{id:int}")]
|
||||
[Tags("Smart Collections")]
|
||||
[EndpointSummary("Update a smart collection")]
|
||||
[EndpointGroupName("general")]
|
||||
public async Task<IActionResult> Update(
|
||||
int id,
|
||||
[Required] [FromBody] UpdateSmartCollectionRequest request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
Either<BaseError, Unit> result = await mediator.Send(new DeleteSmartCollection(id));
|
||||
return result.Match<IActionResult>(_ => Ok(), error => Problem(error.ToString()));
|
||||
Either<BaseError, UpdateSmartCollectionResult> result =
|
||||
await mediator.Send(request.ToCommand(id), cancellationToken);
|
||||
return await result.Match(
|
||||
Left: error => Task.FromResult(error.ToErrorResult()),
|
||||
Right: async _ =>
|
||||
{
|
||||
Option<SmartCollectionViewModel> smartCollection =
|
||||
await mediator.Send(new GetSmartCollectionById(id), cancellationToken);
|
||||
return smartCollection.Match(
|
||||
Some: vm => (IActionResult)new OkObjectResult(vm),
|
||||
None: () => new NotFoundResult());
|
||||
});
|
||||
}
|
||||
|
||||
[HttpDelete("/api/smart-collections/{id:int}")]
|
||||
[Tags("Smart Collections")]
|
||||
[EndpointSummary("Delete a smart collection")]
|
||||
[EndpointGroupName("general")]
|
||||
public async Task<IActionResult> Delete(int id, CancellationToken cancellationToken)
|
||||
{
|
||||
Either<BaseError, Unit> result = await mediator.Send(new DeleteSmartCollection(id), cancellationToken);
|
||||
return result.ToDeletedResult();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user