From 3e341e00197e993b36f13f0cc0e0175310b2d847 Mon Sep 17 00:00:00 2001 From: Jonathan Bourdon Date: Wed, 4 Sep 2024 13:52:47 -0400 Subject: [PATCH] Adds ChangePortrait for User --- .../Users/Commands/UploadProfilePicture.cs | 35 --------- src/Web/Endpoints/UpdateMyUser.cs | 9 --- .../Contents/Handlers/ChangeBanner.cs | 14 +++- .../Features/Contents/Handlers/ChangeLogo.cs | 19 ++++- .../Features/Users/Handlers/ChangePortrait.cs | 74 +++++++++++++++++++ 5 files changed, 103 insertions(+), 48 deletions(-) delete mode 100644 src/Application/Users/Commands/UploadProfilePicture.cs create mode 100644 src/Web/Features/Users/Handlers/ChangePortrait.cs diff --git a/src/Application/Users/Commands/UploadProfilePicture.cs b/src/Application/Users/Commands/UploadProfilePicture.cs deleted file mode 100644 index 3cc34cc..0000000 --- a/src/Application/Users/Commands/UploadProfilePicture.cs +++ /dev/null @@ -1,35 +0,0 @@ -using Hutopy.Application.AzureBlobStorage.Constants; -using Hutopy.Application.Common.Interfaces; -using Microsoft.AspNetCore.Http; - -namespace Hutopy.Application.Users.Commands; - -/// -/// Upload a profile picture. If the user has the url already, set the ProfilePictureUrl in the user only without upload. -/// -public class UploadProfilePictureCommand : IRequest -{ - public required IFormFile File { get; init; } -} - -public class UploadProfilePictureCommandHandler( - IHttpContextAccessor contextAccessor, - IIdentityService identityService, - IBlobStorage blobStorage) : IRequestHandler -{ - public async Task Handle(UploadProfilePictureCommand request, CancellationToken ct) - { - var identityUser = await identityService.GetCurrentUserAsync(); - - var url = await blobStorage.UploadFileAsync( - ContainerNames.Users, - $"{identityUser.Id}/{SubDirectoryNames.Profile}/{CommonFileNames.ProfilePicture}", - request.File.OpenReadStream(), - request.File.ContentType, - ct); - - await identityService.UpdateCurrentUserPortraitUrlAsync(url); - - return Results.Ok(url); - } -} diff --git a/src/Web/Endpoints/UpdateMyUser.cs b/src/Web/Endpoints/UpdateMyUser.cs index 072152f..7118e4e 100644 --- a/src/Web/Endpoints/UpdateMyUser.cs +++ b/src/Web/Endpoints/UpdateMyUser.cs @@ -9,7 +9,6 @@ public class UpdateMyUser : EndpointGroupBase { app.MapGroup(this) .RequireAuthorization() - .MapPost(UpdateCurrentUserProfilePicture, "/profile-picture") .MapPatch("/profile", UpdateCurrentUser); } @@ -17,12 +16,4 @@ public class UpdateMyUser : EndpointGroupBase { return await sender.Send(command); } - - private static async Task UpdateCurrentUserProfilePicture( - ISender sender, - IFormFile formFile) - { - var command = new UploadProfilePictureCommand { File = formFile }; - return await sender.Send(command); - } } diff --git a/src/Web/Features/Contents/Handlers/ChangeBanner.cs b/src/Web/Features/Contents/Handlers/ChangeBanner.cs index b69affb..d33e72a 100644 --- a/src/Web/Features/Contents/Handlers/ChangeBanner.cs +++ b/src/Web/Features/Contents/Handlers/ChangeBanner.cs @@ -9,11 +9,15 @@ public record ChangeBannerRequest( Guid CreatorId, IFormFile File); +[PublicAPI] +public record ChangeBannerResponse( + string BlobUrl); + [PublicAPI] public class ChangeBannerHandler( ContentDbContext context, IBlobStorage blobStorage) - : Endpoint + : Endpoint { public override void Configure() { @@ -22,7 +26,9 @@ public class ChangeBannerHandler( AllowFileUploads(); } - public override async Task HandleAsync(ChangeBannerRequest request, CancellationToken ct) + public override async Task HandleAsync( + ChangeBannerRequest request, + CancellationToken ct) { var creator = await context .Creators @@ -49,6 +55,8 @@ public class ChangeBannerHandler( await context.SaveChangesAsync(ct); - await SendOkAsync(blobUrl, ct); + await SendOkAsync( + new ChangeBannerResponse(blobUrl), + ct); } } diff --git a/src/Web/Features/Contents/Handlers/ChangeLogo.cs b/src/Web/Features/Contents/Handlers/ChangeLogo.cs index 44dd8b8..656bf62 100644 --- a/src/Web/Features/Contents/Handlers/ChangeLogo.cs +++ b/src/Web/Features/Contents/Handlers/ChangeLogo.cs @@ -9,6 +9,21 @@ public record ChangeLogoRequest( Guid CreatorId, IFormFile File); +[PublicAPI] +public sealed class ChangeLogoRequestValidator : Validator +{ + public ChangeLogoRequestValidator() + { + RuleFor(x => x.CreatorId) + .NotNull() + .NotEmpty(); + + RuleFor(x => x.File) + .NotNull() + .NotEmpty(); + } +} + [PublicAPI] public class ChangeLogoHandler( ContentDbContext context, @@ -22,7 +37,9 @@ public class ChangeLogoHandler( AllowFileUploads(); } - public override async Task HandleAsync(ChangeLogoRequest request, CancellationToken ct) + public override async Task HandleAsync( + ChangeLogoRequest request, + CancellationToken ct) { var creator = await context .Creators diff --git a/src/Web/Features/Users/Handlers/ChangePortrait.cs b/src/Web/Features/Users/Handlers/ChangePortrait.cs new file mode 100644 index 0000000..1424fb8 --- /dev/null +++ b/src/Web/Features/Users/Handlers/ChangePortrait.cs @@ -0,0 +1,74 @@ +using Hutopy.Application.AzureBlobStorage.Constants; +using Hutopy.Application.Common.Interfaces; +using Hutopy.Infrastructure.Identity; +using Hutopy.Web.Common; + +namespace Hutopy.Web.Features.Users.Handlers; + +[PublicAPI] +public record ChangePortraitRequest( + IFormFile File); + +[PublicAPI] +public record ChangePortraitResponse( + string BlobUrl); + +[PublicAPI] +public sealed class ChangePortraitRequestValidator : Validator +{ + public ChangePortraitRequestValidator() + { + RuleFor(x => x.File) + .NotNull() + .NotEmpty(); + } +} + +[PublicAPI] +public class ChangePortraitHandler( + ApplicationUserManager userManager, + IBlobStorage blobStorage) + : Endpoint +{ + public override void Configure() + { + Post("/api/users/portrait"); + Options(o => o.WithTags("Users")); + AllowFileUploads(); + } + + public override async Task HandleAsync( + ChangePortraitRequest request, + CancellationToken ct) + { + var user = await userManager.FindByIdAsync(HttpContext.User.GetUserId().ToString()); + + if (user is null) + { + await SendNotFoundAsync(ct); + return; + } + + var blobUrl = await blobStorage.UploadFileAsync( + ContainerNames.Users, + $"{user.Id}/{SubDirectoryNames.Profile}/{CommonFileNames.ProfilePicture}", + request.File.OpenReadStream(), + request.File.ContentType, + ct); + + user.PortraitUrl = blobUrl; + + var result = await userManager.UpdateAsync(user); + + if (result.Succeeded) + { + await SendOkAsync( + new ChangePortraitResponse(blobUrl), + ct); + } + else + { + await SendUnauthorizedAsync(ct); + } + } +}