Files
ersatztv/ErsatzTV.Application/FFmpegProfiles/Commands/DeleteFFmpegProfileHandler.cs
T
timothy 861827dcbc
Build ErsatzTV Image / Build & test (.NET) (pull_request) Successful in 5m12s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Successful in 6m13s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Has been skipped
feat(api): standardize ffmpeg profile endpoints
refs #38
2026-06-30 07:29:47 +02:00

96 lines
3.6 KiB
C#

using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Errors;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Interfaces.Search;
using ErsatzTV.Infrastructure.Data;
using ErsatzTV.Infrastructure.Extensions;
using Microsoft.EntityFrameworkCore;
namespace ErsatzTV.Application.FFmpegProfiles;
public class DeleteFFmpegProfileHandler(
IDbContextFactory<TvContext> dbContextFactory,
IConfigElementRepository configElementRepository,
ISearchTargets searchTargets)
: IRequestHandler<DeleteFFmpegProfile, Either<BaseError, Unit>>
{
public async Task<Either<BaseError, Unit>> Handle(
DeleteFFmpegProfile request,
CancellationToken cancellationToken)
{
await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken);
Option<FFmpegProfile> maybeProfile = await FFmpegProfileMustExist(dbContext, request, cancellationToken);
return await maybeProfile.Match(
Some: async profile =>
{
Validation<BaseError, FFmpegProfile> validation = await Validate(
dbContext,
request,
profile,
cancellationToken);
return await validation.Apply(p => DoDeletion(dbContext, p));
},
None: () => Task.FromResult<Either<BaseError, Unit>>(
new NotFoundError($"FFmpegProfile {request.FFmpegProfileId} does not exist")));
}
private async Task<Unit> DoDeletion(TvContext dbContext, FFmpegProfile ffmpegProfile)
{
dbContext.FFmpegProfiles.Remove(ffmpegProfile);
await dbContext.SaveChangesAsync();
searchTargets.SearchTargetsChanged();
return Unit.Default;
}
private async Task<Validation<BaseError, FFmpegProfile>> Validate(
TvContext dbContext,
DeleteFFmpegProfile request,
FFmpegProfile profile,
CancellationToken cancellationToken) =>
(await FFmpegProfileMustNotBeUsed(dbContext, request, cancellationToken),
await FFmpegProfileMustNotBeDefault(request, cancellationToken))
.Apply((_, _) => profile);
private static Task<Option<FFmpegProfile>> FFmpegProfileMustExist(
TvContext dbContext,
DeleteFFmpegProfile request,
CancellationToken cancellationToken) =>
dbContext.FFmpegProfiles
.SelectOneAsync(p => p.Id, p => p.Id == request.FFmpegProfileId, cancellationToken);
private static async Task<Validation<BaseError, Unit>> FFmpegProfileMustNotBeUsed(
TvContext dbContext,
DeleteFFmpegProfile request,
CancellationToken cancellationToken)
{
int count = await dbContext.Channels
.AsNoTracking()
.Where(c => c.FFmpegProfileId == request.FFmpegProfileId)
.CountAsync(cancellationToken);
if (count > 0)
{
return BaseError.New(
$"Cannot delete FFmpeg Profile that is used by {count} {(count > 1 ? "channels" : "channel")}");
}
return Unit.Default;
}
private async Task<Validation<BaseError, Unit>> FFmpegProfileMustNotBeDefault(
DeleteFFmpegProfile request,
CancellationToken cancellationToken)
{
Option<int> defaultFFmpegProfileId =
await configElementRepository.GetValue<int>(ConfigElementKey.FFmpegDefaultProfileId, cancellationToken);
if (defaultFFmpegProfileId.Any(id => id == request.FFmpegProfileId))
{
return BaseError.New("Cannot delete default FFmpeg Profile");
}
return Unit.Default;
}
}