Adds ChangeBanner for Creators

This commit is contained in:
Jonathan Bourdon
2024-08-05 16:32:00 -04:00
parent e617b5ffd3
commit 8f0ed2644b
8 changed files with 30 additions and 56 deletions

View File

@@ -1,6 +1,6 @@
namespace Hutopy.Application.Common.Interfaces; namespace Hutopy.Application.Common.Interfaces;
public interface IAzureBlobStorageService public interface IBlobStorage
{ {
Task<string> UploadFileAsync(string containerName, string blobName, Stream stream, string contentType, Task<string> UploadFileAsync(string containerName, string blobName, Stream stream, string contentType,
CancellationToken ct = default); CancellationToken ct = default);

View File

@@ -1,6 +1,5 @@
using Hutopy.Application.AzureBlobStorage.Constants; using Hutopy.Application.AzureBlobStorage.Constants;
using Hutopy.Application.Common.Interfaces; using Hutopy.Application.Common.Interfaces;
using Hutopy.Application.Utils;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
namespace Hutopy.Application.Users.Commands; namespace Hutopy.Application.Users.Commands;
@@ -16,19 +15,17 @@ public class UploadProfilePictureCommand : IRequest<IResult>
public class UploadProfilePictureCommandHandler( public class UploadProfilePictureCommandHandler(
IHttpContextAccessor contextAccessor, IHttpContextAccessor contextAccessor,
IIdentityService identityService, IIdentityService identityService,
IAzureBlobStorageService azureBlobStorageService) : IRequestHandler<UploadProfilePictureCommand, IResult> IBlobStorage blobStorage) : IRequestHandler<UploadProfilePictureCommand, IResult>
{ {
public async Task<IResult> Handle(UploadProfilePictureCommand request, CancellationToken ct) public async Task<IResult> Handle(UploadProfilePictureCommand request, CancellationToken ct)
{ {
var contentType = contextAccessor.EnsureContentType();
var identityUser = await identityService.GetCurrentUserAsync(); var identityUser = await identityService.GetCurrentUserAsync();
var url = await azureBlobStorageService.UploadFileAsync( var url = await blobStorage.UploadFileAsync(
ContainerNames.Users, ContainerNames.Users,
$"{identityUser.Id}/{SubDirectoryNames.Profile}/{CommonFileNames.ProfilePicture}", $"{identityUser.Id}/{SubDirectoryNames.Profile}/{CommonFileNames.ProfilePicture}",
request.File.OpenReadStream(), request.File.OpenReadStream(),
contentType, request.File.ContentType,
ct); ct);
await identityService.UpdateCurrentUserPortraitUrlAsync(url); await identityService.UpdateCurrentUserPortraitUrlAsync(url);

View File

@@ -7,7 +7,7 @@ public record GetCurrentUserProfilePictureQuery : IRequest<Stream>;
public class GetCurrentUserProfilePictureQueryHandler( public class GetCurrentUserProfilePictureQueryHandler(
IIdentityService identityService, IIdentityService identityService,
IAzureBlobStorageService azureBlobStorageService IBlobStorage blobStorage
) )
: IRequestHandler<GetCurrentUserProfilePictureQuery, Stream> : IRequestHandler<GetCurrentUserProfilePictureQuery, Stream>
{ {
@@ -15,7 +15,7 @@ public class GetCurrentUserProfilePictureQueryHandler(
{ {
var identityUser = await identityService.GetCurrentUserAsync(); var identityUser = await identityService.GetCurrentUserAsync();
return await azureBlobStorageService.DownloadFileAsync( return await blobStorage.DownloadFileAsync(
ContainerNames.Users, ContainerNames.Users,
$"{identityUser.Id.ToString()}/{SubDirectoryNames.Profile}/{CommonFileNames.ProfilePicture}", $"{identityUser.Id.ToString()}/{SubDirectoryNames.Profile}/{CommonFileNames.ProfilePicture}",
cancellationToken); cancellationToken);

View File

@@ -1,29 +0,0 @@
using Microsoft.AspNetCore.Http;
namespace Hutopy.Application.Utils;
public static class HttpContextAccessorExtensions
{
public static HttpContext EnsureHttpContext(this IHttpContextAccessor httpContextAccessor)
{
if (httpContextAccessor.HttpContext == null)
{
throw new InvalidOperationException("HttpContext is null.");
}
return httpContextAccessor.HttpContext;
}
public static string EnsureContentType(this IHttpContextAccessor httpContextAccessor)
{
var httpContext = EnsureHttpContext(httpContextAccessor);
var contentType = httpContext.Request.ContentType;
if (string.IsNullOrEmpty(contentType))
{
throw new InvalidOperationException("Content-Type header is missing.");
}
return contentType;
}
}

View File

@@ -7,13 +7,14 @@ using Microsoft.Extensions.Logging;
namespace Hutopy.Infrastructure.AzureBlob; namespace Hutopy.Infrastructure.AzureBlob;
public class AzureBlobStorageService : IAzureBlobStorageService public class AzureBlobStorage : IBlobStorage
{ {
private readonly BlobServiceClient _blobServiceClient; private const long MaxUploadSize = 10 * 1024 * 1024; // 10 MB in bytes
private readonly ILogger<AzureBlobStorageService> _logger;
private readonly long _maxUploadSize = 10 * 1024 * 1024; // 10 MB in bytes
public AzureBlobStorageService(IConfiguration configuration, ILogger<AzureBlobStorageService> logger) private readonly BlobServiceClient _blobServiceClient;
private readonly ILogger<AzureBlobStorage> _logger;
public AzureBlobStorage(IConfiguration configuration, ILogger<AzureBlobStorage> logger)
{ {
_logger = logger; _logger = logger;
var connectionString = configuration["Azure-Blob-Connection-String"] ?? ""; var connectionString = configuration["Azure-Blob-Connection-String"] ?? "";
@@ -37,12 +38,12 @@ public class AzureBlobStorageService : IAzureBlobStorageService
stream.Position = 0; stream.Position = 0;
// Check if the file size exceeds the maximum upload size // Check if the file size exceeds the maximum upload size
if (stream.Length > _maxUploadSize) if (stream.Length > MaxUploadSize)
{ {
_logger.LogError( _logger.LogError(
$"Blob storage: File size exceeds the maximum allowed size of {_maxUploadSize} bytes."); $"Blob storage: File size exceeds the maximum allowed size of {MaxUploadSize} bytes.");
throw new InvalidOperationException( throw new InvalidOperationException(
$"Blob storage: File size exceeds the maximum allowed size of {_maxUploadSize} bytes."); $"Blob storage: File size exceeds the maximum allowed size of {MaxUploadSize} bytes.");
} }
// Validate content type // Validate content type

View File

@@ -52,7 +52,7 @@ public static class DependencyInjection
// Singleton services // Singleton services
services.AddSingleton(TimeProvider.System); services.AddSingleton(TimeProvider.System);
services.AddSingleton<IAzureBlobStorageService, AzureBlobStorageService>(); services.AddSingleton<IBlobStorage, AzureBlobStorage>();
// Scoped services // Scoped services
services.AddScoped<IIdentityService, IdentityService>(); services.AddScoped<IIdentityService, IdentityService>();

View File

@@ -1,7 +1,6 @@
using FastEndpoints; using FastEndpoints;
using Hutopy.Application.AzureBlobStorage.Constants; using Hutopy.Application.AzureBlobStorage.Constants;
using Hutopy.Application.Common.Interfaces; using Hutopy.Application.Common.Interfaces;
using Hutopy.Application.Utils;
using Hutopy.Web.Features.Contents.Data; using Hutopy.Web.Features.Contents.Data;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
@@ -14,7 +13,7 @@ public record ChangeBannerRequest(
public class ChangeBannerHandler( public class ChangeBannerHandler(
IHttpContextAccessor contextAccessor, IHttpContextAccessor contextAccessor,
ContentDbContext context, ContentDbContext context,
IAzureBlobStorageService azureBlobStorageService) IBlobStorage blobStorage)
: Endpoint<ChangeBannerRequest> : Endpoint<ChangeBannerRequest>
{ {
public override void Configure() public override void Configure()
@@ -29,19 +28,25 @@ public class ChangeBannerHandler(
var creator = await context var creator = await context
.Creators .Creators
.Include(c => c.StoredDataUrls) .Include(c => c.StoredDataUrls)
.SingleAsync( .SingleOrDefaultAsync(
c => c.Id == request.CreatorId, c => c.Id == request.CreatorId,
cancellationToken: ct); cancellationToken: ct);
var contentType = contextAccessor.EnsureContentType(); if (creator is null)
{
await SendNotFoundAsync(ct);
return;
}
var blobUrl = await azureBlobStorageService.UploadFileAsync( var blobUrl = await blobStorage.UploadFileAsync(
ContainerNames.Users, ContainerNames.Users,
$"{request.CreatorId}/{SubDirectoryNames.Profile}/{CommonFileNames.BannerPicture}", $"{request.CreatorId}/{SubDirectoryNames.Profile}/{CommonFileNames.BannerPicture}",
request.File.OpenReadStream(), request.File.OpenReadStream(),
contentType, request.File.ContentType,
ct); ct);
creator.StoredDataUrls.BannerPictureUrl = blobUrl;
await context.SaveChangesAsync(ct); await context.SaveChangesAsync(ct);
await SendOkAsync(blobUrl, ct); await SendOkAsync(blobUrl, ct);

View File

@@ -38,7 +38,7 @@ public sealed class PostContentRequestValidator : Validator<PostContentRequest>
} }
public sealed class PostContent( public sealed class PostContent(
IAzureBlobStorageService blobStorage, IBlobStorage blobStorage,
ContentDbContext context) ContentDbContext context)
: Endpoint<PostContentRequest> : Endpoint<PostContentRequest>
{ {