Initial commit
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
using ErsatzTV.Core;
|
||||
using LanguageExt;
|
||||
using MediatR;
|
||||
|
||||
namespace ErsatzTV.Application.MediaCollections.Commands
|
||||
{
|
||||
public record CreateSimpleMediaCollection
|
||||
(string Name) : IRequest<Either<BaseError, MediaCollectionViewModel>>;
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
using System.Collections.Generic;
|
||||
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.MediaCollections.Mapper;
|
||||
using static LanguageExt.Prelude;
|
||||
|
||||
namespace ErsatzTV.Application.MediaCollections.Commands
|
||||
{
|
||||
public class CreateSimpleMediaCollectionHandler : IRequestHandler<CreateSimpleMediaCollection,
|
||||
Either<BaseError, MediaCollectionViewModel>>
|
||||
{
|
||||
private readonly IMediaCollectionRepository _mediaCollectionRepository;
|
||||
|
||||
public CreateSimpleMediaCollectionHandler(IMediaCollectionRepository mediaCollectionRepository) =>
|
||||
_mediaCollectionRepository = mediaCollectionRepository;
|
||||
|
||||
public Task<Either<BaseError, MediaCollectionViewModel>> Handle(
|
||||
CreateSimpleMediaCollection request,
|
||||
CancellationToken cancellationToken) =>
|
||||
Validate(request).MapT(PersistCollection).Bind(v => v.ToEitherAsync());
|
||||
|
||||
private Task<MediaCollectionViewModel> PersistCollection(SimpleMediaCollection c) =>
|
||||
_mediaCollectionRepository.Add(c).Map(ProjectToViewModel);
|
||||
|
||||
private Task<Validation<BaseError, SimpleMediaCollection>> Validate(CreateSimpleMediaCollection request) =>
|
||||
ValidateName(request).MapT(name => new SimpleMediaCollection { Name = name });
|
||||
|
||||
private async Task<Validation<BaseError, string>> ValidateName(CreateSimpleMediaCollection createCollection)
|
||||
{
|
||||
List<string> allNames = await _mediaCollectionRepository.GetSimpleMediaCollections()
|
||||
.Map(list => list.Map(c => c.Name).ToList());
|
||||
|
||||
Validation<BaseError, string> result1 = createCollection.NotEmpty(c => c.Name)
|
||||
.Bind(_ => createCollection.NotLongerThan(50)(c => c.Name));
|
||||
|
||||
var result2 = Optional(createCollection.Name)
|
||||
.Filter(name => !allNames.Contains(name))
|
||||
.ToValidation<BaseError>("Media collection name must be unique");
|
||||
|
||||
return (result1, result2).Apply((_, _) => createCollection.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using System.Threading.Tasks;
|
||||
using ErsatzTV.Core;
|
||||
using LanguageExt;
|
||||
using MediatR;
|
||||
|
||||
namespace ErsatzTV.Application.MediaCollections.Commands
|
||||
{
|
||||
public record DeleteSimpleMediaCollection(int SimpleMediaCollectionId) : IRequest<Either<BaseError, Task>>;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using ErsatzTV.Core;
|
||||
using ErsatzTV.Core.Interfaces.Repositories;
|
||||
using LanguageExt;
|
||||
using MediatR;
|
||||
|
||||
namespace ErsatzTV.Application.MediaCollections.Commands
|
||||
{
|
||||
public class
|
||||
DeleteSimpleMediaCollectionHandler : IRequestHandler<DeleteSimpleMediaCollection, Either<BaseError, Task>>
|
||||
{
|
||||
private readonly IMediaCollectionRepository _mediaCollectionRepository;
|
||||
|
||||
public DeleteSimpleMediaCollectionHandler(IMediaCollectionRepository mediaCollectionRepository) =>
|
||||
_mediaCollectionRepository = mediaCollectionRepository;
|
||||
|
||||
public async Task<Either<BaseError, Task>> Handle(
|
||||
DeleteSimpleMediaCollection request,
|
||||
CancellationToken cancellationToken) =>
|
||||
(await SimpleMediaCollectionMustExist(request))
|
||||
.Map(DoDeletion)
|
||||
.ToEither<Task>();
|
||||
|
||||
private Task DoDeletion(int mediaCollectionId) => _mediaCollectionRepository.Delete(mediaCollectionId);
|
||||
|
||||
private async Task<Validation<BaseError, int>> SimpleMediaCollectionMustExist(
|
||||
DeleteSimpleMediaCollection deleteMediaCollection) =>
|
||||
(await _mediaCollectionRepository.GetSimpleMediaCollection(deleteMediaCollection.SimpleMediaCollectionId))
|
||||
.ToValidation<BaseError>(
|
||||
$"SimpleMediaCollection {deleteMediaCollection.SimpleMediaCollectionId} does not exist.")
|
||||
.Map(c => c.Id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
using System.Collections.Generic;
|
||||
using ErsatzTV.Application.MediaItems;
|
||||
using ErsatzTV.Core;
|
||||
using LanguageExt;
|
||||
using MediatR;
|
||||
|
||||
namespace ErsatzTV.Application.MediaCollections.Commands
|
||||
{
|
||||
public record ReplaceSimpleMediaCollectionItems
|
||||
(int MediaCollectionId, List<int> MediaItemIds) : IRequest<Either<BaseError, List<MediaItemViewModel>>>;
|
||||
}
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using ErsatzTV.Application.MediaItems;
|
||||
using ErsatzTV.Core;
|
||||
using ErsatzTV.Core.Domain;
|
||||
using ErsatzTV.Core.Interfaces.Repositories;
|
||||
using LanguageExt;
|
||||
using LanguageExt.UnsafeValueAccess;
|
||||
using MediatR;
|
||||
|
||||
namespace ErsatzTV.Application.MediaCollections.Commands
|
||||
{
|
||||
public class ReplaceSimpleMediaCollectionItemsHandler : IRequestHandler<ReplaceSimpleMediaCollectionItems,
|
||||
Either<BaseError, List<MediaItemViewModel>>>
|
||||
{
|
||||
private readonly IMediaCollectionRepository _mediaCollectionRepository;
|
||||
private readonly IMediaItemRepository _mediaItemRepository;
|
||||
|
||||
public ReplaceSimpleMediaCollectionItemsHandler(
|
||||
IMediaCollectionRepository mediaCollectionRepository,
|
||||
IMediaItemRepository mediaItemRepository)
|
||||
{
|
||||
_mediaCollectionRepository = mediaCollectionRepository;
|
||||
_mediaItemRepository = mediaItemRepository;
|
||||
}
|
||||
|
||||
public Task<Either<BaseError, List<MediaItemViewModel>>> Handle(
|
||||
ReplaceSimpleMediaCollectionItems request,
|
||||
CancellationToken cancellationToken) =>
|
||||
Validate(request)
|
||||
.MapT(mediaItems => PersistItems(request, mediaItems))
|
||||
.Bind(v => v.ToEitherAsync());
|
||||
|
||||
private async Task<List<MediaItemViewModel>> PersistItems(
|
||||
ReplaceSimpleMediaCollectionItems request,
|
||||
List<MediaItem> mediaItems)
|
||||
{
|
||||
await _mediaCollectionRepository.ReplaceItems(request.MediaCollectionId, mediaItems);
|
||||
return mediaItems.Map(MediaItems.Mapper.ProjectToViewModel).ToList();
|
||||
}
|
||||
|
||||
private Task<Validation<BaseError, List<MediaItem>>> Validate(ReplaceSimpleMediaCollectionItems request) =>
|
||||
MediaCollectionMustExist(request).BindT(_ => MediaItemsMustExist(request));
|
||||
|
||||
private async Task<Validation<BaseError, SimpleMediaCollection>> MediaCollectionMustExist(
|
||||
ReplaceSimpleMediaCollectionItems request) =>
|
||||
(await _mediaCollectionRepository.GetSimpleMediaCollection(request.MediaCollectionId))
|
||||
.ToValidation<BaseError>("[MediaCollectionId] does not exist.");
|
||||
|
||||
private async Task<Validation<BaseError, List<MediaItem>>> MediaItemsMustExist(
|
||||
ReplaceSimpleMediaCollectionItems replaceItems)
|
||||
{
|
||||
var allMediaItems = (await replaceItems.MediaItemIds.Map(i => _mediaItemRepository.Get(i)).Sequence())
|
||||
.ToList();
|
||||
if (allMediaItems.Any(x => x.IsNone))
|
||||
{
|
||||
return BaseError.New("[MediaItemId] does not exist");
|
||||
}
|
||||
|
||||
return allMediaItems.Sequence().ValueUnsafe().ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using ErsatzTV.Core;
|
||||
using ErsatzTV.Core.Domain;
|
||||
using ErsatzTV.Core.Interfaces.Repositories;
|
||||
using LanguageExt;
|
||||
|
||||
namespace ErsatzTV.Application.MediaCollections.Commands
|
||||
{
|
||||
public class
|
||||
UpdateSimpleMediaCollectionHandler : MediatR.IRequestHandler<UpdateSimpleMediaCollection,
|
||||
Either<BaseError, Unit>>
|
||||
{
|
||||
private readonly IMediaCollectionRepository _mediaCollectionRepository;
|
||||
|
||||
public UpdateSimpleMediaCollectionHandler(IMediaCollectionRepository mediaCollectionRepository) =>
|
||||
_mediaCollectionRepository = mediaCollectionRepository;
|
||||
|
||||
public Task<Either<BaseError, Unit>> Handle(
|
||||
UpdateSimpleMediaCollection request,
|
||||
CancellationToken cancellationToken) =>
|
||||
Validate(request)
|
||||
.MapT(c => ApplyUpdateRequest(c, request))
|
||||
.Bind(v => v.ToEitherAsync());
|
||||
|
||||
private async Task<Unit> ApplyUpdateRequest(SimpleMediaCollection c, UpdateSimpleMediaCollection update)
|
||||
{
|
||||
c.Name = update.Name;
|
||||
await _mediaCollectionRepository.Update(c);
|
||||
return Unit.Default;
|
||||
}
|
||||
|
||||
private async Task<Validation<BaseError, SimpleMediaCollection>>
|
||||
Validate(UpdateSimpleMediaCollection request) =>
|
||||
(await SimpleMediaCollectionMustExist(request), ValidateName(request))
|
||||
.Apply((simpleMediaCollectionToUpdate, _) => simpleMediaCollectionToUpdate);
|
||||
|
||||
private Task<Validation<BaseError, SimpleMediaCollection>> SimpleMediaCollectionMustExist(
|
||||
UpdateSimpleMediaCollection updateSimpleMediaCollection) =>
|
||||
_mediaCollectionRepository.GetSimpleMediaCollection(updateSimpleMediaCollection.MediaCollectionId)
|
||||
.Map(v => v.ToValidation<BaseError>("SimpleMediaCollection does not exist."));
|
||||
|
||||
private Validation<BaseError, string> ValidateName(UpdateSimpleMediaCollection updateSimpleMediaCollection) =>
|
||||
updateSimpleMediaCollection.NotEmpty(c => c.Name)
|
||||
.Bind(_ => updateSimpleMediaCollection.NotLongerThan(50)(c => c.Name));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using ErsatzTV.Core;
|
||||
using LanguageExt;
|
||||
|
||||
namespace ErsatzTV.Application.MediaCollections.Commands
|
||||
{
|
||||
public record UpdateSimpleMediaCollection
|
||||
(int MediaCollectionId, string Name) : MediatR.IRequest<Either<BaseError, Unit>>;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using ErsatzTV.Core.AggregateModels;
|
||||
using ErsatzTV.Core.Domain;
|
||||
|
||||
namespace ErsatzTV.Application.MediaCollections
|
||||
{
|
||||
internal static class Mapper
|
||||
{
|
||||
internal static MediaCollectionViewModel ProjectToViewModel(MediaCollection mediaCollection) =>
|
||||
new(mediaCollection.Id, mediaCollection.Name);
|
||||
|
||||
internal static MediaCollectionSummaryViewModel ProjectToViewModel(
|
||||
MediaCollectionSummary mediaCollectionSummary) =>
|
||||
new(
|
||||
mediaCollectionSummary.Id,
|
||||
mediaCollectionSummary.Name,
|
||||
mediaCollectionSummary.ItemCount,
|
||||
mediaCollectionSummary.IsSimple);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
namespace ErsatzTV.Application.MediaCollections
|
||||
{
|
||||
public record MediaCollectionSummaryViewModel(int Id, string Name, int ItemCount, bool IsSimple);
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
namespace ErsatzTV.Application.MediaCollections
|
||||
{
|
||||
public record MediaCollectionViewModel(int Id, string Name);
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using MediatR;
|
||||
|
||||
namespace ErsatzTV.Application.MediaCollections.Queries
|
||||
{
|
||||
public record GetAllMediaCollections : IRequest<List<MediaCollectionViewModel>>;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using ErsatzTV.Core.Interfaces.Repositories;
|
||||
using LanguageExt;
|
||||
using MediatR;
|
||||
using static ErsatzTV.Application.MediaCollections.Mapper;
|
||||
|
||||
namespace ErsatzTV.Application.MediaCollections.Queries
|
||||
{
|
||||
public class GetAllMediaCollectionsHandler : IRequestHandler<GetAllMediaCollections, List<MediaCollectionViewModel>>
|
||||
{
|
||||
private readonly IMediaCollectionRepository _mediaCollectionRepository;
|
||||
|
||||
public GetAllMediaCollectionsHandler(IMediaCollectionRepository mediaCollectionRepository) =>
|
||||
_mediaCollectionRepository = mediaCollectionRepository;
|
||||
|
||||
public Task<List<MediaCollectionViewModel>> Handle(
|
||||
GetAllMediaCollections request,
|
||||
CancellationToken cancellationToken) =>
|
||||
_mediaCollectionRepository.GetAll().Map(list => list.Map(ProjectToViewModel).ToList());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using MediatR;
|
||||
|
||||
namespace ErsatzTV.Application.MediaCollections.Queries
|
||||
{
|
||||
public record GetAllSimpleMediaCollections : IRequest<List<MediaCollectionViewModel>>;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using ErsatzTV.Core.Interfaces.Repositories;
|
||||
using MediatR;
|
||||
using static ErsatzTV.Application.MediaCollections.Mapper;
|
||||
|
||||
namespace ErsatzTV.Application.MediaCollections.Queries
|
||||
{
|
||||
public class
|
||||
GetAllSimpleMediaCollectionsHandler : IRequestHandler<GetAllSimpleMediaCollections,
|
||||
List<MediaCollectionViewModel>>
|
||||
{
|
||||
private readonly IMediaCollectionRepository _mediaCollectionRepository;
|
||||
|
||||
public GetAllSimpleMediaCollectionsHandler(IMediaCollectionRepository mediaCollectionRepository) =>
|
||||
_mediaCollectionRepository = mediaCollectionRepository;
|
||||
|
||||
public async Task<List<MediaCollectionViewModel>> Handle(
|
||||
GetAllSimpleMediaCollections request,
|
||||
CancellationToken cancellationToken) =>
|
||||
(await _mediaCollectionRepository.GetSimpleMediaCollections()).Map(ProjectToViewModel).ToList();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using MediatR;
|
||||
|
||||
namespace ErsatzTV.Application.MediaCollections.Queries
|
||||
{
|
||||
public record GetMediaCollectionSummaries(string SearchString) : IRequest<List<MediaCollectionSummaryViewModel>>;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using ErsatzTV.Core.Interfaces.Repositories;
|
||||
using LanguageExt;
|
||||
using MediatR;
|
||||
using static ErsatzTV.Application.MediaCollections.Mapper;
|
||||
|
||||
namespace ErsatzTV.Application.MediaCollections.Queries
|
||||
{
|
||||
public class
|
||||
GetMediaCollectionSummariesHandler : IRequestHandler<GetMediaCollectionSummaries,
|
||||
List<MediaCollectionSummaryViewModel>>
|
||||
{
|
||||
private readonly IMediaCollectionRepository _mediaCollectionRepository;
|
||||
|
||||
public GetMediaCollectionSummariesHandler(IMediaCollectionRepository mediaCollectionRepository) =>
|
||||
_mediaCollectionRepository = mediaCollectionRepository;
|
||||
|
||||
public Task<List<MediaCollectionSummaryViewModel>> Handle(
|
||||
GetMediaCollectionSummaries request,
|
||||
CancellationToken cancellationToken) =>
|
||||
_mediaCollectionRepository.GetSummaries(request.SearchString)
|
||||
.Map(list => list.Map(ProjectToViewModel).ToList());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
using LanguageExt;
|
||||
using MediatR;
|
||||
|
||||
namespace ErsatzTV.Application.MediaCollections.Queries
|
||||
{
|
||||
public record GetSimpleMediaCollectionById(int Id) : IRequest<Option<MediaCollectionViewModel>>;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using ErsatzTV.Core.Interfaces.Repositories;
|
||||
using LanguageExt;
|
||||
using MediatR;
|
||||
using static ErsatzTV.Application.MediaCollections.Mapper;
|
||||
|
||||
namespace ErsatzTV.Application.MediaCollections.Queries
|
||||
{
|
||||
public class
|
||||
GetSimpleMediaCollectionByIdHandler : IRequestHandler<GetSimpleMediaCollectionById,
|
||||
Option<MediaCollectionViewModel>>
|
||||
{
|
||||
private readonly IMediaCollectionRepository _mediaCollectionRepository;
|
||||
|
||||
public GetSimpleMediaCollectionByIdHandler(IMediaCollectionRepository mediaCollectionRepository) =>
|
||||
_mediaCollectionRepository = mediaCollectionRepository;
|
||||
|
||||
public Task<Option<MediaCollectionViewModel>> Handle(
|
||||
GetSimpleMediaCollectionById request,
|
||||
CancellationToken cancellationToken) =>
|
||||
_mediaCollectionRepository.GetSimpleMediaCollection(request.Id)
|
||||
.MapT(ProjectToViewModel);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using System.Collections.Generic;
|
||||
using ErsatzTV.Application.MediaItems;
|
||||
using LanguageExt;
|
||||
using MediatR;
|
||||
|
||||
namespace ErsatzTV.Application.MediaCollections.Queries
|
||||
{
|
||||
public record GetSimpleMediaCollectionItems(int Id) : IRequest<Option<IEnumerable<MediaItemViewModel>>>;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using ErsatzTV.Application.MediaItems;
|
||||
using ErsatzTV.Core.Interfaces.Repositories;
|
||||
using LanguageExt;
|
||||
using MediatR;
|
||||
using static ErsatzTV.Application.MediaItems.Mapper;
|
||||
|
||||
namespace ErsatzTV.Application.MediaCollections.Queries
|
||||
{
|
||||
public class GetSimpleMediaCollectionItemsHandler : IRequestHandler<GetSimpleMediaCollectionItems,
|
||||
Option<IEnumerable<MediaItemViewModel>>>
|
||||
{
|
||||
private readonly IMediaCollectionRepository _mediaCollectionRepository;
|
||||
|
||||
public GetSimpleMediaCollectionItemsHandler(IMediaCollectionRepository mediaCollectionRepository) =>
|
||||
_mediaCollectionRepository = mediaCollectionRepository;
|
||||
|
||||
public Task<Option<IEnumerable<MediaItemViewModel>>> Handle(
|
||||
GetSimpleMediaCollectionItems request,
|
||||
CancellationToken cancellationToken) =>
|
||||
_mediaCollectionRepository.GetSimpleMediaCollectionItems(request.Id)
|
||||
.MapT(mediaItems => mediaItems.Map(ProjectToViewModel));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user