using System.Threading.Channels; using ErsatzTV.Application.Playouts; using ErsatzTV.Application.Search; using ErsatzTV.Core; using ErsatzTV.Core.Domain; using ErsatzTV.Core.Interfaces.Repositories; using ErsatzTV.Core.Scheduling; using ErsatzTV.Infrastructure.Data; using ErsatzTV.Infrastructure.Extensions; using Microsoft.EntityFrameworkCore; namespace ErsatzTV.Application.MediaCollections; public class RemoveItemsFromCollectionHandler : IRequestHandler> { private readonly ChannelWriter _channel; private readonly IDbContextFactory _dbContextFactory; private readonly IMediaCollectionRepository _mediaCollectionRepository; private readonly ChannelWriter _searchChannel; public RemoveItemsFromCollectionHandler( IDbContextFactory dbContextFactory, IMediaCollectionRepository mediaCollectionRepository, ChannelWriter channel, ChannelWriter searchChannel) { _dbContextFactory = dbContextFactory; _mediaCollectionRepository = mediaCollectionRepository; _channel = channel; _searchChannel = searchChannel; } public async Task> Handle( RemoveItemsFromCollection request, CancellationToken cancellationToken) { await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken); Validation validation = await Validate(dbContext, request, cancellationToken); return await validation.Apply(c => ApplyRemoveItemsRequest(dbContext, request, c, cancellationToken)); } private async Task ApplyRemoveItemsRequest( TvContext dbContext, RemoveItemsFromCollection request, Collection collection, CancellationToken cancellationToken) { var itemsToRemove = collection.MediaItems .Filter(m => request.MediaItemIds.Contains(m.Id)) .ToList(); itemsToRemove.ForEach(m => collection.MediaItems.Remove(m)); if (itemsToRemove.Count != 0 && await dbContext.SaveChangesAsync(cancellationToken) > 0) { await _searchChannel.WriteAsync( new ReindexMediaItems(itemsToRemove.Select(mi => mi.Id).ToArray()), cancellationToken); // refresh all playouts that use this collection foreach (int playoutId in await _mediaCollectionRepository.PlayoutIdsUsingCollection(collection.Id)) { await _channel.WriteAsync(new BuildPlayout(playoutId, PlayoutBuildMode.Refresh), cancellationToken); } } return Unit.Default; } private static Task> Validate( TvContext dbContext, RemoveItemsFromCollection request, CancellationToken cancellationToken) => CollectionMustExist(dbContext, request, cancellationToken); private static Task> CollectionMustExist( TvContext dbContext, RemoveItemsFromCollection request, CancellationToken cancellationToken) => dbContext.Collections .Include(c => c.MediaItems) .SelectOneAsync(c => c.Id, c => c.Id == request.MediaCollectionId, cancellationToken) .Map(o => o.ToValidation("Collection does not exist.")); }