initial commit
This commit is contained in:
@@ -0,0 +1,131 @@
|
||||
using Indotalent.Data.Entities;
|
||||
using Indotalent.Infrastructure.Authorization.Identity;
|
||||
using Indotalent.Infrastructure.Database;
|
||||
using MediatR;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.WebUtilities;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.Text;
|
||||
|
||||
namespace Indotalent.Features.Account.Register.Cqrs;
|
||||
|
||||
public class CreateUserRequest
|
||||
{
|
||||
public string FullName { get; set; } = string.Empty;
|
||||
public string Email { get; set; } = string.Empty;
|
||||
public string Password { get; set; } = string.Empty;
|
||||
public bool IsActive { get; set; } = true;
|
||||
public bool EmailConfirmed { get; set; } = false;
|
||||
}
|
||||
|
||||
public class CreateUserResponse
|
||||
{
|
||||
public string? Id { get; set; }
|
||||
public string? Email { get; set; }
|
||||
}
|
||||
|
||||
public record CreateUserCommand(CreateUserRequest Data) : IRequest<CreateUserResponse>;
|
||||
|
||||
public class RegisterHandler : IRequestHandler<CreateUserCommand, CreateUserResponse>
|
||||
{
|
||||
private readonly UserManager<ApplicationUser> _userManager;
|
||||
private readonly IEmailSender<ApplicationUser> _emailSender;
|
||||
private readonly IConfiguration _configuration;
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
private readonly AppDbContext _context;
|
||||
|
||||
public RegisterHandler(
|
||||
UserManager<ApplicationUser> userManager,
|
||||
IEmailSender<ApplicationUser> emailSender,
|
||||
IConfiguration configuration,
|
||||
IHttpContextAccessor httpContextAccessor,
|
||||
AppDbContext context)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_emailSender = emailSender;
|
||||
_configuration = configuration;
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public async Task<CreateUserResponse> Handle(CreateUserCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
var user = new ApplicationUser
|
||||
{
|
||||
UserName = request.Data.Email,
|
||||
Email = request.Data.Email,
|
||||
FullName = request.Data.FullName,
|
||||
IsActive = request.Data.IsActive,
|
||||
EmailConfirmed = request.Data.EmailConfirmed,
|
||||
};
|
||||
|
||||
var result = await _userManager.CreateAsync(user, request.Data.Password);
|
||||
|
||||
if (!result.Succeeded)
|
||||
{
|
||||
var errors = result.Errors.Select(x => x.Description).ToList();
|
||||
throw new Exception(string.Join(", ", errors));
|
||||
}
|
||||
|
||||
// Assign default roles: Member and TenantAdmin (but not Admin)
|
||||
var rolesToAdd = new List<string> { ApplicationRoles.Member, ApplicationRoles.TenantAdmin };
|
||||
|
||||
await _userManager.AddToRolesAsync(user, rolesToAdd);
|
||||
|
||||
// Create default tenant for the new user
|
||||
var tenant = new Data.Entities.Tenant
|
||||
{
|
||||
Name = "Default Tenant",
|
||||
Description = $"Default tenant for {request.Data.Email}",
|
||||
EmailAddress = request.Data.Email,
|
||||
IsActive = true
|
||||
};
|
||||
|
||||
_context.Tenant.Add(tenant);
|
||||
await _context.SaveChangesAsync(cancellationToken);
|
||||
|
||||
// Create TenantUser linking the user to the default tenant
|
||||
var tenantUser = new Data.Entities.TenantUser
|
||||
{
|
||||
TenantId = tenant.Id,
|
||||
UserId = user.Id,
|
||||
Summary = $"Default tenant assignment for {request.Data.FullName}",
|
||||
IsActive = true
|
||||
};
|
||||
|
||||
_context.TenantUser.Add(tenantUser);
|
||||
await _context.SaveChangesAsync(cancellationToken);
|
||||
|
||||
var requireConfirmation = _configuration.GetValue<bool>("IdentitySettings:SignIn:RequireConfirmedAccount");
|
||||
|
||||
if (requireConfirmation)
|
||||
{
|
||||
var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
|
||||
code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
|
||||
|
||||
var requestHttp = _httpContextAccessor.HttpContext?.Request;
|
||||
var scheme = requestHttp?.Scheme ?? "https";
|
||||
var host = requestHttp?.Host.Value ?? "localhost:8080";
|
||||
|
||||
var callbackUrl = $"{scheme}://{host}/account/confirm-email?userId={user.Id}&code={code}";
|
||||
|
||||
var message = $@"
|
||||
<div style=""font-family: Arial, sans-serif;"">
|
||||
<h3>Welcome, {user.FullName}!</h3>
|
||||
<p>Please confirm your account by clicking the link below:</p>
|
||||
<p><a href=""{callbackUrl}"" style=""color: #2196F3; font-weight: bold; text-decoration: underline;"">Confirm Account</a></p>
|
||||
<br/>
|
||||
<p style=""font-size: 0.8em; color: #666;"">If the link doesn't work, copy and paste this URL into your browser:</p>
|
||||
<p style=""font-size: 0.8em; color: #666;"">{callbackUrl}</p>
|
||||
</div>";
|
||||
|
||||
await _emailSender.SendConfirmationLinkAsync(user, user.Email!, message);
|
||||
}
|
||||
|
||||
return new CreateUserResponse
|
||||
{
|
||||
Id = user.Id,
|
||||
Email = user.Email
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user