From 4387aa146eb41da86e5c7213fe2ae3df45d41117 Mon Sep 17 00:00:00 2001 From: XShine555 Date: Fri, 20 Mar 2026 01:35:12 +0100 Subject: [PATCH] QOL Changes --- Application/Configuration/StorageSettings.cs | 2 + .../CreatePlayListCommandHandler.cs | 50 ++++--- .../DeletePlayListCommandHandler.cs | 67 ++++++++-- .../UpdatePlayListCommandHandler.cs | 124 +++++++++++++----- .../GetPlayListById/GetPlayListByIdQuery.cs | 2 +- .../Queries/GetPlayLists/GetPlayListsQuery.cs | 2 +- .../GetPlayListsByUserIdQuery.cs | 2 +- .../GetPlayListsByUserIdQueryHandler.cs | 3 +- .../Commands/CreateUser/CreateUserCommand.cs | 2 +- .../Commands/DeleteUser/DeleteUserCommand.cs | 2 +- .../StorageClientConfiguration.cs | 5 +- .../Storage/StorageDependencyInjection.cs | 1 - 12 files changed, 183 insertions(+), 79 deletions(-) diff --git a/Application/Configuration/StorageSettings.cs b/Application/Configuration/StorageSettings.cs index fa912b5..f2c0af1 100644 --- a/Application/Configuration/StorageSettings.cs +++ b/Application/Configuration/StorageSettings.cs @@ -7,6 +7,8 @@ namespace Musify.Application.Configuration public const string SectionName = "Storage"; [Required] + [MinLength(3)] + [MaxLength(63)] public required string BucketName { get; set; } } } diff --git a/Application/PlayLists/Commands/CreatePlayList/CreatePlayListCommandHandler.cs b/Application/PlayLists/Commands/CreatePlayList/CreatePlayListCommandHandler.cs index 3951ffd..db4f02e 100644 --- a/Application/PlayLists/Commands/CreatePlayList/CreatePlayListCommandHandler.cs +++ b/Application/PlayLists/Commands/CreatePlayList/CreatePlayListCommandHandler.cs @@ -25,8 +25,6 @@ namespace Musify.Application.PlayLists.Commands.CreatePlayList return Result.NotFound($"User with Id {request.UserId} does not exist."); } - var imageId = Guid.NewGuid(); - var playList = new PlayList { UserId = request.UserId, @@ -40,14 +38,15 @@ namespace Musify.Application.PlayLists.Commands.CreatePlayList if (request.Picture is not null) { - playList.OriginalPictureKeyName = $"{imageId}{request.Picture.FileType}"; - var imageKeyName = $"{playListConfiguration.Routes.OriginalPictures}/{imageId}{request.Picture.FileType}"; + var imageId = Guid.NewGuid(); + var pictureName = $"{imageId}{request.Picture.FileType}"; + var originalImageStorageKey = Path.Join(playListConfiguration.Routes.OriginalPictures, pictureName); var uploadResult = await storageHandler.UploadFileAsync( request.Picture.FileStream, request.Picture.ContentType, storageConfiguration.BucketName, - imageKeyName, + originalImageStorageKey, cancellationToken); if (!uploadResult.IsSuccess) @@ -57,25 +56,34 @@ namespace Musify.Application.PlayLists.Commands.CreatePlayList return Result.Error($"Failed to upload picture for PlayList with Id {playList.Id} to storage."); } + playList.OriginalPictureKeyName = pictureName; logger.LogInformation("Playlist image uploaded successfully for PlayList with Id={PlayListId}.", playList.Id); - await publishEndpoint.Publish(new ResizePictureEvent( - storageConfiguration.BucketName, - imageKeyName, - [ + try + { + await publishEndpoint.Publish(new ResizePictureEvent( + storageConfiguration.BucketName, + originalImageStorageKey, + [ 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); + 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); + } + catch (Exception exception) + { + logger.LogError(exception, "Failed to publish resize picture event for PlayList with id={PlayListId}.", playList.Id); + return Result.Error($"Failed to publish resize picture event for PlayList with id {playList.Id}."); + } } else { diff --git a/Application/PlayLists/Commands/DeletePlayList/DeletePlayListCommandHandler.cs b/Application/PlayLists/Commands/DeletePlayList/DeletePlayListCommandHandler.cs index 0b73404..a92e092 100644 --- a/Application/PlayLists/Commands/DeletePlayList/DeletePlayListCommandHandler.cs +++ b/Application/PlayLists/Commands/DeletePlayList/DeletePlayListCommandHandler.cs @@ -5,6 +5,7 @@ using Microsoft.Extensions.Logging; using Musify.Application.Configuration; using Musify.Application.Contracts.Infrastructure; using Musify.Application.Events; +using Musify.Application.PlayLists; namespace Musify.Application.PlayLists.Commands.DeletePlayList { @@ -28,26 +29,66 @@ namespace Musify.Application.PlayLists.Commands.DeletePlayList return Result.Unauthorized(); } - if (!string.IsNullOrWhiteSpace(playList.OriginalPictureKeyName)) + if (!string.IsNullOrWhiteSpace(playList.OriginalPictureKeyName)) { - await publishEndpoint.Publish(new RemoveFileEvent( - storageConfiguration.BucketName, - playList.OriginalPictureKeyName), cancellationToken); + var originalImageStorageKey = Path.Join(playListConfiguration.Routes.OriginalPictures, playList.OriginalPictureKeyName); + + try + { + await publishEndpoint.Publish(new RemoveFileEvent( + storageConfiguration.BucketName, + originalImageStorageKey), cancellationToken); + } + catch (Exception exception) + { + logger.LogError(exception, "Failed to publish remove file event for original picture of PlayList id={PlayListId}.", playList.Id); + return Result.Error($"Failed to publish remove file event for PlayList with id {playList.Id}."); + } if (playList.SmallPictureKeyName != playListConfiguration.Routes.PresetSmallPicture) - await publishEndpoint.Publish(new RemoveFileEvent( - storageConfiguration.BucketName, - playList.SmallPictureKeyName), cancellationToken); + { + try + { + await publishEndpoint.Publish(new RemoveFileEvent( + storageConfiguration.BucketName, + playList.SmallPictureKeyName), cancellationToken); + } + catch (Exception exception) + { + logger.LogError(exception, "Failed to publish remove file event for small picture of PlayList id={PlayListId}.", playList.Id); + return Result.Error($"Failed to publish remove file event for PlayList with id {playList.Id}."); + } + } if (playList.MediumPictureKeyName != playListConfiguration.Routes.PresetMediumPicture) - await publishEndpoint.Publish(new RemoveFileEvent( - storageConfiguration.BucketName, - playList.MediumPictureKeyName), cancellationToken); + { + try + { + await publishEndpoint.Publish(new RemoveFileEvent( + storageConfiguration.BucketName, + playList.MediumPictureKeyName), cancellationToken); + } + catch (Exception exception) + { + logger.LogError(exception, "Failed to publish remove file event for medium picture of PlayList id={PlayListId}.", playList.Id); + return Result.Error($"Failed to publish remove file event for PlayList with id {playList.Id}."); + } + } if (playList.LargePictureKeyName != playListConfiguration.Routes.PresetLargePicture) - await publishEndpoint.Publish(new RemoveFileEvent( - storageConfiguration.BucketName, - playList.LargePictureKeyName), cancellationToken); + { + try + { + await publishEndpoint.Publish(new RemoveFileEvent( + storageConfiguration.BucketName, + playList.LargePictureKeyName), cancellationToken); + } + catch (Exception exception) + { + logger.LogError(exception, "Failed to publish remove file event for large picture of PlayList id={PlayListId}.", playList.Id); + return Result.Error($"Failed to publish remove file event for PlayList with id {playList.Id}."); + } + } } database.PlayLists.Remove(playList); diff --git a/Application/PlayLists/Commands/UpdatePlayList/UpdatePlayListCommandHandler.cs b/Application/PlayLists/Commands/UpdatePlayList/UpdatePlayListCommandHandler.cs index 337b122..0092d1f 100644 --- a/Application/PlayLists/Commands/UpdatePlayList/UpdatePlayListCommandHandler.cs +++ b/Application/PlayLists/Commands/UpdatePlayList/UpdatePlayListCommandHandler.cs @@ -31,7 +31,10 @@ namespace Musify.Application.PlayLists.Commands.UpdatePlayList } if (!string.IsNullOrWhiteSpace(request.NewName)) + { playList.Name = request.NewName; + playList.NormalizedName = request.NewName.Trim().ToUpperInvariant(); + } if (!string.IsNullOrWhiteSpace(request.NewDescription)) playList.Description = request.NewDescription; @@ -46,36 +49,78 @@ namespace Musify.Application.PlayLists.Commands.UpdatePlayList if (!string.IsNullOrWhiteSpace(playList.OriginalPictureKeyName)) { - await publishEndpoint.Publish(new RemoveFileEvent( - storageConfiguration.BucketName, - playList.OriginalPictureKeyName), cancellationToken); + var originalImageStorageKey = Path.Join(playListConfiguration.Routes.OriginalPictures, playList.OriginalPictureKeyName); + + try + { + await publishEndpoint.Publish(new RemoveFileEvent( + storageConfiguration.BucketName, + originalImageStorageKey), cancellationToken); + } + catch (Exception exception) + { + logger.LogError(exception, "Failed to publish remove file event for original picture of PlayList id={PlayListId}.", playList.Id); + return Result.Error($"Failed to publish remove file event for PlayList with id {playList.Id}."); + } + logger.LogInformation("Published event to remove old picture with key name {KeyName} from bucket {BucketName}", - playList.OriginalPictureKeyName, storageConfiguration.BucketName); + originalImageStorageKey, storageConfiguration.BucketName); if (playList.SmallPictureKeyName != playListConfiguration.Routes.PresetSmallPicture) - await publishEndpoint.Publish(new RemoveFileEvent( - storageConfiguration.BucketName, - playList.SmallPictureKeyName), cancellationToken); + { + try + { + await publishEndpoint.Publish(new RemoveFileEvent( + storageConfiguration.BucketName, + playList.SmallPictureKeyName), cancellationToken); + } + catch (Exception exception) + { + logger.LogError(exception, "Failed to publish remove file event for small picture of PlayList id={PlayListId}.", playList.Id); + return Result.Error($"Failed to publish remove file event for PlayList with id {playList.Id}."); + } + } if (playList.MediumPictureKeyName != playListConfiguration.Routes.PresetMediumPicture) - await publishEndpoint.Publish(new RemoveFileEvent( - storageConfiguration.BucketName, - playList.MediumPictureKeyName), cancellationToken); + { + try + { + await publishEndpoint.Publish(new RemoveFileEvent( + storageConfiguration.BucketName, + playList.MediumPictureKeyName), cancellationToken); + } + catch (Exception exception) + { + logger.LogError(exception, "Failed to publish remove file event for medium picture of PlayList id={PlayListId}.", playList.Id); + return Result.Error($"Failed to publish remove file event for PlayList with id {playList.Id}."); + } + } if (playList.LargePictureKeyName != playListConfiguration.Routes.PresetLargePicture) - await publishEndpoint.Publish(new RemoveFileEvent( - storageConfiguration.BucketName, - playList.LargePictureKeyName), cancellationToken); + { + try + { + await publishEndpoint.Publish(new RemoveFileEvent( + storageConfiguration.BucketName, + playList.LargePictureKeyName), cancellationToken); + } + catch (Exception exception) + { + logger.LogError(exception, "Failed to publish remove file event for large picture of PlayList id={PlayListId}.", playList.Id); + return Result.Error($"Failed to publish remove file event for PlayList with id {playList.Id}."); + } + } } var newImageId = Guid.NewGuid(); - var imageKeyName = $"{playListConfiguration.Routes.OriginalPictures}/{newImageId}{request.NewPicture.FileType}"; + var pictureName = $"{newImageId}{request.NewPicture.FileType}"; + var newImageStorageKey = Path.Join(playListConfiguration.Routes.OriginalPictures, pictureName); var uploadResult = await storageHandler.UploadFileAsync( request.NewPicture.FileStream, request.NewPicture.ContentType, storageConfiguration.BucketName, - imageKeyName, + newImageStorageKey, cancellationToken); if (!uploadResult.IsSuccess) @@ -85,30 +130,39 @@ namespace Musify.Application.PlayLists.Commands.UpdatePlayList return Result.Error($"Failed to upload picture for PlayList with Id {playList.Id} to storage."); } - playList.OriginalPictureKeyName = imageKeyName; - 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); + playList.OriginalPictureKeyName = pictureName; + + try + { + await publishEndpoint.Publish(new ResizePictureEvent( + storageConfiguration.BucketName, + newImageStorageKey, + [ + 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); + } + catch (Exception exception) + { + logger.LogError(exception, "Failed to publish resize picture event for PlayList id={PlayListId}.", playList.Id); + return Result.Error($"Failed to publish resize picture event for PlayList with id {playList.Id}."); + } database.PlayLists.Update(playList); await database.SaveChangesAsync(cancellationToken); - logger.LogInformation("Updated PlayList with id={PlayListId} and picture key {PictureKeyName}.", playList.Id, imageKeyName); + logger.LogInformation("Updated PlayList with id={PlayListId} and picture key {PictureKeyName}.", playList.Id, newImageStorageKey); return Result.Success(PlayListResponse.FromEntity(playList)); } } diff --git a/Application/PlayLists/Queries/GetPlayListById/GetPlayListByIdQuery.cs b/Application/PlayLists/Queries/GetPlayListById/GetPlayListByIdQuery.cs index b57ebbc..031af87 100644 --- a/Application/PlayLists/Queries/GetPlayListById/GetPlayListByIdQuery.cs +++ b/Application/PlayLists/Queries/GetPlayListById/GetPlayListByIdQuery.cs @@ -5,5 +5,5 @@ using Musify.Application.PlayLists.Contracts; namespace Musify.Application.PlayLists.Queries.GetPlayListById { public record GetPlayListByIdQuery(Guid Id) - : IRequest>; + : IRequest>>; } \ No newline at end of file diff --git a/Application/PlayLists/Queries/GetPlayLists/GetPlayListsQuery.cs b/Application/PlayLists/Queries/GetPlayLists/GetPlayListsQuery.cs index c01cceb..ba213f7 100644 --- a/Application/PlayLists/Queries/GetPlayLists/GetPlayListsQuery.cs +++ b/Application/PlayLists/Queries/GetPlayLists/GetPlayListsQuery.cs @@ -5,5 +5,5 @@ using Musify.Application.PlayLists.Contracts; namespace Musify.Application.PlayLists.Queries.GetPlayLists { public record GetPlayListsQuery(int PageNumber = 1, int PageSize = 10) - : IRequest>; + : IRequest>>; } \ No newline at end of file diff --git a/Application/PlayLists/Queries/GetPlayListsByUserId/GetPlayListsByUserIdQuery.cs b/Application/PlayLists/Queries/GetPlayListsByUserId/GetPlayListsByUserIdQuery.cs index 0479ccb..efeb755 100644 --- a/Application/PlayLists/Queries/GetPlayListsByUserId/GetPlayListsByUserIdQuery.cs +++ b/Application/PlayLists/Queries/GetPlayListsByUserId/GetPlayListsByUserIdQuery.cs @@ -9,5 +9,5 @@ namespace Musify.Application.PlayLists.Queries.GetPlayListsByUserId string Name = "", int PageNumber = 1, int PageSize = 10) - : IRequest>; + : IRequest>>; } \ No newline at end of file diff --git a/Application/PlayLists/Queries/GetPlayListsByUserId/GetPlayListsByUserIdQueryHandler.cs b/Application/PlayLists/Queries/GetPlayListsByUserId/GetPlayListsByUserIdQueryHandler.cs index 328895f..58403b4 100644 --- a/Application/PlayLists/Queries/GetPlayListsByUserId/GetPlayListsByUserIdQueryHandler.cs +++ b/Application/PlayLists/Queries/GetPlayListsByUserId/GetPlayListsByUserIdQueryHandler.cs @@ -3,7 +3,6 @@ using DispatchR.Abstractions.Send; using Microsoft.EntityFrameworkCore; using Musify.Application.Contracts.Infrastructure; using Musify.Application.PlayLists.Contracts; -using Musify.Domain.Entities; using X.PagedList.EF; namespace Musify.Application.PlayLists.Queries.GetPlayListsByUserId @@ -15,7 +14,7 @@ namespace Musify.Application.PlayLists.Queries.GetPlayListsByUserId { var pageNumber = request.PageNumber < 1 ? 1 : request.PageNumber; var pageSize = request.PageSize < 1 ? 10 : request.PageSize; - var normalizedName = request.Name.Trim().ToUpperInvariant(); + var normalizedName = request.Name?.Trim().ToUpperInvariant() ?? string.Empty; var playListsQuery = database.PlayLists .AsNoTracking() diff --git a/Application/Users/Commands/CreateUser/CreateUserCommand.cs b/Application/Users/Commands/CreateUser/CreateUserCommand.cs index 519e26f..ebb068b 100644 --- a/Application/Users/Commands/CreateUser/CreateUserCommand.cs +++ b/Application/Users/Commands/CreateUser/CreateUserCommand.cs @@ -5,5 +5,5 @@ using Musify.Application.Users.Contracts; namespace Musify.Application.Users.Commands.CreateUser { public record CreateUserCommand(Guid Id) - : IRequest>; + : IRequest>>; } \ No newline at end of file diff --git a/Application/Users/Commands/DeleteUser/DeleteUserCommand.cs b/Application/Users/Commands/DeleteUser/DeleteUserCommand.cs index 571ce4d..720fc53 100644 --- a/Application/Users/Commands/DeleteUser/DeleteUserCommand.cs +++ b/Application/Users/Commands/DeleteUser/DeleteUserCommand.cs @@ -4,5 +4,5 @@ using DispatchR.Abstractions.Send; namespace Musify.Application.Users.Commands.DeleteUser { public record DeleteUserCommand(Guid Id) - : IRequest; + : IRequest>; } \ No newline at end of file diff --git a/Infrastructure/Configuration/StorageClientConfiguration.cs b/Infrastructure/Configuration/StorageClientConfiguration.cs index 92e3caa..7e7fc62 100644 --- a/Infrastructure/Configuration/StorageClientConfiguration.cs +++ b/Infrastructure/Configuration/StorageClientConfiguration.cs @@ -7,18 +7,19 @@ namespace Musify.Infrastructure.Configuration public const string SectionName = "Storage"; [Required] + [Url] public required string ServiceUrl { get; set; } [Required] + [MinLength(3)] public required string AccessKey { get; set; } [Required] + [MinLength(8)] public required string SecretAccessKey { get; set; } - [Required] public bool ForcePathStyle { get; set; } - [Required] public bool UseHttp { get; set; } } } diff --git a/Infrastructure/Storage/StorageDependencyInjection.cs b/Infrastructure/Storage/StorageDependencyInjection.cs index f6c71bd..d0f46ad 100644 --- a/Infrastructure/Storage/StorageDependencyInjection.cs +++ b/Infrastructure/Storage/StorageDependencyInjection.cs @@ -22,7 +22,6 @@ namespace Musify.Infrastructure.Storage } ); serviceDescriptors.AddScoped(); - return serviceDescriptors; } }