diff --git a/Directory.Packages.props b/Directory.Packages.props
index 42adba5..00e2212 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -7,7 +7,7 @@
-
+
diff --git a/src/Application/AzureBlobStorage/Constants/CommonFileNames.cs b/src/Application/AzureBlobStorage/Constants/CommonFileNames.cs
index b6d44aa..6a37a08 100644
--- a/src/Application/AzureBlobStorage/Constants/CommonFileNames.cs
+++ b/src/Application/AzureBlobStorage/Constants/CommonFileNames.cs
@@ -4,5 +4,4 @@ public static class CommonFileNames
{
public static string ProfilePicture = "profilePicture";
public static string BannerPicture = "bannerPicture";
- public static string WebsiteIcon = "websiteIcon";
}
diff --git a/src/Application/Common/Behaviours/AuthorizationBehaviour.cs b/src/Application/Common/Behaviours/AuthorizationBehaviour.cs
index 30de73f..8012cce 100644
--- a/src/Application/Common/Behaviours/AuthorizationBehaviour.cs
+++ b/src/Application/Common/Behaviours/AuthorizationBehaviour.cs
@@ -7,62 +7,74 @@ namespace Hutopy.Application.Common.Behaviours;
public class AuthorizationBehaviour(
IUser user,
- IIdentityService identityService)
+ IIdentityService identityService)
: IPipelineBehavior
where TRequest : notnull
{
- public async Task Handle(TRequest request, RequestHandlerDelegate next, CancellationToken cancellationToken)
+ public async Task Handle(TRequest request, RequestHandlerDelegate next,
+ CancellationToken cancellationToken)
{
- var authorizeAttributes = request.GetType().GetCustomAttributes();
+ var authorizeAttributes = request
+ .GetType()
+ .GetCustomAttributes()
+ .ToArray();
- if (authorizeAttributes.Any())
+ if (authorizeAttributes.Length == 0)
{
- // Must be authenticated user
- if (user.Id == null)
+ return await next();
+ }
+
+ if (user.Id is null)
+ {
+ throw new UnauthorizedAccessException();
+ }
+
+ // Role-based authorization
+ var authorizeAttributesWithRoles = authorizeAttributes
+ .Where(a => !string.IsNullOrWhiteSpace(a.Roles))
+ .ToArray();
+
+ if (authorizeAttributesWithRoles.Length != 0)
+ {
+ var authorized = false;
+
+ foreach (var roles in authorizeAttributesWithRoles.Select(a => a.Roles.Split(',')))
{
- throw new UnauthorizedAccessException();
- }
-
- // Role-based authorization
- var authorizeAttributesWithRoles = authorizeAttributes.Where(a => !string.IsNullOrWhiteSpace(a.Roles));
-
- if (authorizeAttributesWithRoles.Any())
- {
- var authorized = false;
-
- foreach (var roles in authorizeAttributesWithRoles.Select(a => a.Roles.Split(',')))
+ foreach (var role in roles)
{
- foreach (var role in roles)
+ var isInRole = await identityService.IsInRoleAsync(user.Id.Value, role.Trim());
+ if (isInRole)
{
- var isInRole = await identityService.IsInRoleAsync(user.Id, role.Trim());
- if (isInRole)
- {
- authorized = true;
- break;
- }
+ authorized = true;
+ break;
}
}
-
- // Must be a member of at least one role in roles
- if (!authorized)
- {
- throw new ForbiddenAccessException();
- }
}
- // Policy-based authorization
- var authorizeAttributesWithPolicies = authorizeAttributes.Where(a => !string.IsNullOrWhiteSpace(a.Policy));
- if (authorizeAttributesWithPolicies.Any())
+ // Must be a member of at least one role in roles
+ if (!authorized)
{
- foreach (var policy in authorizeAttributesWithPolicies.Select(a => a.Policy))
- {
- var authorized = await identityService.AuthorizeAsync(user.Id, policy);
+ throw new ForbiddenAccessException();
+ }
+ }
- if (!authorized)
- {
- throw new ForbiddenAccessException();
- }
- }
+ // Policy-based authorization
+ var authorizeAttributesWithPolicies = authorizeAttributes
+ .Where(a => !string.IsNullOrWhiteSpace(a.Policy))
+ .ToArray();
+
+ if (authorizeAttributesWithPolicies.Length == 0)
+ {
+ return await next();
+ }
+
+ foreach (var policy in authorizeAttributesWithPolicies.Select(a => a.Policy))
+ {
+ var authorized = await identityService.AuthorizeAsync(user.Id.Value, policy);
+
+ if (!authorized)
+ {
+ throw new ForbiddenAccessException();
}
}
diff --git a/src/Application/Common/Behaviours/LoggingBehaviour.cs b/src/Application/Common/Behaviours/LoggingBehaviour.cs
index 07814ca..def9dca 100644
--- a/src/Application/Common/Behaviours/LoggingBehaviour.cs
+++ b/src/Application/Common/Behaviours/LoggingBehaviour.cs
@@ -5,9 +5,9 @@ using Microsoft.Extensions.Logging;
namespace Hutopy.Application.Common.Behaviours;
public class LoggingBehaviour(
- ILogger logger,
- IUser user,
- IIdentityService identityService)
+ ILogger logger,
+ IUser user,
+ IIdentityService identityService)
: IRequestPreProcessor
where TRequest : notnull
{
@@ -16,15 +16,15 @@ public class LoggingBehaviour(
public async Task Process(TRequest request, CancellationToken cancellationToken)
{
var requestName = typeof(TRequest).Name;
- var userId = user.Id ?? string.Empty;
string? userName = string.Empty;
- if (!string.IsNullOrEmpty(userId))
+ if (user.Id.HasValue)
{
- userName = await identityService.GetUserNameAsync(userId);
+ userName = await identityService.GetUserNameAsync(user.Id.Value);
}
- _logger.LogInformation("Hutopy Request: {Name} {@UserId} {@UserName} {@Request}",
- requestName, userId, userName, request);
+ _logger.LogInformation(
+ "Hutopy Request: {Name} {@UserId} {@UserName} {@Request}",
+ requestName, user.Id ?? Guid.Empty, userName, request);
}
}
diff --git a/src/Application/Common/Behaviours/PerformanceBehaviour.cs b/src/Application/Common/Behaviours/PerformanceBehaviour.cs
index ada438a..20a82a2 100644
--- a/src/Application/Common/Behaviours/PerformanceBehaviour.cs
+++ b/src/Application/Common/Behaviours/PerformanceBehaviour.cs
@@ -26,13 +26,12 @@ public class PerformanceBehaviour(
if (elapsedMilliseconds <= 500) return response;
var requestName = typeof(TRequest).Name;
- var userId = user.Id ?? string.Empty;
var userName = string.Empty;
- if (!string.IsNullOrEmpty(userId)) userName = await identityService.GetUserNameAsync(userId);
+ if (user.Id.HasValue) userName = await identityService.GetUserNameAsync(user.Id.Value);
logger.LogWarning("Hutopy Long Running Request: {Name} ({ElapsedMilliseconds} milliseconds) {@UserId} {@UserName} {@Request}",
- requestName, elapsedMilliseconds, userId, userName, request);
+ requestName, elapsedMilliseconds, user.Id ?? Guid.Empty, userName, request);
return response;
}
diff --git a/src/Application/Common/Interfaces/IAzureBlobStorageService.cs b/src/Application/Common/Interfaces/IAzureBlobStorageService.cs
index e0aa991..83537e9 100644
--- a/src/Application/Common/Interfaces/IAzureBlobStorageService.cs
+++ b/src/Application/Common/Interfaces/IAzureBlobStorageService.cs
@@ -2,6 +2,7 @@
public interface IAzureBlobStorageService
{
- Task UploadFileAsync(string containerName, string blobName, MemoryStream memoryStream, string contentType, CancellationToken ct = default);
+ Task UploadFileAsync(string containerName, string blobName, Stream stream, string contentType,
+ CancellationToken ct = default);
Task DownloadFileAsync(string containerName, string blobName, CancellationToken ct = default);
}
diff --git a/src/Application/Common/Interfaces/IIdentityService.cs b/src/Application/Common/Interfaces/IIdentityService.cs
index e780b94..3ebbfb3 100644
--- a/src/Application/Common/Interfaces/IIdentityService.cs
+++ b/src/Application/Common/Interfaces/IIdentityService.cs
@@ -1,29 +1,27 @@
-using Google.Apis.Oauth2.v2.Data;
-using Hutopy.Application.Common.Models;
+using Hutopy.Application.Common.Models;
namespace Hutopy.Application.Common.Interfaces;
public interface IIdentityService
{
- Task> CreateUserAsync(Userinfo userInfo);
-
- Task> CreateUserAsync(string email, string userName, string firstName, string lastName,
+ Task> CreateUserAsync(
+ string email,
+ string userName,
+ string firstName,
+ string lastName,
string password);
Task GetCurrentUserAsync();
- Task UpdateCurrentUserBannerPictureUrlAsync(string url);
- Task UpdateCurrentUserProfilePictureUrlAsync(string url);
- Task UpdateCurrentUserWebsiteIconUrlAsync(string url);
- Task> UpdateCurrentUserAsync(UserModel userModel);
+ Task UpdateCurrentUserPortraitUrlAsync(string url);
+ Task> UpdateCurrentUserAsync(UserModel userModel);
Task> GetCurrentUserRolesAsync();
Task FindUserByIdAsync(string id);
- Task FindUserByCreatorAliasAsync(string creatorAlias, CancellationToken cancellationToken);
Task FindUserByEmailAsync(string email);
Task GetUserByUserNameAsync(string userName);
Task LoginAsync(string email, string password);
- Task IsInRoleAsync(string userId, string role);
- Task AuthorizeAsync(string userId, string policyName);
- Task GetUserNameAsync(string userId);
+ Task IsInRoleAsync(Guid userId, string role);
+ Task AuthorizeAsync(Guid userId, string policyName);
+ Task GetUserNameAsync(Guid userId);
Task AddRoleAsync(string userId, string role);
Task DeleteUserAsync(string userId);
diff --git a/src/Application/Common/Interfaces/IUser.cs b/src/Application/Common/Interfaces/IUser.cs
index f6112a1..ede555b 100644
--- a/src/Application/Common/Interfaces/IUser.cs
+++ b/src/Application/Common/Interfaces/IUser.cs
@@ -2,5 +2,5 @@
public interface IUser
{
- string? Id { get; }
+ Guid? Id { get; }
}
diff --git a/src/Application/Common/Models/RoleModel.cs b/src/Application/Common/Models/RoleModel.cs
index ed49feb..5c1c786 100644
--- a/src/Application/Common/Models/RoleModel.cs
+++ b/src/Application/Common/Models/RoleModel.cs
@@ -2,6 +2,6 @@ namespace Hutopy.Application.Common.Models;
public class RoleModel
{
- public string? Id { get; set; }
+ public Guid Id { get; set; }
public string? Name { get; set; }
}
diff --git a/src/Application/Common/Models/UserModel.cs b/src/Application/Common/Models/UserModel.cs
index f67d8a9..b38e4b4 100644
--- a/src/Application/Common/Models/UserModel.cs
+++ b/src/Application/Common/Models/UserModel.cs
@@ -1,26 +1,16 @@
-using Hutopy.Application.Users.Models;
-
namespace Hutopy.Application.Common.Models;
public class UserModel
{
- public string Id { get; set; } = string.Empty;
- public string? CreatorAlias { get; set; }
- public string UserName { get; set; } = string.Empty;
- public string? Alias { get; set; }
- public string FirstName { get; set; } = string.Empty;
- public string LastName { get; set; } = string.Empty;
- public string Occupation { get; set; } = string.Empty;
- public string Email { get; init; } = string.Empty;
- public string PhoneNumber { get; init; } = string.Empty;
- public string BirthDate { get; init; } = string.Empty;
- public string Country { get; init; } = string.Empty;
- public string City { get; init; } = string.Empty;
- public string Address { get; init; } = string.Empty;
- public string About { get; init; } = string.Empty;
- public string Description { get; init; } = string.Empty;
- public SocialNetworksModel SocialNetworks { get; init; } = new();
- public ProfileColorsModel ProfileColors { get; init; } = new();
- public StoredDataUrlsModel StoredDataUrls { get; init; } = new();
- public string ProfilePictureUrl { get; set; } = string.Empty;
+ public Guid Id { get; set; }
+ public string UserName { get; init; } = null!;
+ public string? Alias { get; init; }
+ public string? PortraitUrl { get; init; }
+ public string? FirstName { get; init; }
+ public string? LastName { get; init; }
+ public string? Occupation { get; init; }
+ public string? Email { get; init; }
+ public string? PhoneNumber { get; init; }
+ public string? BirthDate { get; init; }
+ public string? Address { get; init; }
}
diff --git a/src/Application/Stripe/Commands/ConfirmStripeTransaction.cs b/src/Application/Stripe/Commands/ConfirmStripeTransaction.cs
index 0c74658..e287b45 100644
--- a/src/Application/Stripe/Commands/ConfirmStripeTransaction.cs
+++ b/src/Application/Stripe/Commands/ConfirmStripeTransaction.cs
@@ -50,7 +50,7 @@ public class ConfirmStripeTransactionCommandHandler(
{
public async Task Handle(ConfirmStripeTransactionCommand request, CancellationToken cancellationToken)
{
- var lastTransaction = await dbContext.UserTransactions.OrderBy(x => x.Created).LastAsync(cancellationToken);
+ var lastTransaction = await dbContext.UserTransactions.OrderBy(x => x.CreatedAt).LastAsync(cancellationToken);
var stripeConfirmation = stripeService.ValidateTransaction(request);
if (stripeConfirmation.Succeeded)
diff --git a/src/Application/Stripe/Commands/CreateSessionCheckoutCommand.cs b/src/Application/Stripe/Commands/CreateSessionCheckoutCommand.cs
index 681c4d8..80249d3 100644
--- a/src/Application/Stripe/Commands/CreateSessionCheckoutCommand.cs
+++ b/src/Application/Stripe/Commands/CreateSessionCheckoutCommand.cs
@@ -2,30 +2,37 @@
using Hutopy.Domain.Entities;
namespace Hutopy.Application.Stripe.Commands;
+
public record CreateSessionCheckoutCommand : IRequest
{
- public required string CreatorId { get; init; }
+ public required Guid CreatorId { get; init; }
public required int Amount { get; init; }
public string Currency { get; init; } = "CAD";
public string TipMessage { get; init; } = string.Empty;
}
public class CreateSessionCheckoutCommandHandler(
- IApplicationDbContext dbContext,
+ IApplicationDbContext dbContext,
IStripeService stripeService
- )
+)
: IRequestHandler
{
public async Task Handle(CreateSessionCheckoutCommand request, CancellationToken cancellationToken)
{
- var stripeSecret = await stripeService.CreateCheckoutSession(request.Amount, request.CreatorId, request.Currency);
+ var stripeSecret = await stripeService.CreateCheckoutSession(
+ request.Amount,
+ request.CreatorId.ToString(),
+ request.Currency);
// ReSharper disable once PossibleLossOfFraction
decimal priceInDollars = (request.Amount / 100);
-
+
var userTransaction = new UserTransaction
{
- Currency = request.Currency, Amount = priceInDollars, TipMessage = request.TipMessage, ApplicationUserId = request.CreatorId
+ Currency = request.Currency,
+ Amount = priceInDollars,
+ TipMessage = request.TipMessage,
+ ApplicationUserId = request.CreatorId
};
await dbContext.UserTransactions.AddAsync(userTransaction, cancellationToken);
diff --git a/src/Application/Stripe/Queries/GetMyLastReceipt.cs b/src/Application/Stripe/Queries/GetMyLastReceipt.cs
index b8a0602..c4feb05 100644
--- a/src/Application/Stripe/Queries/GetMyLastReceipt.cs
+++ b/src/Application/Stripe/Queries/GetMyLastReceipt.cs
@@ -4,25 +4,23 @@ namespace Hutopy.Application.Stripe.Queries;
public record GetMyLastReceiptQuery : IRequest
{
+ public Guid CreatorId { get; set; }
public string Email { get; set; } = string.Empty;
- public string CreatorId { get; set; } = string.Empty;
};
public class GetMyLastReceiptQueryHandler(
IApplicationDbContext dbContext
- )
+)
: IRequestHandler
{
public async Task Handle(GetMyLastReceiptQuery request, CancellationToken cancellationToken)
{
- var lastTransaction = await dbContext.UserTransactions.OrderBy(x => x.Created)
- .LastOrDefaultAsync(x => x.ApplicationUserId == request.CreatorId && x.StripeBillingDetailEmail == request.Email,
+ var lastTransaction = await dbContext.UserTransactions.OrderBy(x => x.CreatedAt)
+ .LastOrDefaultAsync(
+ x => x.ApplicationUserId == request.CreatorId && x.StripeBillingDetailEmail == request.Email,
cancellationToken);
-
- var receiptUrl = new MyLastReceiptDto
- {
- ReceiptUrl = lastTransaction?.StripeReceiptUrl ?? "",
- };
+
+ var receiptUrl = new MyLastReceiptDto { ReceiptUrl = lastTransaction?.StripeReceiptUrl ?? "", };
return receiptUrl;
}
diff --git a/src/Application/Users/Commands/CreateUser.cs b/src/Application/Users/Commands/CreateUser.cs
index 703066c..d84b69b 100644
--- a/src/Application/Users/Commands/CreateUser.cs
+++ b/src/Application/Users/Commands/CreateUser.cs
@@ -28,8 +28,10 @@ public class CreateUserCommandHandler : IRequestHandler
{
- public required string FirstName { get; init; }
- public required string LastName { get; init; }
- public required string Occupation { get; init; }
- public required string PhoneNumber { get; init; }
- public required string BirthDate { get; init; }
- public required string Country { get; init; }
- public required string City { get; init; }
- public required string Address { get; init; }
- public required string About { get; init; }
- public required string Description { get; init; }
- public required SocialNetworksModel SocialNetworks { get; init; }
- public required ProfileColorsModel ProfileColors { get; init; }
+ public required string? Alias { get; init; }
+ public required string? FirstName { get; init; }
+ public required string? LastName { get; init; }
+ public required string? Occupation { get; init; }
+ public required string? BirthDate { get; init; }
+ public required string? Country { get; init; }
+ public required string? City { get; init; }
+ public required string? Address { get; init; }
-
[NotMapped]
private class Mapping : Profile
{
@@ -32,8 +26,11 @@ public class UpdateCurrentUserCommand : IRequest
}
}
-public class UpdateCurrentUserCommandHandler(IApplicationDbContext context, IIdentityService identityService, IMapper mapper) :
- IRequestHandler
+public class UpdateCurrentUserCommandHandler(
+ IApplicationDbContext context,
+ IIdentityService identityService,
+ IMapper mapper)
+ : IRequestHandler
{
public async Task Handle(UpdateCurrentUserCommand request, CancellationToken cancellationToken)
{
@@ -43,12 +40,11 @@ public class UpdateCurrentUserCommandHandler(IApplicationDbContext context, IIde
var userModel = mapper.Map(request);
userModel.Id = identityUser.Id;
-
+
var result = await identityService.UpdateCurrentUserAsync(userModel);
await context.SaveChangesAsync(cancellationToken);
-
+
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
deleted file mode 100644
index 63573fb..0000000
--- a/src/Application/Users/Commands/UploadBannerPicture.cs
+++ /dev/null
@@ -1,47 +0,0 @@
-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 required MemoryStream BannerPicture { get; init; }
- public string BannerPictureUrl { get; init; } = string.Empty;
-}
-
-public class UploadBannerPictureCommandHandler(IHttpContextAccessor contextAccessor, IIdentityService identityService, IAzureBlobStorageService azureBlobStorageService) : IRequestHandler
-{
- 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 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,
- contentType,
- cancellationToken);
-
- await identityService.UpdateCurrentUserBannerPictureUrlAsync(url);
-
- return Results.Ok(url);
- }
-}
-
diff --git a/src/Application/Users/Commands/UploadProfilePicture.cs b/src/Application/Users/Commands/UploadProfilePicture.cs
index 431e014..cbf4b00 100644
--- a/src/Application/Users/Commands/UploadProfilePicture.cs
+++ b/src/Application/Users/Commands/UploadProfilePicture.cs
@@ -10,38 +10,29 @@ namespace Hutopy.Application.Users.Commands;
///
public class UploadProfilePictureCommand : IRequest
{
- public required MemoryStream ProfilePicture { get; init; }
- public string ProfilePictureUrl { get; init; } = string.Empty;
+ public required IFormFile File { get; init; }
}
-public class UploadProfilePictureCommandHandler(IHttpContextAccessor contextAccessor, IIdentityService identityService, IAzureBlobStorageService azureBlobStorageService) : IRequestHandler
+public class UploadProfilePictureCommandHandler(
+ IHttpContextAccessor contextAccessor,
+ IIdentityService identityService,
+ IAzureBlobStorageService azureBlobStorageService) : IRequestHandler
{
public async Task Handle(UploadProfilePictureCommand request, CancellationToken ct)
{
- // 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 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,
+ ContainerNames.Users,
+ $"{identityUser.Id}/{SubDirectoryNames.Profile}/{CommonFileNames.ProfilePicture}",
+ request.File.OpenReadStream(),
contentType,
ct);
- await identityService.UpdateCurrentUserProfilePictureUrlAsync(url);
-
+ await identityService.UpdateCurrentUserPortraitUrlAsync(url);
+
return Results.Ok(url);
}
}
-
diff --git a/src/Application/Users/Commands/UploadWebsiteIcon.cs b/src/Application/Users/Commands/UploadWebsiteIcon.cs
deleted file mode 100644
index 2e74eda..0000000
--- a/src/Application/Users/Commands/UploadWebsiteIcon.cs
+++ /dev/null
@@ -1,50 +0,0 @@
-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 required MemoryStream WebsiteIcon { get; init; }
-
- public string WebsitePictureUrl { get; init; } = string.Empty;
-}
-
-public class UploadWebsiteIconCommandHandler(
- IHttpContextAccessor contextAccessor,
- IIdentityService identityService,
- IAzureBlobStorageService azureBlobStorageService) : IRequestHandler
-{
- public async Task Handle(UploadWebsiteIconCommand request, CancellationToken ct)
- {
- // 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 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,
- contentType,
- ct);
-
- await identityService.UpdateCurrentUserWebsiteIconUrlAsync(url);
-
- return Results.Ok(request.WebsitePictureUrl);
- }
-}
diff --git a/src/Application/Users/Models/ProfileColorsModel.cs b/src/Application/Users/Models/ProfileColorsModel.cs
deleted file mode 100644
index 04baadb..0000000
--- a/src/Application/Users/Models/ProfileColorsModel.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-namespace Hutopy.Application.Users.Models;
-
-public class ProfileColorsModel
-{
- public string BannerTop { get; init; } = String.Empty;
- public string BannerBottom { get; init; } = String.Empty;
- public string Accent { get; init; } = String.Empty;
- public string Menu { get; init; } = String.Empty;
-}
diff --git a/src/Application/Users/Models/SocialNetworksModel.cs b/src/Application/Users/Models/SocialNetworksModel.cs
deleted file mode 100644
index 19a2f02..0000000
--- a/src/Application/Users/Models/SocialNetworksModel.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-namespace Hutopy.Application.Users.Models;
-
-public class SocialNetworksModel
-{
- public string FacebookUrl { get; init; } = string.Empty;
- public string InstagramUrl { get; init; } = string.Empty;
- public string XUrl { get; init; } = string.Empty;
- public string LinkedInUrl { get; init; } = string.Empty;
- public string TikTokUrl { get; init; } = string.Empty;
- public string YoutubeUrl { get; init; } = string.Empty;
- public string RedditUrl { get; init; } = string.Empty;
- public string YourWebsiteUrl { get; init; } = string.Empty;
-}
diff --git a/src/Application/Users/Models/StoredDataUrlsModel.cs b/src/Application/Users/Models/StoredDataUrlsModel.cs
deleted file mode 100644
index 06eb528..0000000
--- a/src/Application/Users/Models/StoredDataUrlsModel.cs
+++ /dev/null
@@ -1,8 +0,0 @@
-namespace Hutopy.Application.Users.Models;
-
-public class StoredDataUrlsModel
-{
- public string? BannerPictureUrl { get; set; }
- public string? ProfilePictureUrl { get; set; }
- public string? WebsiteIconUrl { get; set; }
-}
diff --git a/src/Application/Users/Queries/GetCurrentUser/GetCurrentUser.cs b/src/Application/Users/Queries/GetCurrentUser/GetCurrentUser.cs
index 4429bed..18e3f8e 100644
--- a/src/Application/Users/Queries/GetCurrentUser/GetCurrentUser.cs
+++ b/src/Application/Users/Queries/GetCurrentUser/GetCurrentUser.cs
@@ -11,15 +11,16 @@ public class GetCurrentUserQueryHandler(
)
: IRequestHandler
{
- public async Task Handle(GetCurrentUserQuery request, CancellationToken cancellationToken)
+ public async Task Handle(GetCurrentUserQuery request, CancellationToken cancellationToken)
{
- var identityUser = await identityService.GetCurrentUserAsync();
- var currentUserId = Guid.Parse(identityUser!.Id!);
+ var userModel = await identityService.GetCurrentUserAsync();
+ if (userModel is null) return null;
+
var transactions = await context
.UserTransactions
- .Where(x => x.ApplicationUserId == currentUserId.ToString())
- .OrderBy(x => x.LastModified)
+ .Where(x => x.ApplicationUserId == userModel.Id)
+ .OrderBy(x => x.LastModifiedAt)
.ProjectTo(mapper.ConfigurationProvider)
.Where(x => x.IsConfirmed == true)
.ToListAsync(cancellationToken);
@@ -28,24 +29,17 @@ public class GetCurrentUserQueryHandler(
var user = new UserDto
{
- Id = currentUserId,
- Alias = identityUser.Alias,
- FirstName = identityUser.FirstName,
- LastName = identityUser.LastName,
- UserName = identityUser.UserName,
- CreatorAlias= identityUser.CreatorAlias,
- Occupation = identityUser.Occupation,
- PhoneNumber = identityUser.PhoneNumber,
- Email = identityUser.Email,
- BirthDate = identityUser.BirthDate,
- Country = identityUser.Country,
- City = identityUser.City,
- Address = identityUser.Address,
- About = identityUser.About,
- Description = identityUser.Description,
- SocialNetworks = identityUser.SocialNetworks,
- ProfileColors = identityUser.ProfileColors,
- StoredDataUrls = identityUser.StoredDataUrls,
+ Id = userModel.Id,
+ Alias = userModel.Alias,
+ PortraitUrl = userModel.PortraitUrl,
+ FirstName = userModel.FirstName,
+ LastName = userModel.LastName,
+ UserName = userModel.UserName,
+ Occupation = userModel.Occupation,
+ PhoneNumber = userModel.PhoneNumber,
+ Email = userModel.Email,
+ BirthDate = userModel.BirthDate,
+ Address = userModel.Address,
UserTransactions = transactions,
TotalBalance = transactions.Sum(x => x.Amount),
UserRoles = roles,
diff --git a/src/Application/Users/Queries/GetCurrentUser/GetCurrentUserProfilePicture.cs b/src/Application/Users/Queries/GetCurrentUser/GetCurrentUserProfilePicture.cs
index cb4e6b4..f598887 100644
--- a/src/Application/Users/Queries/GetCurrentUser/GetCurrentUserProfilePicture.cs
+++ b/src/Application/Users/Queries/GetCurrentUser/GetCurrentUserProfilePicture.cs
@@ -8,16 +8,16 @@ public record GetCurrentUserProfilePictureQuery : IRequest;
public class GetCurrentUserProfilePictureQueryHandler(
IIdentityService identityService,
IAzureBlobStorageService azureBlobStorageService
- )
+)
: IRequestHandler
{
public async Task Handle(GetCurrentUserProfilePictureQuery request, CancellationToken cancellationToken)
{
var identityUser = await identityService.GetCurrentUserAsync();
- var currentUserId = new Guid(identityUser?.Id ?? "");
-
- var blobName = $"{currentUserId.ToString()}/{SubDirectoryNames.Profile}/{CommonFileNames.ProfilePicture}";
-
- return await azureBlobStorageService.DownloadFileAsync(ContainerNames.Users, blobName);
+
+ return await azureBlobStorageService.DownloadFileAsync(
+ ContainerNames.Users,
+ $"{identityUser.Id.ToString()}/{SubDirectoryNames.Profile}/{CommonFileNames.ProfilePicture}",
+ cancellationToken);
}
}
diff --git a/src/Application/Users/Queries/GetCurrentUser/UserDto.cs b/src/Application/Users/Queries/GetCurrentUser/UserDto.cs
index 3560de2..689c411 100644
--- a/src/Application/Users/Queries/GetCurrentUser/UserDto.cs
+++ b/src/Application/Users/Queries/GetCurrentUser/UserDto.cs
@@ -1,28 +1,19 @@
-using Hutopy.Application.Users.Models;
-
namespace Hutopy.Application.Users.Queries.GetCurrentUser;
public class UserDto
{
public Guid Id { get; init; }
- public string? Alias { get; init; }
- public required string FirstName { get; init; }
- public required string LastName { get; init; }
- public string? CreatorAlias { get; set; }
- public string UserName { get; init; } = string.Empty;
- public string Occupation { get; init; } = string.Empty;
- public string Email { get; init; } = string.Empty;
- public string PhoneNumber { get; init; } = string.Empty;
- public string BirthDate { get; init; } = string.Empty;
- public string Country { get; init; } = string.Empty;
- public string City { get; init; } = string.Empty;
- public string Address { get; init; } = string.Empty;
- public string About { get; init; } = string.Empty;
- public string Description { get; init; } = string.Empty;
- public SocialNetworksModel SocialNetworks { get; init; } = new();
- public ProfileColorsModel ProfileColors { get; init; } = new();
- public StoredDataUrlsModel StoredDataUrls { get; init; } = new();
- public List UserTransactions { get; init; } = [];
public IList UserRoles { get; init; } = [];
+ public string UserName { get; init; } = null!;
+ public string? Alias { get; init; }
+ public string? PortraitUrl { get; init; }
+ public string? FirstName { get; init; }
+ public string? LastName { get; init; }
+ public string? Occupation { get; init; }
+ public string? Email { get; init; }
+ public string? PhoneNumber { get; init; }
+ public string? BirthDate { get; init; }
+ public string? Address { get; init; }
+ public List UserTransactions { get; init; } = [];
public required decimal TotalBalance { get; init; }
}
diff --git a/src/Application/Users/Queries/GetUser/GetUser.cs b/src/Application/Users/Queries/GetUser/GetUser.cs
deleted file mode 100644
index 3b36caa..0000000
--- a/src/Application/Users/Queries/GetUser/GetUser.cs
+++ /dev/null
@@ -1,46 +0,0 @@
-using Hutopy.Application.Common.Interfaces;
-using Hutopy.Application.Common.Models;
-
-namespace Hutopy.Application.Users.Queries.GetUser;
-
-public record GetUserQuery : IRequest
-{
- public string? UserId { get; set; } = string.Empty;
- public string? UserName { get; set; } = string.Empty;
-};
-
-public class GetUserQueryHandler(
- IIdentityService identityService
- )
- : IRequestHandler
-{
- public async Task Handle(GetUserQuery request, CancellationToken cancellationToken)
- {
- UserModel? identityUser = null;
-
- if (request.UserId != string.Empty)
- {
- identityUser = await identityService.FindUserByIdAsync(request.UserId);
-
- }
-
- if (request.UserName != string.Empty)
- {
- identityUser = await identityService.GetUserByUserNameAsync(request.UserName);
- }
-
- var user = new UserDto
- {
- Id = identityUser?.Id ?? string.Empty,
- FirstName = identityUser?.FirstName ?? string.Empty,
- LastName = identityUser?.LastName ?? string.Empty,
- UserName = identityUser?.UserName ?? string.Empty,
- Occupation = identityUser?.Occupation ?? string.Empty,
- SocialNetworks = identityUser?.SocialNetworks ?? new(),
- ProfileColors = identityUser?.ProfileColors ?? new(),
- StoredDataUrls = identityUser?.StoredDataUrls ?? new(),
- };
-
- return user;
- }
-}
diff --git a/src/Application/Users/Queries/GetUser/GetUserById.cs b/src/Application/Users/Queries/GetUser/GetUserById.cs
new file mode 100644
index 0000000..1128cfc
--- /dev/null
+++ b/src/Application/Users/Queries/GetUser/GetUserById.cs
@@ -0,0 +1,23 @@
+using Hutopy.Application.Common.Interfaces;
+
+namespace Hutopy.Application.Users.Queries.GetUser;
+
+public record GetUserByIdQuery : IRequest
+{
+ public required string UserId { get; init; }
+}
+
+public class GetUserByIdHandler(
+ IIdentityService identityService
+ )
+ : IRequestHandler
+{
+ public async Task Handle(GetUserByIdQuery query, CancellationToken cancellationToken)
+ {
+ var user = await identityService.FindUserByIdAsync(query.UserId);
+
+ if (user is null) throw new InvalidOperationException();
+
+ return user.ToDto();
+ }
+}
diff --git a/src/Application/Users/Queries/GetUser/GetUserByUserName.cs b/src/Application/Users/Queries/GetUser/GetUserByUserName.cs
new file mode 100644
index 0000000..131ac8b
--- /dev/null
+++ b/src/Application/Users/Queries/GetUser/GetUserByUserName.cs
@@ -0,0 +1,23 @@
+using Hutopy.Application.Common.Interfaces;
+
+namespace Hutopy.Application.Users.Queries.GetUser;
+
+public record GetUserByUserNameQuery : IRequest
+{
+ public required string UserName { get; init; }
+};
+
+public class GetUserByUserNameQueryHandler(
+ IIdentityService identityService
+)
+ : IRequestHandler
+{
+ public async Task Handle(GetUserByUserNameQuery query, CancellationToken cancellationToken)
+ {
+ var user = await identityService.GetUserByUserNameAsync(query.UserName);
+
+ if (user is null) throw new InvalidOperationException();
+
+ return user.ToDto();
+ }
+}
diff --git a/src/Application/Users/Queries/GetUser/UserDto.cs b/src/Application/Users/Queries/GetUser/UserDto.cs
index 6c1dc13..86ce3d4 100644
--- a/src/Application/Users/Queries/GetUser/UserDto.cs
+++ b/src/Application/Users/Queries/GetUser/UserDto.cs
@@ -1,17 +1,25 @@
-using Hutopy.Application.Users.Models;
+using Hutopy.Application.Common.Models;
namespace Hutopy.Application.Users.Queries.GetUser;
public class UserDto
{
- public required string Id { get; init; }
- public required string FirstName { get; init; }
- public required string LastName { get; init; }
- public string CreatorAlias { get; set; }
- public required string UserName { get; init; } = String.Empty;
- public required string Occupation { get; init; } = String.Empty;
-
- public SocialNetworksModel SocialNetworks { get; init; } = new();
- public ProfileColorsModel ProfileColors { get; init; } = new();
- public StoredDataUrlsModel StoredDataUrls { get; init; } = new();
+ public required Guid Id { get; init; }
+ public required string UserName { get; init; }
+ public string? FirstName { get; init; }
+ public string? LastName { get; init; }
+ public string? Occupation { get; init; }
+}
+
+public static class UserDtoExtensions
+{
+ public static UserDto ToDto(this UserModel model) =>
+ new()
+ {
+ Id = model.Id,
+ FirstName = model.FirstName,
+ LastName = model.LastName,
+ UserName = model.UserName,
+ Occupation = model.Occupation
+ };
}
diff --git a/src/Domain/Common/BaseAuditableEntity.cs b/src/Domain/Common/BaseAuditableEntity.cs
index f1da955..617d876 100644
--- a/src/Domain/Common/BaseAuditableEntity.cs
+++ b/src/Domain/Common/BaseAuditableEntity.cs
@@ -2,11 +2,11 @@
public abstract class BaseAuditableEntity : BaseEntity
{
- public DateTimeOffset Created { get; set; }
+ public DateTimeOffset CreatedAt { get; set; }
- public string? CreatedBy { get; set; }
+ public Guid? CreatedBy { get; set; }
- public DateTimeOffset LastModified { get; set; }
+ public DateTimeOffset LastModifiedAt { get; set; }
- public string? LastModifiedBy { get; set; }
+ public Guid? LastModifiedBy { get; set; }
}
diff --git a/src/Domain/Entities/UserTransaction.cs b/src/Domain/Entities/UserTransaction.cs
index 78e32d4..b7df7da 100644
--- a/src/Domain/Entities/UserTransaction.cs
+++ b/src/Domain/Entities/UserTransaction.cs
@@ -7,7 +7,7 @@ public class UserTransaction : BaseAuditableEntity
public string TipMessage { get; set; } = string.Empty;
// Foreign key to ApplicationUser
- public required string ApplicationUserId { get; set; }
+ public required Guid ApplicationUserId { get; set; }
public bool IsConfirmed { get; set; }
public string StripeEventId { get; set; } = string.Empty;
public string StripeChargeId { get; set; } = string.Empty;
diff --git a/src/Infrastructure/AzureBlob/AzureBlobStorageService.cs b/src/Infrastructure/AzureBlob/AzureBlobStorageService.cs
index 7887cef..9fee071 100644
--- a/src/Infrastructure/AzureBlob/AzureBlobStorageService.cs
+++ b/src/Infrastructure/AzureBlob/AzureBlobStorageService.cs
@@ -23,21 +23,21 @@ public class AzureBlobStorageService : IAzureBlobStorageService
///
/// Upload a file to microsoft azure blob storage.
///
- /// The blob name (path within the container, include the file name).
/// The name of the container where the file is stored.
- /// The memory stream containing the image.
+ /// The blob name (path within the container, include the file name).
+ ///
/// The content type.
/// The cancellation token
///
- public async Task UploadFileAsync(string containerName, string blobName, MemoryStream memoryStream,
+ public async Task UploadFileAsync(string containerName, string blobName, Stream stream,
string contentType, CancellationToken ct = default)
{
// Read the file stream into a memory stream to determine the length
// WATCH FOR MEMORY USAGE USING THE MEMORY STREAM.
- memoryStream.Position = 0;
+ stream.Position = 0;
// Check if the file size exceeds the maximum upload size
- if (memoryStream.Length > _maxUploadSize)
+ if (stream.Length > _maxUploadSize)
{
_logger.LogError(
$"Blob storage: File size exceeds the maximum allowed size of {_maxUploadSize} bytes.");
@@ -46,7 +46,7 @@ public class AzureBlobStorageService : IAzureBlobStorageService
}
// Validate content type
- if (!ContentTypes.IsAllowed(contentType, memoryStream))
+ if (!ContentTypes.IsAllowed(contentType, stream))
{
_logger.LogError(
$"Blob storage: Unsupported file type {contentType}. Only PNG and JPEG are allowed.");
@@ -71,7 +71,7 @@ public class AzureBlobStorageService : IAzureBlobStorageService
// Upload the file
var response = await blobClient.UploadAsync(
- memoryStream,
+ stream,
new BlobUploadOptions { HttpHeaders = blobHttpHeaders },
ct);
@@ -89,7 +89,7 @@ public class AzureBlobStorageService : IAzureBlobStorageService
blobName,
containerName,
contentType,
- memoryStream.Length,
+ stream.Length,
fileUri
);
@@ -128,6 +128,7 @@ public class AzureBlobStorageService : IAzureBlobStorageService
// Download the blob to a stream
BlobDownloadInfo download = await blobClient.DownloadAsync(ct);
+
MemoryStream memoryStream = new();
await download.Content.CopyToAsync(memoryStream, ct);
memoryStream.Position = 0; // Ensure the stream is at the beginning
diff --git a/src/Infrastructure/Data/ApplicationDbContext.cs b/src/Infrastructure/Data/ApplicationDbContext.cs
index 21b06a4..a8a5d4f 100644
--- a/src/Infrastructure/Data/ApplicationDbContext.cs
+++ b/src/Infrastructure/Data/ApplicationDbContext.cs
@@ -7,13 +7,9 @@ using Microsoft.EntityFrameworkCore;
namespace Hutopy.Infrastructure.Data
{
- public class ApplicationDbContext : IdentityDbContext, IApplicationDbContext
+ public class ApplicationDbContext(DbContextOptions options)
+ : IdentityDbContext(options), IApplicationDbContext
{
- public ApplicationDbContext(DbContextOptions options)
- : base(options)
- {
- }
-
public DbSet FutureCreators => Set();
public DbSet UserTransactions => Set();
diff --git a/src/Infrastructure/Data/ApplicationDbContextInitializer.cs b/src/Infrastructure/Data/ApplicationDbContextInitializer.cs
index ef35783..ff313b4 100644
--- a/src/Infrastructure/Data/ApplicationDbContextInitializer.cs
+++ b/src/Infrastructure/Data/ApplicationDbContextInitializer.cs
@@ -1,4 +1,5 @@
using Hutopy.Domain.Constants;
+using Hutopy.Infrastructure.Identity;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
@@ -24,7 +25,7 @@ public static class InitializerExtensions
public class ApplicationDbContextInitializer(
ILogger logger,
ApplicationDbContext context,
- RoleManager roleManager)
+ RoleManager roleManager)
{
public async Task InitialiseAsync()
{
@@ -54,13 +55,13 @@ public class ApplicationDbContextInitializer(
private async Task TrySeedAsync()
{
- var administratorRole = new IdentityRole(Roles.Administrator);
+ var administratorRole = new ApplicationRole(Roles.Administrator);
if (roleManager.Roles.All(r => r.Name != administratorRole.Name))
{
await roleManager.CreateAsync(administratorRole);
}
- var roleCreator = new IdentityRole(Roles.Creator);
+ var roleCreator = new ApplicationRole(Roles.Creator);
if (roleManager.Roles.All(r => r.Name != roleCreator.Name))
{
await roleManager.CreateAsync(roleCreator);
diff --git a/src/Infrastructure/Data/Configurations/ApplicationUserConfiguration.cs b/src/Infrastructure/Data/Configurations/ApplicationUserConfiguration.cs
deleted file mode 100644
index b3a3735..0000000
--- a/src/Infrastructure/Data/Configurations/ApplicationUserConfiguration.cs
+++ /dev/null
@@ -1,26 +0,0 @@
-using Hutopy.Infrastructure.Identity;
-using Microsoft.EntityFrameworkCore;
-using Microsoft.EntityFrameworkCore.Metadata.Builders;
-
-namespace Hutopy.Infrastructure.Data.Configurations;
-
-public class ApplicationUserConfiguration : IEntityTypeConfiguration
-{
- public void Configure(EntityTypeBuilder builder)
- {
- // Relationship between ApplicationUser and SocialNetworks
- builder
- .OwnsOne(u => u.SocialNetworks)
- .ToTable($"{nameof(ApplicationUser)}_SocialNetworks");
-
- // Relationship between ApplicationUser and ProfileColors
- builder
- .OwnsOne(u => u.ProfileColors)
- .ToTable($"{nameof(ApplicationUser)}_ProfileColors");
-
- // Relationship between ApplicationUser and StoredDataUrls
- builder
- .OwnsOne(u => u.StoredDataUrls)
- .ToTable($"{nameof(ApplicationUser)}_StoredDataUrls");
- }
-}
diff --git a/src/Infrastructure/Data/Interceptors/AuditableEntityInterceptor.cs b/src/Infrastructure/Data/Interceptors/AuditableEntityInterceptor.cs
index f38d7b5..b1d7157 100644
--- a/src/Infrastructure/Data/Interceptors/AuditableEntityInterceptor.cs
+++ b/src/Infrastructure/Data/Interceptors/AuditableEntityInterceptor.cs
@@ -36,10 +36,10 @@ public class AuditableEntityInterceptor(
if (entry.State == EntityState.Added)
{
entry.Entity.CreatedBy = user.Id;
- entry.Entity.Created = utcNow;
+ entry.Entity.CreatedAt = utcNow;
}
entry.Entity.LastModifiedBy = user.Id;
- entry.Entity.LastModified = utcNow;
+ entry.Entity.LastModifiedAt = utcNow;
}
}
}
diff --git a/src/Infrastructure/DependencyInjection.cs b/src/Infrastructure/DependencyInjection.cs
index c4abf71..f7c3525 100644
--- a/src/Infrastructure/DependencyInjection.cs
+++ b/src/Infrastructure/DependencyInjection.cs
@@ -1,5 +1,4 @@
-using System;
-using Hutopy.Application.Common.Interfaces;
+using Hutopy.Application.Common.Interfaces;
using Hutopy.Domain.Constants;
using Hutopy.Infrastructure.AzureBlob;
using Hutopy.Infrastructure.Data;
@@ -45,7 +44,7 @@ public static class DependencyInjection
services
.AddIdentityCore()
.AddUserManager()
- .AddRoles()
+ .AddRoles()
.AddEntityFrameworkStores()
.AddApiEndpoints()
.AddSignInManager>()
diff --git a/src/Infrastructure/Identity/ApplicationRole.cs b/src/Infrastructure/Identity/ApplicationRole.cs
index eba9904..4f90614 100644
--- a/src/Infrastructure/Identity/ApplicationRole.cs
+++ b/src/Infrastructure/Identity/ApplicationRole.cs
@@ -2,6 +2,8 @@
namespace Hutopy.Infrastructure.Identity;
-public class ApplicationRole : IdentityRole
+public class ApplicationRole : IdentityRole
{
+ public ApplicationRole() { }
+ public ApplicationRole(string roleName) : base(roleName) { }
}
diff --git a/src/Infrastructure/Identity/ApplicationUser.cs b/src/Infrastructure/Identity/ApplicationUser.cs
index 9b7ebdd..7d52e10 100644
--- a/src/Infrastructure/Identity/ApplicationUser.cs
+++ b/src/Infrastructure/Identity/ApplicationUser.cs
@@ -1,22 +1,15 @@
-using Hutopy.Infrastructure.Identity.OwnedEntities;
+using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Identity;
namespace Hutopy.Infrastructure.Identity;
-public class ApplicationUser : IdentityUser
-{
- public string? Alias { get; set; }
- public required string FirstName { get; set; }
- public required string LastName { get; set; }
- public string? CreatorAlias { get; set; }
- public string Occupation { get; set; } = string.Empty;
- public string BirthDate { get; set; } = string.Empty;
- public string Country { get; set; } = string.Empty;
- public string City { get; set; } = string.Empty;
- public string Address { get; set; } = string.Empty;
- public string About { get; set; } = string.Empty;
- public string Description { get; set; } = string.Empty;
- public SocialNetworks SocialNetworks { get; set; } = new();
- public ProfileColors ProfileColors { get; set; } = new();
- public StoredDataUrls StoredDataUrls { get; set; } = new();
+public class ApplicationUser : IdentityUser
+{
+ [MaxLength(255)] public string? Alias { get; set; }
+ [MaxLength(255)] public string? FirstName { get; set; }
+ [MaxLength(255)] public string? LastName { get; set; }
+ [MaxLength(255)] public string? Occupation { get; set; }
+ [MaxLength(255)] public string? BirthDate { get; set; }
+ [MaxLength(255)] public string? Address { get; set; }
+ [MaxLength(255)] public string? PortraitUrl { get; set; }
}
diff --git a/src/Infrastructure/Identity/ApplicationUserManager.cs b/src/Infrastructure/Identity/ApplicationUserManager.cs
index 8125aae..1799bbc 100644
--- a/src/Infrastructure/Identity/ApplicationUserManager.cs
+++ b/src/Infrastructure/Identity/ApplicationUserManager.cs
@@ -1,9 +1,4 @@
-using System;
-using System.Collections.Generic;
-using System.Threading;
-using System.Threading.Tasks;
-using Microsoft.AspNetCore.Identity;
-using Microsoft.EntityFrameworkCore;
+using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
@@ -30,17 +25,4 @@ public sealed class ApplicationUserManager(
services,
logger)
{
- public async Task FindByCreatorAliasAsync(string creatorAlias,
- CancellationToken cancellationToken = default)
- {
- ArgumentException.ThrowIfNullOrEmpty(creatorAlias);
- ThrowIfDisposed();
-
- var user = await Users.SingleOrDefaultAsync(u => EF.Functions.Like(
- creatorAlias,
- u.CreatorAlias),
- cancellationToken: cancellationToken);
-
- return user;
- }
}
diff --git a/src/Infrastructure/Identity/IdentityResultExtensions.cs b/src/Infrastructure/Identity/IdentityResultExtensions.cs
index 0902e4f..630c372 100644
--- a/src/Infrastructure/Identity/IdentityResultExtensions.cs
+++ b/src/Infrastructure/Identity/IdentityResultExtensions.cs
@@ -1,5 +1,4 @@
-using System.Linq;
-using Hutopy.Application.Common.Models;
+using Hutopy.Application.Common.Models;
using Microsoft.AspNetCore.Identity;
namespace Hutopy.Infrastructure.Identity;
diff --git a/src/Infrastructure/Identity/IdentityService.cs b/src/Infrastructure/Identity/IdentityService.cs
index beaab6b..f853d1f 100644
--- a/src/Infrastructure/Identity/IdentityService.cs
+++ b/src/Infrastructure/Identity/IdentityService.cs
@@ -17,67 +17,39 @@ public class IdentityService(
IAuthorizationService authorizationService,
IHttpContextAccessor contextAccessor,
IOptionsSnapshot jwtOptions
- )
+)
: IIdentityService
{
- public async Task GetUserNameAsync(string userId)
+ public async Task GetUserNameAsync(Guid userId)
{
- var user = await userManager.FindByIdAsync(userId);
+ var user = await userManager.FindByIdAsync(userId.ToString());
return user?.UserName;
}
-
+
public async Task GetUserByUserNameAsync(string userName)
{
var user = await userManager.FindByNameAsync(userName);
-
+
if (user == null) return null;
return new()
{
Id = user.Id,
- CreatorAlias = user.CreatorAlias,
- UserName = user.UserName ?? string.Empty,
+ UserName = user.UserName!,
+ PhoneNumber = user.PhoneNumber,
+ Email = user.Email,
Alias = user.Alias,
FirstName = user.FirstName,
LastName = user.LastName,
- Email = user.Email ?? string.Empty,
Occupation = user.Occupation,
- PhoneNumber = user.PhoneNumber ?? string.Empty,
BirthDate = user.BirthDate,
- Country = user.Country,
- City = user.City,
Address = user.Address,
- About = user.About,
- Description = user.Description,
- SocialNetworks = new()
- {
- FacebookUrl = user.SocialNetworks.FacebookUrl,
- InstagramUrl = user.SocialNetworks.InstagramUrl,
- XUrl = user.SocialNetworks.XUrl,
- LinkedInUrl = user.SocialNetworks.LinkedInUrl,
- TikTokUrl = user.SocialNetworks.TikTokUrl,
- YoutubeUrl = user.SocialNetworks.YoutubeUrl,
- RedditUrl = user.SocialNetworks.RedditUrl,
- YourWebsiteUrl = user.SocialNetworks.YourWebsiteUrl,
- },
- ProfileColors = new()
- {
- BannerTop = user.ProfileColors.BannerTop,
- BannerBottom = user.ProfileColors.BannerBottom,
- Accent = user.ProfileColors.Accent,
- Menu = user.ProfileColors.Menu
- },
- StoredDataUrls = new()
- {
- ProfilePictureUrl = user.StoredDataUrls.ProfilePictureUrl,
- BannerPictureUrl = user.StoredDataUrls.BannerPictureUrl,
- WebsiteIconUrl = user.StoredDataUrls.WebsiteIconUrl,
- }
+ PortraitUrl = user.PortraitUrl
};
}
-
- public async Task> CreateUserAsync(Userinfo userInfo)
+
+ public async Task> CreateUserAsync(Userinfo userInfo)
{
var applicationUser = new ApplicationUser
{
@@ -86,80 +58,83 @@ public class IdentityService(
FirstName = userInfo.GivenName,
LastName = userInfo.FamilyName
};
-
+
var password = Guid.NewGuid().ToString("N")[..32];
var identityResult = await userManager.CreateAsync(applicationUser, password);
var applicationResult = identityResult.ToApplicationResult();
- var result = new Result(applicationUser.Id, applicationResult.Succeeded, applicationResult.Errors);
-
+ var result = new Result(applicationUser.Id, applicationResult.Succeeded, applicationResult.Errors);
+
return result;
}
-
- public async Task> CreateUserAsync(string email, string userName, string firstName, string lastName, string password)
+
+ public async Task> CreateUserAsync(string email, string userName, string firstName, string lastName,
+ string password)
{
var applicationUser = new ApplicationUser
{
- UserName = userName,
- Email = email,
- FirstName = firstName,
- LastName = lastName
+ UserName = userName, Email = email, FirstName = firstName, LastName = lastName
};
var response = await userManager.CreateAsync(applicationUser, password);
-
- var result = new Result(applicationUser.Id, response.Succeeded, response.ToApplicationResult().Errors);
+
+ var result = new Result(applicationUser.Id, response.Succeeded, response.ToApplicationResult().Errors);
return result;
}
- public async Task> UpdateCurrentUserAsync(UserModel userModel)
+ public async Task> UpdateCurrentUserAsync(UserModel userModel)
{
- var applicationUser = await userManager.FindByIdAsync(userModel.Id);
+ var applicationUser = await userManager.FindByIdAsync(userModel.Id.ToString());
- if (applicationUser is null) return Result.Failure("", new[] { "User not found." });
+ if (applicationUser is null) return Result.Failure(Guid.Empty, new[] { "User not found." });
+ applicationUser.Id = userModel.Id;
+ applicationUser.Email = userModel.Email;
+ applicationUser.PhoneNumber = userModel.PhoneNumber;
+ applicationUser.Alias = userModel.Alias;
applicationUser.FirstName = userModel.FirstName;
applicationUser.LastName = userModel.LastName;
applicationUser.Occupation = userModel.Occupation;
- applicationUser.PhoneNumber = userModel.PhoneNumber;
applicationUser.BirthDate = userModel.BirthDate;
- applicationUser.Country = userModel.Country;
- applicationUser.City = userModel.City;
applicationUser.Address = userModel.Address;
- applicationUser.About = userModel.About;
- applicationUser.Description = userModel.Description;
- applicationUser.SocialNetworks = new()
- {
- FacebookUrl = userModel.SocialNetworks.FacebookUrl,
- InstagramUrl = userModel.SocialNetworks.InstagramUrl,
- XUrl = userModel.SocialNetworks.XUrl,
- LinkedInUrl = userModel.SocialNetworks.LinkedInUrl,
- TikTokUrl = userModel.SocialNetworks.TikTokUrl,
- YoutubeUrl = userModel.SocialNetworks.YoutubeUrl,
- RedditUrl = userModel.SocialNetworks.RedditUrl,
- YourWebsiteUrl = userModel.SocialNetworks.YourWebsiteUrl
- };
- applicationUser.ProfileColors = new()
- {
- BannerTop = userModel.ProfileColors.BannerTop,
- BannerBottom = userModel.ProfileColors.BannerBottom,
- Accent = userModel.ProfileColors.Accent,
- Menu = userModel.ProfileColors.Menu
- };
+ applicationUser.PortraitUrl = userModel.PortraitUrl;
var response = await userManager.UpdateAsync(applicationUser);
var applicationResult = response.ToApplicationResult();
- var result = new Result(userModel.Id, applicationResult.Succeeded,
+ var result = new Result(
+ userModel.Id,
+ applicationResult.Succeeded,
applicationResult.Errors);
-
+
return result;
}
-
+
+
+ private static UserModel BuildModelFrom(ApplicationUser response)
+ {
+ var userModel = new UserModel
+ {
+ Id = response.Id,
+ UserName = response.UserName ?? string.Empty,
+ PhoneNumber = response.PhoneNumber ?? string.Empty,
+ Email = response.Email ?? string.Empty,
+ PortraitUrl = response.PortraitUrl,
+ Alias = response.Alias,
+ FirstName = response.FirstName,
+ LastName = response.LastName,
+ Occupation = response.Occupation,
+ BirthDate = response.BirthDate,
+ Address = response.Address,
+ };
+
+ return userModel;
+ }
+
public async Task FindUserByIdAsync(string id)
{
var user = await userManager.FindByIdAsync(id);
@@ -170,64 +145,6 @@ public class IdentityService(
return userModel;
}
-
- public async Task FindUserByCreatorAliasAsync(string creatorAlias, CancellationToken cancellationToken = default)
- {
- var user = await userManager.FindByCreatorAliasAsync(creatorAlias, cancellationToken);
-
- if (user == null) return null;
-
- var userModel = BuildModelFrom(user);
-
- return userModel;
- }
-
- private static UserModel BuildModelFrom(ApplicationUser response)
- {
- var userModel = new UserModel
- {
- Id = response.Id,
- CreatorAlias = response.CreatorAlias,
- UserName = response.UserName ?? string.Empty,
- Alias = response.Alias,
- FirstName = response.FirstName,
- LastName = response.LastName,
- Email = response.Email ?? string.Empty,
- Occupation = response.Occupation,
- PhoneNumber = response.PhoneNumber ?? string.Empty,
- BirthDate = response.BirthDate,
- Country = response.Country,
- City = response.City,
- Address = response.Address,
- About = response.About,
- Description = response.Description,
- SocialNetworks = new()
- {
- FacebookUrl = response.SocialNetworks.FacebookUrl,
- InstagramUrl = response.SocialNetworks.InstagramUrl,
- XUrl = response.SocialNetworks.XUrl,
- LinkedInUrl = response.SocialNetworks.LinkedInUrl,
- TikTokUrl = response.SocialNetworks.TikTokUrl,
- YoutubeUrl = response.SocialNetworks.YoutubeUrl,
- RedditUrl = response.SocialNetworks.RedditUrl,
- YourWebsiteUrl = response.SocialNetworks.YourWebsiteUrl,
- },
- ProfileColors = new()
- {
- BannerTop = response.ProfileColors.BannerTop,
- BannerBottom = response.ProfileColors.BannerBottom,
- Accent = response.ProfileColors.Accent,
- Menu = response.ProfileColors.Menu
- },
- StoredDataUrls = new()
- {
- ProfilePictureUrl = response.StoredDataUrls.ProfilePictureUrl,
- BannerPictureUrl = response.StoredDataUrls.BannerPictureUrl,
- WebsiteIconUrl = response.StoredDataUrls.WebsiteIconUrl,
- }
- };
- return userModel;
- }
public async Task FindUserByEmailAsync(string email)
{
@@ -235,51 +152,9 @@ public class IdentityService(
if (response == null) return null;
- var userModel = new UserModel
- {
- Id = response.Id,
- CreatorAlias = response.CreatorAlias,
- UserName = response.UserName ?? string.Empty,
- FirstName = response.FirstName,
- LastName = response.LastName,
- Email = response.Email ?? string.Empty,
- Occupation = response.Occupation,
- PhoneNumber = response.PhoneNumber ?? string.Empty,
- BirthDate = response.BirthDate,
- Country = response.Country,
- City = response.City,
- Address = response.Address,
- About = response.About,
- Description = response.Description,
- SocialNetworks = new()
- {
- FacebookUrl = response.SocialNetworks.FacebookUrl,
- InstagramUrl = response.SocialNetworks.InstagramUrl,
- XUrl = response.SocialNetworks.XUrl,
- LinkedInUrl = response.SocialNetworks.LinkedInUrl,
- TikTokUrl = response.SocialNetworks.TikTokUrl,
- YoutubeUrl = response.SocialNetworks.YoutubeUrl,
- RedditUrl = response.SocialNetworks.RedditUrl,
- YourWebsiteUrl = response.SocialNetworks.YourWebsiteUrl,
- },
- ProfileColors = new()
- {
- BannerTop = response.ProfileColors.BannerTop,
- BannerBottom = response.ProfileColors.BannerBottom,
- Accent = response.ProfileColors.Accent,
- Menu = response.ProfileColors.Menu
- },
- StoredDataUrls = new()
- {
- ProfilePictureUrl = response.StoredDataUrls.ProfilePictureUrl,
- BannerPictureUrl = response.StoredDataUrls.BannerPictureUrl,
- WebsiteIconUrl = response.StoredDataUrls.WebsiteIconUrl,
- }
- };
-
- return userModel;
+ return BuildModelFrom(response);
}
-
+
public async Task GetCurrentUserAsync()
{
var currentUserId = contextAccessor.HttpContext?.User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
@@ -291,69 +166,38 @@ public class IdentityService(
return await FindUserByIdAsync(currentUserId);
}
- public async Task UpdateCurrentUserBannerPictureUrlAsync(string url)
+ public async Task UpdateCurrentUserPortraitUrlAsync(string url)
{
var userModel = await GetCurrentUserAsync();
- if (userModel is null) return Result.Failure(new[] { "User not found." });
- var applicationUser = await userManager.FindByIdAsync(userModel.Id);
- if (applicationUser is null) return Result.Failure(new[] { "ApplicationUser not found." });
+ var applicationUser = await userManager.FindByIdAsync(userModel.Id.ToString());
+ if (applicationUser is null) return Result.Failure(["ApplicationUser not found."]);
+
+ applicationUser.PortraitUrl = url;
- applicationUser.StoredDataUrls.BannerPictureUrl = url;
-
var response = await userManager.UpdateAsync(applicationUser);
return response.ToApplicationResult();
}
- public async Task UpdateCurrentUserProfilePictureUrlAsync(string url)
+ public async Task IsInRoleAsync(Guid userId, string role)
{
- var userModel = await GetCurrentUserAsync();
- if (userModel is null) return Result.Failure(new[] { "User not found." });
-
- var applicationUser = await userManager.FindByIdAsync(userModel.Id);
- if (applicationUser is null) return Result.Failure(new[] { "ApplicationUser not found." });
-
- applicationUser.StoredDataUrls.ProfilePictureUrl = url;
-
- var response = await userManager.UpdateAsync(applicationUser);
-
- return response.ToApplicationResult();
- }
-
- public async Task UpdateCurrentUserWebsiteIconUrlAsync(string url)
- {
- var userModel = await GetCurrentUserAsync();
- if (userModel is null) return Result.Failure(new[] { "User not found." });
-
- var applicationUser = await userManager.FindByIdAsync(userModel.Id);
- if (applicationUser is null) return Result.Failure(new[] { "ApplicationUser not found." });
-
- applicationUser.StoredDataUrls.WebsiteIconUrl = url;
-
- var response = await userManager.UpdateAsync(applicationUser);
-
- return response.ToApplicationResult();
- }
-
- public async Task IsInRoleAsync(string userId, string role)
- {
- var user = await userManager.FindByIdAsync(userId);
+ var user = await userManager.FindByIdAsync(userId.ToString());
return user != null && await userManager.IsInRoleAsync(user, role);
}
-
+
public async Task CurrentUserIsInRoleAsync(string role)
{
var currentUserModel = await GetCurrentUserAsync();
- var currentUser = await userManager.FindByIdAsync(currentUserModel?.Id ?? "");
+ var currentUser = await userManager.FindByIdAsync(currentUserModel.Id.ToString());
return currentUser != null && await userManager.IsInRoleAsync(currentUser, role);
}
- public async Task AuthorizeAsync(string userId, string policyName)
+ public async Task AuthorizeAsync(Guid userId, string policyName)
{
- var user = await userManager.FindByIdAsync(userId);
+ var user = await userManager.FindByIdAsync(userId.ToString());
if (user == null)
{
@@ -380,44 +224,45 @@ public class IdentityService(
return result.ToApplicationResult();
}
-
+
public async Task AddRoleAsync(string userId, string role)
{
var hasAdminAccess = await CurrentUserIsInRoleAsync("Administrator");
-
- if (!hasAdminAccess) return Result.Failure(new []{"Only administrator can assign new roles to a user."});
+
+ if (!hasAdminAccess) return Result.Failure(new[] { "Only administrator can assign new roles to a user." });
var user = await userManager.FindByIdAsync(userId);
-
- if (user is null) return Result.Failure(new []{"User not found."});
-
+
+ if (user is null) return Result.Failure(new[] { "User not found." });
+
var result = await userManager.AddToRoleAsync(user, role);
return result.ToApplicationResult();
}
-
+
public async Task> GetCurrentUserRolesAsync()
{
var currentUserModel = await GetCurrentUserAsync();
-
- var currentUser = await userManager.FindByIdAsync(currentUserModel?.Id ?? "");
-
- if (currentUser is null) return [];
+
+ var currentUser = await userManager.FindByIdAsync(currentUserModel.Id.ToString());
+
+ if (currentUser is null) return [];
var userRoles = await userManager.GetRolesAsync(currentUser);
return userRoles;
}
-
+
public async Task LoginAsync(string userName, string password)
{
- var result = await signInManager.PasswordSignInAsync(userName, password, isPersistent: false, lockoutOnFailure: false);
-
+ var result =
+ await signInManager.PasswordSignInAsync(userName, password, isPersistent: false, lockoutOnFailure: false);
+
if (!result.Succeeded)
{
return null;
}
-
+
var user = await GetUserByUserNameAsync(userName);
if (user is null) throw new InvalidOperationException();
@@ -427,12 +272,12 @@ public class IdentityService(
issuer: jwtOptions.Value.Issuer,
audience: jwtOptions.Value.Audience,
key: jwtOptions.Value.Key,
- userId: user.Id,
+ userId: user.Id.ToString(),
email: user.Email,
alias: user.Alias,
firstname: user.FirstName,
lastname: user.LastName,
- profilePictureUrl: user.StoredDataUrls.ProfilePictureUrl);
+ portraitUrl: user.PortraitUrl);
return token;
}
diff --git a/src/Infrastructure/Identity/OwnedEntities/ProfileColors.cs b/src/Infrastructure/Identity/OwnedEntities/ProfileColors.cs
deleted file mode 100644
index 3783044..0000000
--- a/src/Infrastructure/Identity/OwnedEntities/ProfileColors.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-namespace Hutopy.Infrastructure.Identity.OwnedEntities;
-
-public class ProfileColors
-{
- public string BannerTop { get; init; } = string.Empty;
- public string BannerBottom { get; init; } = string.Empty;
- public string Accent { get; init; } = string.Empty;
- public string Menu { get; init; } = string.Empty;
-}
diff --git a/src/Infrastructure/Identity/OwnedEntities/SocialNetworks.cs b/src/Infrastructure/Identity/OwnedEntities/SocialNetworks.cs
deleted file mode 100644
index a03e139..0000000
--- a/src/Infrastructure/Identity/OwnedEntities/SocialNetworks.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-namespace Hutopy.Infrastructure.Identity.OwnedEntities;
-
-public class SocialNetworks
-{
- public string FacebookUrl { get; init; } = string.Empty;
- public string InstagramUrl { get; init; } = string.Empty;
- public string XUrl { get; init; } = string.Empty;
- public string LinkedInUrl { get; init; } = string.Empty;
- public string TikTokUrl { get; init; } = string.Empty;
- public string YoutubeUrl { get; init; } = string.Empty;
- public string RedditUrl { get; init; } = string.Empty;
- public string YourWebsiteUrl { get; init; } = string.Empty;
-}
diff --git a/src/Infrastructure/Identity/OwnedEntities/StoredDataUrls.cs b/src/Infrastructure/Identity/OwnedEntities/StoredDataUrls.cs
deleted file mode 100644
index 53d5346..0000000
--- a/src/Infrastructure/Identity/OwnedEntities/StoredDataUrls.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-using System.ComponentModel.DataAnnotations;
-
-namespace Hutopy.Infrastructure.Identity.OwnedEntities;
-
-public class StoredDataUrls
-{
- [MaxLength(255)] public string? BannerPictureUrl { get; set; }
- [MaxLength(255)] public string? ProfilePictureUrl { get; set; }
- [MaxLength(255)] public string? WebsiteIconUrl { get; set; }
-}
diff --git a/src/Infrastructure/Identity/RoleService.cs b/src/Infrastructure/Identity/RoleService.cs
index 59fc22b..ef8749a 100644
--- a/src/Infrastructure/Identity/RoleService.cs
+++ b/src/Infrastructure/Identity/RoleService.cs
@@ -1,6 +1,4 @@
-using System;
-using System.Threading.Tasks;
-using Hutopy.Application.Common.Interfaces;
+using Hutopy.Application.Common.Interfaces;
using Hutopy.Application.Common.Models;
using Microsoft.AspNetCore.Identity;
@@ -13,7 +11,7 @@ public class RoleService(
{
public async Task CreateRoleAsync(string roleName)
{
- var role = new ApplicationRole { Name = roleName, Id = Guid.NewGuid().ToString()};
+ var role = new ApplicationRole { Name = roleName, Id = Guid.NewGuid()};
var result = await roleManager.CreateAsync(role);
return result.ToApplicationResult();
diff --git a/src/Infrastructure/Infrastructure.csproj b/src/Infrastructure/Infrastructure.csproj
index 36b3844..93b2a22 100644
--- a/src/Infrastructure/Infrastructure.csproj
+++ b/src/Infrastructure/Infrastructure.csproj
@@ -4,21 +4,24 @@
Hutopy.Infrastructure
-
-
-
-
+
+
+
+
runtime; build; native; contentfiles; analyzers; buildtransitive
all
-
-
-
-
-
+
+
+
+
+
-
+
+
+
+
diff --git a/src/Infrastructure/Migrations/20240418221249_InitialMigration.Designer.cs b/src/Infrastructure/Migrations/20240418221249_InitialMigration.Designer.cs
deleted file mode 100644
index e1c834e..0000000
--- a/src/Infrastructure/Migrations/20240418221249_InitialMigration.Designer.cs
+++ /dev/null
@@ -1,334 +0,0 @@
-//
-using System;
-using Hutopy.Infrastructure.Data;
-using Microsoft.EntityFrameworkCore;
-using Microsoft.EntityFrameworkCore.Infrastructure;
-using Microsoft.EntityFrameworkCore.Metadata;
-using Microsoft.EntityFrameworkCore.Migrations;
-using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
-
-#nullable disable
-
-namespace Hutopy.Infrastructure.Migrations
-{
- [DbContext(typeof(ApplicationDbContext))]
- [Migration("20240418221249_InitialMigration")]
- partial class InitialMigration
- {
- ///
- protected override void BuildTargetModel(ModelBuilder modelBuilder)
- {
-#pragma warning disable 612, 618
- modelBuilder
- .HasAnnotation("ProductVersion", "8.0.3")
- .HasAnnotation("Relational:MaxIdentifierLength", 128);
-
- SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
-
- modelBuilder.Entity("Hutopy.Domain.Entities.FutureCreator", b =>
- {
- b.Property("Id")
- .ValueGeneratedOnAdd()
- .HasColumnType("uniqueidentifier");
-
- b.Property("Created")
- .HasColumnType("datetimeoffset");
-
- b.Property("CreatedBy")
- .HasColumnType("nvarchar(max)");
-
- b.Property("EmailAddress")
- .IsRequired()
- .HasColumnType("nvarchar(max)");
-
- b.Property("FirstName")
- .IsRequired()
- .HasColumnType("nvarchar(max)");
-
- b.Property("LastModified")
- .HasColumnType("datetimeoffset");
-
- b.Property("LastModifiedBy")
- .HasColumnType("nvarchar(max)");
-
- b.Property("LastName")
- .IsRequired()
- .HasColumnType("nvarchar(max)");
-
- b.Property("PhoneNumber")
- .IsRequired()
- .HasColumnType("nvarchar(max)");
-
- b.Property("ReasonToJoin")
- .IsRequired()
- .HasColumnType("nvarchar(max)");
-
- b.Property("SocialNetworkAccount")
- .IsRequired()
- .HasColumnType("nvarchar(max)");
-
- b.HasKey("Id");
-
- b.ToTable("FutureCreators");
- });
-
- modelBuilder.Entity("Hutopy.Infrastructure.Identity.ApplicationUser", b =>
- {
- b.Property("Id")
- .HasColumnType("nvarchar(450)");
-
- b.Property("AccessFailedCount")
- .HasColumnType("int");
-
- b.Property("ConcurrencyStamp")
- .IsConcurrencyToken()
- .HasColumnType("nvarchar(max)");
-
- b.Property("Email")
- .HasMaxLength(256)
- .HasColumnType("nvarchar(256)");
-
- b.Property("EmailConfirmed")
- .HasColumnType("bit");
-
- b.Property("FirstName")
- .IsRequired()
- .HasColumnType("nvarchar(max)");
-
- b.Property("LastName")
- .IsRequired()
- .HasColumnType("nvarchar(max)");
-
- b.Property("LockoutEnabled")
- .HasColumnType("bit");
-
- b.Property("LockoutEnd")
- .HasColumnType("datetimeoffset");
-
- b.Property("NormalizedEmail")
- .HasMaxLength(256)
- .HasColumnType("nvarchar(256)");
-
- b.Property("NormalizedUserName")
- .HasMaxLength(256)
- .HasColumnType("nvarchar(256)");
-
- b.Property("PasswordHash")
- .HasColumnType("nvarchar(max)");
-
- b.Property("PhoneNumber")
- .HasColumnType("nvarchar(max)");
-
- b.Property("PhoneNumberConfirmed")
- .HasColumnType("bit");
-
- b.Property("SecurityStamp")
- .HasColumnType("nvarchar(max)");
-
- b.Property("TwoFactorEnabled")
- .HasColumnType("bit");
-
- b.Property("UserName")
- .HasMaxLength(256)
- .HasColumnType("nvarchar(256)");
-
- b.HasKey("Id");
-
- b.HasIndex("NormalizedEmail")
- .HasDatabaseName("EmailIndex");
-
- b.HasIndex("NormalizedUserName")
- .IsUnique()
- .HasDatabaseName("UserNameIndex")
- .HasFilter("[NormalizedUserName] IS NOT NULL");
-
- b.ToTable("AspNetUsers", (string)null);
- });
-
- modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
- {
- b.Property("Id")
- .HasColumnType("nvarchar(450)");
-
- b.Property("ConcurrencyStamp")
- .IsConcurrencyToken()
- .HasColumnType("nvarchar(max)");
-
- b.Property("Name")
- .HasMaxLength(256)
- .HasColumnType("nvarchar(256)");
-
- b.Property("NormalizedName")
- .HasMaxLength(256)
- .HasColumnType("nvarchar(256)");
-
- b.HasKey("Id");
-
- b.HasIndex("NormalizedName")
- .IsUnique()
- .HasDatabaseName("RoleNameIndex")
- .HasFilter("[NormalizedName] IS NOT NULL");
-
- b.ToTable("AspNetRoles", (string)null);
- });
-
- modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b =>
- {
- b.Property("Id")
- .ValueGeneratedOnAdd()
- .HasColumnType("int");
-
- SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
-
- b.Property("ClaimType")
- .HasColumnType("nvarchar(max)");
-
- b.Property("ClaimValue")
- .HasColumnType("nvarchar(max)");
-
- b.Property("RoleId")
- .IsRequired()
- .HasColumnType("nvarchar(450)");
-
- b.HasKey("Id");
-
- b.HasIndex("RoleId");
-
- b.ToTable("AspNetRoleClaims", (string)null);
- });
-
- modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b =>
- {
- b.Property("Id")
- .ValueGeneratedOnAdd()
- .HasColumnType("int");
-
- SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
-
- b.Property("ClaimType")
- .HasColumnType("nvarchar(max)");
-
- b.Property("ClaimValue")
- .HasColumnType("nvarchar(max)");
-
- b.Property("UserId")
- .IsRequired()
- .HasColumnType("nvarchar(450)");
-
- b.HasKey("Id");
-
- b.HasIndex("UserId");
-
- b.ToTable("AspNetUserClaims", (string)null);
- });
-
- modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b =>
- {
- b.Property("LoginProvider")
- .HasColumnType("nvarchar(450)");
-
- b.Property("ProviderKey")
- .HasColumnType("nvarchar(450)");
-
- b.Property("ProviderDisplayName")
- .HasColumnType("nvarchar(max)");
-
- b.Property("UserId")
- .IsRequired()
- .HasColumnType("nvarchar(450)");
-
- b.HasKey("LoginProvider", "ProviderKey");
-
- b.HasIndex("UserId");
-
- b.ToTable("AspNetUserLogins", (string)null);
- });
-
- modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b =>
- {
- b.Property("UserId")
- .HasColumnType("nvarchar(450)");
-
- b.Property("RoleId")
- .HasColumnType("nvarchar(450)");
-
- b.HasKey("UserId", "RoleId");
-
- b.HasIndex("RoleId");
-
- b.ToTable("AspNetUserRoles", (string)null);
- });
-
- modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b =>
- {
- b.Property("UserId")
- .HasColumnType("nvarchar(450)");
-
- b.Property("LoginProvider")
- .HasColumnType("nvarchar(450)");
-
- b.Property("Name")
- .HasColumnType("nvarchar(450)");
-
- b.Property("Value")
- .HasColumnType("nvarchar(max)");
-
- b.HasKey("UserId", "LoginProvider", "Name");
-
- b.ToTable("AspNetUserTokens", (string)null);
- });
-
- modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b =>
- {
- b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
- .WithMany()
- .HasForeignKey("RoleId")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired();
- });
-
- modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b =>
- {
- b.HasOne("Hutopy.Infrastructure.Identity.ApplicationUser", null)
- .WithMany()
- .HasForeignKey("UserId")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired();
- });
-
- modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b =>
- {
- b.HasOne("Hutopy.Infrastructure.Identity.ApplicationUser", null)
- .WithMany()
- .HasForeignKey("UserId")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired();
- });
-
- modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b =>
- {
- b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null)
- .WithMany()
- .HasForeignKey("RoleId")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired();
-
- b.HasOne("Hutopy.Infrastructure.Identity.ApplicationUser", null)
- .WithMany()
- .HasForeignKey("UserId")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired();
- });
-
- modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b =>
- {
- b.HasOne("Hutopy.Infrastructure.Identity.ApplicationUser", null)
- .WithMany()
- .HasForeignKey("UserId")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired();
- });
-#pragma warning restore 612, 618
- }
- }
-}
diff --git a/src/Infrastructure/Migrations/20240422173330_AddUserTransactions.Designer.cs b/src/Infrastructure/Migrations/20240422173330_AddUserTransactions.Designer.cs
deleted file mode 100644
index cc634ad..0000000
--- a/src/Infrastructure/Migrations/20240422173330_AddUserTransactions.Designer.cs
+++ /dev/null
@@ -1,383 +0,0 @@
-//
-using System;
-using Hutopy.Infrastructure.Data;
-using Microsoft.EntityFrameworkCore;
-using Microsoft.EntityFrameworkCore.Infrastructure;
-using Microsoft.EntityFrameworkCore.Metadata;
-using Microsoft.EntityFrameworkCore.Migrations;
-using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
-
-#nullable disable
-
-namespace Hutopy.Infrastructure.Migrations
-{
- [DbContext(typeof(ApplicationDbContext))]
- [Migration("20240422173330_AddUserTransactions")]
- partial class AddUserTransactions
- {
- ///
- protected override void BuildTargetModel(ModelBuilder modelBuilder)
- {
-#pragma warning disable 612, 618
- modelBuilder
- .HasAnnotation("ProductVersion", "8.0.3")
- .HasAnnotation("Relational:MaxIdentifierLength", 128);
-
- SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
-
- modelBuilder.Entity("Hutopy.Domain.Entities.FutureCreator", b =>
- {
- b.Property("Id")
- .ValueGeneratedOnAdd()
- .HasColumnType("uniqueidentifier");
-
- b.Property("Created")
- .HasColumnType("datetimeoffset");
-
- b.Property("CreatedBy")
- .HasColumnType("nvarchar(max)");
-
- b.Property("EmailAddress")
- .IsRequired()
- .HasColumnType("nvarchar(max)");
-
- b.Property("FirstName")
- .IsRequired()
- .HasColumnType("nvarchar(max)");
-
- b.Property("LastModified")
- .HasColumnType("datetimeoffset");
-
- b.Property("LastModifiedBy")
- .HasColumnType("nvarchar(max)");
-
- b.Property("LastName")
- .IsRequired()
- .HasColumnType("nvarchar(max)");
-
- b.Property("PhoneNumber")
- .IsRequired()
- .HasColumnType("nvarchar(max)");
-
- b.Property("ReasonToJoin")
- .IsRequired()
- .HasColumnType("nvarchar(max)");
-
- b.Property("SocialNetworkAccount")
- .IsRequired()
- .HasColumnType("nvarchar(max)");
-
- b.HasKey("Id");
-
- b.ToTable("FutureCreators");
- });
-
- modelBuilder.Entity("Hutopy.Domain.Entities.UserTransaction", b =>
- {
- b.Property("Id")
- .ValueGeneratedOnAdd()
- .HasColumnType("uniqueidentifier");
-
- b.Property("Amount")
- .HasColumnType("decimal(18,2)");
-
- b.Property("ApplicationUserId")
- .IsRequired()
- .HasColumnType("nvarchar(450)");
-
- b.Property("Created")
- .HasColumnType("datetimeoffset");
-
- b.Property("CreatedBy")
- .HasColumnType("nvarchar(max)");
-
- b.Property("Currency")
- .IsRequired()
- .HasColumnType("nvarchar(max)");
-
- b.Property("LastModified")
- .HasColumnType("datetimeoffset");
-
- b.Property("LastModifiedBy")
- .HasColumnType("nvarchar(max)");
-
- b.Property("TipMessage")
- .IsRequired()
- .HasColumnType("nvarchar(max)");
-
- b.HasKey("Id");
-
- b.HasIndex("ApplicationUserId");
-
- b.ToTable("UserTransactions");
- });
-
- modelBuilder.Entity("Hutopy.Infrastructure.Identity.ApplicationUser", b =>
- {
- b.Property("Id")
- .HasColumnType("nvarchar(450)");
-
- b.Property("AccessFailedCount")
- .HasColumnType("int");
-
- b.Property("ConcurrencyStamp")
- .IsConcurrencyToken()
- .HasColumnType("nvarchar(max)");
-
- b.Property("Email")
- .HasMaxLength(256)
- .HasColumnType("nvarchar(256)");
-
- b.Property("EmailConfirmed")
- .HasColumnType("bit");
-
- b.Property("FirstName")
- .IsRequired()
- .HasColumnType("nvarchar(max)");
-
- b.Property("LastName")
- .IsRequired()
- .HasColumnType("nvarchar(max)");
-
- b.Property("LockoutEnabled")
- .HasColumnType("bit");
-
- b.Property("LockoutEnd")
- .HasColumnType("datetimeoffset");
-
- b.Property("NormalizedEmail")
- .HasMaxLength(256)
- .HasColumnType("nvarchar(256)");
-
- b.Property("NormalizedUserName")
- .HasMaxLength(256)
- .HasColumnType("nvarchar(256)");
-
- b.Property("PasswordHash")
- .HasColumnType("nvarchar(max)");
-
- b.Property("PhoneNumber")
- .HasColumnType("nvarchar(max)");
-
- b.Property("PhoneNumberConfirmed")
- .HasColumnType("bit");
-
- b.Property("SecurityStamp")
- .HasColumnType("nvarchar(max)");
-
- b.Property("TwoFactorEnabled")
- .HasColumnType("bit");
-
- b.Property("UserName")
- .HasMaxLength(256)
- .HasColumnType("nvarchar(256)");
-
- b.HasKey("Id");
-
- b.HasIndex("NormalizedEmail")
- .HasDatabaseName("EmailIndex");
-
- b.HasIndex("NormalizedUserName")
- .IsUnique()
- .HasDatabaseName("UserNameIndex")
- .HasFilter("[NormalizedUserName] IS NOT NULL");
-
- b.ToTable("AspNetUsers", (string)null);
- });
-
- modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
- {
- b.Property("Id")
- .HasColumnType("nvarchar(450)");
-
- b.Property("ConcurrencyStamp")
- .IsConcurrencyToken()
- .HasColumnType("nvarchar(max)");
-
- b.Property("Name")
- .HasMaxLength(256)
- .HasColumnType("nvarchar(256)");
-
- b.Property("NormalizedName")
- .HasMaxLength(256)
- .HasColumnType("nvarchar(256)");
-
- b.HasKey("Id");
-
- b.HasIndex("NormalizedName")
- .IsUnique()
- .HasDatabaseName("RoleNameIndex")
- .HasFilter("[NormalizedName] IS NOT NULL");
-
- b.ToTable("AspNetRoles", (string)null);
- });
-
- modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b =>
- {
- b.Property("Id")
- .ValueGeneratedOnAdd()
- .HasColumnType("int");
-
- SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
-
- b.Property("ClaimType")
- .HasColumnType("nvarchar(max)");
-
- b.Property("ClaimValue")
- .HasColumnType("nvarchar(max)");
-
- b.Property("RoleId")
- .IsRequired()
- .HasColumnType("nvarchar(450)");
-
- b.HasKey("Id");
-
- b.HasIndex("RoleId");
-
- b.ToTable("AspNetRoleClaims", (string)null);
- });
-
- modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b =>
- {
- b.Property("Id")
- .ValueGeneratedOnAdd()
- .HasColumnType("int");
-
- SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
-
- b.Property