218 lines
7.9 KiB
C#
218 lines
7.9 KiB
C#
using LiteCqrs;
|
|
using TeleWave.Api.Common;
|
|
using TeleWave.Application.Broadcast;
|
|
using TeleWave.Application.Broadcast.CreateChannel;
|
|
using TeleWave.Application.Broadcast.GetChannel;
|
|
using TeleWave.Application.Broadcast.GetSchedule;
|
|
using TeleWave.Application.Broadcast.ListChannels;
|
|
using TeleWave.Application.Broadcast.RegenerateSchedule;
|
|
using TeleWave.Application.Broadcast.UpdateChannelSettings;
|
|
using TeleWave.Domain.Broadcast;
|
|
using TeleWave.Infrastructure.Identity;
|
|
|
|
namespace TeleWave.Api.Endpoints;
|
|
|
|
/// <summary>
|
|
/// Админ-эндпоинты канала. Реализация разнесена по partial-файлам под-ресурсов:
|
|
/// <c>ChannelEndpoints.Shows.cs</c> (шоу+реклама), <c>ChannelEndpoints.Bumpers.cs</c>
|
|
/// (блоки/подблоки/файлы/preview), <c>ChannelEndpoints.Overrides.cs</c> (override'ы). Здесь —
|
|
/// регистрация всех маршрутов и хендлеры уровня канала (создание/список/настройки/расписание).
|
|
/// </summary>
|
|
public static partial class ChannelEndpoints
|
|
{
|
|
public static IEndpointRouteBuilder MapChannelEndpoints(this IEndpointRouteBuilder app)
|
|
{
|
|
var admin = app.MapGroup("/api/admin/channels")
|
|
.WithTags("Admin.Channels")
|
|
.RequireAuthorization(policy => policy.RequireRole(RoleNames.Admin));
|
|
|
|
admin.MapPost("", CreateChannel).Produces<CreatedIdResponse>(StatusCodes.Status201Created);
|
|
admin.MapGet("", ListChannels).Produces<IReadOnlyList<ChannelSummaryDto>>();
|
|
admin.MapGet("/{id:guid}", GetChannel).Produces<ChannelDto>();
|
|
admin
|
|
.MapPut("/{id:guid}/settings", UpdateSettings)
|
|
.Produces(StatusCodes.Status204NoContent);
|
|
|
|
admin
|
|
.MapPost("/{id:guid}/shows", AddShow)
|
|
.Produces<CreatedIdResponse>(StatusCodes.Status201Created);
|
|
admin
|
|
.MapPut("/{id:guid}/shows/{channelShowId:guid}", UpdateShow)
|
|
.Produces(StatusCodes.Status204NoContent);
|
|
admin
|
|
.MapDelete("/{id:guid}/shows/{channelShowId:guid}", RemoveShow)
|
|
.Produces(StatusCodes.Status204NoContent);
|
|
|
|
admin
|
|
.MapPost("/{id:guid}/ads", AddAd)
|
|
.Produces<CreatedIdResponse>(StatusCodes.Status201Created);
|
|
admin
|
|
.MapDelete("/{id:guid}/ads/{channelAdId:guid}", RemoveAd)
|
|
.Produces(StatusCodes.Status204NoContent);
|
|
|
|
admin
|
|
.MapPost("/{id:guid}/bumper/templates", AddBumperTemplate)
|
|
.Produces<CreatedIdResponse>(StatusCodes.Status201Created);
|
|
admin
|
|
.MapPut("/{id:guid}/bumper/templates/{templateId:guid}", UpdateBumperTemplate)
|
|
.Produces(StatusCodes.Status204NoContent);
|
|
admin
|
|
.MapDelete("/{id:guid}/bumper/templates/{templateId:guid}", RemoveBumperTemplate)
|
|
.Produces(StatusCodes.Status204NoContent);
|
|
admin
|
|
.MapPut("/{id:guid}/bumper/templates/{templateId:guid}/audio", UploadTemplateAudio)
|
|
.Produces(StatusCodes.Status204NoContent);
|
|
admin
|
|
.MapDelete("/{id:guid}/bumper/templates/{templateId:guid}/audio", ClearTemplateAudio)
|
|
.Produces(StatusCodes.Status204NoContent);
|
|
admin
|
|
.MapPut(
|
|
"/{id:guid}/bumper/templates/{templateId:guid}/background",
|
|
SetTemplateBackground
|
|
)
|
|
.Produces(StatusCodes.Status204NoContent);
|
|
admin
|
|
.MapDelete(
|
|
"/{id:guid}/bumper/templates/{templateId:guid}/background",
|
|
ClearTemplateBackground
|
|
)
|
|
.Produces(StatusCodes.Status204NoContent);
|
|
|
|
admin
|
|
.MapPost("/{id:guid}/bumper/templates/{templateId:guid}/preview", RenderPreview)
|
|
.Produces(StatusCodes.Status204NoContent);
|
|
admin.MapGet(
|
|
"/{id:guid}/bumper/templates/{templateId:guid}/preview/{variantId:guid}/index.m3u8",
|
|
PreviewPlaylist
|
|
);
|
|
admin.MapGet(
|
|
"/{id:guid}/bumper/templates/{templateId:guid}/preview/{variantId:guid}/{file}",
|
|
PreviewSegment
|
|
);
|
|
|
|
admin
|
|
.MapPost("/{id:guid}/bumper/templates/{templateId:guid}/variants", AddBumperVariant)
|
|
.Produces<CreatedIdResponse>(StatusCodes.Status201Created);
|
|
admin
|
|
.MapPut(
|
|
"/{id:guid}/bumper/templates/{templateId:guid}/variants/{variantId:guid}",
|
|
UpdateBumperVariant
|
|
)
|
|
.Produces(StatusCodes.Status204NoContent);
|
|
admin
|
|
.MapDelete(
|
|
"/{id:guid}/bumper/templates/{templateId:guid}/variants/{variantId:guid}",
|
|
RemoveBumperVariant
|
|
)
|
|
.Produces(StatusCodes.Status204NoContent);
|
|
|
|
admin
|
|
.MapPost("/{id:guid}/overrides", CreateOverride)
|
|
.Produces<CreatedIdResponse>(StatusCodes.Status201Created);
|
|
admin
|
|
.MapDelete("/{id:guid}/overrides/{overrideId:guid}", DeleteOverride)
|
|
.Produces(StatusCodes.Status204NoContent);
|
|
|
|
admin.MapPost("/{id:guid}/regenerate", Regenerate).Produces(StatusCodes.Status204NoContent);
|
|
admin
|
|
.MapGet("/{id:guid}/schedule", GetSchedule)
|
|
.Produces<IReadOnlyList<ScheduleEntryDto>>();
|
|
|
|
return app;
|
|
}
|
|
|
|
private static async Task<IResult> CreateChannel(
|
|
CreateChannelCommand command,
|
|
ISender sender,
|
|
CancellationToken cancellationToken
|
|
)
|
|
{
|
|
var result = await sender.Send(command, cancellationToken);
|
|
return result.IsSuccess
|
|
? Results.Created(
|
|
$"/api/admin/channels/{result.Value}",
|
|
new CreatedIdResponse(result.Value)
|
|
)
|
|
: result.ToHttpResult();
|
|
}
|
|
|
|
private static async Task<IResult> ListChannels(
|
|
ISender sender,
|
|
CancellationToken cancellationToken
|
|
)
|
|
{
|
|
var result = await sender.Send(new ListChannelsQuery(), cancellationToken);
|
|
return Results.Ok(result);
|
|
}
|
|
|
|
private static async Task<IResult> GetChannel(
|
|
Guid id,
|
|
ISender sender,
|
|
CancellationToken cancellationToken
|
|
)
|
|
{
|
|
var result = await sender.Send(new GetChannelQuery(id), cancellationToken);
|
|
return result.ToHttpResult();
|
|
}
|
|
|
|
private static async Task<IResult> UpdateSettings(
|
|
Guid id,
|
|
UpdateChannelSettingsBody body,
|
|
ISender sender,
|
|
CancellationToken cancellationToken
|
|
)
|
|
{
|
|
var result = await sender.Send(
|
|
new UpdateChannelSettingsCommand(
|
|
id,
|
|
body.Name,
|
|
body.IsEnabled,
|
|
body.AdInsertion,
|
|
body.AdsPerBreak,
|
|
body.BumpersEnabled,
|
|
body.Bumper,
|
|
body.FillerAssetId
|
|
),
|
|
cancellationToken
|
|
);
|
|
return result.ToHttpResult();
|
|
}
|
|
|
|
private static async Task<IResult> Regenerate(
|
|
Guid id,
|
|
ISender sender,
|
|
CancellationToken cancellationToken
|
|
)
|
|
{
|
|
var result = await sender.Send(new RegenerateChannelScheduleCommand(id), cancellationToken);
|
|
return result.ToHttpResult();
|
|
}
|
|
|
|
private static async Task<IResult> GetSchedule(
|
|
Guid id,
|
|
DateTimeOffset? from,
|
|
DateTimeOffset? to,
|
|
ISender sender,
|
|
CancellationToken cancellationToken
|
|
)
|
|
{
|
|
var fromUtc = from ?? DateTimeOffset.UtcNow;
|
|
var toUtc = to ?? fromUtc.AddDays(1);
|
|
var result = await sender.Send(
|
|
new GetChannelScheduleQuery(id, fromUtc, toUtc),
|
|
cancellationToken
|
|
);
|
|
return result.ToHttpResult();
|
|
}
|
|
}
|
|
|
|
public sealed record UpdateChannelSettingsBody(
|
|
string Name,
|
|
bool IsEnabled,
|
|
AdInsertion AdInsertion,
|
|
int AdsPerBreak,
|
|
bool BumpersEnabled,
|
|
BumperSettingsInput Bumper,
|
|
Guid? FillerAssetId
|
|
);
|