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:
@@ -0,0 +1,8 @@
|
||||
using LiteCqrs;
|
||||
using TeleWave.Application.Common.Models;
|
||||
|
||||
namespace TeleWave.Application.Broadcast.Bumpers;
|
||||
|
||||
/// <summary>Добавить подблок (текст-вариант) в блок заставки.</summary>
|
||||
public sealed record AddBumperTextVariantCommand(Guid ChannelId, Guid TemplateId, string Name)
|
||||
: ICommand<Result<Guid>>;
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
using LiteCqrs;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using TeleWave.Application.Common.Interfaces;
|
||||
using TeleWave.Application.Common.Models;
|
||||
|
||||
namespace TeleWave.Application.Broadcast.Bumpers;
|
||||
|
||||
public sealed class AddBumperTextVariantCommandHandler(IAppDbContext dbContext)
|
||||
: ICommandHandler<AddBumperTextVariantCommand, Result<Guid>>
|
||||
{
|
||||
public async Task<Result<Guid>> Handle(
|
||||
AddBumperTextVariantCommand command,
|
||||
CancellationToken cancellationToken
|
||||
)
|
||||
{
|
||||
var channel = await dbContext.Channels
|
||||
.Include(c => c.BumperTemplates)
|
||||
.ThenInclude(t => t.Variants)
|
||||
.FirstOrDefaultAsync(c => c.Id == command.ChannelId, cancellationToken);
|
||||
if (channel is null)
|
||||
return Result.Failure<Guid>(ChannelErrors.NotFound);
|
||||
|
||||
var template = channel.FindBumperTemplate(command.TemplateId);
|
||||
if (template is null)
|
||||
return Result.Failure<Guid>(ChannelErrors.BumperTemplateNotFound);
|
||||
|
||||
var name = string.IsNullOrWhiteSpace(command.Name)
|
||||
? $"Текст {template.Variants.Count + 1}"
|
||||
: command.Name.Trim();
|
||||
var variant = template.AddVariant(name);
|
||||
return Result.Success(variant.Id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using LiteCqrs;
|
||||
using TeleWave.Application.Common.Models;
|
||||
|
||||
namespace TeleWave.Application.Broadcast.Bumpers;
|
||||
|
||||
/// <summary>Удалить подблок (кроме последнего) из блока заставки.</summary>
|
||||
public sealed record RemoveBumperTextVariantCommand(Guid ChannelId, Guid TemplateId, Guid VariantId)
|
||||
: ICommand<Result>;
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
using LiteCqrs;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using TeleWave.Application.Common.Interfaces;
|
||||
using TeleWave.Application.Common.Models;
|
||||
|
||||
namespace TeleWave.Application.Broadcast.Bumpers;
|
||||
|
||||
public sealed class RemoveBumperTextVariantCommandHandler(IAppDbContext dbContext)
|
||||
: ICommandHandler<RemoveBumperTextVariantCommand, Result>
|
||||
{
|
||||
public async Task<Result> Handle(
|
||||
RemoveBumperTextVariantCommand command,
|
||||
CancellationToken cancellationToken
|
||||
)
|
||||
{
|
||||
var channel = await dbContext.Channels
|
||||
.Include(c => c.BumperTemplates)
|
||||
.ThenInclude(t => t.Variants)
|
||||
.FirstOrDefaultAsync(c => c.Id == command.ChannelId, cancellationToken);
|
||||
if (channel is null)
|
||||
return Result.Failure(ChannelErrors.NotFound);
|
||||
|
||||
var template = channel.FindBumperTemplate(command.TemplateId);
|
||||
if (template is null)
|
||||
return Result.Failure(ChannelErrors.BumperTemplateNotFound);
|
||||
if (template.FindVariant(command.VariantId) is null)
|
||||
return Result.Failure(ChannelErrors.BumperTextVariantNotFound);
|
||||
|
||||
return template.RemoveVariant(command.VariantId)
|
||||
? Result.Success()
|
||||
: Result.Failure(ChannelErrors.CannotRemoveLastBumperTextVariant);
|
||||
}
|
||||
}
|
||||
+16
-5
@@ -30,7 +30,9 @@ public sealed class RenderBumperPreviewQueryHandler(
|
||||
{
|
||||
var channel = await dbContext.Channels.AsNoTracking()
|
||||
.Include(c => c.BumperTemplates)
|
||||
.ThenInclude(t => t.Variants)
|
||||
.Include(c => c.Shows)
|
||||
.AsSplitQuery()
|
||||
.FirstOrDefaultAsync(c => c.Id == query.ChannelId, cancellationToken);
|
||||
if (channel is null)
|
||||
return Result.Failure<Guid>(ChannelErrors.NotFound);
|
||||
@@ -39,7 +41,13 @@ public sealed class RenderBumperPreviewQueryHandler(
|
||||
if (template is null)
|
||||
return Result.Failure<Guid>(ChannelErrors.BumperTemplateNotFound);
|
||||
|
||||
// Превью показываем по первому подблоку (стиль/звук блока + его текст).
|
||||
var variant = template.Variants.OrderBy(v => v.Position).FirstOrDefault();
|
||||
if (variant is null)
|
||||
return Result.Failure<Guid>(ChannelErrors.BumperTemplateNotFound);
|
||||
|
||||
var (fromName, toName) = await SampleNamesAsync(channel, cancellationToken);
|
||||
var free = variant.Kind == BumperTextKind.Free;
|
||||
|
||||
// Фон блока — из общего реестра по id.
|
||||
string? backgroundPath = null;
|
||||
@@ -68,14 +76,17 @@ public sealed class RenderBumperPreviewQueryHandler(
|
||||
template.AccentColor,
|
||||
template.TextColor,
|
||||
channel.BumperFont == BumperFont.Serif ? _bumper.FontFileSerif : _bumper.FontFileSans,
|
||||
channel.BumperNowLabel,
|
||||
fromName,
|
||||
channel.BumperNextLabel,
|
||||
toName,
|
||||
free ? "" : variant.NowLabel,
|
||||
free ? "" : fromName,
|
||||
free ? "" : variant.NextLabel,
|
||||
free ? "" : toName,
|
||||
backgroundPath,
|
||||
storage.AudioPath(template.Id, template.AudioExtension),
|
||||
// Постер зависит от конкретного «следующего» шоу — в превью не подставляем.
|
||||
null
|
||||
null,
|
||||
free,
|
||||
variant.Line1,
|
||||
variant.Line2
|
||||
);
|
||||
|
||||
var previewId = BumperPreview.AssetId(template.Id);
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
using LiteCqrs;
|
||||
using TeleWave.Application.Common.Models;
|
||||
using TeleWave.Domain.Broadcast;
|
||||
|
||||
namespace TeleWave.Application.Broadcast.Bumpers;
|
||||
|
||||
/// <summary>Обновить подблок: имя, режим текста, текст и правило показа.</summary>
|
||||
public sealed record UpdateBumperTextVariantCommand(
|
||||
Guid ChannelId,
|
||||
Guid TemplateId,
|
||||
Guid VariantId,
|
||||
string Name,
|
||||
BumperTextKind Kind,
|
||||
string NowLabel,
|
||||
string NextLabel,
|
||||
string Line1,
|
||||
string Line2,
|
||||
BumperTrigger Trigger
|
||||
) : ICommand<Result>;
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
using LiteCqrs;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using TeleWave.Application.Common.Interfaces;
|
||||
using TeleWave.Application.Common.Models;
|
||||
|
||||
namespace TeleWave.Application.Broadcast.Bumpers;
|
||||
|
||||
public sealed class UpdateBumperTextVariantCommandHandler(IAppDbContext dbContext)
|
||||
: ICommandHandler<UpdateBumperTextVariantCommand, Result>
|
||||
{
|
||||
public async Task<Result> Handle(
|
||||
UpdateBumperTextVariantCommand command,
|
||||
CancellationToken cancellationToken
|
||||
)
|
||||
{
|
||||
var channel = await dbContext.Channels
|
||||
.Include(c => c.BumperTemplates)
|
||||
.ThenInclude(t => t.Variants)
|
||||
.FirstOrDefaultAsync(c => c.Id == command.ChannelId, cancellationToken);
|
||||
if (channel is null)
|
||||
return Result.Failure(ChannelErrors.NotFound);
|
||||
|
||||
var template = channel.FindBumperTemplate(command.TemplateId);
|
||||
if (template is null)
|
||||
return Result.Failure(ChannelErrors.BumperTemplateNotFound);
|
||||
|
||||
var variant = template.FindVariant(command.VariantId);
|
||||
if (variant is null)
|
||||
return Result.Failure(ChannelErrors.BumperTextVariantNotFound);
|
||||
|
||||
variant.Update(
|
||||
command.Name.Trim(),
|
||||
command.Kind,
|
||||
command.NowLabel,
|
||||
command.NextLabel,
|
||||
command.Line1,
|
||||
command.Line2,
|
||||
command.Trigger
|
||||
);
|
||||
return Result.Success();
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
using FluentValidation;
|
||||
|
||||
namespace TeleWave.Application.Broadcast.Bumpers;
|
||||
|
||||
public sealed class UpdateBumperTextVariantCommandValidator
|
||||
: AbstractValidator<UpdateBumperTextVariantCommand>
|
||||
{
|
||||
public UpdateBumperTextVariantCommandValidator()
|
||||
{
|
||||
RuleFor(x => x.Name).NotEmpty().MaximumLength(64);
|
||||
RuleFor(x => x.NowLabel).MaximumLength(64);
|
||||
RuleFor(x => x.NextLabel).MaximumLength(64);
|
||||
RuleFor(x => x.Line1).MaximumLength(120);
|
||||
RuleFor(x => x.Line2).MaximumLength(120);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user