Implement collection suggestions and bulk show addition features
Added new API endpoints for suggesting collections based on existing shows and for bulk adding shows to collections. Enhanced the backend with necessary logic and DTOs to support these features. Updated the frontend to include new components for displaying collection suggestions and managing bulk additions, improving the user experience for collection management. Localization updates were made to support these new features in both English and Russian.
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
using LiteCqrs;
|
||||
using TeleWave.Application.Common.Models;
|
||||
|
||||
namespace TeleWave.Application.Library.GetShowUsage;
|
||||
|
||||
/// <summary>
|
||||
/// Где шоу задействовано: группы, коллекции и каналы. Нужно до удаления — сейчас оно просто
|
||||
/// отбивается ошибкой «используется», не говоря где, и приходится обходить экраны вручную.
|
||||
/// </summary>
|
||||
public sealed record GetShowUsageQuery(Guid ShowId) : IQuery<Result<ShowUsageDto>>;
|
||||
|
||||
/// <param name="Groups">Группы, в состав которых шоу входит (в том числе по правилу).</param>
|
||||
/// <param name="Collections">Франшизы, частью которых оно является.</param>
|
||||
/// <param name="Channels">Каналы, в чьём расписании оно уже стоит.</param>
|
||||
public sealed record ShowUsageDto(
|
||||
IReadOnlyList<ShowUsageRefDto> Groups,
|
||||
IReadOnlyList<ShowUsageRefDto> Collections,
|
||||
IReadOnlyList<ShowUsageRefDto> Channels
|
||||
);
|
||||
|
||||
/// <param name="ViaRule">Шоу попало в группу правилом, а не явной позицией.</param>
|
||||
public sealed record ShowUsageRefDto(Guid Id, string Name, bool ViaRule = false);
|
||||
@@ -0,0 +1,90 @@
|
||||
using LiteCqrs;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using TeleWave.Application.Common.Interfaces;
|
||||
using TeleWave.Application.Common.Models;
|
||||
using TeleWave.Application.Programming.Groups;
|
||||
using TeleWave.Domain.Programming;
|
||||
|
||||
namespace TeleWave.Application.Library.GetShowUsage;
|
||||
|
||||
public sealed class GetShowUsageQueryHandler(
|
||||
IAppDbContext dbContext,
|
||||
DynamicGroupResolver dynamicResolver
|
||||
) : IQueryHandler<GetShowUsageQuery, Result<ShowUsageDto>>
|
||||
{
|
||||
public async Task<Result<ShowUsageDto>> Handle(
|
||||
GetShowUsageQuery query,
|
||||
CancellationToken cancellationToken
|
||||
)
|
||||
{
|
||||
if (!await dbContext.Shows.AnyAsync(s => s.Id == query.ShowId, cancellationToken))
|
||||
return Result.Failure<ShowUsageDto>(ShowErrors.NotFound);
|
||||
|
||||
var collections = await dbContext
|
||||
.Collections.AsNoTracking()
|
||||
.Where(c => c.Items.Any(i => i.ShowId == query.ShowId))
|
||||
.Select(c => new ShowUsageRefDto(c.Id, c.Name, false))
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
var channels = await dbContext
|
||||
.ScheduleEntries.AsNoTracking()
|
||||
.Where(e => e.ShowId == query.ShowId)
|
||||
.Select(e => e.ChannelId)
|
||||
.Distinct()
|
||||
.Join(
|
||||
dbContext.Channels.AsNoTracking(),
|
||||
id => id,
|
||||
channel => channel.Id,
|
||||
(_, channel) => new ShowUsageRefDto(channel.Id, channel.Name, false)
|
||||
)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
return Result.Success(
|
||||
new ShowUsageDto(
|
||||
await GroupsAsync(query.ShowId, collections, cancellationToken),
|
||||
collections,
|
||||
channels
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Группы считаем по вычисленному составу: у динамической шоу может входить правилом, без своей
|
||||
/// позиции, и такое участие для «можно ли удалять» ничем не отличается от явного. Коллекции
|
||||
/// учитываются заодно — шоу попадает в группу и через франшизу, целиком.
|
||||
/// </summary>
|
||||
private async Task<IReadOnlyList<ShowUsageRefDto>> GroupsAsync(
|
||||
Guid showId,
|
||||
IReadOnlyList<ShowUsageRefDto> collections,
|
||||
CancellationToken cancellationToken
|
||||
)
|
||||
{
|
||||
var groups = await dbContext
|
||||
.Groups.AsNoTracking()
|
||||
.Include(g => g.Items)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
var collectionIds = collections.Select(c => c.Id).ToHashSet();
|
||||
var result = new List<ShowUsageRefDto>();
|
||||
|
||||
foreach (var group in groups)
|
||||
{
|
||||
var composition = await dynamicResolver.ResolveAsync(group, cancellationToken);
|
||||
var element = composition.FirstOrDefault(e =>
|
||||
(e.Kind == GroupElementKind.Show && e.Id == showId)
|
||||
|| (e.Kind == GroupElementKind.Collection && collectionIds.Contains(e.Id))
|
||||
);
|
||||
if (element is null)
|
||||
continue;
|
||||
|
||||
result.Add(
|
||||
new ShowUsageRefDto(group.Id, group.Name, !element.Pinned && HasRule(group))
|
||||
);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static bool HasRule(Domain.Programming.Group group) =>
|
||||
group.Mode == GroupMode.Dynamic && group.FilterJson is not null;
|
||||
}
|
||||
Reference in New Issue
Block a user