Update scheduling parameters and refactor channel endpoints: extend HorizonDays to 7 and RetentionDays to 90 in appsettings.json. Consolidate channel-related endpoint logic by removing obsolete files and enhancing the ShowEndpoints with audience and genre management capabilities. Improve error handling and streamline command handlers for channel operations.
build / backend (push) Successful in 7m40s
build / frontend (push) Failing after 39s
tests / backend-tests (push) Successful in 6m9s

This commit is contained in:
Leonid Pershin
2026-07-26 13:32:13 +03:00
parent c4ef954dea
commit 66040a8841
272 changed files with 27944 additions and 8699 deletions
@@ -0,0 +1,122 @@
using LiteCqrs;
using Microsoft.EntityFrameworkCore;
using TeleWave.Application.Common.Interfaces;
using TeleWave.Application.Common.Models;
using TeleWave.Domain.Programming;
namespace TeleWave.Application.Programming.Templates.Layers;
public sealed class CreateLayerCommandHandler(IAppDbContext dbContext)
: ICommandHandler<CreateLayerCommand, Result<Guid>>
{
public async Task<Result<Guid>> Handle(
CreateLayerCommand command,
CancellationToken cancellationToken
)
{
var template = await LayerLoader.ByTemplateAsync(
dbContext,
command.TemplateId,
cancellationToken
);
if (template is null)
return Result.Failure<Guid>(TemplateErrors.NotFound);
var layer = template.AddLayer(command.Name, command.Priority);
template.MarkChanged();
return Result.Success(layer.Id);
}
}
public sealed class UpdateLayerCommandHandler(IAppDbContext dbContext)
: ICommandHandler<UpdateLayerCommand, Result>
{
public async Task<Result> Handle(UpdateLayerCommand command, CancellationToken cancellationToken)
{
var template = await LayerLoader.ByLayerAsync(dbContext, command.LayerId, cancellationToken);
var layer = template?.FindLayer(command.LayerId);
if (template is null || layer is null)
return Result.Failure(TemplateErrors.LayerNotFound);
layer.Update(
command.Name,
command.Priority,
command.Applicability?.ToJson(),
command.IsEnabled
);
template.MarkChanged();
return Result.Success();
}
}
public sealed class DeleteLayerCommandHandler(IAppDbContext dbContext)
: ICommandHandler<DeleteLayerCommand, Result>
{
public async Task<Result> Handle(DeleteLayerCommand command, CancellationToken cancellationToken)
{
var template = await LayerLoader.ByLayerAsync(dbContext, command.LayerId, cancellationToken);
var layer = template?.FindLayer(command.LayerId);
if (template is null || layer is null)
return Result.Failure(TemplateErrors.LayerNotFound);
if (layer.IsBackground)
return Result.Failure(TemplateErrors.BackgroundLayerCannotBeDeleted);
template.RemoveLayer(command.LayerId);
template.MarkChanged();
return Result.Success();
}
}
public sealed class UpdateTemplateCommandHandler(IAppDbContext dbContext)
: ICommandHandler<UpdateTemplateCommand, Result>
{
public async Task<Result> Handle(
UpdateTemplateCommand command,
CancellationToken cancellationToken
)
{
var template = await dbContext.ScheduleTemplates.FirstOrDefaultAsync(
t => t.Id == command.TemplateId,
cancellationToken
);
if (template is null)
return Result.Failure(TemplateErrors.NotFound);
if (
command.FallbackGroupId is { } groupId
&& !await dbContext.Groups.AnyAsync(g => g.Id == groupId, cancellationToken)
)
return Result.Failure(TemplateErrors.GroupNotFound);
template.Rename(command.Name);
template.SetFallbackGroup(command.FallbackGroupId);
template.SetDefaultJunction(command.DefaultJunctionId);
template.MarkChanged();
return Result.Success();
}
}
/// <summary>Загрузка шаблона со слоями и слотами: любая правка слоя меняет ревизию всего шаблона.</summary>
internal static class LayerLoader
{
public static Task<ScheduleTemplate?> ByTemplateAsync(
IAppDbContext dbContext,
Guid templateId,
CancellationToken cancellationToken
) =>
dbContext
.ScheduleTemplates.Include(t => t.Layers)
.ThenInclude(l => l.Slots)
.FirstOrDefaultAsync(t => t.Id == templateId, cancellationToken);
public static Task<ScheduleTemplate?> ByLayerAsync(
IAppDbContext dbContext,
Guid layerId,
CancellationToken cancellationToken
) =>
dbContext
.ScheduleTemplates.Include(t => t.Layers)
.ThenInclude(l => l.Slots)
.FirstOrDefaultAsync(t => t.Layers.Any(l => l.Id == layerId), cancellationToken);
}