Merged PR 99: Add-logs-for-blob-storage-calls and verify file type and size into master
This commit is contained in:
@@ -11,6 +11,7 @@
|
||||
<PackageReference Include="FluentValidation.DependencyInjectionExtensions" />
|
||||
<PackageReference Include="Google.Apis.Oauth2.v2" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" />
|
||||
<PackageReference Include="MinimalApis.Extensions" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
public static class CommonFileNames
|
||||
{
|
||||
public static string ProfilePicture = "profilePicture.png";
|
||||
public static string BannerPicture = "bannerPicture.png";
|
||||
public static string WebsiteIcon = "websiteIcon.png";
|
||||
public static string ProfilePicture = "profilePicture";
|
||||
public static string BannerPicture = "bannerPicture";
|
||||
public static string WebsiteIcon = "websiteIcon";
|
||||
}
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
namespace Hutopy.Application.AzureBlobStorage.Constants;
|
||||
|
||||
public static class ContentTypes
|
||||
{
|
||||
public static string ImagePng = "image/png";
|
||||
}
|
||||
@@ -31,6 +31,11 @@ public class Result<T>(
|
||||
{
|
||||
return Value ?? default(T)!;
|
||||
}
|
||||
|
||||
public string GetErrorsAsString()
|
||||
{
|
||||
return Errors.Length == 0 ? string.Empty : string.Join(", ", Errors);
|
||||
}
|
||||
|
||||
public static Result<T> Success(T value)
|
||||
{
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
using Hutopy.Application.Common.Interfaces;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Hutopy.Application.Users.Commands;
|
||||
public record CreateUserCommand : IRequest<Guid>
|
||||
public record CreateUserCommand : IRequest<IResult>
|
||||
{
|
||||
public required string FirstName { get; init; }
|
||||
public required string LastName { get; init; }
|
||||
@@ -10,7 +11,7 @@ public record CreateUserCommand : IRequest<Guid>
|
||||
public required string Password { get; init; }
|
||||
}
|
||||
|
||||
public class CreateUserCommandHandler : IRequestHandler<CreateUserCommand, Guid>
|
||||
public class CreateUserCommandHandler : IRequestHandler<CreateUserCommand, IResult>
|
||||
{
|
||||
private readonly IApplicationDbContext _context;
|
||||
private readonly IIdentityService _identityService;
|
||||
@@ -21,7 +22,7 @@ public class CreateUserCommandHandler : IRequestHandler<CreateUserCommand, Guid>
|
||||
_identityService = identityService;
|
||||
}
|
||||
|
||||
public async Task<Guid> Handle(CreateUserCommand request, CancellationToken cancellationToken)
|
||||
public async Task<IResult> Handle(CreateUserCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
await _identityService.CreateUserAsync(request.EmailAddress, request.UserName, request.FirstName, request.LastName, request.Password);
|
||||
|
||||
@@ -29,6 +30,6 @@ public class CreateUserCommandHandler : IRequestHandler<CreateUserCommand, Guid>
|
||||
|
||||
await _context.SaveChangesAsync(cancellationToken);
|
||||
|
||||
return new Guid(user?.Id ?? string.Empty);
|
||||
return Results.Ok(new Guid(user?.Id ?? string.Empty));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,10 +2,11 @@ using System.ComponentModel.DataAnnotations.Schema;
|
||||
using Hutopy.Application.Common.Interfaces;
|
||||
using Hutopy.Application.Common.Models;
|
||||
using Hutopy.Application.Users.Models;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Hutopy.Application.Users.Commands;
|
||||
|
||||
public class UpdateCurrentUserCommand : IRequest<string>
|
||||
public class UpdateCurrentUserCommand : IRequest<IResult>
|
||||
{
|
||||
public required string FirstName { get; init; }
|
||||
public required string LastName { get; init; }
|
||||
@@ -32,13 +33,13 @@ public class UpdateCurrentUserCommand : IRequest<string>
|
||||
}
|
||||
|
||||
public class UpdateCurrentUserCommandHandler(IApplicationDbContext context, IIdentityService identityService, IMapper mapper) :
|
||||
IRequestHandler<UpdateCurrentUserCommand, string>
|
||||
IRequestHandler<UpdateCurrentUserCommand, IResult>
|
||||
{
|
||||
public async Task<string> Handle(UpdateCurrentUserCommand request, CancellationToken cancellationToken)
|
||||
public async Task<IResult> Handle(UpdateCurrentUserCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
var identityUser = await identityService.GetCurrentUserAsync();
|
||||
|
||||
if (identityUser?.Id is null) return string.Empty;
|
||||
if (identityUser?.Id is null) return Results.Problem("Current user not found.");
|
||||
|
||||
var userModel = mapper.Map<UserModel>(request);
|
||||
userModel.Id = identityUser.Id;
|
||||
@@ -46,8 +47,8 @@ public class UpdateCurrentUserCommandHandler(IApplicationDbContext context, IIde
|
||||
var result = await identityService.UpdateCurrentUserAsync(userModel);
|
||||
|
||||
await context.SaveChangesAsync(cancellationToken);
|
||||
|
||||
return result.GetValueOrDefault();
|
||||
|
||||
return result.Succeeded ? Results.Ok(result.GetValueOrDefault()) : Results.Problem(result.GetErrorsAsString());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,37 +1,42 @@
|
||||
using Hutopy.Application.AzureBlobStorage.Constants;
|
||||
using Hutopy.Application.Common.Interfaces;
|
||||
using Hutopy.Application.Utils;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Hutopy.Application.Users.Commands;
|
||||
|
||||
/// <summary>
|
||||
/// Upload a banner picture. If the user has the url already, set the BannerPictureUrl in the user only without upload.
|
||||
/// </summary>
|
||||
public class UploadBannerPictureCommand : IRequest<string>
|
||||
public class UploadBannerPictureCommand : IRequest<IResult>
|
||||
{
|
||||
public required Stream BannerPicture { get; init; }
|
||||
public string BannerPictureUrl { get; init; } = string.Empty;
|
||||
}
|
||||
|
||||
public class UploadBannerPictureCommandHandler(IIdentityService identityService, IAzureBlobStorageService azureBlobStorageService) : IRequestHandler<UploadBannerPictureCommand, string>
|
||||
public class UploadBannerPictureCommandHandler(IHttpContextAccessor contextAccessor, IIdentityService identityService, IAzureBlobStorageService azureBlobStorageService) : IRequestHandler<UploadBannerPictureCommand, IResult>
|
||||
{
|
||||
public async Task<string> Handle(UploadBannerPictureCommand request, CancellationToken cancellationToken)
|
||||
public async Task<IResult> Handle(UploadBannerPictureCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
// If an url to the picture is provided, use it right away and don't upload anything.
|
||||
if (!string.IsNullOrEmpty(request.BannerPictureUrl))
|
||||
{
|
||||
await identityService.UpdateCurrentUserBannerPictureUrlAsync(request.BannerPictureUrl);
|
||||
return request.BannerPictureUrl;
|
||||
return Results.Ok(request.BannerPictureUrl);
|
||||
}
|
||||
|
||||
var contentType = contextAccessor.EnsureContentType();
|
||||
|
||||
var identityUser = await identityService.GetCurrentUserAsync();
|
||||
var currentUserId = new Guid(identityUser?.Id ?? "").ToString();
|
||||
|
||||
var blobName = $"{currentUserId}/{SubDirectoryNames.Profile}/{CommonFileNames.BannerPicture}";
|
||||
|
||||
var url = await azureBlobStorageService.UploadFileAsync(ContainerNames.Users, blobName, request.BannerPicture, ContentTypes.ImagePng);
|
||||
var url = await azureBlobStorageService.UploadFileAsync(ContainerNames.Users, blobName, request.BannerPicture, contentType);
|
||||
|
||||
await identityService.UpdateCurrentUserBannerPictureUrlAsync(url);
|
||||
|
||||
return url;
|
||||
|
||||
return Results.Ok(url);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,37 +1,42 @@
|
||||
using Hutopy.Application.AzureBlobStorage.Constants;
|
||||
using Hutopy.Application.Common.Interfaces;
|
||||
using Hutopy.Application.Utils;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Hutopy.Application.Users.Commands;
|
||||
|
||||
/// <summary>
|
||||
/// Upload a profile picture. If the user has the url already, set the ProfilePictureUrl in the user only without upload.
|
||||
/// </summary>
|
||||
public class UploadProfilePictureCommand : IRequest<string>
|
||||
public class UploadProfilePictureCommand : IRequest<IResult>
|
||||
{
|
||||
public required Stream ProfilePicture { get; init; }
|
||||
public string ProfilePictureUrl { get; init; } = string.Empty;
|
||||
}
|
||||
|
||||
public class UploadProfilePictureCommandHandler(IIdentityService identityService, IAzureBlobStorageService azureBlobStorageService) : IRequestHandler<UploadProfilePictureCommand, string>
|
||||
public class UploadProfilePictureCommandHandler(IHttpContextAccessor contextAccessor, IIdentityService identityService, IAzureBlobStorageService azureBlobStorageService) : IRequestHandler<UploadProfilePictureCommand, IResult>
|
||||
{
|
||||
public async Task<string> Handle(UploadProfilePictureCommand request, CancellationToken cancellationToken)
|
||||
public async Task<IResult> Handle(UploadProfilePictureCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
// If an url to the picture is provided, use it right away and don't upload anything.
|
||||
if (!string.IsNullOrEmpty(request.ProfilePictureUrl))
|
||||
{
|
||||
await identityService.UpdateCurrentUserProfilePictureUrlAsync(request.ProfilePictureUrl);
|
||||
return request.ProfilePictureUrl;
|
||||
return Results.Ok(request.ProfilePictureUrl);
|
||||
}
|
||||
|
||||
var contentType = contextAccessor.EnsureContentType();
|
||||
|
||||
var identityUser = await identityService.GetCurrentUserAsync();
|
||||
var currentUserId = new Guid(identityUser?.Id ?? "").ToString();
|
||||
|
||||
var blobName = $"{currentUserId}/{SubDirectoryNames.Profile}/{CommonFileNames.ProfilePicture}";
|
||||
|
||||
var url = await azureBlobStorageService.UploadFileAsync(ContainerNames.Users, blobName, request.ProfilePicture, ContentTypes.ImagePng);
|
||||
var url = await azureBlobStorageService.UploadFileAsync(ContainerNames.Users, blobName, request.ProfilePicture, contentType);
|
||||
|
||||
await identityService.UpdateCurrentUserProfilePictureUrlAsync(url);
|
||||
|
||||
return url;
|
||||
return Results.Ok(url);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,38 +1,43 @@
|
||||
using Hutopy.Application.AzureBlobStorage.Constants;
|
||||
using Hutopy.Application.Common.Interfaces;
|
||||
using Hutopy.Application.Utils;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace Hutopy.Application.Users.Commands;
|
||||
|
||||
/// <summary>
|
||||
/// Upload a website icon. If the user has the url already, set the WebsitePictureUrl in the user only without upload.
|
||||
/// </summary>
|
||||
public class UploadWebsiteIconCommand : IRequest<string>
|
||||
public class UploadWebsiteIconCommand : IRequest<IResult>
|
||||
{
|
||||
public required Stream WebsiteIcon { get; init; }
|
||||
|
||||
public string WebsitePictureUrl { get; init; } = string.Empty;
|
||||
}
|
||||
|
||||
public class UploadWebsiteIconCommandHandler(IIdentityService identityService, IAzureBlobStorageService azureBlobStorageService) : IRequestHandler<UploadWebsiteIconCommand, string>
|
||||
public class UploadWebsiteIconCommandHandler(IHttpContextAccessor contextAccessor, IIdentityService identityService, IAzureBlobStorageService azureBlobStorageService) : IRequestHandler<UploadWebsiteIconCommand, IResult>
|
||||
{
|
||||
public async Task<string> Handle(UploadWebsiteIconCommand request, CancellationToken cancellationToken)
|
||||
public async Task<IResult> Handle(UploadWebsiteIconCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
// If an url to the picture is provided, use it right away and don't upload anything.
|
||||
if (!string.IsNullOrEmpty(request.WebsitePictureUrl))
|
||||
{
|
||||
await identityService.UpdateCurrentUserWebsiteIconUrlAsync(request.WebsitePictureUrl);
|
||||
return request.WebsitePictureUrl;
|
||||
return Results.Ok(request.WebsitePictureUrl);
|
||||
}
|
||||
|
||||
var contentType = contextAccessor.EnsureContentType();
|
||||
|
||||
var identityUser = await identityService.GetCurrentUserAsync();
|
||||
var currentUserId = new Guid(identityUser?.Id ?? "").ToString();
|
||||
|
||||
var blobName = $"{currentUserId}/{SubDirectoryNames.Profile}/{CommonFileNames.WebsiteIcon}";
|
||||
|
||||
var url = await azureBlobStorageService.UploadFileAsync(ContainerNames.Users, blobName, request.WebsiteIcon, ContentTypes.ImagePng);
|
||||
var url = await azureBlobStorageService.UploadFileAsync(ContainerNames.Users, blobName, request.WebsiteIcon, contentType);
|
||||
|
||||
await identityService.UpdateCurrentUserWebsiteIconUrlAsync(url);
|
||||
|
||||
return url;
|
||||
return Results.Ok(request.WebsitePictureUrl);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
29
src/Application/Utils/HttpContextAccessorExtensions.cs
Normal file
29
src/Application/Utils/HttpContextAccessorExtensions.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user