using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; using ErsatzTV.Core; using ErsatzTV.Core.Domain; using ErsatzTV.Core.Interfaces.Repositories; using LanguageExt; using MediatR; using static ErsatzTV.Application.MediaSources.Mapper; using static LanguageExt.Prelude; namespace ErsatzTV.Application.MediaSources.Commands { public class CreateLocalMediaSourceHandler : IRequestHandler> { private readonly IMediaSourceRepository _mediaSourceRepository; public CreateLocalMediaSourceHandler(IMediaSourceRepository mediaSourceRepository) => _mediaSourceRepository = mediaSourceRepository; public Task> Handle( CreateLocalMediaSource request, CancellationToken cancellationToken) => Validate(request).MapT(PersistLocalMediaSource).Bind(v => v.ToEitherAsync()); private Task PersistLocalMediaSource(LocalMediaSource c) => _mediaSourceRepository.Add(c).Map(ProjectToViewModel); private async Task> Validate(CreateLocalMediaSource request) => (await ValidateName(request), await ValidateFolder(request)) .Apply( (name, folder) => new LocalMediaSource { Name = name, MediaType = request.MediaType, Folder = folder }); private async Task> ValidateName(CreateLocalMediaSource createCollection) { List allNames = await _mediaSourceRepository.GetAll() .Map(list => list.Map(c => c.Name).ToList()); Validation result1 = createCollection.NotEmpty(c => c.Name) .Bind(_ => createCollection.NotLongerThan(50)(c => c.Name)); var result2 = Optional(createCollection.Name) .Filter(name => !allNames.Contains(name)) .ToValidation("Media source name must be unique"); return (result1, result2).Apply((_, _) => createCollection.Name); } private async Task> ValidateFolder(CreateLocalMediaSource createCollection) { List allFolders = await _mediaSourceRepository.GetAll() .Map(list => list.OfType().Map(c => c.Folder).ToList()); return Optional(createCollection.Folder) .Filter(folder => allFolders.ForAll(f => !AreSubPaths(f, folder))) .ToValidation("Folder must not belong to another media source"); } private static bool AreSubPaths(string path1, string path2) { string one = path1 + Path.DirectorySeparatorChar; string two = path2 + Path.DirectorySeparatorChar; return one == two || one.StartsWith(two, StringComparison.OrdinalIgnoreCase) || two.StartsWith(one, StringComparison.OrdinalIgnoreCase); } } }