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.
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
namespace TeleWave.Domain.Programming;
|
||||
|
||||
/// <summary>
|
||||
/// Шаблон сетки канала: слои со слотами плюс аварийные настройки. Один активный шаблон на канал —
|
||||
/// сезонность выражается слоями внутри него, а не вторым шаблоном, иначе получились бы два механизма
|
||||
/// для одного и того же. На другой канал переносится глубокой копией.
|
||||
///
|
||||
/// <see cref="Revision"/> растёт при любой правке правил. Эфир при этом не меняется: правка помечает
|
||||
/// шаблон изменённым, а хвост пересобирается отдельной командой применения.
|
||||
/// </summary>
|
||||
public class ScheduleTemplate
|
||||
{
|
||||
private readonly List<GridLayer> _layers = new();
|
||||
|
||||
public Guid Id { get; private set; }
|
||||
public Guid ChannelId { get; private set; }
|
||||
public string Name { get; private set; } = string.Empty;
|
||||
|
||||
/// <summary>Аварийная группа, если пуст даже фоновый слой.</summary>
|
||||
public Guid? FallbackGroupId { get; private set; }
|
||||
|
||||
/// <summary>Стык по умолчанию — для слотов, у которых свой не задан.</summary>
|
||||
public Guid? DefaultJunctionId { get; private set; }
|
||||
|
||||
/// <summary>Номер правки правил; входит в кэш-ключи и историю.</summary>
|
||||
public int Revision { get; private set; }
|
||||
|
||||
/// <summary>Ревизия, по которой собрано текущее будущее расписание.</summary>
|
||||
public int AppliedRevision { get; private set; }
|
||||
|
||||
public DateTimeOffset CreatedAt { get; private set; }
|
||||
|
||||
public IReadOnlyList<GridLayer> Layers => _layers;
|
||||
|
||||
/// <summary>Есть ли правки, не применённые к эфиру.</summary>
|
||||
public bool HasPendingChanges => Revision != AppliedRevision;
|
||||
|
||||
private const string BackgroundLayerName = "Фон";
|
||||
|
||||
private ScheduleTemplate() { }
|
||||
|
||||
public static ScheduleTemplate Create(Guid channelId, string name)
|
||||
{
|
||||
var template = new ScheduleTemplate
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
ChannelId = channelId,
|
||||
Name = name.Trim(),
|
||||
Revision = 0,
|
||||
AppliedRevision = 0,
|
||||
CreatedAt = DateTimeOffset.UtcNow,
|
||||
};
|
||||
// Фоновый слой заводится сразу: без него первая же дыра в сетке осталась бы нечем закрыть.
|
||||
template._layers.Add(
|
||||
GridLayer.Create(template.Id, BackgroundLayerName, GridLayer.BackgroundPriority, isBackground: true)
|
||||
);
|
||||
return template;
|
||||
}
|
||||
|
||||
public void Rename(string name) => Name = name.Trim();
|
||||
|
||||
public void SetFallbackGroup(Guid? groupId) => FallbackGroupId = groupId;
|
||||
|
||||
public void SetDefaultJunction(Guid? junctionId) => DefaultJunctionId = junctionId;
|
||||
|
||||
/// <summary>Отметить, что правила изменились — эфир пойдёт по старым до применения.</summary>
|
||||
public void MarkChanged() => Revision++;
|
||||
|
||||
/// <summary>Отметить, что хвост пересобран по текущей ревизии.</summary>
|
||||
public void MarkApplied() => AppliedRevision = Revision;
|
||||
|
||||
public GridLayer? FindLayer(Guid layerId) => _layers.FirstOrDefault(l => l.Id == layerId);
|
||||
|
||||
public GridLayer? Background => _layers.FirstOrDefault(l => l.IsBackground);
|
||||
|
||||
public GridLayer AddLayer(string name, int priority)
|
||||
{
|
||||
var layer = GridLayer.Create(Id, name, priority);
|
||||
_layers.Add(layer);
|
||||
return layer;
|
||||
}
|
||||
|
||||
/// <summary>Удаляет слой. Фоновый удалить нельзя — вернёт false.</summary>
|
||||
public bool RemoveLayer(Guid layerId)
|
||||
{
|
||||
var layer = _layers.FirstOrDefault(l => l.Id == layerId);
|
||||
if (layer is null || layer.IsBackground)
|
||||
return false;
|
||||
_layers.Remove(layer);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>Слой, содержащий слот, или null.</summary>
|
||||
public GridLayer? FindLayerOfSlot(Guid slotId) =>
|
||||
_layers.FirstOrDefault(l => l.FindSlot(slotId) is not null);
|
||||
}
|
||||
Reference in New Issue
Block a user