Implement template export/import endpoints and enhance grid generation logic
Added new endpoints for exporting and importing grid configurations in TemplateEndpoints, allowing for better management of template data. Enhanced the GenerateGridCommandHandler to support seasonal layers in grid generation, improving scheduling accuracy during holiday periods. Updated related classes and records to accommodate these changes, ensuring a cohesive integration of new features. Improved documentation for clarity and maintainability.
This commit is contained in:
+100
@@ -0,0 +1,100 @@
|
||||
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.Transfer;
|
||||
|
||||
public sealed class ExportGridQueryHandler(IAppDbContext dbContext)
|
||||
: IQueryHandler<ExportGridQuery, Result<GridConfig>>
|
||||
{
|
||||
public async Task<Result<GridConfig>> Handle(
|
||||
ExportGridQuery query,
|
||||
CancellationToken cancellationToken
|
||||
)
|
||||
{
|
||||
var channel = await dbContext
|
||||
.Channels.AsNoTracking()
|
||||
.FirstOrDefaultAsync(c => c.Id == query.ChannelId, cancellationToken);
|
||||
if (channel is null)
|
||||
return Result.Failure<GridConfig>(ChannelErrors.NotFound);
|
||||
|
||||
var template = await dbContext
|
||||
.ScheduleTemplates.AsNoTracking()
|
||||
.Include(t => t.Layers)
|
||||
.ThenInclude(l => l.Slots)
|
||||
.AsSplitQuery()
|
||||
.FirstOrDefaultAsync(t => t.ChannelId == query.ChannelId, cancellationToken);
|
||||
if (template is null)
|
||||
return Result.Failure<GridConfig>(ChannelErrors.TemplateNotFound);
|
||||
|
||||
var groups = await dbContext
|
||||
.Groups.AsNoTracking()
|
||||
.ToDictionaryAsync(g => g.Id, g => g.Name, cancellationToken);
|
||||
var junctions = await dbContext
|
||||
.JunctionTemplates.AsNoTracking()
|
||||
.ToDictionaryAsync(j => j.Id, j => j.Name, cancellationToken);
|
||||
|
||||
var layers = template
|
||||
.Layers.OrderBy(l => l.Priority)
|
||||
.Select(layer => new GridConfigLayer(
|
||||
layer.Name,
|
||||
layer.Priority,
|
||||
[
|
||||
.. layer
|
||||
.Slots.OrderBy(s => s.Weekday ?? -1)
|
||||
.ThenBy(s => s.TargetStart)
|
||||
.Select(slot => ToConfig(slot, groups, junctions)),
|
||||
],
|
||||
layer.IsEnabled,
|
||||
layer.IsBackground,
|
||||
LayerApplicability.FromJson(layer.ApplicabilityJson)
|
||||
))
|
||||
.ToList();
|
||||
|
||||
return Result.Success(
|
||||
new GridConfig(
|
||||
layers,
|
||||
Channel: new GridConfigChannel(
|
||||
channel.Name,
|
||||
channel.DayStartTime,
|
||||
channel.UtcOffsetMinutes
|
||||
),
|
||||
Rules: PlanningRules.FromJson(template.RulesJson),
|
||||
FallbackGroup: Name(template.FallbackGroupId, groups),
|
||||
DefaultJunction: Name(template.DefaultJunctionId, junctions)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private static GridConfigSlot ToConfig(
|
||||
Slot slot,
|
||||
IReadOnlyDictionary<Guid, string> groups,
|
||||
IReadOnlyDictionary<Guid, string> junctions
|
||||
) =>
|
||||
new(
|
||||
slot.Title,
|
||||
slot.TargetStart,
|
||||
slot.TargetDurationMinutes,
|
||||
slot.Daypart,
|
||||
slot.SlotKind,
|
||||
slot.Weekday,
|
||||
Name(slot.GroupId, groups),
|
||||
SlotStrategy.FromJson(slot.StrategyJson),
|
||||
RepeatSource.FromJson(slot.RepeatSourceJson),
|
||||
slot.BlockMode,
|
||||
slot.BlockValue,
|
||||
slot.OverflowPolicy,
|
||||
slot.IsAnchor,
|
||||
slot.MaxDriftMinutes,
|
||||
slot.SnapToMinutes,
|
||||
Name(slot.JunctionBetweenId, junctions),
|
||||
Name(slot.JunctionAfterId, junctions)
|
||||
);
|
||||
|
||||
/// <summary>Имя по ссылке. Пропавшая ссылка выгружается пустой — файл важнее её сохранности.</summary>
|
||||
private static string? Name(Guid? id, IReadOnlyDictionary<Guid, string> names) =>
|
||||
id is { } value ? names.GetValueOrDefault(value) : null;
|
||||
}
|
||||
Reference in New Issue
Block a user