Add CreateTemplate endpoint and related functionality for channels without grids
build / backend (push) Successful in 3m23s
build / frontend (push) Successful in 34s
tests / backend-tests (push) Successful in 1m38s

Implement a new API endpoint to create a template for channels lacking a grid, enhancing the template management capabilities. Update frontend components to support the creation of templates directly from the channel detail view, including user feedback and translations for improved clarity. Add integration tests to ensure the new functionality works as expected.
This commit is contained in:
Leonid Pershin
2026-07-26 20:10:47 +03:00
parent 69c236d8cc
commit 9c865e1faa
7 changed files with 153 additions and 8 deletions
@@ -6,6 +6,7 @@ using TeleWave.Application.Programming.Planning.Preview;
using TeleWave.Application.Programming.Templates;
using TeleWave.Application.Programming.Templates.CopyTemplate;
using TeleWave.Application.Programming.Templates.CreateSlot;
using TeleWave.Application.Programming.Templates.CreateTemplate;
using TeleWave.Application.Programming.Templates.DeleteSlot;
using TeleWave.Application.Programming.Templates.GetTemplate;
using TeleWave.Application.Programming.Templates.Layers;
@@ -30,6 +31,10 @@ public static class TemplateEndpoints
admin
.MapGet("/channels/{channelId:guid}/template", GetTemplate)
.Produces<ScheduleTemplateDto>();
// Завести сетку каналу, у которого её нет (напр. пережившему снос старой ротации).
admin
.MapPost("/channels/{channelId:guid}/template", CreateTemplate)
.Produces<CreatedIdResponse>(StatusCodes.Status201Created);
admin
.MapPut("/templates/{templateId:guid}", UpdateTemplate)
.Produces(StatusCodes.Status204NoContent);
@@ -81,6 +86,24 @@ public static class TemplateEndpoints
return result.ToHttpResult();
}
private static async Task<IResult> CreateTemplate(
Guid channelId,
ISender sender,
CancellationToken cancellationToken
)
{
var result = await sender.Send(
new CreateChannelTemplateCommand(channelId),
cancellationToken
);
return result.IsSuccess
? Results.Created(
$"/api/admin/channels/{channelId}/template",
new CreatedIdResponse(result.Value)
)
: result.ToHttpResult();
}
private static async Task<IResult> ApplyTemplate(
Guid channelId,
ISender sender,
@@ -0,0 +1,11 @@
using LiteCqrs;
using TeleWave.Application.Common.Models;
namespace TeleWave.Application.Programming.Templates.CreateTemplate;
/// <summary>
/// Заводит каналу сетку, если её нет. Новые каналы получают шаблон при создании, но каналы,
/// пережившие снос старой ротации, остались без него — и чинить это пересозданием канала было бы
/// перебором.
/// </summary>
public sealed record CreateChannelTemplateCommand(Guid ChannelId) : ICommand<Result<Guid>>;
@@ -0,0 +1,43 @@
using LiteCqrs;
using Microsoft.EntityFrameworkCore;
using TeleWave.Application.Broadcast;
using TeleWave.Application.Common.Interfaces;
using TeleWave.Application.Common.Models;
using TeleWave.Domain.Programming;
namespace TeleWave.Application.Programming.Templates.CreateTemplate;
public sealed class CreateChannelTemplateCommandHandler(IAppDbContext dbContext)
: ICommandHandler<CreateChannelTemplateCommand, Result<Guid>>
{
public async Task<Result<Guid>> Handle(
CreateChannelTemplateCommand command,
CancellationToken cancellationToken
)
{
var channel = await dbContext.Channels.FirstOrDefaultAsync(
c => c.Id == command.ChannelId,
cancellationToken
);
if (channel is null)
return Result.Failure<Guid>(ChannelErrors.NotFound);
// Шаблон мог остаться от прошлой жизни канала, потеряв ссылку на себя, — тогда просто
// возвращаем его, а не заводим второй: одна сетка на канал.
var existing = await dbContext
.ScheduleTemplates.FirstOrDefaultAsync(
t => t.ChannelId == channel.Id,
cancellationToken
);
if (existing is not null)
{
channel.SetTemplate(existing.Id);
return Result.Success(existing.Id);
}
var template = ScheduleTemplate.Create(channel.Id, channel.Name);
dbContext.ScheduleTemplates.Add(template);
channel.SetTemplate(template.Id);
return Result.Success(template.Id);
}
}