diff --git a/src/Application/Common/Interfaces/IAzureBlobStorageService.cs b/src/Application/Common/Interfaces/IBlobStorage.cs similarity index 88% rename from src/Application/Common/Interfaces/IAzureBlobStorageService.cs rename to src/Application/Common/Interfaces/IBlobStorage.cs index 83537e9..7dac254 100644 --- a/src/Application/Common/Interfaces/IAzureBlobStorageService.cs +++ b/src/Application/Common/Interfaces/IBlobStorage.cs @@ -1,6 +1,6 @@ namespace Hutopy.Application.Common.Interfaces; -public interface IAzureBlobStorageService +public interface IBlobStorage { Task UploadFileAsync(string containerName, string blobName, Stream stream, string contentType, CancellationToken ct = default); diff --git a/src/Application/Users/Commands/UploadProfilePicture.cs b/src/Application/Users/Commands/UploadProfilePicture.cs index cbf4b00..3cc34cc 100644 --- a/src/Application/Users/Commands/UploadProfilePicture.cs +++ b/src/Application/Users/Commands/UploadProfilePicture.cs @@ -1,6 +1,5 @@ using Hutopy.Application.AzureBlobStorage.Constants; using Hutopy.Application.Common.Interfaces; -using Hutopy.Application.Utils; using Microsoft.AspNetCore.Http; namespace Hutopy.Application.Users.Commands; @@ -16,19 +15,17 @@ public class UploadProfilePictureCommand : IRequest public class UploadProfilePictureCommandHandler( IHttpContextAccessor contextAccessor, IIdentityService identityService, - IAzureBlobStorageService azureBlobStorageService) : IRequestHandler + IBlobStorage blobStorage) : IRequestHandler { public async Task Handle(UploadProfilePictureCommand request, CancellationToken ct) { - var contentType = contextAccessor.EnsureContentType(); - var identityUser = await identityService.GetCurrentUserAsync(); - var url = await azureBlobStorageService.UploadFileAsync( + var url = await blobStorage.UploadFileAsync( ContainerNames.Users, $"{identityUser.Id}/{SubDirectoryNames.Profile}/{CommonFileNames.ProfilePicture}", request.File.OpenReadStream(), - contentType, + request.File.ContentType, ct); await identityService.UpdateCurrentUserPortraitUrlAsync(url); diff --git a/src/Application/Users/Queries/GetCurrentUser/GetCurrentUserProfilePicture.cs b/src/Application/Users/Queries/GetCurrentUser/GetCurrentUserProfilePicture.cs index f598887..26865b7 100644 --- a/src/Application/Users/Queries/GetCurrentUser/GetCurrentUserProfilePicture.cs +++ b/src/Application/Users/Queries/GetCurrentUser/GetCurrentUserProfilePicture.cs @@ -7,7 +7,7 @@ public record GetCurrentUserProfilePictureQuery : IRequest; public class GetCurrentUserProfilePictureQueryHandler( IIdentityService identityService, - IAzureBlobStorageService azureBlobStorageService + IBlobStorage blobStorage ) : IRequestHandler { @@ -15,7 +15,7 @@ public class GetCurrentUserProfilePictureQueryHandler( { var identityUser = await identityService.GetCurrentUserAsync(); - return await azureBlobStorageService.DownloadFileAsync( + return await blobStorage.DownloadFileAsync( ContainerNames.Users, $"{identityUser.Id.ToString()}/{SubDirectoryNames.Profile}/{CommonFileNames.ProfilePicture}", cancellationToken); diff --git a/src/Application/Utils/HttpContextAccessorExtensions.cs b/src/Application/Utils/HttpContextAccessorExtensions.cs deleted file mode 100644 index 849e1a8..0000000 --- a/src/Application/Utils/HttpContextAccessorExtensions.cs +++ /dev/null @@ -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; - } -} diff --git a/src/Infrastructure/AzureBlob/AzureBlobStorageService.cs b/src/Infrastructure/AzureBlob/AzureBlobStorage.cs similarity index 92% rename from src/Infrastructure/AzureBlob/AzureBlobStorageService.cs rename to src/Infrastructure/AzureBlob/AzureBlobStorage.cs index 9fee071..2016b7f 100644 --- a/src/Infrastructure/AzureBlob/AzureBlobStorageService.cs +++ b/src/Infrastructure/AzureBlob/AzureBlobStorage.cs @@ -7,13 +7,14 @@ using Microsoft.Extensions.Logging; namespace Hutopy.Infrastructure.AzureBlob; -public class AzureBlobStorageService : IAzureBlobStorageService +public class AzureBlobStorage : IBlobStorage { + private const long MaxUploadSize = 10 * 1024 * 1024; // 10 MB in bytes + private readonly BlobServiceClient _blobServiceClient; - private readonly ILogger _logger; - private readonly long _maxUploadSize = 10 * 1024 * 1024; // 10 MB in bytes + private readonly ILogger _logger; - public AzureBlobStorageService(IConfiguration configuration, ILogger logger) + public AzureBlobStorage(IConfiguration configuration, ILogger logger) { _logger = logger; var connectionString = configuration["Azure-Blob-Connection-String"] ?? ""; @@ -37,12 +38,12 @@ public class AzureBlobStorageService : IAzureBlobStorageService stream.Position = 0; // Check if the file size exceeds the maximum upload size - if (stream.Length > _maxUploadSize) + if (stream.Length > MaxUploadSize) { _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( - $"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 diff --git a/src/Infrastructure/DependencyInjection.cs b/src/Infrastructure/DependencyInjection.cs index f7c3525..f816daa 100644 --- a/src/Infrastructure/DependencyInjection.cs +++ b/src/Infrastructure/DependencyInjection.cs @@ -52,7 +52,7 @@ public static class DependencyInjection // Singleton services services.AddSingleton(TimeProvider.System); - services.AddSingleton(); + services.AddSingleton(); // Scoped services services.AddScoped(); diff --git a/src/Web/Features/Contents/Handlers/ChangeBanner.cs b/src/Web/Features/Contents/Handlers/ChangeBanner.cs index 8601ff4..e5f64da 100644 --- a/src/Web/Features/Contents/Handlers/ChangeBanner.cs +++ b/src/Web/Features/Contents/Handlers/ChangeBanner.cs @@ -1,7 +1,6 @@ using FastEndpoints; using Hutopy.Application.AzureBlobStorage.Constants; using Hutopy.Application.Common.Interfaces; -using Hutopy.Application.Utils; using Hutopy.Web.Features.Contents.Data; using Microsoft.EntityFrameworkCore; @@ -14,7 +13,7 @@ public record ChangeBannerRequest( public class ChangeBannerHandler( IHttpContextAccessor contextAccessor, ContentDbContext context, - IAzureBlobStorageService azureBlobStorageService) + IBlobStorage blobStorage) : Endpoint { public override void Configure() @@ -29,21 +28,27 @@ public class ChangeBannerHandler( var creator = await context .Creators .Include(c => c.StoredDataUrls) - .SingleAsync( + .SingleOrDefaultAsync( c => c.Id == request.CreatorId, cancellationToken: ct); - var contentType = contextAccessor.EnsureContentType(); - - var blobUrl = await azureBlobStorageService.UploadFileAsync( + if (creator is null) + { + await SendNotFoundAsync(ct); + return; + } + + var blobUrl = await blobStorage.UploadFileAsync( ContainerNames.Users, $"{request.CreatorId}/{SubDirectoryNames.Profile}/{CommonFileNames.BannerPicture}", request.File.OpenReadStream(), - contentType, + request.File.ContentType, ct); - + + creator.StoredDataUrls.BannerPictureUrl = blobUrl; + await context.SaveChangesAsync(ct); - + await SendOkAsync(blobUrl, ct); } } diff --git a/src/Web/Features/Contents/Handlers/CreateContent.cs b/src/Web/Features/Contents/Handlers/CreateContent.cs index 836dbe1..14496f0 100644 --- a/src/Web/Features/Contents/Handlers/CreateContent.cs +++ b/src/Web/Features/Contents/Handlers/CreateContent.cs @@ -38,7 +38,7 @@ public sealed class PostContentRequestValidator : Validator } public sealed class PostContent( - IAzureBlobStorageService blobStorage, + IBlobStorage blobStorage, ContentDbContext context) : Endpoint {