Introduced a new endpoint for bulk filling collection posters, allowing for automatic assignment of posters to collections without existing images. Updated the DeleteShowCommand to include an option for cutting shows from future airings, enhancing the deletion process. Refactored related components and API calls to support these features, ensuring a seamless user experience. Additionally, updated localization strings to reflect the new functionalities and adjusted tests to verify correct behavior.
246 lines
8.3 KiB
C#
246 lines
8.3 KiB
C#
using LiteCqrs;
|
|
using TeleWave.Api.Common;
|
|
using TeleWave.Application.Library.Collections;
|
|
using TeleWave.Application.Library.Collections.AddCollectionShow;
|
|
using TeleWave.Application.Library.Collections.AddShowsToCollection;
|
|
using TeleWave.Application.Library.Collections.CreateCollection;
|
|
using TeleWave.Application.Library.Collections.DeleteCollection;
|
|
using TeleWave.Application.Library.Collections.FillCollectionPosters;
|
|
using TeleWave.Application.Library.Collections.GetCollection;
|
|
using TeleWave.Application.Library.Collections.ListCollections;
|
|
using TeleWave.Application.Library.Collections.RemoveCollectionShow;
|
|
using TeleWave.Application.Library.Collections.ReorderCollection;
|
|
using TeleWave.Application.Library.Collections.SetCollectionPoster;
|
|
using TeleWave.Application.Library.Collections.Suggest;
|
|
using TeleWave.Application.Library.Collections.UpdateCollection;
|
|
using TeleWave.Infrastructure.Identity;
|
|
|
|
namespace TeleWave.Api.Endpoints;
|
|
|
|
public static class CollectionEndpoints
|
|
{
|
|
public static IEndpointRouteBuilder MapCollectionEndpoints(this IEndpointRouteBuilder app)
|
|
{
|
|
var admin = app.MapGroup("/api/admin/collections")
|
|
.WithTags("Admin.Collections")
|
|
.RequireAuthorization(policy => policy.RequireRole(RoleNames.Admin));
|
|
|
|
admin.MapGet("", ListCollections).Produces<IReadOnlyList<CollectionSummaryDto>>();
|
|
admin.MapGet("/{id:guid}", GetCollection).Produces<CollectionDto>();
|
|
admin
|
|
.MapPost("", CreateCollection)
|
|
.Produces<CreatedIdResponse>(StatusCodes.Status201Created);
|
|
admin.MapPut("/{id:guid}", UpdateCollection).Produces(StatusCodes.Status204NoContent);
|
|
admin.MapDelete("/{id:guid}", DeleteCollection).Produces(StatusCodes.Status204NoContent);
|
|
admin.MapPost("/{id:guid}/shows", AddShow).Produces(StatusCodes.Status204NoContent);
|
|
admin
|
|
.MapDelete("/{id:guid}/shows/{showId:guid}", RemoveShow)
|
|
.Produces(StatusCodes.Status204NoContent);
|
|
admin.MapPut("/{id:guid}/order", Reorder).Produces(StatusCodes.Status204NoContent);
|
|
admin.MapPut("/{id:guid}/poster-image", SetPoster).Produces(StatusCodes.Status204NoContent);
|
|
|
|
// Сборка франшиз: массовое добавление отмеченных шоу и предложения по библиотеке.
|
|
admin.MapPost("/bulk/shows", AddShows).Produces<AddShowsToCollectionResultDto>();
|
|
// Постеры по частям: без списка — всем коллекциям, у которых постера ещё нет.
|
|
admin.MapPost("/bulk/posters", FillPosters).Produces<int>();
|
|
admin
|
|
.MapGet("/suggestions", Suggestions)
|
|
.Produces<IReadOnlyList<CollectionSuggestionDto>>();
|
|
admin
|
|
.MapPost("/suggestions", CreateFromSuggestion)
|
|
.Produces<CreatedIdResponse>(StatusCodes.Status201Created);
|
|
|
|
return app;
|
|
}
|
|
|
|
private static async Task<IResult> FillPosters(
|
|
FillCollectionPostersBody? body,
|
|
ISender sender,
|
|
CancellationToken cancellationToken
|
|
)
|
|
{
|
|
var result = await sender.Send(
|
|
new FillCollectionPostersCommand(body?.CollectionIds),
|
|
cancellationToken
|
|
);
|
|
return result.ToHttpResult();
|
|
}
|
|
|
|
private static async Task<IResult> AddShows(
|
|
AddShowsToCollectionBody body,
|
|
ISender sender,
|
|
CancellationToken cancellationToken
|
|
)
|
|
{
|
|
var result = await sender.Send(
|
|
new AddShowsToCollectionCommand(
|
|
body.ShowIds,
|
|
body.CollectionId,
|
|
body.NewCollectionName
|
|
),
|
|
cancellationToken
|
|
);
|
|
return result.ToHttpResult();
|
|
}
|
|
|
|
private static async Task<IResult> Suggestions(
|
|
ISender sender,
|
|
CancellationToken cancellationToken
|
|
)
|
|
{
|
|
var result = await sender.Send(new SuggestCollectionsQuery(), cancellationToken);
|
|
return Results.Ok(result);
|
|
}
|
|
|
|
private static async Task<IResult> CreateFromSuggestion(
|
|
CreateCollectionFromSuggestionBody body,
|
|
ISender sender,
|
|
CancellationToken cancellationToken
|
|
)
|
|
{
|
|
var result = await sender.Send(
|
|
new CreateCollectionFromSuggestionCommand(body.Key),
|
|
cancellationToken
|
|
);
|
|
return result.IsSuccess
|
|
? Results.Created(
|
|
$"/api/admin/collections/{result.Value}",
|
|
new CreatedIdResponse(result.Value)
|
|
)
|
|
: result.ToHttpResult();
|
|
}
|
|
|
|
private static async Task<IResult> ListCollections(
|
|
ISender sender,
|
|
CancellationToken cancellationToken
|
|
)
|
|
{
|
|
var result = await sender.Send(new ListCollectionsQuery(), cancellationToken);
|
|
return Results.Ok(result);
|
|
}
|
|
|
|
private static async Task<IResult> GetCollection(
|
|
Guid id,
|
|
ISender sender,
|
|
CancellationToken cancellationToken
|
|
)
|
|
{
|
|
var result = await sender.Send(new GetCollectionQuery(id), cancellationToken);
|
|
return result.ToHttpResult();
|
|
}
|
|
|
|
private static async Task<IResult> CreateCollection(
|
|
CreateCollectionCommand command,
|
|
ISender sender,
|
|
CancellationToken cancellationToken
|
|
)
|
|
{
|
|
var result = await sender.Send(command, cancellationToken);
|
|
return result.IsSuccess
|
|
? Results.Created(
|
|
$"/api/admin/collections/{result.Value}",
|
|
new CreatedIdResponse(result.Value)
|
|
)
|
|
: result.ToHttpResult();
|
|
}
|
|
|
|
private static async Task<IResult> UpdateCollection(
|
|
Guid id,
|
|
UpdateCollectionBody body,
|
|
ISender sender,
|
|
CancellationToken cancellationToken
|
|
)
|
|
{
|
|
var result = await sender.Send(
|
|
new UpdateCollectionCommand(id, body.Name, body.Description),
|
|
cancellationToken
|
|
);
|
|
return result.ToHttpResult();
|
|
}
|
|
|
|
private static async Task<IResult> DeleteCollection(
|
|
Guid id,
|
|
ISender sender,
|
|
CancellationToken cancellationToken
|
|
)
|
|
{
|
|
var result = await sender.Send(new DeleteCollectionCommand(id), cancellationToken);
|
|
return result.ToHttpResult();
|
|
}
|
|
|
|
private static async Task<IResult> AddShow(
|
|
Guid id,
|
|
CollectionShowBody body,
|
|
ISender sender,
|
|
CancellationToken cancellationToken
|
|
)
|
|
{
|
|
var result = await sender.Send(
|
|
new AddCollectionShowCommand(id, body.ShowId),
|
|
cancellationToken
|
|
);
|
|
return result.ToHttpResult();
|
|
}
|
|
|
|
private static async Task<IResult> RemoveShow(
|
|
Guid id,
|
|
Guid showId,
|
|
ISender sender,
|
|
CancellationToken cancellationToken
|
|
)
|
|
{
|
|
var result = await sender.Send(
|
|
new RemoveCollectionShowCommand(id, showId),
|
|
cancellationToken
|
|
);
|
|
return result.ToHttpResult();
|
|
}
|
|
|
|
private static async Task<IResult> Reorder(
|
|
Guid id,
|
|
ReorderCollectionBody body,
|
|
ISender sender,
|
|
CancellationToken cancellationToken
|
|
)
|
|
{
|
|
var result = await sender.Send(
|
|
new ReorderCollectionCommand(id, body.ShowIdsInOrder),
|
|
cancellationToken
|
|
);
|
|
return result.ToHttpResult();
|
|
}
|
|
|
|
private static async Task<IResult> SetPoster(
|
|
Guid id,
|
|
CollectionPosterBody body,
|
|
ISender sender,
|
|
CancellationToken cancellationToken
|
|
)
|
|
{
|
|
var result = await sender.Send(
|
|
new SetCollectionPosterCommand(id, body.ImageId),
|
|
cancellationToken
|
|
);
|
|
return result.ToHttpResult();
|
|
}
|
|
}
|
|
|
|
public sealed record UpdateCollectionBody(string Name, string? Description);
|
|
|
|
public sealed record CollectionShowBody(Guid ShowId);
|
|
|
|
public sealed record ReorderCollectionBody(IReadOnlyList<Guid> ShowIdsInOrder);
|
|
|
|
public sealed record CollectionPosterBody(Guid? ImageId);
|
|
|
|
/// <summary>Куда складывать: существующая коллекция либо новая по имени.</summary>
|
|
public sealed record AddShowsToCollectionBody(
|
|
IReadOnlyList<Guid> ShowIds,
|
|
Guid? CollectionId = null,
|
|
string? NewCollectionName = null
|
|
);
|
|
|
|
public sealed record CreateCollectionFromSuggestionBody(string Key);
|
|
|
|
public sealed record FillCollectionPostersBody(IReadOnlyList<Guid>? CollectionIds);
|