diff --git a/Directory.Packages.props b/Directory.Packages.props
index be8b079..cad324b 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -36,6 +36,7 @@
+
diff --git a/src/Application/Application.csproj b/src/Application/Application.csproj
index 34570d3..996edb9 100644
--- a/src/Application/Application.csproj
+++ b/src/Application/Application.csproj
@@ -11,6 +11,7 @@
+
diff --git a/src/Application/AzureBlobStorage/Constants/CommonFileNames.cs b/src/Application/AzureBlobStorage/Constants/CommonFileNames.cs
index 8ffc63c..b6d44aa 100644
--- a/src/Application/AzureBlobStorage/Constants/CommonFileNames.cs
+++ b/src/Application/AzureBlobStorage/Constants/CommonFileNames.cs
@@ -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";
}
diff --git a/src/Application/AzureBlobStorage/Constants/ContentTypes.cs b/src/Application/AzureBlobStorage/Constants/ContentTypes.cs
deleted file mode 100644
index ff3bcf7..0000000
--- a/src/Application/AzureBlobStorage/Constants/ContentTypes.cs
+++ /dev/null
@@ -1,6 +0,0 @@
-namespace Hutopy.Application.AzureBlobStorage.Constants;
-
-public static class ContentTypes
-{
- public static string ImagePng = "image/png";
-}
diff --git a/src/Application/Common/Models/Result.cs b/src/Application/Common/Models/Result.cs
index 294e2ed..8c30b4a 100644
--- a/src/Application/Common/Models/Result.cs
+++ b/src/Application/Common/Models/Result.cs
@@ -31,6 +31,11 @@ public class Result(
{
return Value ?? default(T)!;
}
+
+ public string GetErrorsAsString()
+ {
+ return Errors.Length == 0 ? string.Empty : string.Join(", ", Errors);
+ }
public static Result Success(T value)
{
diff --git a/src/Application/Users/Commands/CreateUser.cs b/src/Application/Users/Commands/CreateUser.cs
index 54077eb..703066c 100644
--- a/src/Application/Users/Commands/CreateUser.cs
+++ b/src/Application/Users/Commands/CreateUser.cs
@@ -1,7 +1,8 @@
using Hutopy.Application.Common.Interfaces;
+using Microsoft.AspNetCore.Http;
namespace Hutopy.Application.Users.Commands;
-public record CreateUserCommand : IRequest
+public record CreateUserCommand : IRequest
{
public required string FirstName { get; init; }
public required string LastName { get; init; }
@@ -10,7 +11,7 @@ public record CreateUserCommand : IRequest
public required string Password { get; init; }
}
-public class CreateUserCommandHandler : IRequestHandler
+public class CreateUserCommandHandler : IRequestHandler
{
private readonly IApplicationDbContext _context;
private readonly IIdentityService _identityService;
@@ -21,7 +22,7 @@ public class CreateUserCommandHandler : IRequestHandler
_identityService = identityService;
}
- public async Task Handle(CreateUserCommand request, CancellationToken cancellationToken)
+ public async Task 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
await _context.SaveChangesAsync(cancellationToken);
- return new Guid(user?.Id ?? string.Empty);
+ return Results.Ok(new Guid(user?.Id ?? string.Empty));
}
}
diff --git a/src/Application/Users/Commands/UpdateCurrentUserCommand.cs b/src/Application/Users/Commands/UpdateCurrentUserCommand.cs
index 7d55961..682cc3e 100644
--- a/src/Application/Users/Commands/UpdateCurrentUserCommand.cs
+++ b/src/Application/Users/Commands/UpdateCurrentUserCommand.cs
@@ -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
+public class UpdateCurrentUserCommand : IRequest
{
public required string FirstName { get; init; }
public required string LastName { get; init; }
@@ -32,13 +33,13 @@ public class UpdateCurrentUserCommand : IRequest
}
public class UpdateCurrentUserCommandHandler(IApplicationDbContext context, IIdentityService identityService, IMapper mapper) :
- IRequestHandler
+ IRequestHandler
{
- public async Task Handle(UpdateCurrentUserCommand request, CancellationToken cancellationToken)
+ public async Task 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(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());
}
}
diff --git a/src/Application/Users/Commands/UploadBannerPicture.cs b/src/Application/Users/Commands/UploadBannerPicture.cs
index e99f28a..be7590f 100644
--- a/src/Application/Users/Commands/UploadBannerPicture.cs
+++ b/src/Application/Users/Commands/UploadBannerPicture.cs
@@ -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;
///
/// Upload a banner picture. If the user has the url already, set the BannerPictureUrl in the user only without upload.
///
-public class UploadBannerPictureCommand : IRequest
+public class UploadBannerPictureCommand : IRequest
{
public required Stream BannerPicture { get; init; }
public string BannerPictureUrl { get; init; } = string.Empty;
}
-public class UploadBannerPictureCommandHandler(IIdentityService identityService, IAzureBlobStorageService azureBlobStorageService) : IRequestHandler
+public class UploadBannerPictureCommandHandler(IHttpContextAccessor contextAccessor, IIdentityService identityService, IAzureBlobStorageService azureBlobStorageService) : IRequestHandler
{
- public async Task Handle(UploadBannerPictureCommand request, CancellationToken cancellationToken)
+ public async Task 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);
}
}
diff --git a/src/Application/Users/Commands/UploadProfilePicture.cs b/src/Application/Users/Commands/UploadProfilePicture.cs
index ae15d31..2e017d2 100644
--- a/src/Application/Users/Commands/UploadProfilePicture.cs
+++ b/src/Application/Users/Commands/UploadProfilePicture.cs
@@ -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;
///
/// Upload a profile picture. If the user has the url already, set the ProfilePictureUrl in the user only without upload.
///
-public class UploadProfilePictureCommand : IRequest
+public class UploadProfilePictureCommand : IRequest
{
public required Stream ProfilePicture { get; init; }
public string ProfilePictureUrl { get; init; } = string.Empty;
}
-public class UploadProfilePictureCommandHandler(IIdentityService identityService, IAzureBlobStorageService azureBlobStorageService) : IRequestHandler
+public class UploadProfilePictureCommandHandler(IHttpContextAccessor contextAccessor, IIdentityService identityService, IAzureBlobStorageService azureBlobStorageService) : IRequestHandler
{
- public async Task Handle(UploadProfilePictureCommand request, CancellationToken cancellationToken)
+ public async Task 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);
}
}
diff --git a/src/Application/Users/Commands/UploadWebsiteIcon.cs b/src/Application/Users/Commands/UploadWebsiteIcon.cs
index 31f3f5f..eaa8cd6 100644
--- a/src/Application/Users/Commands/UploadWebsiteIcon.cs
+++ b/src/Application/Users/Commands/UploadWebsiteIcon.cs
@@ -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;
///
/// Upload a website icon. If the user has the url already, set the WebsitePictureUrl in the user only without upload.
///
-public class UploadWebsiteIconCommand : IRequest
+public class UploadWebsiteIconCommand : IRequest
{
public required Stream WebsiteIcon { get; init; }
public string WebsitePictureUrl { get; init; } = string.Empty;
}
-public class UploadWebsiteIconCommandHandler(IIdentityService identityService, IAzureBlobStorageService azureBlobStorageService) : IRequestHandler
+public class UploadWebsiteIconCommandHandler(IHttpContextAccessor contextAccessor, IIdentityService identityService, IAzureBlobStorageService azureBlobStorageService) : IRequestHandler
{
- public async Task Handle(UploadWebsiteIconCommand request, CancellationToken cancellationToken)
+ public async Task 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);
}
}
diff --git a/src/Application/Utils/HttpContextAccessorExtensions.cs b/src/Application/Utils/HttpContextAccessorExtensions.cs
new file mode 100644
index 0000000..849e1a8
--- /dev/null
+++ b/src/Application/Utils/HttpContextAccessorExtensions.cs
@@ -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;
+ }
+}
diff --git a/src/Infrastructure/AzureBlob/AzureBlobStorageService.cs b/src/Infrastructure/AzureBlob/AzureBlobStorageService.cs
index 18d7856..8f12630 100644
--- a/src/Infrastructure/AzureBlob/AzureBlobStorageService.cs
+++ b/src/Infrastructure/AzureBlob/AzureBlobStorageService.cs
@@ -1,22 +1,23 @@
-using System;
-using System.IO;
-using System.Threading.Tasks;
+using Azure;
using Azure.Storage.Blobs;
using Azure.Storage.Blobs.Models;
using Hutopy.Application.Common.Interfaces;
using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.Logging;
namespace Hutopy.Infrastructure.AzureBlob;
public class AzureBlobStorageService : IAzureBlobStorageService
{
private readonly BlobServiceClient _blobServiceClient;
+ private readonly ILogger _logger;
+ private readonly long _maxUploadSize = 10 * 1024 * 1024; // 10 MB in bytes
- public AzureBlobStorageService(IConfiguration configuration)
+ public AzureBlobStorageService(IConfiguration configuration, ILogger logger)
{
+ _logger = logger;
var connectionString = configuration["Azure-Blob-Connection-String"] ?? "";
_blobServiceClient = new BlobServiceClient(connectionString);
-
}
///
@@ -29,29 +30,72 @@ public class AzureBlobStorageService : IAzureBlobStorageService
///
public async Task UploadFileAsync(string containerName, string blobName, Stream fileStream, string contentType)
{
- // Get a reference to a container
- var containerClient = _blobServiceClient.GetBlobContainerClient(containerName);
-
- // Create the container if it does not exist
- await containerClient.CreateIfNotExistsAsync();
+ // Read the file stream into a memory stream to determine the length
+ // WATCH FOR MEMORY USAGE USING THE MEMORY STREAM.
+ var memoryStream = new MemoryStream();
+ await fileStream.CopyToAsync(memoryStream);
+ memoryStream.Position = 0;
- // Get a reference to a blob
- var blobClient = containerClient.GetBlobClient(blobName);
-
- // Define the BlobHttpHeaders to include the content type
- var blobHttpHeaders = new BlobHttpHeaders
+ // Check if the file size exceeds the maximum upload size
+ if (memoryStream.Length > _maxUploadSize)
{
- ContentType = contentType
- };
+ _logger.LogInformation($"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.");
+ }
+
+ // Validate content type
+ if (!ContentTypes.IsAllowed(contentType, memoryStream))
+ {
+ _logger.LogInformation($"Blob storage: Unsupported file type {contentType}. Only PNG and JPEG are allowed.");
+ throw new InvalidOperationException("Unsupported file type. Only PNG and JPEG are allowed.");
+ }
+
+ try
+ {
+ // Get a reference to a container
+ var containerClient = _blobServiceClient.GetBlobContainerClient(containerName);
- // Upload the file
- await blobClient.UploadAsync(fileStream, new BlobUploadOptions
+ // Create the container if it does not exist
+ await containerClient.CreateIfNotExistsAsync();
+
+ // Get a reference to a blob
+ var blobClient = containerClient.GetBlobClient(blobName);
+
+ // Define the BlobHttpHeaders to include the content type
+ var blobHttpHeaders = new BlobHttpHeaders
+ {
+ ContentType = contentType
+ };
+
+ // Upload the file
+ var response = await blobClient.UploadAsync(memoryStream, new BlobUploadOptions
+ {
+ HttpHeaders = blobHttpHeaders
+ });
+
+ var fileUri = blobClient.Uri.ToString();
+
+ _logger.LogInformation(
+ $"Blob storage: Status [ {response.GetRawResponse().Status.ToString()} ] " +
+ $"Uploaded [ {blobName} ] to the container [ {containerName} ] " +
+ $"with contentType [ {contentType} ] " +
+ $"with a length of [ {memoryStream.Length} bytes ]" +
+ $"with the uri [ {fileUri} ]"
+ );
+
+ // Return the URI of the uploaded blob
+ return fileUri;
+ }
+ catch (RequestFailedException ex)
{
- HttpHeaders = blobHttpHeaders
- });
-
- // Return the URI of the uploaded blob
- return blobClient.Uri.ToString();
+ _logger.LogError($"Blob storage: Azure Storage request failed: {ex.Message}");
+ throw new Exception("Error uploading file to Azure Blob Storage", ex);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError($"Blob storage: An error occurred: {ex.Message}");
+ throw;
+ }
}
///
@@ -62,14 +106,14 @@ public class AzureBlobStorageService : IAzureBlobStorageService
///
public async Task DownloadFileAsync(string containerName, string blobName)
{
- // Get a reference to a container
- var containerClient = _blobServiceClient.GetBlobContainerClient(containerName);
-
- // Get a reference to a blob
- var blobClient = containerClient.GetBlobClient(blobName);
-
try
{
+ // Get a reference to a container
+ var containerClient = _blobServiceClient.GetBlobContainerClient(containerName);
+
+ // Get a reference to a blob
+ var blobClient = containerClient.GetBlobClient(blobName);
+
// Download the blob to a stream
BlobDownloadInfo download = await blobClient.DownloadAsync();
MemoryStream memoryStream = new();
@@ -78,9 +122,14 @@ public class AzureBlobStorageService : IAzureBlobStorageService
return memoryStream;
}
+ catch (RequestFailedException ex)
+ {
+ _logger.LogError($"Azure Storage request failed: {ex.Message}");
+ throw new Exception("Error downloading file from Azure Blob Storage", ex);
+ }
catch (Exception ex)
{
- // Log and handle the exception as needed
+ _logger.LogError($"An error occurred: {ex.Message}");
throw new ApplicationException("Error downloading file from Azure Blob Storage.", ex);
}
}
diff --git a/src/Infrastructure/AzureBlob/ContentTypes.cs b/src/Infrastructure/AzureBlob/ContentTypes.cs
new file mode 100644
index 0000000..2637fc9
--- /dev/null
+++ b/src/Infrastructure/AzureBlob/ContentTypes.cs
@@ -0,0 +1,36 @@
+namespace Hutopy.Infrastructure.AzureBlob;
+
+public static class ContentTypes
+{
+ private static string ImagePng = "image/png";
+ private static string ImageJpeg = "image/jpeg";
+ private static string ImageJpg = "image/jpg";
+
+ public static HashSet AllowedContentTypes = new HashSet { ImagePng, ImageJpeg, ImageJpg };
+
+ public static bool IsAllowed(string contentType, Stream fileStream)
+ {
+ return IsValidFileType(fileStream) && AllowedContentTypes.Contains(contentType);
+ }
+
+ private static bool IsValidFileType(Stream fileStream)
+ {
+ byte[] buffer = new byte[4];
+ fileStream.Read(buffer, 0, buffer.Length);
+ fileStream.Position = 0;
+
+ // PNG file signature: 89 50 4E 47 (in hex)
+ if (buffer[0] == 0x89 && buffer[1] == 0x50 && buffer[2] == 0x4E && buffer[3] == 0x47)
+ {
+ return true;
+ }
+
+ // JPEG file signature: FF D8 FF (in hex)
+ if (buffer[0] == 0xFF && buffer[1] == 0xD8 && buffer[2] == 0xFF)
+ {
+ return true;
+ }
+
+ return false;
+ }
+}
diff --git a/src/Infrastructure/GlobalUsings.cs b/src/Infrastructure/GlobalUsings.cs
index 4668da2..f176ce1 100644
--- a/src/Infrastructure/GlobalUsings.cs
+++ b/src/Infrastructure/GlobalUsings.cs
@@ -1 +1,4 @@
-global using Ardalis.GuardClauses;
\ No newline at end of file
+global using System;
+global using System.Linq;
+global using System.Threading;
+global using System.Threading.Tasks;
diff --git a/src/Web/Endpoints/UpdateMyUser.cs b/src/Web/Endpoints/UpdateMyUser.cs
index 8f13133..b26303a 100644
--- a/src/Web/Endpoints/UpdateMyUser.cs
+++ b/src/Web/Endpoints/UpdateMyUser.cs
@@ -14,24 +14,24 @@ public class UpdateMyUser : EndpointGroupBase
.MapPatch("/profile", UpdateCurrentUser);
}
- private static async Task UpdateCurrentUser(ISender sender, UpdateCurrentUserCommand command)
+ private static async Task UpdateCurrentUser(ISender sender, UpdateCurrentUserCommand command)
{
return await sender.Send(command);
}
- private static async Task UpdateCurrentUserProfilePicture(ISender sender, Stream stream, string url = "")
+ private static async Task UpdateCurrentUserProfilePicture(ISender sender, Stream stream, string url = "")
{
var command = new UploadProfilePictureCommand { ProfilePicture = stream, ProfilePictureUrl = url};
return await sender.Send(command);
}
- private static async Task UpdateCurrentUserBannerPicture(ISender sender, Stream stream, string url = "")
+ private static async Task UpdateCurrentUserBannerPicture(ISender sender, Stream stream, string url = "")
{
var command = new UploadBannerPictureCommand { BannerPicture = stream, BannerPictureUrl = url};
return await sender.Send(command);
}
- private static async Task UpdateCurrentUserWebsiteIcon(ISender sender, Stream stream, string url = "")
+ private static async Task UpdateCurrentUserWebsiteIcon(ISender sender, Stream stream, string url = "")
{
var command = new UploadWebsiteIconCommand { WebsiteIcon = stream, WebsitePictureUrl = url};
return await sender.Send(command);
diff --git a/src/Web/Endpoints/Users.cs b/src/Web/Endpoints/Users.cs
index 39bc408..bbdeb4c 100644
--- a/src/Web/Endpoints/Users.cs
+++ b/src/Web/Endpoints/Users.cs
@@ -10,11 +10,10 @@ public class Users : EndpointGroupBase
app.MapGroup(this)
.MapPost(CreateUser)
.MapPost(Login, "/login")
- .MapPost(UploadProfilePicture, "/upload-profile-picture")
.MapGet(GetUser);
}
- private static async Task CreateUser(ISender sender, CreateUserCommand command)
+ private static async Task CreateUser(ISender sender, CreateUserCommand command)
{
return await sender.Send(command);
}
@@ -28,11 +27,4 @@ public class Users : EndpointGroupBase
{
return await sender.Send(command);
}
-
- private static async Task UploadProfilePicture(ISender sender, Stream stream)
- {
- var command = new UploadProfilePictureCommand { ProfilePicture = stream };
-
- return await sender.Send(command);
- }
}