From 954101548a102a20216cb2f0b0df9294f4d3e449 Mon Sep 17 00:00:00 2001 From: XShine555 Date: Thu, 19 Mar 2026 19:50:15 +0100 Subject: [PATCH] Update playlist and some changes --- Application/Application.csproj | 5 - .../Contracts/Application/IFileData.cs | 13 ++ .../CreatePlayList/CreatePlayListCommand.cs | 5 +- .../CreatePlayListCommandHandler.cs | 56 +++++---- .../DeletePlayListCommandHandler.cs | 33 ++--- .../UpdatePlayList/UpdatePlayListCommand.cs | 15 +++ .../UpdatePlayListCommandHandler.cs | 115 ++++++++++++++++++ Domain/Entities/PlayList.cs | 3 +- 8 files changed, 196 insertions(+), 49 deletions(-) create mode 100644 Application/Contracts/Application/IFileData.cs create mode 100644 Application/PlayLists/Commands/UpdatePlayList/UpdatePlayListCommand.cs create mode 100644 Application/PlayLists/Commands/UpdatePlayList/UpdatePlayListCommandHandler.cs diff --git a/Application/Application.csproj b/Application/Application.csproj index 0ae48f6..cde91d6 100644 --- a/Application/Application.csproj +++ b/Application/Application.csproj @@ -24,9 +24,4 @@ - - - - - diff --git a/Application/Contracts/Application/IFileData.cs b/Application/Contracts/Application/IFileData.cs new file mode 100644 index 0000000..96a9347 --- /dev/null +++ b/Application/Contracts/Application/IFileData.cs @@ -0,0 +1,13 @@ +namespace Musify.Application.Contracts.Application +{ + public interface IFileData + { + Stream FileStream { get; } + + string FileName { get; } + + string FileType { get; } + + string ContentType { get; } + } +} \ No newline at end of file diff --git a/Application/PlayLists/Commands/CreatePlayList/CreatePlayListCommand.cs b/Application/PlayLists/Commands/CreatePlayList/CreatePlayListCommand.cs index c00a97b..b59d8ec 100644 --- a/Application/PlayLists/Commands/CreatePlayList/CreatePlayListCommand.cs +++ b/Application/PlayLists/Commands/CreatePlayList/CreatePlayListCommand.cs @@ -1,5 +1,6 @@ using Ardalis.Result; using DispatchR.Abstractions.Send; +using Musify.Application.Contracts.Application; using Musify.Application.PlayLists.Contracts; namespace Musify.Application.PlayLists.Commands.CreatePlayList @@ -8,8 +9,6 @@ namespace Musify.Application.PlayLists.Commands.CreatePlayList Guid UserId, string Name, string Description, - Stream PictureStream, - string PictureFileType, - string PictureContentType) + IFileData? Picture) : IRequest> >; } \ No newline at end of file diff --git a/Application/PlayLists/Commands/CreatePlayList/CreatePlayListCommandHandler.cs b/Application/PlayLists/Commands/CreatePlayList/CreatePlayListCommandHandler.cs index f122f2f..32c3ee8 100644 --- a/Application/PlayLists/Commands/CreatePlayList/CreatePlayListCommandHandler.cs +++ b/Application/PlayLists/Commands/CreatePlayList/CreatePlayListCommandHandler.cs @@ -33,36 +33,37 @@ namespace Musify.Application.PlayLists.Commands.CreatePlayList Name = request.Name, NormalizedName = request.Name.Trim().ToUpperInvariant(), Description = request.Description, - OriginalPictureKeyName = $"{imageId}{request.PictureFileType}", SmallPictureKeyName = playListConfiguration.Routes.PresetSmallPicture, MediumPictureKeyName = playListConfiguration.Routes.PresetMediumPicture, LargePictureKeyName = playListConfiguration.Routes.PresetLargePicture, }; - await database.PlayLists.AddAsync(playList, cancellationToken); - var imageKeyName = $"{playListConfiguration.Routes.OriginalPictures}/{imageId}{request.PictureFileType}"; - - var uploadResult = await storageHandler.UploadFileAsync( - request.PictureStream, - request.PictureContentType, - storageConfiguration.BucketName, - imageKeyName, - cancellationToken); - - if (!uploadResult.IsSuccess) + if (request.Picture is not null) { - logger.LogError("Failed to upload picture for PlayList with Id={PlayListId} to storage. Storage handler returned error: {ErrorMessage}", - playList.Id, string.Join("; ", uploadResult.Errors)); - return Result.Error($"Failed to upload picture for PlayList with Id {playList.Id} to storage."); - } + playList.OriginalPictureKeyName = $"{imageId}{request.Picture.FileType}"; + var imageKeyName = $"{playListConfiguration.Routes.OriginalPictures}/{imageId}{request.Picture.FileType}"; - logger.LogInformation("PlayList with Id={PlayListId} created successfully for UserId={UserId}.", playList.Id, request.UserId); + var uploadResult = await storageHandler.UploadFileAsync( + request.Picture.FileStream, + request.Picture.ContentType, + storageConfiguration.BucketName, + imageKeyName, + cancellationToken); - await publishEndpoint.Publish(new ResizePictureEvent( - storageConfiguration.BucketName, - imageKeyName, - [ - new ResizePictureItems( + if (!uploadResult.IsSuccess) + { + logger.LogError("Failed to upload picture for PlayList with Id={PlayListId} to storage. Storage handler returned error: {ErrorMessage}", + playList.Id, string.Join("; ", uploadResult.Errors)); + return Result.Error($"Failed to upload picture for PlayList with Id {playList.Id} to storage."); + } + + logger.LogInformation("PlayList with Id={PlayListId} created successfully for UserId={UserId}.", playList.Id, request.UserId); + + await publishEndpoint.Publish(new ResizePictureEvent( + storageConfiguration.BucketName, + imageKeyName, + [ + new ResizePictureItems( playListConfiguration.PicturesSizes.SmallPictureWidth, playListConfiguration.PicturesSizes.SmallPictureHeight, playListConfiguration.Routes.SmallPictures), @@ -74,10 +75,17 @@ namespace Musify.Application.PlayLists.Commands.CreatePlayList playListConfiguration.PicturesSizes.LargePictureWidth, playListConfiguration.PicturesSizes.LargePictureHeight, playListConfiguration.Routes.LargePictures) - ] ), cancellationToken); + ] ), cancellationToken); + } + else + { + logger.LogInformation("No picture provided for PlayList with Id={PlayListId}. Using Preset pictures.", playList.Id); + } + + await database.PlayLists.AddAsync(playList, cancellationToken); + await database.SaveChangesAsync(cancellationToken); logger.LogInformation("Picture for PlayList with Id={PlayListId} ", playList.Id); - return Result.Created(PlayListResponse.FromEntity(playList)); } } diff --git a/Application/PlayLists/Commands/DeletePlayList/DeletePlayListCommandHandler.cs b/Application/PlayLists/Commands/DeletePlayList/DeletePlayListCommandHandler.cs index 5738e15..ca066f3 100644 --- a/Application/PlayLists/Commands/DeletePlayList/DeletePlayListCommandHandler.cs +++ b/Application/PlayLists/Commands/DeletePlayList/DeletePlayListCommandHandler.cs @@ -28,24 +28,27 @@ namespace Musify.Application.PlayLists.Commands.DeletePlayList return Result.Unauthorized(); } - await publishEndpoint.Publish(new RemoveFileEvent( - storageConfiguration.BucketName, - playList.OriginalPictureKeyName), cancellationToken); - - if (playList.SmallPictureKeyName != playListConfiguration.Routes.PresetSmallPicture) + if (!string.IsNullOrWhiteSpace(playList.OriginalPictureKeyName)) + { await publishEndpoint.Publish(new RemoveFileEvent( - storageConfiguration.BucketName, - playList.SmallPictureKeyName), cancellationToken); + storageConfiguration.BucketName, + playList.OriginalPictureKeyName), cancellationToken); - if (playList.MediumPictureKeyName != playListConfiguration.Routes.PresetMediumPicture) - await publishEndpoint.Publish(new RemoveFileEvent( - storageConfiguration.BucketName, - playList.MediumPictureKeyName), cancellationToken); + if (playList.SmallPictureKeyName != playListConfiguration.Routes.PresetSmallPicture) + await publishEndpoint.Publish(new RemoveFileEvent( + storageConfiguration.BucketName, + playList.SmallPictureKeyName), cancellationToken); - if (playList.LargePictureKeyName != playListConfiguration.Routes.PresetLargePicture) - await publishEndpoint.Publish(new RemoveFileEvent( - storageConfiguration.BucketName, - playList.LargePictureKeyName), cancellationToken); + if (playList.MediumPictureKeyName != playListConfiguration.Routes.PresetMediumPicture) + await publishEndpoint.Publish(new RemoveFileEvent( + storageConfiguration.BucketName, + playList.MediumPictureKeyName), cancellationToken); + + if (playList.LargePictureKeyName != playListConfiguration.Routes.PresetLargePicture) + await publishEndpoint.Publish(new RemoveFileEvent( + storageConfiguration.BucketName, + playList.LargePictureKeyName), cancellationToken); + } database.PlayLists.Remove(playList); await database.SaveChangesAsync(cancellationToken); diff --git a/Application/PlayLists/Commands/UpdatePlayList/UpdatePlayListCommand.cs b/Application/PlayLists/Commands/UpdatePlayList/UpdatePlayListCommand.cs new file mode 100644 index 0000000..1ef0e49 --- /dev/null +++ b/Application/PlayLists/Commands/UpdatePlayList/UpdatePlayListCommand.cs @@ -0,0 +1,15 @@ +using Ardalis.Result; +using DispatchR.Abstractions.Send; +using Musify.Application.Contracts.Application; +using Musify.Application.PlayLists.Contracts; + +namespace Musify.Application.PlayLists.Commands.UpdatePlayList +{ + public record UpdatePlayListCommand( + Guid UserId, + Guid PlayListId, + string? NewName, + string? NewDescription, + IFileData? NewPicture) + : IRequest> >; +} \ No newline at end of file diff --git a/Application/PlayLists/Commands/UpdatePlayList/UpdatePlayListCommandHandler.cs b/Application/PlayLists/Commands/UpdatePlayList/UpdatePlayListCommandHandler.cs new file mode 100644 index 0000000..4a7b7de --- /dev/null +++ b/Application/PlayLists/Commands/UpdatePlayList/UpdatePlayListCommandHandler.cs @@ -0,0 +1,115 @@ +using Ardalis.Result; +using DispatchR.Abstractions.Send; +using MassTransit; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging; +using Musify.Application.Configuration; +using Musify.Application.Contracts.Infrastructure; +using Musify.Application.Events; +using Musify.Application.PlayLists.Contracts; + +namespace Musify.Application.PlayLists.Commands.UpdatePlayList +{ + public class UpdatePlayListCommandHandler(IPublishEndpoint publishEndpoint, IDatabase database, IStorageHandler storageHandler, + ILogger logger, StorageConfiguration storageConfiguration, PlayListConfiguration playListConfiguration) + : IRequestHandler> > + { + public async Task> Handle(UpdatePlayListCommand request, CancellationToken cancellationToken) + { + var playList = await database.PlayLists.SingleOrDefaultAsync(pl => pl.Id == request.PlayListId, cancellationToken); + + if (playList is null) + { + logger.LogInformation("PlayList with id {PlayListId} not found", request.PlayListId); + return Result.NotFound(); + } + + if (playList.UserId != request.UserId) + { + logger.LogWarning("User with id {UserId} is not the owner of the PlayList with id {PlayListId}", request.UserId, request.PlayListId); + return Result.Unauthorized(); + } + + if (!string.IsNullOrWhiteSpace(request.NewName)) + playList.Name = request.NewName; + + if (!string.IsNullOrWhiteSpace(request.NewDescription)) + playList.Description = request.NewDescription; + + if (request.NewPicture is null) + { + database.PlayLists.Update(playList); + await database.SaveChangesAsync(cancellationToken); + logger.LogInformation("Updated PlayList with id={PlayListId}.", playList.Id); + return Result.Success(PlayListResponse.FromEntity(playList)); + } + + if (!string.IsNullOrWhiteSpace(playList.OriginalPictureKeyName)) + { + await publishEndpoint.Publish(new RemoveFileEvent( + storageConfiguration.BucketName, + playList.OriginalPictureKeyName), cancellationToken); + logger.LogInformation("Published event to remove old picture with key name {KeyName} from bucket {BucketName}", + playList.OriginalPictureKeyName, storageConfiguration.BucketName); + + if (playList.SmallPictureKeyName != playListConfiguration.Routes.PresetSmallPicture) + await publishEndpoint.Publish(new RemoveFileEvent( + storageConfiguration.BucketName, + playList.SmallPictureKeyName), cancellationToken); + + if (playList.MediumPictureKeyName != playListConfiguration.Routes.PresetMediumPicture) + await publishEndpoint.Publish(new RemoveFileEvent( + storageConfiguration.BucketName, + playList.MediumPictureKeyName), cancellationToken); + + if (playList.LargePictureKeyName != playListConfiguration.Routes.PresetLargePicture) + await publishEndpoint.Publish(new RemoveFileEvent( + storageConfiguration.BucketName, + playList.LargePictureKeyName), cancellationToken); + } + + var newImageId = Guid.NewGuid(); + var imageKeyName = $"{playListConfiguration.Routes.OriginalPictures}/{newImageId}{request.NewPicture.FileType}"; + + var uploadResult = await storageHandler.UploadFileAsync( + request.NewPicture.FileStream, + request.NewPicture.ContentType, + storageConfiguration.BucketName, + imageKeyName, + cancellationToken); + + if (!uploadResult.IsSuccess) + { + logger.LogError("Failed to upload picture for PlayList with Id={PlayListId} to storage. Storage handler returned error: {ErrorMessage}", + playList.Id, string.Join("; ", uploadResult.Errors)); + return Result.Error($"Failed to upload picture for PlayList with Id {playList.Id} to storage."); + } + + playList.OriginalPictureKeyName = newImageId.ToString(); + await publishEndpoint.Publish(new ResizePictureEvent( + storageConfiguration.BucketName, + imageKeyName, + [ + new ResizePictureItems( + playListConfiguration.PicturesSizes.SmallPictureWidth, + playListConfiguration.PicturesSizes.SmallPictureHeight, + playListConfiguration.Routes.SmallPictures), + new ResizePictureItems( + playListConfiguration.PicturesSizes.MediumPictureWidth, + playListConfiguration.PicturesSizes.MediumPictureHeight, + playListConfiguration.Routes.MediumPictures), + new ResizePictureItems( + playListConfiguration.PicturesSizes.LargePictureWidth, + playListConfiguration.PicturesSizes.LargePictureHeight, + playListConfiguration.Routes.LargePictures) + ] + ), cancellationToken); + + database.PlayLists.Update(playList); + await database.SaveChangesAsync(cancellationToken); + + logger.LogInformation("Updated PlayList with id={PlayListId}.", playList.Id); + return Result.Success(PlayListResponse.FromEntity(playList)); + } + } +} \ No newline at end of file diff --git a/Domain/Entities/PlayList.cs b/Domain/Entities/PlayList.cs index 876854e..7975558 100644 --- a/Domain/Entities/PlayList.cs +++ b/Domain/Entities/PlayList.cs @@ -25,9 +25,8 @@ namespace Musify.Domain.Entities [MaxLength(254)] public required string Description { get; set; } = "No description was provided."; - [Required] [MaxLength(64)] - public required string OriginalPictureKeyName { get; set; } + public string? OriginalPictureKeyName { get; set; } [Required] [MaxLength(64)]