using Domain.Exceptions; using Features.Auth.Dtos; using Features.Auth.Repository; using Features.Auth.Services; using Infrastructure.PasswordHashing; using MediatR; using Shared.Application.Emails; namespace Features.Auth.Commands.RegisterUser; /// /// Handles : validates uniqueness, hashes the password, persists the /// account, issues access/refresh/confirmation tokens, and attempts to send the registration /// confirmation email via Features.Emails. /// /// Repository used to check for existing users and persist the new account. /// Infrastructure component used to hash the user's plain-text password. /// Service used to generate access, refresh, and confirmation tokens. /// Used to send the cross-slice command that triggers the confirmation email. public class RegisterUserHandler( IAuthRepository authRepo, IPasswordInfrastructure passwordInfrastructure, ITokenService tokenService, IMediator mediator ) : IRequestHandler { /// /// Thrown when an existing account already has the same username or email address. /// public async Task Handle(RegisterUserCommand request, CancellationToken cancellationToken) { await ValidateUserDoesNotExist(request.Username, request.Email); var hashed = passwordInfrastructure.Hash(request.Password); var createdUser = await authRepo.RegisterUserAsync( request.Username, request.FirstName, request.LastName, request.Email, request.DateOfBirth, hashed ); var accessToken = tokenService.GenerateAccessToken(createdUser); var refreshToken = tokenService.GenerateRefreshToken(createdUser); var confirmationToken = tokenService.GenerateConfirmationToken(createdUser); if (string.IsNullOrEmpty(accessToken) || string.IsNullOrEmpty(refreshToken)) { return new RegistrationPayload(createdUser.UserAccountId, createdUser.Username, string.Empty, string.Empty, false); } var emailSent = false; try { await mediator.Send( new SendRegistrationEmailCommand(createdUser.FirstName, createdUser.Email, confirmationToken), cancellationToken ); emailSent = true; } catch (Exception ex) { await Console.Error.WriteLineAsync(ex.Message); Console.WriteLine("Could not send email."); // ignored } return new RegistrationPayload(createdUser.UserAccountId, createdUser.Username, refreshToken, accessToken, emailSent); } /// /// Thrown when an existing account already has the same username or email address. /// private async Task ValidateUserDoesNotExist(string username, string email) { var existingUsername = await authRepo.GetUserByUsernameAsync(username); var existingEmail = await authRepo.GetUserByEmailAsync(email); if (existingUsername != null || existingEmail != null) { throw new ConflictException("Username or email already exists"); } } }