using AutoMapper; using MediatR; using Mws.Application.Auth; using Mws.Application.Common; using Mws.Application.Permissions; using Mws.Domain.Users; namespace Mws.Application.Accounts; public record CreateAccountCommand(Guid ActorUserId, CreateAccountRequest Request) : IRequest; public class CreateAccountHandler(IUnitOfWork uow, IPasswordHasher passwordHasher, IPermissionService permissions, IMapper mapper) : IRequestHandler { private const string Screen = "accounts"; public async Task Handle(CreateAccountCommand command, CancellationToken ct) { await permissions.EnsureAsync(command.ActorUserId, Screen, PermissionAction.Create, ct); var request = command.Request; var username = request.Username.Trim(); if (string.IsNullOrWhiteSpace(username) || string.IsNullOrWhiteSpace(request.Password)) { throw new BadRequestException("Username and password are required"); } if (await uow.Users.ExistsByUsernameAsync(username, ct)) { throw new BadRequestException("Username already exists"); } var role = await uow.Roles.GetByIdAsync(request.RoleId, ct) ?? throw new BadRequestException("Role not found"); var now = DateTime.UtcNow; var user = new User { Id = Guid.NewGuid(), Username = username, PasswordHash = passwordHasher.Hash(request.Password), DisplayName = request.DisplayName.Trim(), RoleId = role.Id, IsActive = true, CreatedAt = now, UpdatedAt = now, }; uow.Users.Add(user); await uow.SaveChangesAsync(ct); user.Role = role; return mapper.Map(user); } }