using Socialize.Infrastructure.BlobStorage.Contracts; using Socialize.Infrastructure.Security; using Socialize.Modules.Clients.Data; namespace Socialize.Modules.Clients.Handlers; public record ChangeClientPortraitRequest( IFormFile File); public record ChangeClientPortraitResponse( string BlobUrl); public sealed class ChangeClientPortraitRequestValidator : Validator { public ChangeClientPortraitRequestValidator() { RuleFor(x => x.File) .NotNull() .NotEmpty(); } } public class ChangeClientPortraitHandler( AppDbContext clientsDbContext, IBlobStorage blobStorage, AccessScopeService accessScopeService) : Endpoint { public override void Configure() { Post("/api/clients/{id}/portrait"); Options(o => o.WithTags("Clients")); AllowFileUploads(); } public override async Task HandleAsync(ChangeClientPortraitRequest request, CancellationToken ct) { Guid id = Route("id"); Client? client = await clientsDbContext.Clients.SingleOrDefaultAsync(candidate => candidate.Id == id, ct); if (client is null) { await SendNotFoundAsync(ct); return; } if (!accessScopeService.CanManageWorkspace(User, client.WorkspaceId)) { await SendForbiddenAsync(ct); return; } string blobUrl = await blobStorage.UploadFileAsync( ContainerNames.Clients, $"{client.Id}/{SubDirectoryNames.Profile}/{CommonFileNames.LogoPicture}", request.File.OpenReadStream(), request.File.ContentType, ct); client.PortraitUrl = blobUrl; await clientsDbContext.SaveChangesAsync(ct); await SendOkAsync(new ChangeClientPortraitResponse(blobUrl), ct); } }