Files
TeleWave/backend/src/TeleWave.Application/Programming/Templates/CopyTemplate/CopyTemplateCommandHandler.cs
T
Leonid Pershin ba3721eb92
ci / build-backend (push) Successful in 1m39s
ci / build-frontend (push) Failing after 26s
ci / tests (push) Skipped
ci / sonar (push) Skipped
Implement BumperEndpoints and remove deprecated bumper-related functionality
Added new BumperEndpoints to the API for managing bumper templates and variants, enhancing the channel management capabilities. Removed outdated bumper-related commands and handlers from the application, streamlining the codebase and improving maintainability. Updated ChannelEndpoints to reflect these changes and ensure proper routing for the new endpoints.
2026-07-27 22:01:56 +03:00

119 lines
4.5 KiB
C#

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.CopyTemplate;
public sealed class CopyTemplateCommandHandler(IAppDbContext dbContext)
: ICommandHandler<CopyTemplateCommand, Result<CopyTemplateResultDto>>
{
public async Task<Result<CopyTemplateResultDto>> Handle(
CopyTemplateCommand command,
CancellationToken cancellationToken
)
{
var target = await dbContext.Channels.FirstOrDefaultAsync(
c => c.Id == command.TargetChannelId,
cancellationToken
);
if (target is null)
return Result.Failure<CopyTemplateResultDto>(ChannelErrors.NotFound);
var source = await dbContext
.ScheduleTemplates.AsNoTracking()
.Include(t => t.Layers)
.ThenInclude(l => l.Slots)
.AsSplitQuery()
.FirstOrDefaultAsync(t => t.ChannelId == command.SourceChannelId, cancellationToken);
if (source is null)
return Result.Failure<CopyTemplateResultDto>(ChannelErrors.TemplateNotFound);
// Прежняя сетка приёмника заменяется целиком: слить две сетки автоматически нельзя,
// а «добавить поверх» дало бы кашу из пересекающихся слотов.
var existing = await dbContext
.ScheduleTemplates.Where(t => t.ChannelId == target.Id)
.ToListAsync(cancellationToken);
dbContext.ScheduleTemplates.RemoveRange(existing);
var copyTemplate = ScheduleTemplate.Create(target.Id, source.Name);
copyTemplate.SetFallbackGroup(source.FallbackGroupId);
copyTemplate.SetRules(source.RulesJson);
// Стыки и заставки общие для всех каналов — копия ссылается на те же, без перевешивания.
copyTemplate.SetDefaultJunction(source.DefaultJunctionId);
var (layers, slots) = CopyGrid(source, copyTemplate);
dbContext.ScheduleTemplates.Add(copyTemplate);
target.SetTemplate(copyTemplate.Id);
return Result.Success(new CopyTemplateResultDto(layers, slots));
}
/// <summary>Переносит слои со слотами. Возвращает, сколько слоёв (кроме фонового) и слотов скопировано.</summary>
private static (int Layers, int Slots) CopyGrid(
ScheduleTemplate source,
ScheduleTemplate copyTemplate
)
{
var layers = 0;
var slots = 0;
foreach (var layer in source.Layers.OrderByDescending(l => l.Priority))
{
// Фоновый слой у нового шаблона уже есть — в него переносим слоты, а не заводим второй.
var copyLayer = layer.IsBackground
? copyTemplate.Background!
: copyTemplate.AddLayer(layer.Name, layer.Priority);
copyLayer.Update(layer.Name, layer.Priority, layer.ApplicabilityJson, layer.IsEnabled);
if (!layer.IsBackground)
layers++;
foreach (var slot in layer.Slots)
{
CopySlot(slot, copyLayer);
slots++;
}
}
return (layers, slots);
}
private static void CopySlot(Slot slot, GridLayer copyLayer)
{
var copySlot = copyLayer.AddSlot(
slot.Title,
slot.TargetStart,
slot.TargetDurationMinutes,
slot.Daypart,
slot.SlotKind,
slot.Weekday
);
copySlot.UpdateTiming(
slot.Weekday,
slot.TargetStart,
slot.TargetDurationMinutes,
slot.Daypart,
slot.IsAnchor,
slot.MaxDriftMinutes,
slot.SnapToMinutes
);
copySlot.UpdateContent(
new SlotContent(
slot.Title,
slot.SlotKind,
slot.GroupId,
slot.StrategyJson,
slot.RepeatSourceJson,
slot.BlockMode,
slot.BlockValue,
slot.OverflowPolicy,
slot.JunctionBetweenId,
slot.JunctionAfterId
)
);
}
}