Upload playlist image

This commit is contained in:
2026-03-18 10:26:40 +01:00
parent 199ff3f104
commit 2549dc7a78
14 changed files with 174 additions and 37 deletions
-2
View File
@@ -21,8 +21,6 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Folder Include="Contracts\Application\" />
<Folder Include="PlayLists\Commands\CreatePlayList\" />
<Folder Include="PlayLists\Commands\DeletePlayList\" /> <Folder Include="PlayLists\Commands\DeletePlayList\" />
<Folder Include="PlayLists\Commands\UpdatePlayList\" /> <Folder Include="PlayLists\Commands\UpdatePlayList\" />
</ItemGroup> </ItemGroup>
@@ -14,7 +14,7 @@
public int LargePictureWidth { get; private set; } = 512; public int LargePictureWidth { get; private set; } = 512;
public float LargePictureHeight { get; private set; } = 512; public int LargePictureHeight { get; private set; } = 512;
} }
public class PlayListRoutes public class PlayListRoutes
@@ -26,5 +26,11 @@
public string MediumPictures { get; set; } = "MediumPictures"; public string MediumPictures { get; set; } = "MediumPictures";
public string LargePictures { get; set; } = "LargePictures"; public string LargePictures { get; set; } = "LargePictures";
public string DefaultSmallPicture { get; set; } = "DefaultSmallPicture.webp";
public string DefaultMediumPicture { get; set; } = "DefaultMediumPicture.webp";
public string DefaultLargePicture { get; set; } = "DefaultLargePicture.webp";
} }
} }
@@ -0,0 +1,11 @@
using Ardalis.Result;
using Musify.Application.Pictures.Contracts;
namespace Musify.Application.Contracts.Application
{
public interface IPictureService
{
Task<Result<Guid>> ResizePictureAsync(string keyName, string contentType, Stream pictureStream, PictureResize[] pictureResizes,
CancellationToken cancellationToken);
}
}
@@ -1,13 +1,13 @@
using Ardalis.Result; using Ardalis.Result;
using DispatchR.Abstractions.Send; using DispatchR.Abstractions.Send;
using Musify.Application.Pictures.Contracts;
namespace Musify.Application.Pictures.Commands.ResizeImage namespace Musify.Application.Pictures.Commands.ResizePicture
{ {
public record ResizeCommand( public record ResizeCommand(
Stream PictureStream, string KeyName,
string ContentType, string ContentType,
int Width, Stream PictureStream,
int Height, PictureResize[] PictureResizes)
string SaveRoute)
: IRequest<ResizeCommand, Result<Guid>>; : IRequest<ResizeCommand, Result<Guid>>;
} }
@@ -0,0 +1,17 @@
using Ardalis.Result;
using DispatchR.Abstractions.Send;
using Musify.Application.Contracts.Application;
namespace Musify.Application.Pictures.Commands.ResizePicture
{
public class ResizeCommandHandler(IPictureService pictureService)
: IRequestHandler<ResizeCommand, Task<Result<Guid> >>
{
public async Task<Result<Guid>> Handle(ResizeCommand request, CancellationToken cancellationToken)
{
var result = await pictureService.ResizePictureAsync(request.KeyName, request.ContentType, request.PictureStream, request.PictureResizes, cancellationToken);
return result;
}
}
}
@@ -0,0 +1,6 @@
namespace Musify.Application.Pictures.Contracts
{
public record PictureResize(
int Width,
int Height);
}
@@ -1,8 +0,0 @@
namespace Musify.Application.Pictures.Events
{
public record ImageResizeEvent(
Guid UploadId,
int Width,
int Height,
string SaveRoute);
}
@@ -0,0 +1,8 @@
using Musify.Application.Pictures.Contracts;
namespace Musify.Application.Pictures.Events
{
public record PictureResizeEvent(
Guid UploadId,
PictureResize[] ImageResizes);
}
@@ -1,19 +1,22 @@
using Ardalis.Result; using Ardalis.Result;
using DispatchR.Abstractions.Send;
using MassTransit; using MassTransit;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Musify.Application.Configuration; using Musify.Application.Configuration;
using Musify.Application.Contracts.Application;
using Musify.Application.Contracts.Infrastructure; using Musify.Application.Contracts.Infrastructure;
using Musify.Application.Pictures.Commands.ResizePicture;
using Musify.Application.Pictures.Contracts;
using Musify.Application.Pictures.Events; using Musify.Application.Pictures.Events;
using Musify.Domain.Entities; using Musify.Domain.Entities;
namespace Musify.Application.Pictures.Commands.ResizeImage namespace Musify.Application.Pictures
{ {
public class ResizeCommandHandler(IStorageHandler storageHandler, IDatabase database, IPublishEndpoint publishEndpoint, public class PictureService(IStorageHandler storageHandler, IDatabase database, IPublishEndpoint publishEndpoint,
ILogger<ResizeCommandHandler> logger, StorageConfiguration storageConfiguration) ILogger<ResizeCommandHandler> logger, StorageConfiguration storageConfiguration)
: IRequestHandler<ResizeCommand, Task<Result<Guid> >> : IPictureService
{ {
public async Task<Result<Guid>> Handle(ResizeCommand request, CancellationToken cancellationToken) public async Task<Result<Guid>> ResizePictureAsync(string keyName, string contentType, Stream pictureStream, PictureResize[] pictureResizes,
CancellationToken cancellationToken)
{ {
var pictureId = Guid.NewGuid(); var pictureId = Guid.NewGuid();
@@ -21,7 +24,7 @@ namespace Musify.Application.Pictures.Commands.ResizeImage
{ {
Id = pictureId, Id = pictureId,
KeyName = $"{storageConfiguration.Routes.Uploads}/{pictureId}", KeyName = $"{storageConfiguration.Routes.Uploads}/{pictureId}",
ContentType = request.ContentType, ContentType = contentType,
BucketName = storageConfiguration.BucketName, BucketName = storageConfiguration.BucketName,
}; };
@@ -30,10 +33,10 @@ namespace Musify.Application.Pictures.Commands.ResizeImage
await database.SaveChangesAsync(cancellationToken); await database.SaveChangesAsync(cancellationToken);
var uploadResult = await storageHandler.UploadFileAsync( var uploadResult = await storageHandler.UploadFileAsync(
request.PictureStream, pictureStream,
request.ContentType, contentType,
storageConfiguration.BucketName, storageConfiguration.BucketName,
pictureId.ToString(), $"{storageConfiguration.Routes.Uploads}/{pictureId}",
cancellationToken); cancellationToken);
if (!uploadResult.IsSuccess) if (!uploadResult.IsSuccess)
@@ -42,12 +45,7 @@ namespace Musify.Application.Pictures.Commands.ResizeImage
return Result.Error("Failed to upload the picture."); return Result.Error("Failed to upload the picture.");
} }
await publishEndpoint.Publish(new ImageResizeEvent( await publishEndpoint.Publish(new PictureResizeEvent(pictureId, pictureResizes));
pictureId,
request.Width,
request.Height,
request.SaveRoute),
cancellationToken);
return Result.Success(); return Result.Success();
} }
@@ -0,0 +1,14 @@
using Ardalis.Result;
using DispatchR.Abstractions.Send;
using Musify.Application.PlayLists.Contracts;
namespace Musify.Application.PlayLists.Commands.CreatePlayList
{
public record CreatePlayListCommand(
Guid UserId,
string Name,
string Description,
Stream PictureStream,
string PictureContentType)
: IRequest<CreatePlayListCommand, Result<PlayListResponse>>;
}
@@ -0,0 +1,61 @@
using Ardalis.Result;
using DispatchR.Abstractions.Send;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Musify.Application.Configuration;
using Musify.Application.Contracts.Application;
using Musify.Application.Contracts.Infrastructure;
using Musify.Application.Pictures.Contracts;
using Musify.Application.PlayLists.Contracts;
using Musify.Domain.Entities;
namespace Musify.Application.PlayLists.Commands.CreatePlayList
{
public class CreatePlayListCommandHandler(IPictureService pictureService, IDatabase database, ILogger<CreatePlayListCommandHandler> logger,
PlayListConfiguration playListConfiguration)
: IRequestHandler<CreatePlayListCommand, Task<Result<PlayListResponse>> >
{
public async Task<Result<PlayListResponse>> Handle(CreatePlayListCommand request, CancellationToken cancellationToken)
{
var userExists = await database.Users.AnyAsync(u => u.Id == request.UserId, cancellationToken);
if (!userExists)
{
logger.LogWarning("User with Id={UserId} does not exist.", request.UserId);
return Result.NotFound($"User with Id {request.UserId} does not exist.");
}
var playList = new PlayList
{
UserId = request.UserId,
Name = request.Name,
NormalizedName = request.Name.Trim().ToUpperInvariant(),
Description = request.Description,
SmallPictureKeyName = playListConfiguration.Routes.SmallPictures,
MediumPictureKeyName = playListConfiguration.Routes.MediumPictures,
LargePictureKeyName = playListConfiguration.Routes.LargePictures,
};
await database.PlayLists.AddAsync(playList, cancellationToken);
await database.SaveChangesAsync(cancellationToken);
logger.LogInformation("PlayList with Id={PlayListId} created successfully for UserId={UserId}.", playList.Id, request.UserId);
await pictureService.ResizePictureAsync(
playList.Id.ToString(),
request.PictureContentType,
request.PictureStream,
[
new PictureResize(playListConfiguration.SmallPictureWidth, playListConfiguration.SmallPictureHeight),
new PictureResize(playListConfiguration.MediumPictureWidth, playListConfiguration.MediumPictureHeight),
new PictureResize(playListConfiguration.LargePictureWidth, playListConfiguration.LargePictureHeight)
],
cancellationToken);
logger.LogInformation("Picture for PlayList with Id={PlayListId} ", playList.Id);
return Result.Created(PlayListResponse.Map(playList));
}
}
}
@@ -1,10 +1,28 @@
namespace Musify.Application.PlayLists.Contracts using Musify.Domain.Entities;
namespace Musify.Application.PlayLists.Contracts
{ {
public record PlayListResponse( public record PlayListResponse(
Guid Id, Guid Id,
string Name, string Name,
string Description, string Description,
string ImageName, string SmallImageKeyName,
string MediumImageKeyName,
string LargeImageKeyName,
DateTime CreatedAt, DateTime CreatedAt,
DateTime UpdatedAt); DateTime UpdatedAt)
{
public static PlayListResponse Map(PlayList playList)
{
return new PlayListResponse(
playList.Id,
playList.Name,
playList.Description,
playList.SmallPictureKeyName,
playList.MediumPictureKeyName,
playList.LargePictureKeyName,
playList.CreatedDate,
playList.UpdatedDate);
}
}
} }
@@ -9,9 +9,9 @@ using Musify.Domain.Entities;
namespace Musify.Infrastructure.Messaging.Consumers namespace Musify.Infrastructure.Messaging.Consumers
{ {
public class ImageResizedConsumer(IStorageHandler storageHandler, IDatabase database, IPictureHandler pictureHandler, ILogger<ImageResizedConsumer> logger) public class ImageResizedConsumer(IStorageHandler storageHandler, IDatabase database, IPictureHandler pictureHandler, ILogger<ImageResizedConsumer> logger)
: IConsumer<ImageResizeEvent> : IConsumer<PictureResizeEvent>
{ {
public async Task Consume(ConsumeContext<ImageResizeEvent> consumeContext) public async Task Consume(ConsumeContext<PictureResizeEvent> consumeContext)
{ {
try try
{ {
+9 -1
View File
@@ -27,7 +27,15 @@ namespace Musify.Domain.Entities
[Required] [Required]
[MaxLength(64)] [MaxLength(64)]
public required string ImageName { get; set; } public required string SmallPictureKeyName { get; set; }
[Required]
[MaxLength(64)]
public required string MediumPictureKeyName { get; set; }
[Required]
[MaxLength(64)]
public required string LargePictureKeyName { get; set; }
[Required] [Required]
public DateTime CreatedDate { get; set; } = DateTime.UtcNow; public DateTime CreatedDate { get; set; } = DateTime.UtcNow;