using BCrypt.Net; using Knot.Contracts.Auth.Application.Abstractions; using Knot.Contracts.Auth.Application.Auth.DTOs; using Knot.Contracts.Settings.Application.Abstractions; using Knot.Contracts.Settings.Application.DTOs; using Knot.Modules.Auth.Domain; using Knot.Shared.Kernel; namespace Knot.Modules.Auth.Application.Users.Register; public sealed record RegisterUserCommand( string Username, string Password, string DisplayName, string? Email, string? Bio) : ICommand; internal sealed class RegisterUserCommandHandler : ICommandHandler { private readonly IUserRepository _userRepository; private readonly IAuthUnitOfWork _unitOfWork; private readonly ISystemSettings _settings; private readonly IJwtTokenProvider _tokenProvider; public RegisterUserCommandHandler( IUserRepository userRepository, IAuthUnitOfWork unitOfWork, ISystemSettings settings, IJwtTokenProvider tokenProvider) { _userRepository = userRepository; _unitOfWork = unitOfWork; _settings = settings; _tokenProvider = tokenProvider; } public async Task> Handle(RegisterUserCommand request, CancellationToken cancellationToken) { if (!_settings.Current.EnableRegistration) { return Result.Failure(AuthErrors.IdentityRegistrationDisabled); } if (!await _userRepository.IsUsernameUniqueAsync(request.Username, cancellationToken)) { return Result.Failure(AuthErrors.IdentityUsernameNotUnique); } string passwordHash = BCrypt.Net.BCrypt.HashPassword(request.Password); var user = User.Create( request.Username, passwordHash, request.DisplayName, request.Email, request.Bio); var repoImpl = _userRepository as Infrastructure.Persistence.UserRepository; repoImpl?.Add(user); await _unitOfWork.SaveChangesAsync(cancellationToken); // Get the saved user as contract var userContract = await _userRepository.GetByUsernameAsync(request.Username, cancellationToken); if (userContract == null) { return Result.Failure(AuthErrors.IdentityRegistrationFailed); } string token = _tokenProvider.Generate(userContract.Id, userContract.Username, userContract.DisplayName, userContract.Avatar); string refreshToken = _tokenProvider.GenerateRefreshToken(); DateTime refreshExpiry = _tokenProvider.GetRefreshTokenExpiry(); userContract.SetRefreshToken(refreshToken, refreshExpiry); await _userRepository.UpdateAsync(userContract, cancellationToken); return Result.Success(new AuthResponseDto { AccessToken = token, RefreshToken = refreshToken, UserId = userContract.Id, Username = userContract.Username, DisplayName = userContract.DisplayName }); } }