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,6 @@
using LiteCqrs;
using TeleWave.Application.Common.Models;
namespace TeleWave.Application.Programming.Templates.GetTemplate;
public sealed record GetChannelTemplateQuery(Guid ChannelId) : IQuery<Result<ScheduleTemplateDto>>;
@@ -0,0 +1,100 @@
using LiteCqrs;
using Microsoft.EntityFrameworkCore;
using TeleWave.Application.Broadcast;
using TeleWave.Application.Common.Interfaces;
using TeleWave.Application.Common.Models;
namespace TeleWave.Application.Programming.Templates.GetTemplate;
public sealed class GetChannelTemplateQueryHandler(IAppDbContext dbContext)
: IQueryHandler<GetChannelTemplateQuery, Result<ScheduleTemplateDto>>
{
public async Task<Result<ScheduleTemplateDto>> Handle(
GetChannelTemplateQuery query,
CancellationToken cancellationToken
)
{
var channel = await dbContext
.Channels.AsNoTracking()
.FirstOrDefaultAsync(c => c.Id == query.ChannelId, cancellationToken);
if (channel is null)
return Result.Failure<ScheduleTemplateDto>(ChannelErrors.NotFound);
var template = await dbContext
.ScheduleTemplates.AsNoTracking()
.Include(t => t.Layers)
.ThenInclude(l => l.Slots)
.FirstOrDefaultAsync(t => t.ChannelId == channel.Id, cancellationToken);
if (template is null)
return Result.Failure<ScheduleTemplateDto>(ChannelErrors.TemplateNotFound);
// Имена групп резолвим одним запросом: инспектор слота показывает их сразу, без второго обхода.
var groupIds = template
.Layers.SelectMany(l => l.Slots)
.Select(s => s.GroupId)
.Where(id => id is not null)
.Select(id => id!.Value)
.Distinct()
.ToList();
var groupNames = await dbContext
.Groups.AsNoTracking()
.Where(g => groupIds.Contains(g.Id))
.ToDictionaryAsync(g => g.Id, g => g.Name, cancellationToken);
var layers = template
.Layers.OrderByDescending(l => l.Priority)
.Select(layer => new GridLayerDto(
layer.Id,
layer.Name,
layer.Priority,
layer.IsEnabled,
layer.IsBackground,
LayerApplicability.FromJson(layer.ApplicabilityJson),
layer
.Slots.OrderBy(s => s.Weekday ?? -1)
.ThenBy(s => s.TargetStart)
.Select(slot => new SlotDto(
slot.Id,
slot.LayerId,
slot.Weekday,
slot.TargetStart,
slot.TargetDurationMinutes,
slot.Title,
slot.Daypart,
slot.SlotKind,
slot.GroupId,
slot.GroupId is { } gid && groupNames.TryGetValue(gid, out var gname)
? gname
: null,
SlotStrategy.FromJson(slot.StrategyJson),
RepeatSource.FromJson(slot.RepeatSourceJson),
slot.BlockMode,
slot.BlockValue,
slot.OverflowPolicy,
slot.IsAnchor,
slot.MaxDriftMinutes,
slot.SnapToMinutes,
slot.JunctionBetweenId,
slot.JunctionAfterId
))
.ToList()
))
.ToList();
return Result.Success(
new ScheduleTemplateDto(
template.Id,
template.ChannelId,
template.Name,
template.FallbackGroupId,
template.DefaultJunctionId,
template.Revision,
template.AppliedRevision,
template.HasPendingChanges,
channel.UtcOffsetMinutes,
channel.DayStartTime,
layers
)
);
}
}