Add bumper variant management: implement API endpoints for adding, updating, and removing bumper text variants, enhance data models to support variant details, and update scheduling logic to utilize variants. Refactor related components for improved bumper template handling and ensure proper error management for variant operations.

This commit is contained in:
Leonid Pershin
2026-07-25 13:24:11 +03:00
parent f640af1fc4
commit a65bcf4258
34 changed files with 2009 additions and 170 deletions
@@ -21,23 +21,23 @@ public class SchedulePlannerTests
items.ToDictionary(x => x.Id, x => TimeSpan.FromMinutes(x.Minutes));
private static readonly Guid DefaultTemplate = Guid.NewGuid();
private static readonly Guid DefaultVariant = Guid.NewGuid();
/// <summary>Конфиг заставок с одним дефолтным блоком (8с), если явно не заданы блоки.</summary>
/// <summary>Конфиг заставок с одним дефолтным подблоком (8с) заданного триггера, если варианты не заданы.</summary>
private static PlannerBumperConfig Bumper(
bool enabled,
bool onlyBetweenDifferentShows,
BumperTrigger trigger,
TimeSpan minInterval,
BumperSelection selection = BumperSelection.Rotation,
params PlannerBumperTemplate[] templates
params PlannerBumperVariant[] variants
) =>
new(
enabled,
onlyBetweenDifferentShows,
minInterval,
selection,
templates.Length == 0
? [new PlannerBumperTemplate(DefaultTemplate, TimeSpan.FromSeconds(8))]
: templates
variants.Length == 0
? [new PlannerBumperVariant(DefaultVariant, DefaultTemplate, TimeSpan.FromSeconds(8), trigger)]
: variants
);
[Fact]
@@ -232,7 +232,7 @@ public class SchedulePlannerTests
var input = BaseInput([a, b], durations, Start.AddMinutes(50)) with
{
Bumpers = Bumper(true, onlyBetweenDifferentShows: true, TimeSpan.Zero),
Bumpers = Bumper(true, BumperTrigger.OnShowChange, TimeSpan.Zero),
};
// Чередуем выбор: roll 0 → a, roll 1 → b (веса 1/1, total 2).
@@ -267,7 +267,7 @@ public class SchedulePlannerTests
horizonEnd: Start.AddMinutes(50)
) with
{
Bumpers = Bumper(true, onlyBetweenDifferentShows: true, TimeSpan.Zero),
Bumpers = Bumper(true, BumperTrigger.OnShowChange, TimeSpan.Zero),
};
var result = SchedulePlanner.Plan(input, new FixedRandom(0));
@@ -287,7 +287,7 @@ public class SchedulePlannerTests
horizonEnd: Start.AddMinutes(50)
) with
{
Bumpers = Bumper(true, onlyBetweenDifferentShows: false, TimeSpan.Zero),
Bumpers = Bumper(true, BumperTrigger.Both, TimeSpan.Zero),
};
var result = SchedulePlanner.Plan(input, new FixedRandom(0));
@@ -305,7 +305,7 @@ public class SchedulePlannerTests
// Два перехода в горизонте (~на 20-й и ~40-й минуте), но интервал 30 мин пропускает второй.
var input = BaseInput([a, b], durations, Start.AddMinutes(50)) with
{
Bumpers = Bumper(true, onlyBetweenDifferentShows: true, TimeSpan.FromMinutes(30)),
Bumpers = Bumper(true, BumperTrigger.OnShowChange, TimeSpan.FromMinutes(30)),
};
var result = SchedulePlanner.Plan(input, new FixedRandom(0, 1));
@@ -326,11 +326,11 @@ public class SchedulePlannerTests
{
Bumpers = Bumper(
true,
onlyBetweenDifferentShows: true,
BumperTrigger.Both,
TimeSpan.Zero,
BumperSelection.Rotation,
new PlannerBumperTemplate(t0, TimeSpan.FromSeconds(8)),
new PlannerBumperTemplate(t1, TimeSpan.FromSeconds(4))
new PlannerBumperVariant(Guid.NewGuid(), t0, TimeSpan.FromSeconds(8), BumperTrigger.Both),
new PlannerBumperVariant(Guid.NewGuid(), t1, TimeSpan.FromSeconds(4), BumperTrigger.Both)
),
};
@@ -338,7 +338,7 @@ public class SchedulePlannerTests
var bumpers = result.Entries.Where(e => e.Kind == ScheduleEntryKind.Bumper).ToList();
Assert.True(bumpers.Count >= 2);
// Ротация: первый блок → t0 (8с), второй → t1 (4с). Все — плейсхолдеры по паре шоу.
// Ротация: первый подблок → t0 (8с), второй → t1 (4с). Все — плейсхолдеры по паре шоу.
Assert.Equal(t0, bumpers[0].BumperTemplateId);
Assert.Equal(TimeSpan.FromSeconds(8), bumpers[0].EndsAtUtc - bumpers[0].StartsAtUtc);
Assert.Equal(t1, bumpers[1].BumperTemplateId);
@@ -360,11 +360,11 @@ public class SchedulePlannerTests
{
Bumpers = Bumper(
true,
onlyBetweenDifferentShows: true,
BumperTrigger.Both,
TimeSpan.Zero,
BumperSelection.AlwaysFirst,
new PlannerBumperTemplate(t0, TimeSpan.FromSeconds(8)),
new PlannerBumperTemplate(t1, TimeSpan.FromSeconds(4))
new PlannerBumperVariant(Guid.NewGuid(), t0, TimeSpan.FromSeconds(8), BumperTrigger.Both),
new PlannerBumperVariant(Guid.NewGuid(), t1, TimeSpan.FromSeconds(4), BumperTrigger.Both)
),
};
@@ -387,10 +387,9 @@ public class SchedulePlannerTests
{
Bumpers = new PlannerBumperConfig(
true,
OnlyBetweenDifferentShows: true,
MinInterval: TimeSpan.Zero,
Selection: BumperSelection.Rotation,
Templates: []
Variants: []
),
};
@@ -408,7 +407,7 @@ public class SchedulePlannerTests
var input = BaseInput([a, b], durations, Start.AddMinutes(50)) with
{
Bumpers = Bumper(false, onlyBetweenDifferentShows: true, TimeSpan.Zero),
Bumpers = Bumper(false, BumperTrigger.OnShowChange, TimeSpan.Zero),
};
var result = SchedulePlanner.Plan(input, new FixedRandom(0, 1));