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; public class RegisterHandler : IRequestHandler { private readonly UserManager _userManager; private readonly IEmailSender _emailSender; private readonly IConfiguration _configuration; private readonly IHttpContextAccessor _httpContextAccessor; private readonly AppDbContext _context; public RegisterHandler( UserManager userManager, IEmailSender emailSender, IConfiguration configuration, IHttpContextAccessor httpContextAccessor, AppDbContext context) { _userManager = userManager; _emailSender = emailSender; _configuration = configuration; _httpContextAccessor = httpContextAccessor; _context = context; } public async Task 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 { 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("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 = $@"

Welcome, {user.FullName}!

Please confirm your account by clicking the link below:

Confirm Account


If the link doesn't work, copy and paste this URL into your browser:

{callbackUrl}

"; await _emailSender.SendConfirmationLinkAsync(user, user.Email!, message); } return new CreateUserResponse { Id = user.Id, Email = user.Email }; } }