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)]