using Domain.Entities; 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. /// 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); string hashed = passwordInfrastructure.Hash(request.Password); UserAccount createdUser = await authRepo.RegisterUserAsync( new UserAccount { Username = request.Username, FirstName = request.FirstName, LastName = request.LastName, DateOfBirth = request.DateOfBirth, Email = request.Email, UserCredential = new UserCredential { Hash = hashed, } } ); string accessToken = tokenService.GenerateAccessToken(createdUser); string refreshToken = tokenService.GenerateRefreshToken(createdUser); string confirmationToken = tokenService.GenerateConfirmationToken(createdUser); if (string.IsNullOrEmpty(accessToken) || string.IsNullOrEmpty(refreshToken)) return new RegistrationPayload( createdUser.UserAccountId, createdUser.Username, string.Empty, string.Empty, false ); bool 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) { UserAccount? existingUsername = await authRepo.GetUserByUsernameAsync(username); UserAccount? existingEmail = await authRepo.GetUserByEmailAsync(email); if (existingUsername != null || existingEmail != null) throw new ConflictException("Username or email already exists"); } }