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>
<Folder Include="Contracts\Application\" />
<Folder Include="PlayLists\Commands\CreatePlayList\" />
<Folder Include="PlayLists\Commands\DeletePlayList\" />
<Folder Include="PlayLists\Commands\UpdatePlayList\" />
</ItemGroup>
@@ -14,7 +14,7 @@
public int LargePictureWidth { get; private set; } = 512;
public float LargePictureHeight { get; private set; } = 512;
public int LargePictureHeight { get; private set; } = 512;
}
public class PlayListRoutes
@@ -26,5 +26,11 @@
public string MediumPictures { get; set; } = "MediumPictures";
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 DispatchR.Abstractions.Send;
using Musify.Application.Pictures.Contracts;
namespace Musify.Application.Pictures.Commands.ResizeImage
namespace Musify.Application.Pictures.Commands.ResizePicture
{
public record ResizeCommand(
Stream PictureStream,
string KeyName,
string ContentType,
int Width,
int Height,
string SaveRoute)
Stream PictureStream,
PictureResize[] PictureResizes)
: 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 DispatchR.Abstractions.Send;
using MassTransit;
using Microsoft.Extensions.Logging;
using Musify.Application.Configuration;
using Musify.Application.Contracts.Application;
using Musify.Application.Contracts.Infrastructure;
using Musify.Application.Pictures.Commands.ResizePicture;
using Musify.Application.Pictures.Contracts;
using Musify.Application.Pictures.Events;
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)
: 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();
@@ -21,7 +24,7 @@ namespace Musify.Application.Pictures.Commands.ResizeImage
{
Id = pictureId,
KeyName = $"{storageConfiguration.Routes.Uploads}/{pictureId}",
ContentType = request.ContentType,
ContentType = contentType,
BucketName = storageConfiguration.BucketName,
};
@@ -30,10 +33,10 @@ namespace Musify.Application.Pictures.Commands.ResizeImage
await database.SaveChangesAsync(cancellationToken);
var uploadResult = await storageHandler.UploadFileAsync(
request.PictureStream,
request.ContentType,
pictureStream,
contentType,
storageConfiguration.BucketName,
pictureId.ToString(),
$"{storageConfiguration.Routes.Uploads}/{pictureId}",
cancellationToken);
if (!uploadResult.IsSuccess)
@@ -42,12 +45,7 @@ namespace Musify.Application.Pictures.Commands.ResizeImage
return Result.Error("Failed to upload the picture.");
}
await publishEndpoint.Publish(new ImageResizeEvent(
pictureId,
request.Width,
request.Height,
request.SaveRoute),
cancellationToken);
await publishEndpoint.Publish(new PictureResizeEvent(pictureId, pictureResizes));
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(
Guid Id,
string Name,
string Description,
string ImageName,
string SmallImageKeyName,
string MediumImageKeyName,
string LargeImageKeyName,
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
{
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
{
+9 -1
View File
@@ -27,7 +27,15 @@ namespace Musify.Domain.Entities
[Required]
[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]
public DateTime CreatedDate { get; set; } = DateTime.UtcNow;