using Hutopy.Infrastructure.BlobStorage.Contracts; using Hutopy.Infrastructure.Security; using Hutopy.Modules.Identity.Data; using Microsoft.AspNetCore.Identity; namespace Hutopy.Modules.Identity.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( UserManager 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) { User? user = await userManager.FindByIdAsync(HttpContext.User.GetUserId().ToString()); if (user is null) { await SendNotFoundAsync(ct); return; } string blobUrl = await blobStorage.UploadFileAsync( ContainerNames.Users, $"{user.Id}/{SubDirectoryNames.Profile}/{CommonFileNames.ProfilePicture}", request.File.OpenReadStream(), request.File.ContentType, ct); user.PortraitUrl = blobUrl; IdentityResult result = await userManager.UpdateAsync(user); if (result.Succeeded) { await SendOkAsync( new ChangePortraitResponse(blobUrl), ct); } else { await SendUnauthorizedAsync(ct); } } }