137 lines
5.0 KiB
C#
137 lines
5.0 KiB
C#
using MediatR;
|
|
using TakeoutSaaS.Application.Identity.Commands;
|
|
using TakeoutSaaS.Application.Identity.Contracts;
|
|
using TakeoutSaaS.Domain.Identity.Entities;
|
|
using TakeoutSaaS.Domain.Identity.Enums;
|
|
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;
|
|
|
|
/// <summary>
|
|
/// 角色模板复制处理器。
|
|
/// </summary>
|
|
public sealed class CopyRoleTemplateCommandHandler(
|
|
IRoleTemplateRepository roleTemplateRepository,
|
|
IRoleRepository roleRepository,
|
|
IPermissionRepository permissionRepository,
|
|
IRolePermissionRepository rolePermissionRepository,
|
|
ITenantProvider tenantProvider)
|
|
: IRequestHandler<CopyRoleTemplateCommand, RoleDto>
|
|
{
|
|
/// <inheritdoc />
|
|
public async Task<RoleDto> Handle(CopyRoleTemplateCommand request, CancellationToken cancellationToken)
|
|
{
|
|
// 1. 查询模板与模板权限
|
|
var template = await roleTemplateRepository.FindByCodeAsync(request.TemplateCode, cancellationToken)
|
|
?? throw new BusinessException(ErrorCodes.NotFound, $"角色模板 {request.TemplateCode} 不存在");
|
|
|
|
var templatePermissions = await roleTemplateRepository.GetPermissionsAsync(template.Id, cancellationToken);
|
|
var permissionCodes = templatePermissions
|
|
.Select(x => x.PermissionCode)
|
|
.Where(code => !string.IsNullOrWhiteSpace(code))
|
|
.Distinct(StringComparer.OrdinalIgnoreCase)
|
|
.ToArray();
|
|
|
|
// 2. 计算角色名称/编码与描述
|
|
var tenantId = tenantProvider.GetCurrentTenantId();
|
|
|
|
// 3. 固定复制为租户侧角色
|
|
var portal = PortalType.Tenant;
|
|
var roleCode = string.IsNullOrWhiteSpace(request.RoleCode) ? template.TemplateCode : request.RoleCode.Trim();
|
|
var roleName = string.IsNullOrWhiteSpace(request.RoleName) ? template.Name : request.RoleName.Trim();
|
|
var roleDescription = request.Description ?? template.Description;
|
|
|
|
// 4. 准备或更新角色主体(幂等创建)。
|
|
var role = await roleRepository.FindByCodeAsync(portal, tenantId, roleCode, cancellationToken);
|
|
if (role is null)
|
|
{
|
|
role = new Role
|
|
{
|
|
Portal = portal,
|
|
TenantId = tenantId,
|
|
Name = roleName,
|
|
Code = roleCode,
|
|
Description = roleDescription
|
|
};
|
|
await roleRepository.AddAsync(role, cancellationToken);
|
|
}
|
|
else
|
|
{
|
|
if (!string.IsNullOrWhiteSpace(request.RoleName))
|
|
{
|
|
role.Name = roleName;
|
|
}
|
|
|
|
if (request.Description is not null)
|
|
{
|
|
role.Description = roleDescription;
|
|
}
|
|
|
|
await roleRepository.UpdateAsync(role, cancellationToken);
|
|
}
|
|
|
|
// 5. 确保模板权限全部存在,不存在则按模板定义创建。
|
|
var existingPermissions = await permissionRepository.GetByCodesAsync(permissionCodes, cancellationToken);
|
|
var permissionMap = existingPermissions.ToDictionary(x => x.Code, StringComparer.OrdinalIgnoreCase);
|
|
|
|
foreach (var code in permissionCodes)
|
|
{
|
|
if (permissionMap.ContainsKey(code))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
var permission = new Permission
|
|
{
|
|
Name = code,
|
|
Code = code,
|
|
Description = code
|
|
};
|
|
|
|
await permissionRepository.AddAsync(permission, cancellationToken);
|
|
permissionMap[code] = permission;
|
|
}
|
|
|
|
await roleRepository.SaveChangesAsync(cancellationToken);
|
|
|
|
// 6. 绑定缺失的权限,保留租户自定义的已有授权。
|
|
var rolePermissions = await rolePermissionRepository.GetByRoleIdsAsync(portal, tenantId, new[] { role.Id }, cancellationToken);
|
|
var existingPermissionIds = rolePermissions
|
|
.Select(x => x.PermissionId)
|
|
.ToHashSet();
|
|
|
|
var targetPermissionIds = permissionCodes
|
|
.Select(code => permissionMap[code].Id)
|
|
.ToHashSet();
|
|
|
|
var toAdd = targetPermissionIds.Except(existingPermissionIds).ToArray();
|
|
if (toAdd.Length > 0)
|
|
{
|
|
var relations = toAdd.Select(permissionId => new RolePermission
|
|
{
|
|
Portal = portal,
|
|
TenantId = tenantId,
|
|
RoleId = role.Id,
|
|
PermissionId = permissionId
|
|
});
|
|
|
|
await rolePermissionRepository.AddRangeAsync(relations, cancellationToken);
|
|
}
|
|
|
|
await rolePermissionRepository.SaveChangesAsync(cancellationToken);
|
|
|
|
return new RoleDto
|
|
{
|
|
Id = role.Id,
|
|
Portal = role.Portal,
|
|
TenantId = role.TenantId,
|
|
Name = role.Name,
|
|
Code = role.Code,
|
|
Description = role.Description
|
|
};
|
|
}
|
|
}
|