mirror of https://github.com/ErsatzTV/ErsatzTV.git
Browse Source
* refactor create playout handler * refactor get all playouts handler * refactor delete playout handler * remove dead code * ignore unnamed artists for collections * more repository cleanup * more schedule items refactoring * more playout refactoring * refactor playout builder * refactor ffmpeg profiles * more ffmpeg profile refactoring * rework resolutions * refactor media collections * refactor config elements * update changelog * more cleanuppull/259/head
208 changed files with 1515 additions and 16917 deletions
@ -0,0 +1,4 @@ |
|||||||
|
namespace ErsatzTV.Application.Channels.Commands |
||||||
|
{ |
||||||
|
public record CreateChannelResult(int ChannelId) : EntityIdResult(ChannelId); |
||||||
|
} |
||||||
@ -0,0 +1,4 @@ |
|||||||
|
namespace ErsatzTV.Application |
||||||
|
{ |
||||||
|
public record EntityIdResult(int Id); |
||||||
|
} |
||||||
@ -0,0 +1,4 @@ |
|||||||
|
namespace ErsatzTV.Application.FFmpegProfiles.Commands |
||||||
|
{ |
||||||
|
public record CreateFFmpegProfileResult(int FFmpegProfileId) : EntityIdResult(FFmpegProfileId); |
||||||
|
} |
||||||
@ -1,9 +1,7 @@ |
|||||||
using System.Threading.Tasks; |
using ErsatzTV.Core; |
||||||
using ErsatzTV.Core; |
|
||||||
using LanguageExt; |
using LanguageExt; |
||||||
using MediatR; |
|
||||||
|
|
||||||
namespace ErsatzTV.Application.FFmpegProfiles.Commands |
namespace ErsatzTV.Application.FFmpegProfiles.Commands |
||||||
{ |
{ |
||||||
public record DeleteFFmpegProfile(int FFmpegProfileId) : IRequest<Either<BaseError, Task>>; |
public record DeleteFFmpegProfile(int FFmpegProfileId) : MediatR.IRequest<Either<BaseError, Unit>>; |
||||||
} |
} |
||||||
|
|||||||
@ -1,32 +1,43 @@ |
|||||||
using System.Threading; |
using System.Threading; |
||||||
using System.Threading.Tasks; |
using System.Threading.Tasks; |
||||||
using ErsatzTV.Core; |
using ErsatzTV.Core; |
||||||
using ErsatzTV.Core.Interfaces.Repositories; |
using ErsatzTV.Core.Domain; |
||||||
|
using ErsatzTV.Infrastructure.Data; |
||||||
|
using ErsatzTV.Infrastructure.Extensions; |
||||||
using LanguageExt; |
using LanguageExt; |
||||||
using MediatR; |
using MediatR; |
||||||
|
using Microsoft.EntityFrameworkCore; |
||||||
|
|
||||||
namespace ErsatzTV.Application.FFmpegProfiles.Commands |
namespace ErsatzTV.Application.FFmpegProfiles.Commands |
||||||
{ |
{ |
||||||
public class DeleteFFmpegProfileHandler : IRequestHandler<DeleteFFmpegProfile, Either<BaseError, Task>> |
public class DeleteFFmpegProfileHandler : IRequestHandler<DeleteFFmpegProfile, Either<BaseError, LanguageExt.Unit>> |
||||||
{ |
{ |
||||||
private readonly IFFmpegProfileRepository _ffmpegProfileRepository; |
private readonly IDbContextFactory<TvContext> _dbContextFactory; |
||||||
|
|
||||||
public DeleteFFmpegProfileHandler(IFFmpegProfileRepository ffmpegProfileRepository) => |
public DeleteFFmpegProfileHandler(IDbContextFactory<TvContext> dbContextFactory) => |
||||||
_ffmpegProfileRepository = ffmpegProfileRepository; |
_dbContextFactory = dbContextFactory; |
||||||
|
|
||||||
public async Task<Either<BaseError, Task>> Handle( |
public async Task<Either<BaseError, LanguageExt.Unit>> Handle( |
||||||
DeleteFFmpegProfile request, |
DeleteFFmpegProfile request, |
||||||
CancellationToken cancellationToken) => |
CancellationToken cancellationToken) |
||||||
(await FFmpegProfileMustExist(request)) |
{ |
||||||
.Map(DoDeletion) |
await using TvContext dbContext = _dbContextFactory.CreateDbContext(); |
||||||
.ToEither<Task>(); |
Validation<BaseError, FFmpegProfile> validation = await FFmpegProfileMustExist(dbContext, request); |
||||||
|
return await validation.Apply(p => DoDeletion(dbContext, p)); |
||||||
|
} |
||||||
|
|
||||||
private Task DoDeletion(int channelId) => _ffmpegProfileRepository.Delete(channelId); |
private static async Task<LanguageExt.Unit> DoDeletion(TvContext dbContext, FFmpegProfile ffmpegProfile) |
||||||
|
{ |
||||||
|
dbContext.FFmpegProfiles.Remove(ffmpegProfile); |
||||||
|
await dbContext.SaveChangesAsync(); |
||||||
|
return LanguageExt.Unit.Default; |
||||||
|
} |
||||||
|
|
||||||
private async Task<Validation<BaseError, int>> FFmpegProfileMustExist( |
private static Task<Validation<BaseError, FFmpegProfile>> FFmpegProfileMustExist( |
||||||
DeleteFFmpegProfile deleteFFmpegProfile) => |
TvContext dbContext, |
||||||
(await _ffmpegProfileRepository.Get(deleteFFmpegProfile.FFmpegProfileId)) |
DeleteFFmpegProfile request) => |
||||||
.ToValidation<BaseError>($"FFmpegProfile {deleteFFmpegProfile.FFmpegProfileId} does not exist.") |
dbContext.FFmpegProfiles |
||||||
.Map(c => c.Id); |
.SelectOneAsync(p => p.Id, p => p.Id == request.FFmpegProfileId) |
||||||
|
.Map(o => o.ToValidation<BaseError>($"FFmpegProfile {request.FFmpegProfileId} does not exist")); |
||||||
} |
} |
||||||
} |
} |
||||||
|
|||||||
@ -0,0 +1,4 @@ |
|||||||
|
namespace ErsatzTV.Application.FFmpegProfiles.Commands |
||||||
|
{ |
||||||
|
public record UpdateFFmpegProfileResult(int FFmpegProfileId) : EntityIdResult(FFmpegProfileId); |
||||||
|
} |
||||||
@ -1,23 +1,30 @@ |
|||||||
using System.Threading; |
using System.Threading; |
||||||
using System.Threading.Tasks; |
using System.Threading.Tasks; |
||||||
using ErsatzTV.Core.Interfaces.Repositories; |
using ErsatzTV.Infrastructure.Data; |
||||||
|
using ErsatzTV.Infrastructure.Extensions; |
||||||
using LanguageExt; |
using LanguageExt; |
||||||
using MediatR; |
using MediatR; |
||||||
|
using Microsoft.EntityFrameworkCore; |
||||||
using static ErsatzTV.Application.FFmpegProfiles.Mapper; |
using static ErsatzTV.Application.FFmpegProfiles.Mapper; |
||||||
|
|
||||||
namespace ErsatzTV.Application.FFmpegProfiles.Queries |
namespace ErsatzTV.Application.FFmpegProfiles.Queries |
||||||
{ |
{ |
||||||
public class GetFFmpegProfileByIdHandler : IRequestHandler<GetFFmpegProfileById, Option<FFmpegProfileViewModel>> |
public class GetFFmpegProfileByIdHandler : IRequestHandler<GetFFmpegProfileById, Option<FFmpegProfileViewModel>> |
||||||
{ |
{ |
||||||
private readonly IFFmpegProfileRepository _ffmpegProfileRepository; |
private readonly IDbContextFactory<TvContext> _dbContextFactory; |
||||||
|
|
||||||
public GetFFmpegProfileByIdHandler(IFFmpegProfileRepository ffmpegProfileRepository) => |
public GetFFmpegProfileByIdHandler(IDbContextFactory<TvContext> dbContextFactory) => |
||||||
_ffmpegProfileRepository = ffmpegProfileRepository; |
_dbContextFactory = dbContextFactory; |
||||||
|
|
||||||
public Task<Option<FFmpegProfileViewModel>> Handle( |
public async Task<Option<FFmpegProfileViewModel>> Handle( |
||||||
GetFFmpegProfileById request, |
GetFFmpegProfileById request, |
||||||
CancellationToken cancellationToken) => |
CancellationToken cancellationToken) |
||||||
_ffmpegProfileRepository.Get(request.Id) |
{ |
||||||
|
await using TvContext dbContext = _dbContextFactory.CreateDbContext(); |
||||||
|
return await dbContext.FFmpegProfiles |
||||||
|
.Include(p => p.Resolution) |
||||||
|
.SelectOneAsync(p => p.Id, p => p.Id == request.Id) |
||||||
.MapT(ProjectToViewModel); |
.MapT(ProjectToViewModel); |
||||||
|
} |
||||||
} |
} |
||||||
} |
} |
||||||
|
|||||||
@ -1,9 +1,8 @@ |
|||||||
using System.Threading.Tasks; |
using ErsatzTV.Core; |
||||||
using ErsatzTV.Core; |
|
||||||
using LanguageExt; |
using LanguageExt; |
||||||
using MediatR; |
using MediatR; |
||||||
|
|
||||||
namespace ErsatzTV.Application.MediaCollections.Commands |
namespace ErsatzTV.Application.MediaCollections.Commands |
||||||
{ |
{ |
||||||
public record DeleteCollection(int CollectionId) : IRequest<Either<BaseError, Task>>; |
public record DeleteCollection(int CollectionId) : IRequest<Either<BaseError, LanguageExt.Unit>>; |
||||||
} |
} |
||||||
|
|||||||
@ -1,33 +1,42 @@ |
|||||||
using System.Threading; |
using System.Threading; |
||||||
using System.Threading.Tasks; |
using System.Threading.Tasks; |
||||||
using ErsatzTV.Core; |
using ErsatzTV.Core; |
||||||
using ErsatzTV.Core.Interfaces.Repositories; |
using ErsatzTV.Core.Domain; |
||||||
|
using ErsatzTV.Infrastructure.Data; |
||||||
|
using ErsatzTV.Infrastructure.Extensions; |
||||||
using LanguageExt; |
using LanguageExt; |
||||||
using MediatR; |
using Microsoft.EntityFrameworkCore; |
||||||
|
|
||||||
namespace ErsatzTV.Application.MediaCollections.Commands |
namespace ErsatzTV.Application.MediaCollections.Commands |
||||||
{ |
{ |
||||||
public class DeleteCollectionHandler : IRequestHandler<DeleteCollection, Either<BaseError, Task>> |
public class DeleteCollectionHandler : MediatR.IRequestHandler<DeleteCollection, Either<BaseError, Unit>> |
||||||
{ |
{ |
||||||
private readonly IMediaCollectionRepository _mediaCollectionRepository; |
private readonly IDbContextFactory<TvContext> _dbContextFactory; |
||||||
|
|
||||||
public DeleteCollectionHandler(IMediaCollectionRepository mediaCollectionRepository) => |
public DeleteCollectionHandler(IDbContextFactory<TvContext> dbContextFactory) => |
||||||
_mediaCollectionRepository = mediaCollectionRepository; |
_dbContextFactory = dbContextFactory; |
||||||
|
|
||||||
public async Task<Either<BaseError, Task>> Handle( |
public async Task<Either<BaseError, Unit>> Handle( |
||||||
DeleteCollection request, |
DeleteCollection request, |
||||||
CancellationToken cancellationToken) => |
CancellationToken cancellationToken) |
||||||
(await CollectionMustExist(request)) |
{ |
||||||
.Map(DoDeletion) |
await using TvContext dbContext = _dbContextFactory.CreateDbContext(); |
||||||
.ToEither<Task>(); |
|
||||||
|
|
||||||
private Task DoDeletion(int mediaCollectionId) => _mediaCollectionRepository.Delete(mediaCollectionId); |
Validation<BaseError, Collection> validation = await CollectionMustExist(dbContext, request); |
||||||
|
return await validation.Apply(c => DoDeletion(dbContext, c)); |
||||||
|
} |
||||||
|
|
||||||
private async Task<Validation<BaseError, int>> CollectionMustExist( |
private static Task<Unit> DoDeletion(TvContext dbContext, Collection collection) |
||||||
DeleteCollection deleteMediaCollection) => |
{ |
||||||
(await _mediaCollectionRepository.Get(deleteMediaCollection.CollectionId)) |
dbContext.Collections.Remove(collection); |
||||||
.ToValidation<BaseError>( |
return dbContext.SaveChangesAsync().ToUnit(); |
||||||
$"Collection {deleteMediaCollection.CollectionId} does not exist.") |
} |
||||||
.Map(c => c.Id); |
|
||||||
|
private static Task<Validation<BaseError, Collection>> CollectionMustExist( |
||||||
|
TvContext dbContext, |
||||||
|
DeleteCollection request) => |
||||||
|
dbContext.Collections |
||||||
|
.SelectOneAsync(c => c.Id, c => c.Id == request.CollectionId) |
||||||
|
.Map(o => o.ToValidation<BaseError>($"Collection {request.CollectionId} does not exist.")); |
||||||
} |
} |
||||||
} |
} |
||||||
|
|||||||
@ -1,25 +1,30 @@ |
|||||||
using System.Threading; |
using System.Threading; |
||||||
using System.Threading.Tasks; |
using System.Threading.Tasks; |
||||||
using ErsatzTV.Core.Interfaces.Repositories; |
using ErsatzTV.Infrastructure.Data; |
||||||
|
using ErsatzTV.Infrastructure.Extensions; |
||||||
using LanguageExt; |
using LanguageExt; |
||||||
using MediatR; |
using MediatR; |
||||||
|
using Microsoft.EntityFrameworkCore; |
||||||
using static ErsatzTV.Application.MediaCollections.Mapper; |
using static ErsatzTV.Application.MediaCollections.Mapper; |
||||||
|
|
||||||
namespace ErsatzTV.Application.MediaCollections.Queries |
namespace ErsatzTV.Application.MediaCollections.Queries |
||||||
{ |
{ |
||||||
public class |
public class GetCollectionByIdHandler : |
||||||
GetCollectionByIdHandler : IRequestHandler<GetCollectionById, |
IRequestHandler<GetCollectionById, Option<MediaCollectionViewModel>> |
||||||
Option<MediaCollectionViewModel>> |
|
||||||
{ |
{ |
||||||
private readonly IMediaCollectionRepository _mediaCollectionRepository; |
private readonly IDbContextFactory<TvContext> _dbContextFactory; |
||||||
|
|
||||||
public GetCollectionByIdHandler(IMediaCollectionRepository mediaCollectionRepository) => |
public GetCollectionByIdHandler(IDbContextFactory<TvContext> dbContextFactory) => |
||||||
_mediaCollectionRepository = mediaCollectionRepository; |
_dbContextFactory = dbContextFactory; |
||||||
|
|
||||||
public Task<Option<MediaCollectionViewModel>> Handle( |
public async Task<Option<MediaCollectionViewModel>> Handle( |
||||||
GetCollectionById request, |
GetCollectionById request, |
||||||
CancellationToken cancellationToken) => |
CancellationToken cancellationToken) |
||||||
_mediaCollectionRepository.Get(request.Id) |
{ |
||||||
|
await using TvContext dbContext = _dbContextFactory.CreateDbContext(); |
||||||
|
return await dbContext.Collections |
||||||
|
.SelectOneAsync(c => c.Id, c => c.Id == request.Id) |
||||||
.MapT(ProjectToViewModel); |
.MapT(ProjectToViewModel); |
||||||
|
} |
||||||
} |
} |
||||||
} |
} |
||||||
|
|||||||
@ -1,9 +0,0 @@ |
|||||||
using System.Collections.Generic; |
|
||||||
using ErsatzTV.Application.MediaItems; |
|
||||||
using LanguageExt; |
|
||||||
using MediatR; |
|
||||||
|
|
||||||
namespace ErsatzTV.Application.MediaCollections.Queries |
|
||||||
{ |
|
||||||
public record GetCollectionItems(int Id) : IRequest<Option<IEnumerable<MediaItemViewModel>>>; |
|
||||||
} |
|
||||||
@ -1,26 +0,0 @@ |
|||||||
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 GetCollectionItemsHandler : IRequestHandler<GetCollectionItems, |
|
||||||
Option<IEnumerable<MediaItemViewModel>>> |
|
||||||
{ |
|
||||||
private readonly IMediaCollectionRepository _mediaCollectionRepository; |
|
||||||
|
|
||||||
public GetCollectionItemsHandler(IMediaCollectionRepository mediaCollectionRepository) => |
|
||||||
_mediaCollectionRepository = mediaCollectionRepository; |
|
||||||
|
|
||||||
public Task<Option<IEnumerable<MediaItemViewModel>>> Handle( |
|
||||||
GetCollectionItems request, |
|
||||||
CancellationToken cancellationToken) => |
|
||||||
_mediaCollectionRepository.GetItems(request.Id) |
|
||||||
.MapT(mediaItems => mediaItems.Map(ProjectToViewModel)); |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,9 +0,0 @@ |
|||||||
namespace ErsatzTV.Application.MediaItems |
|
||||||
{ |
|
||||||
public record MediaItemSearchResultViewModel( |
|
||||||
int Id, |
|
||||||
string Source, |
|
||||||
string MediaType, |
|
||||||
string Title, |
|
||||||
string Duration); |
|
||||||
} |
|
||||||
@ -1,4 +0,0 @@ |
|||||||
namespace ErsatzTV.Application.MediaItems |
|
||||||
{ |
|
||||||
public record MediaItemViewModel(int Id, int LibraryPathId); |
|
||||||
} |
|
||||||
@ -1,7 +0,0 @@ |
|||||||
using System.Collections.Generic; |
|
||||||
using MediatR; |
|
||||||
|
|
||||||
namespace ErsatzTV.Application.MediaItems.Queries |
|
||||||
{ |
|
||||||
public record GetAllMediaItems : IRequest<List<MediaItemViewModel>>; |
|
||||||
} |
|
||||||
@ -1,24 +0,0 @@ |
|||||||
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.MediaItems.Mapper; |
|
||||||
|
|
||||||
namespace ErsatzTV.Application.MediaItems.Queries |
|
||||||
{ |
|
||||||
public class GetAllMediaItemsHandler : IRequestHandler<GetAllMediaItems, List<MediaItemViewModel>> |
|
||||||
{ |
|
||||||
private readonly IMediaItemRepository _mediaItemRepository; |
|
||||||
|
|
||||||
public GetAllMediaItemsHandler(IMediaItemRepository mediaItemRepository) => |
|
||||||
_mediaItemRepository = mediaItemRepository; |
|
||||||
|
|
||||||
public Task<List<MediaItemViewModel>> Handle( |
|
||||||
GetAllMediaItems request, |
|
||||||
CancellationToken cancellationToken) => |
|
||||||
_mediaItemRepository.GetAll().Map(list => list.Map(ProjectToViewModel).ToList()); |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,7 +0,0 @@ |
|||||||
using LanguageExt; |
|
||||||
using MediatR; |
|
||||||
|
|
||||||
namespace ErsatzTV.Application.MediaItems.Queries |
|
||||||
{ |
|
||||||
public record GetMediaItemById(int Id) : IRequest<Option<MediaItemViewModel>>; |
|
||||||
} |
|
||||||
@ -1,23 +0,0 @@ |
|||||||
using System.Threading; |
|
||||||
using System.Threading.Tasks; |
|
||||||
using ErsatzTV.Core.Interfaces.Repositories; |
|
||||||
using LanguageExt; |
|
||||||
using MediatR; |
|
||||||
using static ErsatzTV.Application.MediaItems.Mapper; |
|
||||||
|
|
||||||
namespace ErsatzTV.Application.MediaItems.Queries |
|
||||||
{ |
|
||||||
public class GetMediaItemByIdHandler : IRequestHandler<GetMediaItemById, Option<MediaItemViewModel>> |
|
||||||
{ |
|
||||||
private readonly IMediaItemRepository _mediaItemRepository; |
|
||||||
|
|
||||||
public GetMediaItemByIdHandler(IMediaItemRepository mediaItemRepository) => |
|
||||||
_mediaItemRepository = mediaItemRepository; |
|
||||||
|
|
||||||
public Task<Option<MediaItemViewModel>> Handle( |
|
||||||
GetMediaItemById request, |
|
||||||
CancellationToken cancellationToken) => |
|
||||||
_mediaItemRepository.Get(request.Id) |
|
||||||
.MapT(ProjectToViewModel); |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,16 +0,0 @@ |
|||||||
using System; |
|
||||||
using ErsatzTV.Core.Domain; |
|
||||||
|
|
||||||
namespace ErsatzTV.Application.MediaSources |
|
||||||
{ |
|
||||||
internal static class Mapper |
|
||||||
{ |
|
||||||
internal static MediaSourceViewModel ProjectToViewModel(MediaSource mediaSource) => |
|
||||||
mediaSource switch |
|
||||||
{ |
|
||||||
LocalMediaSource lms => new LocalMediaSourceViewModel(lms.Id), |
|
||||||
PlexMediaSource pms => Plex.Mapper.ProjectToViewModel(pms), |
|
||||||
_ => throw new NotSupportedException($"Unsupported media source {mediaSource.GetType().Name}") |
|
||||||
}; |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,6 +0,0 @@ |
|||||||
using MediatR; |
|
||||||
|
|
||||||
namespace ErsatzTV.Application.MediaSources.Queries |
|
||||||
{ |
|
||||||
public record CountMediaItemsById(int MediaSourceId) : IRequest<int>; |
|
||||||
} |
|
||||||
@ -1,18 +0,0 @@ |
|||||||
using System.Threading; |
|
||||||
using System.Threading.Tasks; |
|
||||||
using ErsatzTV.Core.Interfaces.Repositories; |
|
||||||
using MediatR; |
|
||||||
|
|
||||||
namespace ErsatzTV.Application.MediaSources.Queries |
|
||||||
{ |
|
||||||
public class CountMediaItemsByIdHandler : IRequestHandler<CountMediaItemsById, int> |
|
||||||
{ |
|
||||||
private readonly IMediaSourceRepository _mediaSourceRepository; |
|
||||||
|
|
||||||
public CountMediaItemsByIdHandler(IMediaSourceRepository mediaSourceRepository) => |
|
||||||
_mediaSourceRepository = mediaSourceRepository; |
|
||||||
|
|
||||||
public Task<int> Handle(CountMediaItemsById request, CancellationToken cancellationToken) => |
|
||||||
_mediaSourceRepository.CountMediaItems(request.MediaSourceId); |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,7 +0,0 @@ |
|||||||
using System.Collections.Generic; |
|
||||||
using MediatR; |
|
||||||
|
|
||||||
namespace ErsatzTV.Application.MediaSources.Queries |
|
||||||
{ |
|
||||||
public record GetAllMediaSources : IRequest<List<MediaSourceViewModel>>; |
|
||||||
} |
|
||||||
@ -1,23 +0,0 @@ |
|||||||
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.MediaSources.Mapper; |
|
||||||
|
|
||||||
namespace ErsatzTV.Application.MediaSources.Queries |
|
||||||
{ |
|
||||||
public class GetAllMediaSourcesHandler : IRequestHandler<GetAllMediaSources, List<MediaSourceViewModel>> |
|
||||||
{ |
|
||||||
private readonly IMediaSourceRepository _mediaSourceRepository; |
|
||||||
|
|
||||||
public GetAllMediaSourcesHandler(IMediaSourceRepository mediaSourceRepository) => |
|
||||||
_mediaSourceRepository = mediaSourceRepository; |
|
||||||
|
|
||||||
public async Task<List<MediaSourceViewModel>> Handle( |
|
||||||
GetAllMediaSources request, |
|
||||||
CancellationToken cancellationToken) => |
|
||||||
(await _mediaSourceRepository.GetAll()).Map(ProjectToViewModel).ToList(); |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,7 +0,0 @@ |
|||||||
using LanguageExt; |
|
||||||
using MediatR; |
|
||||||
|
|
||||||
namespace ErsatzTV.Application.MediaSources.Queries |
|
||||||
{ |
|
||||||
public record GetMediaSourceById(int Id) : IRequest<Option<MediaSourceViewModel>>; |
|
||||||
} |
|
||||||
@ -1,23 +0,0 @@ |
|||||||
using System.Threading; |
|
||||||
using System.Threading.Tasks; |
|
||||||
using ErsatzTV.Core.Interfaces.Repositories; |
|
||||||
using LanguageExt; |
|
||||||
using MediatR; |
|
||||||
using static ErsatzTV.Application.MediaSources.Mapper; |
|
||||||
|
|
||||||
namespace ErsatzTV.Application.MediaSources.Queries |
|
||||||
{ |
|
||||||
public class GetMediaSourceByIdHandler : IRequestHandler<GetMediaSourceById, Option<MediaSourceViewModel>> |
|
||||||
{ |
|
||||||
private readonly IMediaSourceRepository _mediaSourceRepository; |
|
||||||
|
|
||||||
public GetMediaSourceByIdHandler(IMediaSourceRepository mediaSourceRepository) => |
|
||||||
_mediaSourceRepository = mediaSourceRepository; |
|
||||||
|
|
||||||
public Task<Option<MediaSourceViewModel>> Handle( |
|
||||||
GetMediaSourceById request, |
|
||||||
CancellationToken cancellationToken) => |
|
||||||
_mediaSourceRepository.Get(request.Id) |
|
||||||
.MapT(ProjectToViewModel); |
|
||||||
} |
|
||||||
} |
|
||||||
@ -0,0 +1,4 @@ |
|||||||
|
namespace ErsatzTV.Application.Playouts.Commands |
||||||
|
{ |
||||||
|
public record CreatePlayoutResponse(int PlayoutId); |
||||||
|
} |
||||||
@ -1,9 +1,9 @@ |
|||||||
using System.Threading.Tasks; |
using ErsatzTV.Core; |
||||||
using ErsatzTV.Core; |
|
||||||
using LanguageExt; |
using LanguageExt; |
||||||
using MediatR; |
using MediatR; |
||||||
|
using Unit = LanguageExt.Unit; |
||||||
|
|
||||||
namespace ErsatzTV.Application.Playouts.Commands |
namespace ErsatzTV.Application.Playouts.Commands |
||||||
{ |
{ |
||||||
public record DeletePlayout(int PlayoutId) : IRequest<Either<BaseError, Task>>; |
public record DeletePlayout(int PlayoutId) : IRequest<Either<BaseError, Unit>>; |
||||||
} |
} |
||||||
|
|||||||
@ -1,32 +1,42 @@ |
|||||||
using System.Threading; |
using System.Linq; |
||||||
|
using System.Threading; |
||||||
using System.Threading.Tasks; |
using System.Threading.Tasks; |
||||||
using ErsatzTV.Core; |
using ErsatzTV.Core; |
||||||
using ErsatzTV.Core.Interfaces.Repositories; |
using ErsatzTV.Core.Domain; |
||||||
|
using ErsatzTV.Infrastructure.Data; |
||||||
using LanguageExt; |
using LanguageExt; |
||||||
using MediatR; |
using MediatR; |
||||||
|
using Microsoft.EntityFrameworkCore; |
||||||
|
using Unit = LanguageExt.Unit; |
||||||
|
|
||||||
namespace ErsatzTV.Application.Playouts.Commands |
namespace ErsatzTV.Application.Playouts.Commands |
||||||
{ |
{ |
||||||
public class DeletePlayoutHandler : IRequestHandler<DeletePlayout, Either<BaseError, Task>> |
public class DeletePlayoutHandler : IRequestHandler<DeletePlayout, Either<BaseError, Unit>> |
||||||
{ |
{ |
||||||
private readonly IPlayoutRepository _playoutRepository; |
private readonly IDbContextFactory<TvContext> _dbContextFactory; |
||||||
|
|
||||||
public DeletePlayoutHandler(IPlayoutRepository playoutRepository) => |
public DeletePlayoutHandler(IDbContextFactory<TvContext> dbContextFactory) => |
||||||
_playoutRepository = playoutRepository; |
_dbContextFactory = dbContextFactory; |
||||||
|
|
||||||
public async Task<Either<BaseError, Task>> Handle( |
public async Task<Either<BaseError, Unit>> Handle( |
||||||
DeletePlayout request, |
DeletePlayout request, |
||||||
CancellationToken cancellationToken) => |
CancellationToken cancellationToken) |
||||||
(await PlayoutMustExist(request)) |
{ |
||||||
.Map(DoDeletion) |
await using TvContext dbContext = _dbContextFactory.CreateDbContext(); |
||||||
.ToEither<Task>(); |
|
||||||
|
|
||||||
private Task DoDeletion(int playoutId) => _playoutRepository.Delete(playoutId); |
Option<Playout> maybePlayout = await dbContext.Playouts |
||||||
|
.OrderBy(p => p.Id) |
||||||
|
.FirstOrDefaultAsync(p => p.Id == request.PlayoutId, cancellationToken); |
||||||
|
|
||||||
private async Task<Validation<BaseError, int>> PlayoutMustExist( |
foreach (Playout playout in maybePlayout) |
||||||
DeletePlayout deletePlayout) => |
{ |
||||||
(await _playoutRepository.Get(deletePlayout.PlayoutId)) |
dbContext.Playouts.Remove(playout); |
||||||
.ToValidation<BaseError>($"Playout {deletePlayout.PlayoutId} does not exist.") |
await dbContext.SaveChangesAsync(cancellationToken); |
||||||
.Map(c => c.Id); |
} |
||||||
|
|
||||||
|
return maybePlayout |
||||||
|
.Map(_ => Unit.Default) |
||||||
|
.ToEither(BaseError.New($"Playout {request.PlayoutId} does not exist.")); |
||||||
|
} |
||||||
} |
} |
||||||
} |
} |
||||||
|
|||||||
@ -1,13 +0,0 @@ |
|||||||
using ErsatzTV.Core; |
|
||||||
using ErsatzTV.Core.Domain; |
|
||||||
using LanguageExt; |
|
||||||
using MediatR; |
|
||||||
|
|
||||||
namespace ErsatzTV.Application.Playouts.Commands |
|
||||||
{ |
|
||||||
public record UpdatePlayout( |
|
||||||
int PlayoutId, |
|
||||||
int ChannelId, |
|
||||||
int ProgramScheduleId, |
|
||||||
ProgramSchedulePlayoutType ProgramSchedulePlayoutType) : IRequest<Either<BaseError, PlayoutViewModel>>; |
|
||||||
} |
|
||||||
@ -1,75 +0,0 @@ |
|||||||
using System.Threading; |
|
||||||
using System.Threading.Channels; |
|
||||||
using System.Threading.Tasks; |
|
||||||
using ErsatzTV.Core; |
|
||||||
using ErsatzTV.Core.Domain; |
|
||||||
using ErsatzTV.Core.Interfaces.Repositories; |
|
||||||
using LanguageExt; |
|
||||||
using MediatR; |
|
||||||
using static LanguageExt.Prelude; |
|
||||||
using static ErsatzTV.Application.Playouts.Mapper; |
|
||||||
using Channel = ErsatzTV.Core.Domain.Channel; |
|
||||||
|
|
||||||
namespace ErsatzTV.Application.Playouts.Commands |
|
||||||
{ |
|
||||||
public class UpdatePlayoutHandler : IRequestHandler<UpdatePlayout, Either<BaseError, PlayoutViewModel>> |
|
||||||
{ |
|
||||||
private readonly ChannelWriter<IBackgroundServiceRequest> _channel; |
|
||||||
private readonly IChannelRepository _channelRepository; |
|
||||||
private readonly IPlayoutRepository _playoutRepository; |
|
||||||
private readonly IProgramScheduleRepository _programScheduleRepository; |
|
||||||
|
|
||||||
public UpdatePlayoutHandler( |
|
||||||
IPlayoutRepository playoutRepository, |
|
||||||
IChannelRepository channelRepository, |
|
||||||
IProgramScheduleRepository programScheduleRepository, |
|
||||||
ChannelWriter<IBackgroundServiceRequest> channel) |
|
||||||
{ |
|
||||||
_playoutRepository = playoutRepository; |
|
||||||
_channelRepository = channelRepository; |
|
||||||
_programScheduleRepository = programScheduleRepository; |
|
||||||
_channel = channel; |
|
||||||
} |
|
||||||
|
|
||||||
public Task<Either<BaseError, PlayoutViewModel>> Handle( |
|
||||||
UpdatePlayout request, |
|
||||||
CancellationToken cancellationToken) => |
|
||||||
Validate(request) |
|
||||||
.MapT(c => ApplyUpdateRequest(c, request)) |
|
||||||
.Bind(v => v.ToEitherAsync()); |
|
||||||
|
|
||||||
private async Task<PlayoutViewModel> ApplyUpdateRequest(Playout p, UpdatePlayout update) |
|
||||||
{ |
|
||||||
p.ChannelId = update.ChannelId; |
|
||||||
p.ProgramScheduleId = update.ProgramScheduleId; |
|
||||||
p.ProgramSchedulePlayoutType = update.ProgramSchedulePlayoutType; |
|
||||||
await _playoutRepository.Update(p); |
|
||||||
await _channel.WriteAsync(new BuildPlayout(p.Id)); |
|
||||||
return ProjectToViewModel(p); |
|
||||||
} |
|
||||||
|
|
||||||
private async Task<Validation<BaseError, Playout>> Validate(UpdatePlayout request) => |
|
||||||
(await PlayoutMustExist(request), await ChannelMustExist(request), await ProgramScheduleMustExist(request), |
|
||||||
ValidatePlayoutType(request)) |
|
||||||
.Apply( |
|
||||||
(playoutToUpdate, _, _, _) => playoutToUpdate); |
|
||||||
|
|
||||||
private async Task<Validation<BaseError, Playout>> PlayoutMustExist(UpdatePlayout updatePlayout) => |
|
||||||
(await _playoutRepository.Get(updatePlayout.PlayoutId)) |
|
||||||
.ToValidation<BaseError>("Playout does not exist."); |
|
||||||
|
|
||||||
private async Task<Validation<BaseError, Channel>> ChannelMustExist(UpdatePlayout createPlayout) => |
|
||||||
(await _channelRepository.Get(createPlayout.ChannelId)) |
|
||||||
.ToValidation<BaseError>("Channel does not exist."); |
|
||||||
|
|
||||||
private async Task<Validation<BaseError, ProgramSchedule>> |
|
||||||
ProgramScheduleMustExist(UpdatePlayout createPlayout) => |
|
||||||
(await _programScheduleRepository.Get(createPlayout.ProgramScheduleId)) |
|
||||||
.ToValidation<BaseError>("ProgramSchedule does not exist."); |
|
||||||
|
|
||||||
private Validation<BaseError, ProgramSchedulePlayoutType> ValidatePlayoutType(UpdatePlayout createPlayout) => |
|
||||||
Optional(createPlayout.ProgramSchedulePlayoutType) |
|
||||||
.Filter(playoutType => playoutType != ProgramSchedulePlayoutType.None) |
|
||||||
.ToValidation<BaseError>("[ProgramSchedulePlayoutType] must not be None"); |
|
||||||
} |
|
||||||
} |
|
||||||
@ -0,0 +1,8 @@ |
|||||||
|
namespace ErsatzTV.Application.Playouts |
||||||
|
{ |
||||||
|
public record PlayoutNameViewModel( |
||||||
|
int PlayoutId, |
||||||
|
string ChannelName, |
||||||
|
string ChannelNumber, |
||||||
|
string ScheduleName); |
||||||
|
} |
||||||
@ -1,24 +1,28 @@ |
|||||||
using System.Collections.Generic; |
using System.Collections.Generic; |
||||||
using System.Linq; |
|
||||||
using System.Threading; |
using System.Threading; |
||||||
using System.Threading.Tasks; |
using System.Threading.Tasks; |
||||||
using ErsatzTV.Core.Interfaces.Repositories; |
using ErsatzTV.Infrastructure.Data; |
||||||
using LanguageExt; |
|
||||||
using MediatR; |
using MediatR; |
||||||
using static ErsatzTV.Application.Playouts.Mapper; |
using Microsoft.EntityFrameworkCore; |
||||||
|
|
||||||
namespace ErsatzTV.Application.Playouts.Queries |
namespace ErsatzTV.Application.Playouts.Queries |
||||||
{ |
{ |
||||||
public class GetAllPlayoutsHandler : IRequestHandler<GetAllPlayouts, List<PlayoutViewModel>> |
public class GetAllPlayoutsHandler : IRequestHandler<GetAllPlayouts, List<PlayoutNameViewModel>> |
||||||
{ |
{ |
||||||
private readonly IPlayoutRepository _playoutRepository; |
private readonly IDbContextFactory<TvContext> _dbContextFactory; |
||||||
|
|
||||||
public GetAllPlayoutsHandler(IPlayoutRepository playoutRepository) => |
public GetAllPlayoutsHandler(IDbContextFactory<TvContext> dbContextFactory) => |
||||||
_playoutRepository = playoutRepository; |
_dbContextFactory = dbContextFactory; |
||||||
|
|
||||||
public Task<List<PlayoutViewModel>> Handle( |
public async Task<List<PlayoutNameViewModel>> Handle( |
||||||
GetAllPlayouts request, |
GetAllPlayouts request, |
||||||
CancellationToken cancellationToken) => |
CancellationToken cancellationToken) |
||||||
_playoutRepository.GetAll().Map(list => list.Map(ProjectToViewModel).ToList()); |
{ |
||||||
|
await using TvContext dbContext = _dbContextFactory.CreateDbContext(); |
||||||
|
return await dbContext.Playouts |
||||||
|
.Filter(p => p.Channel != null && p.ProgramSchedule != null) |
||||||
|
.Map(p => new PlayoutNameViewModel(p.Id, p.Channel.Name, p.Channel.Number, p.ProgramSchedule.Name)) |
||||||
|
.ToListAsync(cancellationToken); |
||||||
|
} |
||||||
} |
} |
||||||
} |
} |
||||||
|
|||||||
@ -1,7 +0,0 @@ |
|||||||
using LanguageExt; |
|
||||||
using MediatR; |
|
||||||
|
|
||||||
namespace ErsatzTV.Application.Playouts.Queries |
|
||||||
{ |
|
||||||
public record GetPlayoutById(int Id) : IRequest<Option<PlayoutViewModel>>; |
|
||||||
} |
|
||||||
@ -1,24 +0,0 @@ |
|||||||
using System.Threading; |
|
||||||
using System.Threading.Tasks; |
|
||||||
using ErsatzTV.Core.Interfaces.Repositories; |
|
||||||
using LanguageExt; |
|
||||||
using MediatR; |
|
||||||
using static ErsatzTV.Application.Playouts.Mapper; |
|
||||||
|
|
||||||
namespace ErsatzTV.Application.Playouts.Queries |
|
||||||
{ |
|
||||||
public class |
|
||||||
GetPlayoutByIdHandler : IRequestHandler<GetPlayoutById, Option<PlayoutViewModel>> |
|
||||||
{ |
|
||||||
private readonly IPlayoutRepository _playoutRepository; |
|
||||||
|
|
||||||
public GetPlayoutByIdHandler(IPlayoutRepository playoutRepository) => |
|
||||||
_playoutRepository = playoutRepository; |
|
||||||
|
|
||||||
public Task<Option<PlayoutViewModel>> Handle( |
|
||||||
GetPlayoutById request, |
|
||||||
CancellationToken cancellationToken) => |
|
||||||
_playoutRepository.Get(request.Id) |
|
||||||
.MapT(ProjectToViewModel); |
|
||||||
} |
|
||||||
} |
|
||||||
@ -0,0 +1,4 @@ |
|||||||
|
namespace ErsatzTV.Application.ProgramSchedules.Commands |
||||||
|
{ |
||||||
|
public record CreateProgramScheduleResult(int ProgramScheduleId) : EntityIdResult(ProgramScheduleId); |
||||||
|
} |
||||||
@ -1,9 +1,8 @@ |
|||||||
using System.Threading.Tasks; |
using ErsatzTV.Core; |
||||||
using ErsatzTV.Core; |
|
||||||
using LanguageExt; |
using LanguageExt; |
||||||
using MediatR; |
using MediatR; |
||||||
|
|
||||||
namespace ErsatzTV.Application.ProgramSchedules.Commands |
namespace ErsatzTV.Application.ProgramSchedules.Commands |
||||||
{ |
{ |
||||||
public record DeleteProgramSchedule(int ProgramScheduleId) : IRequest<Either<BaseError, Task>>; |
public record DeleteProgramSchedule(int ProgramScheduleId) : IRequest<Either<BaseError, LanguageExt.Unit>>; |
||||||
} |
} |
||||||
|
|||||||
@ -1,32 +1,43 @@ |
|||||||
using System.Threading; |
using System.Threading; |
||||||
using System.Threading.Tasks; |
using System.Threading.Tasks; |
||||||
using ErsatzTV.Core; |
using ErsatzTV.Core; |
||||||
using ErsatzTV.Core.Interfaces.Repositories; |
using ErsatzTV.Core.Domain; |
||||||
|
using ErsatzTV.Infrastructure.Data; |
||||||
|
using ErsatzTV.Infrastructure.Extensions; |
||||||
using LanguageExt; |
using LanguageExt; |
||||||
using MediatR; |
using MediatR; |
||||||
|
using Microsoft.EntityFrameworkCore; |
||||||
|
using Unit = LanguageExt.Unit; |
||||||
|
|
||||||
namespace ErsatzTV.Application.ProgramSchedules.Commands |
namespace ErsatzTV.Application.ProgramSchedules.Commands |
||||||
{ |
{ |
||||||
public class DeleteProgramScheduleHandler : IRequestHandler<DeleteProgramSchedule, Either<BaseError, Task>> |
public class DeleteProgramScheduleHandler : IRequestHandler<DeleteProgramSchedule, Either<BaseError, Unit>> |
||||||
{ |
{ |
||||||
private readonly IProgramScheduleRepository _programScheduleRepository; |
private readonly IDbContextFactory<TvContext> _dbContextFactory; |
||||||
|
|
||||||
public DeleteProgramScheduleHandler(IProgramScheduleRepository programScheduleRepository) => |
public DeleteProgramScheduleHandler(IDbContextFactory<TvContext> dbContextFactory) => |
||||||
_programScheduleRepository = programScheduleRepository; |
_dbContextFactory = dbContextFactory; |
||||||
|
|
||||||
public async Task<Either<BaseError, Task>> Handle( |
public async Task<Either<BaseError, Unit>> Handle( |
||||||
DeleteProgramSchedule request, |
DeleteProgramSchedule request, |
||||||
CancellationToken cancellationToken) => |
CancellationToken cancellationToken) |
||||||
(await ProgramScheduleMustExist(request)) |
{ |
||||||
.Map(DoDeletion) |
await using TvContext dbContext = _dbContextFactory.CreateDbContext(); |
||||||
.ToEither<Task>(); |
Validation<BaseError, ProgramSchedule> validation = await ProgramScheduleMustExist(dbContext, request); |
||||||
|
return await validation.Apply(ps => DoDeletion(dbContext, ps)); |
||||||
|
} |
||||||
|
|
||||||
private Task DoDeletion(int programScheduleId) => _programScheduleRepository.Delete(programScheduleId); |
private static Task<Unit> DoDeletion(TvContext dbContext, ProgramSchedule programSchedule) |
||||||
|
{ |
||||||
|
dbContext.ProgramSchedules.Remove(programSchedule); |
||||||
|
return dbContext.SaveChangesAsync().ToUnit(); |
||||||
|
} |
||||||
|
|
||||||
private async Task<Validation<BaseError, int>> ProgramScheduleMustExist( |
private Task<Validation<BaseError, ProgramSchedule>> ProgramScheduleMustExist( |
||||||
DeleteProgramSchedule deleteProgramSchedule) => |
TvContext dbContext, |
||||||
(await _programScheduleRepository.Get(deleteProgramSchedule.ProgramScheduleId)) |
DeleteProgramSchedule request) => |
||||||
.ToValidation<BaseError>($"ProgramSchedule {deleteProgramSchedule.ProgramScheduleId} does not exist.") |
dbContext.ProgramSchedules |
||||||
.Map(c => c.Id); |
.SelectOneAsync(ps => ps.Id, ps => ps.Id == request.ProgramScheduleId) |
||||||
|
.Map(o => o.ToValidation<BaseError>($"ProgramSchedule {request.ProgramScheduleId} does not exist.")); |
||||||
} |
} |
||||||
} |
} |
||||||
|
|||||||
@ -1,79 +1,94 @@ |
|||||||
using System.Threading; |
using System.Collections.Generic; |
||||||
|
using System.Threading; |
||||||
using System.Threading.Channels; |
using System.Threading.Channels; |
||||||
using System.Threading.Tasks; |
using System.Threading.Tasks; |
||||||
using ErsatzTV.Application.Playouts.Commands; |
using ErsatzTV.Application.Playouts.Commands; |
||||||
using ErsatzTV.Core; |
using ErsatzTV.Core; |
||||||
using ErsatzTV.Core.Domain; |
using ErsatzTV.Core.Domain; |
||||||
using ErsatzTV.Core.Interfaces.Repositories; |
using ErsatzTV.Infrastructure.Data; |
||||||
|
using ErsatzTV.Infrastructure.Extensions; |
||||||
using LanguageExt; |
using LanguageExt; |
||||||
using MediatR; |
using MediatR; |
||||||
using static ErsatzTV.Application.ProgramSchedules.Mapper; |
using Microsoft.EntityFrameworkCore; |
||||||
|
|
||||||
namespace ErsatzTV.Application.ProgramSchedules.Commands |
namespace ErsatzTV.Application.ProgramSchedules.Commands |
||||||
{ |
{ |
||||||
public class |
public class UpdateProgramScheduleHandler : |
||||||
UpdateProgramScheduleHandler : IRequestHandler<UpdateProgramSchedule, |
IRequestHandler<UpdateProgramSchedule, Either<BaseError, UpdateProgramScheduleResult>> |
||||||
Either<BaseError, ProgramScheduleViewModel>> |
|
||||||
{ |
{ |
||||||
private readonly ChannelWriter<IBackgroundServiceRequest> _channel; |
private readonly ChannelWriter<IBackgroundServiceRequest> _channel; |
||||||
private readonly IProgramScheduleRepository _programScheduleRepository; |
private readonly IDbContextFactory<TvContext> _dbContextFactory; |
||||||
|
|
||||||
public UpdateProgramScheduleHandler( |
public UpdateProgramScheduleHandler( |
||||||
IProgramScheduleRepository programScheduleRepository, |
IDbContextFactory<TvContext> dbContextFactory, |
||||||
ChannelWriter<IBackgroundServiceRequest> channel) |
ChannelWriter<IBackgroundServiceRequest> channel) |
||||||
{ |
{ |
||||||
_programScheduleRepository = programScheduleRepository; |
_dbContextFactory = dbContextFactory; |
||||||
_channel = channel; |
_channel = channel; |
||||||
} |
} |
||||||
|
|
||||||
public Task<Either<BaseError, ProgramScheduleViewModel>> Handle( |
public async Task<Either<BaseError, UpdateProgramScheduleResult>> Handle( |
||||||
UpdateProgramSchedule request, |
UpdateProgramSchedule request, |
||||||
CancellationToken cancellationToken) => |
CancellationToken cancellationToken) |
||||||
Validate(request) |
{ |
||||||
.MapT(c => ApplyUpdateRequest(c, request)) |
await using TvContext dbContext = _dbContextFactory.CreateDbContext(); |
||||||
.Bind(v => v.ToEitherAsync()); |
|
||||||
|
Validation<BaseError, ProgramSchedule> validation = await Validate(dbContext, request); |
||||||
|
return await validation.Apply(ps => ApplyUpdateRequest(dbContext, ps, request)); |
||||||
|
} |
||||||
|
|
||||||
private async Task<ProgramScheduleViewModel> ApplyUpdateRequest( |
private async Task<UpdateProgramScheduleResult> ApplyUpdateRequest( |
||||||
|
TvContext dbContext, |
||||||
ProgramSchedule programSchedule, |
ProgramSchedule programSchedule, |
||||||
UpdateProgramSchedule update) |
UpdateProgramSchedule request) |
||||||
{ |
{ |
||||||
// we need to rebuild playouts if the playback order or keep multi-episodes has been modified
|
// we need to rebuild playouts if the playback order or keep multi-episodes has been modified
|
||||||
bool needToRebuildPlayout = |
bool needToRebuildPlayout = |
||||||
programSchedule.MediaCollectionPlaybackOrder != update.MediaCollectionPlaybackOrder || |
programSchedule.MediaCollectionPlaybackOrder != request.MediaCollectionPlaybackOrder || |
||||||
programSchedule.KeepMultiPartEpisodesTogether != update.KeepMultiPartEpisodesTogether || |
programSchedule.KeepMultiPartEpisodesTogether != request.KeepMultiPartEpisodesTogether || |
||||||
programSchedule.TreatCollectionsAsShows != update.TreatCollectionsAsShows; |
programSchedule.TreatCollectionsAsShows != request.TreatCollectionsAsShows; |
||||||
|
|
||||||
programSchedule.Name = update.Name; |
programSchedule.Name = request.Name; |
||||||
programSchedule.MediaCollectionPlaybackOrder = update.MediaCollectionPlaybackOrder; |
programSchedule.MediaCollectionPlaybackOrder = request.MediaCollectionPlaybackOrder; |
||||||
programSchedule.KeepMultiPartEpisodesTogether = |
programSchedule.KeepMultiPartEpisodesTogether = |
||||||
update.MediaCollectionPlaybackOrder == PlaybackOrder.Shuffle && |
request.MediaCollectionPlaybackOrder == PlaybackOrder.Shuffle && |
||||||
update.KeepMultiPartEpisodesTogether; |
request.KeepMultiPartEpisodesTogether; |
||||||
programSchedule.TreatCollectionsAsShows = programSchedule.KeepMultiPartEpisodesTogether && |
programSchedule.TreatCollectionsAsShows = programSchedule.KeepMultiPartEpisodesTogether && |
||||||
update.TreatCollectionsAsShows; |
request.TreatCollectionsAsShows; |
||||||
await _programScheduleRepository.Update(programSchedule); |
|
||||||
|
await dbContext.SaveChangesAsync(); |
||||||
|
|
||||||
if (needToRebuildPlayout) |
if (needToRebuildPlayout) |
||||||
{ |
{ |
||||||
foreach (Playout playout in programSchedule.Playouts) |
List<int> playoutIds = await dbContext.Playouts |
||||||
|
.Filter(p => p.ProgramScheduleId == programSchedule.Id) |
||||||
|
.Map(p => p.Id) |
||||||
|
.ToListAsync(); |
||||||
|
|
||||||
|
foreach (int playoutId in playoutIds) |
||||||
{ |
{ |
||||||
await _channel.WriteAsync(new BuildPlayout(playout.Id, true)); |
await _channel.WriteAsync(new BuildPlayout(playoutId, true)); |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
return ProjectToViewModel(programSchedule); |
return new UpdateProgramScheduleResult(programSchedule.Id); |
||||||
} |
} |
||||||
|
|
||||||
private async Task<Validation<BaseError, ProgramSchedule>> Validate(UpdateProgramSchedule request) => |
private static async Task<Validation<BaseError, ProgramSchedule>> Validate( |
||||||
(await ProgramScheduleMustExist(request), ValidateName(request)) |
TvContext dbContext, |
||||||
.Apply((programScheduleToUpdate, _) => programScheduleToUpdate); |
UpdateProgramSchedule request) => |
||||||
|
(await ProgramScheduleMustExist(dbContext, request), ValidateName(request)) |
||||||
|
.Apply((programSchedule, _) => programSchedule); |
||||||
|
|
||||||
private async Task<Validation<BaseError, ProgramSchedule>> ProgramScheduleMustExist( |
private static Task<Validation<BaseError, ProgramSchedule>> ProgramScheduleMustExist( |
||||||
UpdateProgramSchedule updateProgramSchedule) => |
TvContext dbContext, |
||||||
(await _programScheduleRepository.GetWithPlayouts(updateProgramSchedule.ProgramScheduleId)) |
UpdateProgramSchedule request) => |
||||||
.ToValidation<BaseError>("ProgramSchedule does not exist."); |
dbContext.ProgramSchedules |
||||||
|
.SelectOneAsync(ps => ps.Id, ps => ps.Id == request.ProgramScheduleId) |
||||||
|
.Map(o => o.ToValidation<BaseError>("ProgramSchedule does not exist")); |
||||||
|
|
||||||
private Validation<BaseError, string> ValidateName(UpdateProgramSchedule updateProgramSchedule) => |
private static Validation<BaseError, string> ValidateName(UpdateProgramSchedule request) => |
||||||
updateProgramSchedule.NotEmpty(c => c.Name) |
request.NotEmpty(c => c.Name) |
||||||
.Bind(_ => updateProgramSchedule.NotLongerThan(50)(c => c.Name)); |
.Bind(_ => request.NotLongerThan(50)(c => c.Name)); |
||||||
} |
} |
||||||
} |
} |
||||||
|
|||||||
@ -0,0 +1,4 @@ |
|||||||
|
namespace ErsatzTV.Application.ProgramSchedules.Commands |
||||||
|
{ |
||||||
|
public record UpdateProgramScheduleResult(int ProgramScheduleId) : EntityIdResult(ProgramScheduleId); |
||||||
|
} |
||||||
@ -1,23 +1,33 @@ |
|||||||
using System.Collections.Generic; |
using System.Collections.Generic; |
||||||
using System.Linq; |
|
||||||
using System.Threading; |
using System.Threading; |
||||||
using System.Threading.Tasks; |
using System.Threading.Tasks; |
||||||
using ErsatzTV.Core.Interfaces.Repositories; |
using ErsatzTV.Infrastructure.Data; |
||||||
using MediatR; |
using MediatR; |
||||||
using static ErsatzTV.Application.ProgramSchedules.Mapper; |
using Microsoft.EntityFrameworkCore; |
||||||
|
|
||||||
namespace ErsatzTV.Application.ProgramSchedules.Queries |
namespace ErsatzTV.Application.ProgramSchedules.Queries |
||||||
{ |
{ |
||||||
public class GetAllProgramSchedulesHandler : IRequestHandler<GetAllProgramSchedules, List<ProgramScheduleViewModel>> |
public class GetAllProgramSchedulesHandler : IRequestHandler<GetAllProgramSchedules, List<ProgramScheduleViewModel>> |
||||||
{ |
{ |
||||||
private readonly IProgramScheduleRepository _programScheduleRepository; |
private readonly IDbContextFactory<TvContext> _dbContextFactory; |
||||||
|
|
||||||
public GetAllProgramSchedulesHandler(IProgramScheduleRepository programScheduleRepository) => |
public GetAllProgramSchedulesHandler(IDbContextFactory<TvContext> dbContextFactory) => |
||||||
_programScheduleRepository = programScheduleRepository; |
_dbContextFactory = dbContextFactory; |
||||||
|
|
||||||
public async Task<List<ProgramScheduleViewModel>> Handle( |
public async Task<List<ProgramScheduleViewModel>> Handle( |
||||||
GetAllProgramSchedules request, |
GetAllProgramSchedules request, |
||||||
CancellationToken cancellationToken) => |
CancellationToken cancellationToken) |
||||||
(await _programScheduleRepository.GetAll()).Map(ProjectToViewModel).ToList(); |
{ |
||||||
|
await using TvContext dbContext = _dbContextFactory.CreateDbContext(); |
||||||
|
return await dbContext.ProgramSchedules |
||||||
|
.Map( |
||||||
|
ps => new ProgramScheduleViewModel( |
||||||
|
ps.Id, |
||||||
|
ps.Name, |
||||||
|
ps.MediaCollectionPlaybackOrder, |
||||||
|
ps.KeepMultiPartEpisodesTogether, |
||||||
|
ps.TreatCollectionsAsShows)) |
||||||
|
.ToListAsync(cancellationToken); |
||||||
|
} |
||||||
} |
} |
||||||
} |
} |
||||||
|
|||||||
@ -1,24 +1,30 @@ |
|||||||
using System.Threading; |
using System.Threading; |
||||||
using System.Threading.Tasks; |
using System.Threading.Tasks; |
||||||
using ErsatzTV.Core.Interfaces.Repositories; |
using ErsatzTV.Infrastructure.Data; |
||||||
|
using ErsatzTV.Infrastructure.Extensions; |
||||||
using LanguageExt; |
using LanguageExt; |
||||||
using MediatR; |
using MediatR; |
||||||
|
using Microsoft.EntityFrameworkCore; |
||||||
using static ErsatzTV.Application.ProgramSchedules.Mapper; |
using static ErsatzTV.Application.ProgramSchedules.Mapper; |
||||||
|
|
||||||
namespace ErsatzTV.Application.ProgramSchedules.Queries |
namespace ErsatzTV.Application.ProgramSchedules.Queries |
||||||
{ |
{ |
||||||
public class |
public class GetProgramScheduleByIdHandler : |
||||||
GetProgramScheduleByIdHandler : IRequestHandler<GetProgramScheduleById, Option<ProgramScheduleViewModel>> |
IRequestHandler<GetProgramScheduleById, Option<ProgramScheduleViewModel>> |
||||||
{ |
{ |
||||||
private readonly IProgramScheduleRepository _programScheduleRepository; |
private readonly IDbContextFactory<TvContext> _dbContextFactory; |
||||||
|
|
||||||
public GetProgramScheduleByIdHandler(IProgramScheduleRepository programScheduleRepository) => |
public GetProgramScheduleByIdHandler(IDbContextFactory<TvContext> dbContextFactory) => |
||||||
_programScheduleRepository = programScheduleRepository; |
_dbContextFactory = dbContextFactory; |
||||||
|
|
||||||
public Task<Option<ProgramScheduleViewModel>> Handle( |
public async Task<Option<ProgramScheduleViewModel>> Handle( |
||||||
GetProgramScheduleById request, |
GetProgramScheduleById request, |
||||||
CancellationToken cancellationToken) => |
CancellationToken cancellationToken) |
||||||
_programScheduleRepository.Get(request.Id) |
{ |
||||||
|
await using TvContext dbContext = _dbContextFactory.CreateDbContext(); |
||||||
|
return await dbContext.ProgramSchedules |
||||||
|
.SelectOneAsync(ps => ps.Id, ps => ps.Id == request.Id) |
||||||
.MapT(ProjectToViewModel); |
.MapT(ProjectToViewModel); |
||||||
|
} |
||||||
} |
} |
||||||
} |
} |
||||||
|
|||||||
@ -1,8 +1,7 @@ |
|||||||
using System.Collections.Generic; |
using System.Collections.Generic; |
||||||
using LanguageExt; |
|
||||||
using MediatR; |
using MediatR; |
||||||
|
|
||||||
namespace ErsatzTV.Application.ProgramSchedules.Queries |
namespace ErsatzTV.Application.ProgramSchedules.Queries |
||||||
{ |
{ |
||||||
public record GetProgramScheduleItems(int Id) : IRequest<Option<IEnumerable<ProgramScheduleItemViewModel>>>; |
public record GetProgramScheduleItems(int Id) : IRequest<List<ProgramScheduleItemViewModel>>; |
||||||
} |
} |
||||||
|
|||||||
@ -1,25 +1,50 @@ |
|||||||
using System.Collections.Generic; |
using System.Collections.Generic; |
||||||
|
using System.Linq; |
||||||
using System.Threading; |
using System.Threading; |
||||||
using System.Threading.Tasks; |
using System.Threading.Tasks; |
||||||
using ErsatzTV.Core.Interfaces.Repositories; |
using ErsatzTV.Core.Domain; |
||||||
|
using ErsatzTV.Infrastructure.Data; |
||||||
using LanguageExt; |
using LanguageExt; |
||||||
using MediatR; |
using MediatR; |
||||||
|
using Microsoft.EntityFrameworkCore; |
||||||
using static ErsatzTV.Application.ProgramSchedules.Mapper; |
using static ErsatzTV.Application.ProgramSchedules.Mapper; |
||||||
|
|
||||||
namespace ErsatzTV.Application.ProgramSchedules.Queries |
namespace ErsatzTV.Application.ProgramSchedules.Queries |
||||||
{ |
{ |
||||||
public class GetProgramScheduleItemsHandler : IRequestHandler<GetProgramScheduleItems, |
public class GetProgramScheduleItemsHandler : |
||||||
Option<IEnumerable<ProgramScheduleItemViewModel>>> |
IRequestHandler<GetProgramScheduleItems, List<ProgramScheduleItemViewModel>> |
||||||
{ |
{ |
||||||
private readonly IProgramScheduleRepository _programScheduleRepository; |
private readonly IDbContextFactory<TvContext> _dbContextFactory; |
||||||
|
|
||||||
public GetProgramScheduleItemsHandler(IProgramScheduleRepository programScheduleRepository) => |
public GetProgramScheduleItemsHandler(IDbContextFactory<TvContext> dbContextFactory) => |
||||||
_programScheduleRepository = programScheduleRepository; |
_dbContextFactory = dbContextFactory; |
||||||
|
|
||||||
public Task<Option<IEnumerable<ProgramScheduleItemViewModel>>> Handle( |
public async Task<List<ProgramScheduleItemViewModel>> Handle( |
||||||
GetProgramScheduleItems request, |
GetProgramScheduleItems request, |
||||||
CancellationToken cancellationToken) => |
CancellationToken cancellationToken) |
||||||
_programScheduleRepository.GetItems(request.Id) |
{ |
||||||
.MapT(programScheduleItems => programScheduleItems.Map(ProjectToViewModel)); |
await using TvContext dbContext = _dbContextFactory.CreateDbContext(); |
||||||
|
return await dbContext.ProgramScheduleItems |
||||||
|
.Filter(psi => psi.ProgramScheduleId == request.Id) |
||||||
|
.Include(i => i.Collection) |
||||||
|
.Include(i => i.MediaItem) |
||||||
|
.ThenInclude(i => (i as Movie).MovieMetadata) |
||||||
|
.ThenInclude(mm => mm.Artwork) |
||||||
|
.Include(i => i.MediaItem) |
||||||
|
.ThenInclude(i => (i as Season).SeasonMetadata) |
||||||
|
.ThenInclude(sm => sm.Artwork) |
||||||
|
.Include(i => i.MediaItem) |
||||||
|
.ThenInclude(i => (i as Season).Show) |
||||||
|
.ThenInclude(s => s.ShowMetadata) |
||||||
|
.ThenInclude(sm => sm.Artwork) |
||||||
|
.Include(i => i.MediaItem) |
||||||
|
.ThenInclude(i => (i as Show).ShowMetadata) |
||||||
|
.ThenInclude(sm => sm.Artwork) |
||||||
|
.Include(i => i.MediaItem) |
||||||
|
.ThenInclude(i => (i as Artist).ArtistMetadata) |
||||||
|
.ThenInclude(am => am.Artwork) |
||||||
|
.ToListAsync(cancellationToken) |
||||||
|
.Map(programScheduleItems => programScheduleItems.Map(ProjectToViewModel).ToList()); |
||||||
|
} |
||||||
} |
} |
||||||
} |
} |
||||||
|
|||||||
@ -1,7 +0,0 @@ |
|||||||
using LanguageExt; |
|
||||||
using MediatR; |
|
||||||
|
|
||||||
namespace ErsatzTV.Application.Television.Queries |
|
||||||
{ |
|
||||||
public record GetTelevisionEpisodeById(int EpisodeId) : IRequest<Option<TelevisionEpisodeViewModel>>; |
|
||||||
} |
|
||||||
@ -1,24 +0,0 @@ |
|||||||
using System.Threading; |
|
||||||
using System.Threading.Tasks; |
|
||||||
using ErsatzTV.Core.Interfaces.Repositories; |
|
||||||
using LanguageExt; |
|
||||||
using MediatR; |
|
||||||
using static ErsatzTV.Application.Television.Mapper; |
|
||||||
|
|
||||||
namespace ErsatzTV.Application.Television.Queries |
|
||||||
{ |
|
||||||
public class |
|
||||||
GetTelevisionEpisodeByIdHandler : IRequestHandler<GetTelevisionEpisodeById, Option<TelevisionEpisodeViewModel>> |
|
||||||
{ |
|
||||||
private readonly ITelevisionRepository _televisionRepository; |
|
||||||
|
|
||||||
public GetTelevisionEpisodeByIdHandler(ITelevisionRepository televisionRepository) => |
|
||||||
_televisionRepository = televisionRepository; |
|
||||||
|
|
||||||
public Task<Option<TelevisionEpisodeViewModel>> Handle( |
|
||||||
GetTelevisionEpisodeById request, |
|
||||||
CancellationToken cancellationToken) => |
|
||||||
_televisionRepository.GetEpisode(request.EpisodeId) |
|
||||||
.MapT(ProjectToViewModel); |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,10 +0,0 @@ |
|||||||
namespace ErsatzTV.Application.Television |
|
||||||
{ |
|
||||||
public record TelevisionEpisodeViewModel( |
|
||||||
int ShowId, |
|
||||||
int SeasonId, |
|
||||||
int Episode, |
|
||||||
string Title, |
|
||||||
string Plot, |
|
||||||
string Poster); |
|
||||||
} |
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue