using System.Threading.Channels; using ErsatzTV.Application.Playouts; using ErsatzTV.Core; using ErsatzTV.Core.Domain; using ErsatzTV.Core.Interfaces.Repositories; using ErsatzTV.Core.Interfaces.Search; using ErsatzTV.Core.Scheduling; using ErsatzTV.Infrastructure.Data; using ErsatzTV.Infrastructure.Extensions; using Microsoft.EntityFrameworkCore; namespace ErsatzTV.Application.MediaCollections; public class UpdateCollectionHandler : IRequestHandler> { private readonly ChannelWriter _channel; private readonly IDbContextFactory _dbContextFactory; private readonly IMediaCollectionRepository _mediaCollectionRepository; private readonly ISearchTargets _searchTargets; public UpdateCollectionHandler( IDbContextFactory dbContextFactory, IMediaCollectionRepository mediaCollectionRepository, ChannelWriter channel, ISearchTargets searchTargets) { _dbContextFactory = dbContextFactory; _mediaCollectionRepository = mediaCollectionRepository; _channel = channel; _searchTargets = searchTargets; } public async Task> Handle( UpdateCollection request, CancellationToken cancellationToken) { await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken); Validation validation = await Validate(dbContext, request, cancellationToken); return await validation.Apply(c => ApplyUpdateRequest(dbContext, c, request, cancellationToken)); } private async Task ApplyUpdateRequest( TvContext dbContext, Collection c, UpdateCollection request, CancellationToken cancellationToken) { c.Name = request.Name; foreach (bool useCustomPlaybackOrder in request.UseCustomPlaybackOrder) { c.UseCustomPlaybackOrder = useCustomPlaybackOrder; } if (await dbContext.SaveChangesAsync(cancellationToken) > 0 && request.UseCustomPlaybackOrder.IsSome) { // refresh all playouts that use this collection foreach (int playoutId in await _mediaCollectionRepository.PlayoutIdsUsingCollection( request.CollectionId)) { await _channel.WriteAsync(new BuildPlayout(playoutId, PlayoutBuildMode.Refresh), cancellationToken); } } _searchTargets.SearchTargetsChanged(); return Unit.Default; } private static async Task> Validate( TvContext dbContext, UpdateCollection request, CancellationToken cancellationToken) => (await CollectionMustExist(dbContext, request, cancellationToken), ValidateName(request)) .Apply((collectionToUpdate, _) => collectionToUpdate); private static Task> CollectionMustExist( TvContext dbContext, UpdateCollection updateCollection, CancellationToken cancellationToken) => dbContext.Collections .SelectOneAsync(c => c.Id, c => c.Id == updateCollection.CollectionId, cancellationToken) .Map(o => o.ToValidation("Collection does not exist.")); private static Validation ValidateName(UpdateCollection updateSimpleMediaCollection) => updateSimpleMediaCollection.NotEmpty(c => c.Name) .Bind(_ => updateSimpleMediaCollection.NotLongerThan(50)(c => c.Name)); }