using MediatR; using TakeoutSaaS.Application.Identity.Commands; using TakeoutSaaS.Application.Identity.Contracts; using TakeoutSaaS.Domain.Identity.Entities; using TakeoutSaaS.Domain.Identity.Repositories; using TakeoutSaaS.Shared.Abstractions.Constants; using TakeoutSaaS.Shared.Abstractions.Exceptions; using TakeoutSaaS.Shared.Abstractions.Tenancy; namespace TakeoutSaaS.Application.Identity.Handlers; /// /// 创建角色处理器。 /// public sealed class CreateRoleCommandHandler( IRoleRepository roleRepository, ITenantProvider tenantProvider) : IRequestHandler { /// /// 处理创建角色请求。 /// /// 创建命令。 /// 取消标记。 /// 创建后的角色 DTO。 public async Task Handle(CreateRoleCommand request, CancellationToken cancellationToken) { // 1. 获取租户上下文并校验跨租户 var currentTenantId = tenantProvider.GetCurrentTenantId(); if (currentTenantId <= 0) { throw new BusinessException(ErrorCodes.BadRequest, "缺少租户标识"); } // 2. (空行后) 禁止跨租户创建 if (request.TenantId.HasValue && request.TenantId.Value != currentTenantId) { throw new BusinessException(ErrorCodes.Forbidden, "禁止跨租户创建角色"); } // 3. (空行后) 使用当前租户创建角色 var tenantId = currentTenantId; // 4. (空行后) 归一化输入并校验唯一 var name = request.Name?.Trim() ?? string.Empty; var code = request.Code?.Trim() ?? string.Empty; if (string.IsNullOrWhiteSpace(name) || string.IsNullOrWhiteSpace(code)) { throw new BusinessException(ErrorCodes.BadRequest, "角色名称与编码不能为空"); } var exists = await roleRepository.FindByCodeAsync(code, tenantId, cancellationToken); if (exists is not null) { throw new BusinessException(ErrorCodes.Conflict, "角色编码已存在"); } // 5. (空行后) 构建角色实体 var role = new Role { TenantId = tenantId, Name = name, Code = code, Description = request.Description }; // 6. (空行后) 持久化 await roleRepository.AddAsync(role, cancellationToken); await roleRepository.SaveChangesAsync(cancellationToken); // 7. (空行后) 返回 DTO return new RoleDto { Id = role.Id, TenantId = role.TenantId, Name = role.Name, Code = role.Code, Description = role.Description }; } }