chore: add documentation comments and stylecop rules

This commit is contained in:
2025-12-04 11:25:01 +08:00
parent 17d143a351
commit 8e4c2b0e45
142 changed files with 1309 additions and 439 deletions

View File

@@ -15,9 +15,14 @@ public sealed class AssignUserRolesCommandHandler(
{
public async Task<bool> Handle(AssignUserRolesCommand request, CancellationToken cancellationToken)
{
// 1. 获取租户上下文
var tenantId = tenantProvider.GetCurrentTenantId();
// 2. 覆盖式绑定角色
await userRoleRepository.ReplaceUserRolesAsync(tenantId, request.UserId, request.RoleIds, cancellationToken);
await userRoleRepository.SaveChangesAsync(cancellationToken);
// 3. 返回执行结果
return true;
}
}

View File

@@ -15,9 +15,14 @@ public sealed class BindRolePermissionsCommandHandler(
{
public async Task<bool> Handle(BindRolePermissionsCommand request, CancellationToken cancellationToken)
{
// 1. 获取租户上下文
var tenantId = tenantProvider.GetCurrentTenantId();
// 2. 覆盖式绑定权限
await rolePermissionRepository.ReplaceRolePermissionsAsync(tenantId, request.RoleId, request.PermissionIds, cancellationToken);
await rolePermissionRepository.SaveChangesAsync(cancellationToken);
// 3. 返回执行结果
return true;
}
}

View File

@@ -26,6 +26,7 @@ public sealed class CopyRoleTemplateCommandHandler(
/// <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} 不存在");
@@ -36,6 +37,7 @@ public sealed class CopyRoleTemplateCommandHandler(
.Distinct(StringComparer.OrdinalIgnoreCase)
.ToArray();
// 2. 计算角色名称/编码与描述
var tenantId = tenantProvider.GetCurrentTenantId();
var roleCode = string.IsNullOrWhiteSpace(request.RoleCode) ? template.TemplateCode : request.RoleCode.Trim();
var roleName = string.IsNullOrWhiteSpace(request.RoleName) ? template.Name : request.RoleName.Trim();
@@ -69,7 +71,7 @@ public sealed class CopyRoleTemplateCommandHandler(
await roleRepository.UpdateAsync(role, cancellationToken);
}
// 2. 确保模板权限全部存在,不存在则按模板定义创建。
// 3. 确保模板权限全部存在,不存在则按模板定义创建。
var existingPermissions = await permissionRepository.GetByCodesAsync(tenantId, permissionCodes, cancellationToken);
var permissionMap = existingPermissions.ToDictionary(x => x.Code, StringComparer.OrdinalIgnoreCase);
@@ -94,7 +96,7 @@ public sealed class CopyRoleTemplateCommandHandler(
await roleRepository.SaveChangesAsync(cancellationToken);
// 3. 绑定缺失的权限,保留租户自定义的已有授权。
// 4. 绑定缺失的权限,保留租户自定义的已有授权。
var rolePermissions = await rolePermissionRepository.GetByRoleIdsAsync(tenantId, new[] { role.Id }, cancellationToken);
var existingPermissionIds = rolePermissions
.Select(x => x.PermissionId)

View File

@@ -17,7 +17,10 @@ public sealed class CreatePermissionCommandHandler(
{
public async Task<PermissionDto> Handle(CreatePermissionCommand request, CancellationToken cancellationToken)
{
// 1. 获取租户上下文
var tenantId = tenantProvider.GetCurrentTenantId();
// 2. 构建权限实体
var permission = new Permission
{
TenantId = tenantId,
@@ -26,9 +29,11 @@ public sealed class CreatePermissionCommandHandler(
Description = request.Description
};
// 3. 持久化
await permissionRepository.AddAsync(permission, cancellationToken);
await permissionRepository.SaveChangesAsync(cancellationToken);
// 4. 返回 DTO
return new PermissionDto
{
Id = permission.Id,

View File

@@ -17,7 +17,10 @@ public sealed class CreateRoleCommandHandler(
{
public async Task<RoleDto> Handle(CreateRoleCommand request, CancellationToken cancellationToken)
{
// 1. 获取租户上下文
var tenantId = tenantProvider.GetCurrentTenantId();
// 2. 构建角色实体
var role = new Role
{
TenantId = tenantId,
@@ -26,9 +29,11 @@ public sealed class CreateRoleCommandHandler(
Description = request.Description
};
// 3. 持久化
await roleRepository.AddAsync(role, cancellationToken);
await roleRepository.SaveChangesAsync(cancellationToken);
// 4. 返回 DTO
return new RoleDto
{
Id = role.Id,

View File

@@ -19,17 +19,20 @@ public sealed class CreateRoleTemplateCommandHandler(IRoleTemplateRepository rol
/// <inheritdoc />
public async Task<RoleTemplateDto> Handle(CreateRoleTemplateCommand request, CancellationToken cancellationToken)
{
// 1. 校验必填
if (string.IsNullOrWhiteSpace(request.TemplateCode) || string.IsNullOrWhiteSpace(request.Name))
{
throw new BusinessException(ErrorCodes.BadRequest, "模板编码与名称不能为空");
}
// 2. 检查编码唯一
var existing = await roleTemplateRepository.FindByCodeAsync(request.TemplateCode, cancellationToken);
if (existing != null)
{
throw new BusinessException(ErrorCodes.Conflict, $"模板编码 {request.TemplateCode} 已存在");
}
// 3. 构建模板实体
var template = new RoleTemplate
{
TemplateCode = request.TemplateCode.Trim(),
@@ -38,12 +41,14 @@ public sealed class CreateRoleTemplateCommandHandler(IRoleTemplateRepository rol
IsActive = request.IsActive
};
// 4. 清洗权限编码
var permissions = request.PermissionCodes
.Where(code => !string.IsNullOrWhiteSpace(code))
.Select(code => code.Trim())
.Distinct(StringComparer.OrdinalIgnoreCase)
.ToArray();
// 5. 持久化并返回 DTO
await roleTemplateRepository.AddAsync(template, permissions, cancellationToken);
await roleTemplateRepository.SaveChangesAsync(cancellationToken);

View File

@@ -15,9 +15,14 @@ public sealed class DeletePermissionCommandHandler(
{
public async Task<bool> Handle(DeletePermissionCommand request, CancellationToken cancellationToken)
{
// 1. 获取租户上下文
var tenantId = tenantProvider.GetCurrentTenantId();
// 2. 删除权限
await permissionRepository.DeleteAsync(request.PermissionId, tenantId, cancellationToken);
await permissionRepository.SaveChangesAsync(cancellationToken);
// 3. 返回执行结果
return true;
}
}

View File

@@ -15,9 +15,14 @@ public sealed class DeleteRoleCommandHandler(
{
public async Task<bool> Handle(DeleteRoleCommand request, CancellationToken cancellationToken)
{
// 1. 获取租户上下文
var tenantId = tenantProvider.GetCurrentTenantId();
// 2. 删除角色
await roleRepository.DeleteAsync(request.RoleId, tenantId, cancellationToken);
await roleRepository.SaveChangesAsync(cancellationToken);
// 3. 返回执行结果
return true;
}
}

View File

@@ -12,14 +12,18 @@ public sealed class DeleteRoleTemplateCommandHandler(IRoleTemplateRepository rol
{
public async Task<bool> Handle(DeleteRoleTemplateCommand request, CancellationToken cancellationToken)
{
// 1. 查询模板
var template = await roleTemplateRepository.FindByCodeAsync(request.TemplateCode, cancellationToken);
if (template == null)
{
return false;
}
// 2. 删除并保存
await roleTemplateRepository.DeleteAsync(template.Id, cancellationToken);
await roleTemplateRepository.SaveChangesAsync(cancellationToken);
// 3. 返回执行结果
return true;
}
}

View File

@@ -15,14 +15,18 @@ public sealed class GetRoleTemplateQueryHandler(IRoleTemplateRepository roleTemp
/// <inheritdoc />
public async Task<RoleTemplateDto?> Handle(GetRoleTemplateQuery request, CancellationToken cancellationToken)
{
// 1. 查询模板
var template = await roleTemplateRepository.FindByCodeAsync(request.TemplateCode, cancellationToken);
if (template == null)
{
return null;
}
// 2. 查询模板权限
var permissions = await roleTemplateRepository.GetPermissionsAsync(template.Id, cancellationToken);
var codes = permissions.Select(x => x.PermissionCode).ToArray();
// 3. 返回 DTO
return TemplateMapper.ToDto(template, codes);
}
}

View File

@@ -20,26 +20,22 @@ public sealed class GetUserPermissionsQueryHandler(
ITenantProvider tenantProvider)
: IRequestHandler<GetUserPermissionsQuery, UserPermissionDto?>
{
private readonly IIdentityUserRepository _identityUserRepository = identityUserRepository;
private readonly IUserRoleRepository _userRoleRepository = userRoleRepository;
private readonly IRoleRepository _roleRepository = roleRepository;
private readonly IPermissionRepository _permissionRepository = permissionRepository;
private readonly IRolePermissionRepository _rolePermissionRepository = rolePermissionRepository;
private readonly ITenantProvider _tenantProvider = tenantProvider;
/// <inheritdoc />
public async Task<UserPermissionDto?> Handle(GetUserPermissionsQuery request, CancellationToken cancellationToken)
{
var tenantId = _tenantProvider.GetCurrentTenantId();
var user = await _identityUserRepository.FindByIdAsync(request.UserId, cancellationToken);
// 1. 获取租户并查询用户
var tenantId = tenantProvider.GetCurrentTenantId();
var user = await identityUserRepository.FindByIdAsync(request.UserId, cancellationToken);
if (user == null || user.TenantId != tenantId)
{
return null;
}
// 2. 解析角色与权限
var roleCodes = await ResolveUserRolesAsync(tenantId, user.Id, cancellationToken);
var permissionCodes = await ResolveUserPermissionsAsync(tenantId, user.Id, cancellationToken);
// 3. 返回用户权限概览
return new UserPermissionDto
{
UserId = user.Id,
@@ -55,34 +51,39 @@ public sealed class GetUserPermissionsQueryHandler(
private async Task<string[]> ResolveUserRolesAsync(long tenantId, long userId, CancellationToken cancellationToken)
{
var relations = await _userRoleRepository.GetByUserIdAsync(tenantId, userId, cancellationToken);
// 1. 查询用户角色关系
var relations = await userRoleRepository.GetByUserIdAsync(tenantId, userId, cancellationToken);
var roleIds = relations.Select(x => x.RoleId).Distinct().ToArray();
if (roleIds.Length == 0)
{
return Array.Empty<string>();
}
var roles = await _roleRepository.GetByIdsAsync(tenantId, roleIds, cancellationToken);
// 2. 查询角色编码
var roles = await roleRepository.GetByIdsAsync(tenantId, roleIds, cancellationToken);
return roles.Select(x => x.Code).Distinct(StringComparer.OrdinalIgnoreCase).ToArray();
}
private async Task<string[]> ResolveUserPermissionsAsync(long tenantId, long userId, CancellationToken cancellationToken)
{
var relations = await _userRoleRepository.GetByUserIdAsync(tenantId, userId, cancellationToken);
// 1. 查询用户角色关系
var relations = await userRoleRepository.GetByUserIdAsync(tenantId, userId, cancellationToken);
var roleIds = relations.Select(x => x.RoleId).Distinct().ToArray();
if (roleIds.Length == 0)
{
return Array.Empty<string>();
}
var rolePermissions = await _rolePermissionRepository.GetByRoleIdsAsync(tenantId, roleIds, cancellationToken);
// 2. 查询角色-权限关系
var rolePermissions = await rolePermissionRepository.GetByRoleIdsAsync(tenantId, roleIds, cancellationToken);
var permissionIds = rolePermissions.Select(x => x.PermissionId).Distinct().ToArray();
if (permissionIds.Length == 0)
{
return Array.Empty<string>();
}
var permissions = await _permissionRepository.GetByIdsAsync(tenantId, permissionIds, cancellationToken);
// 3. 查询权限编码
var permissions = await permissionRepository.GetByIdsAsync(tenantId, permissionIds, cancellationToken);
return permissions.Select(x => x.Code).Distinct(StringComparer.OrdinalIgnoreCase).ToArray();
}
}

View File

@@ -16,9 +16,11 @@ public sealed class ListRoleTemplatesQueryHandler(IRoleTemplateRepository roleTe
/// <inheritdoc />
public async Task<IReadOnlyList<RoleTemplateDto>> Handle(ListRoleTemplatesQuery request, CancellationToken cancellationToken)
{
// 1. 查询模板与权限映射
var templates = await roleTemplateRepository.GetAllAsync(request.IsActive, cancellationToken);
var permissionsMap = await roleTemplateRepository.GetPermissionsAsync(templates.Select(t => t.Id), cancellationToken);
// 2. 排序并映射 DTO
var dtos = templates
.OrderBy(template => template.TemplateCode, StringComparer.OrdinalIgnoreCase)
.Select(template =>
@@ -30,6 +32,7 @@ public sealed class ListRoleTemplatesQueryHandler(IRoleTemplateRepository roleTe
})
.ToArray();
// 3. 返回结果
return dtos;
}
}

View File

@@ -19,9 +19,11 @@ public sealed class SearchPermissionsQueryHandler(
{
public async Task<PagedResult<PermissionDto>> Handle(SearchPermissionsQuery request, CancellationToken cancellationToken)
{
// 1. 获取租户上下文并查询权限
var tenantId = tenantProvider.GetCurrentTenantId();
var permissions = await permissionRepository.SearchAsync(tenantId, request.Keyword, cancellationToken);
// 2. 排序
var sorted = request.SortBy?.ToLowerInvariant() switch
{
"name" => request.SortDescending
@@ -35,11 +37,13 @@ public sealed class SearchPermissionsQueryHandler(
: permissions.OrderBy(x => x.CreatedAt)
};
// 3. 分页
var paged = sorted
.Skip((request.Page - 1) * request.PageSize)
.Take(request.PageSize)
.ToList();
// 4. 映射 DTO
var items = paged.Select(permission => new PermissionDto
{
Id = permission.Id,
@@ -49,6 +53,7 @@ public sealed class SearchPermissionsQueryHandler(
Description = permission.Description
}).ToList();
// 5. 返回分页结果
return new PagedResult<PermissionDto>(items, request.Page, request.PageSize, permissions.Count);
}
}

View File

@@ -19,9 +19,11 @@ public sealed class SearchRolesQueryHandler(
{
public async Task<PagedResult<RoleDto>> Handle(SearchRolesQuery request, CancellationToken cancellationToken)
{
// 1. 获取租户上下文并查询角色
var tenantId = tenantProvider.GetCurrentTenantId();
var roles = await roleRepository.SearchAsync(tenantId, request.Keyword, cancellationToken);
// 2. 排序
var sorted = request.SortBy?.ToLowerInvariant() switch
{
"name" => request.SortDescending
@@ -32,11 +34,13 @@ public sealed class SearchRolesQueryHandler(
: roles.OrderBy(x => x.CreatedAt)
};
// 3. 分页
var paged = sorted
.Skip((request.Page - 1) * request.PageSize)
.Take(request.PageSize)
.ToList();
// 4. 映射 DTO
var items = paged.Select(role => new RoleDto
{
Id = role.Id,
@@ -46,6 +50,7 @@ public sealed class SearchRolesQueryHandler(
Description = role.Description
}).ToList();
// 5. 返回分页结果
return new PagedResult<RoleDto>(items, request.Page, request.PageSize, roles.Count);
}
}

View File

@@ -22,25 +22,21 @@ public sealed class SearchUserPermissionsQueryHandler(
ITenantProvider tenantProvider)
: IRequestHandler<SearchUserPermissionsQuery, PagedResult<UserPermissionDto>>
{
private readonly IIdentityUserRepository _identityUserRepository = identityUserRepository;
private readonly IUserRoleRepository _userRoleRepository = userRoleRepository;
private readonly IRoleRepository _roleRepository = roleRepository;
private readonly IPermissionRepository _permissionRepository = permissionRepository;
private readonly IRolePermissionRepository _rolePermissionRepository = rolePermissionRepository;
private readonly ITenantProvider _tenantProvider = tenantProvider;
/// <inheritdoc />
public async Task<PagedResult<UserPermissionDto>> Handle(SearchUserPermissionsQuery request, CancellationToken cancellationToken)
{
var tenantId = _tenantProvider.GetCurrentTenantId();
var users = await _identityUserRepository.SearchAsync(tenantId, request.Keyword, cancellationToken);
// 1. 获取租户并查询用户
var tenantId = tenantProvider.GetCurrentTenantId();
var users = await identityUserRepository.SearchAsync(tenantId, request.Keyword, cancellationToken);
// 2. 排序与分页
var sorted = SortUsers(users, request.SortBy, request.SortDescending);
var paged = sorted
.Skip((request.Page - 1) * request.PageSize)
.Take(request.PageSize)
.ToList();
// 3. 解析角色与权限
var resolved = await ResolveRolesAndPermissionsAsync(tenantId, paged, cancellationToken);
var items = paged.Select(user => new UserPermissionDto
{
@@ -81,23 +77,27 @@ public sealed class SearchUserPermissionsQueryHandler(
IReadOnlyCollection<Domain.Identity.Entities.IdentityUser> users,
CancellationToken cancellationToken)
{
// 1. 查询用户角色关系
var userIds = users.Select(x => x.Id).ToArray();
var userRoleRelations = await _userRoleRepository.GetByUserIdsAsync(tenantId, userIds, cancellationToken);
var userRoleRelations = await userRoleRepository.GetByUserIdsAsync(tenantId, userIds, cancellationToken);
var roleIds = userRoleRelations.Select(x => x.RoleId).Distinct().ToArray();
// 2. 查询角色信息
var roles = roleIds.Length == 0
? Array.Empty<Domain.Identity.Entities.Role>()
: await _roleRepository.GetByIdsAsync(tenantId, roleIds, cancellationToken);
: await roleRepository.GetByIdsAsync(tenantId, roleIds, cancellationToken);
var roleCodeMap = roles.ToDictionary(r => r.Id, r => r.Code, comparer: EqualityComparer<long>.Default);
// 3. 查询角色-权限关系
var rolePermissions = roleIds.Length == 0
? Array.Empty<Domain.Identity.Entities.RolePermission>()
: await _rolePermissionRepository.GetByRoleIdsAsync(tenantId, roleIds, cancellationToken);
: await rolePermissionRepository.GetByRoleIdsAsync(tenantId, roleIds, cancellationToken);
var permissionIds = rolePermissions.Select(x => x.PermissionId).Distinct().ToArray();
// 4. 查询权限详情
var permissions = permissionIds.Length == 0
? Array.Empty<Domain.Identity.Entities.Permission>()
: await _permissionRepository.GetByIdsAsync(tenantId, permissionIds, cancellationToken);
: await permissionRepository.GetByIdsAsync(tenantId, permissionIds, cancellationToken);
var permissionCodeMap = permissions.ToDictionary(p => p.Id, p => p.Code, comparer: EqualityComparer<long>.Default);
var rolePermissionsLookup = rolePermissions
@@ -107,6 +107,7 @@ public sealed class SearchUserPermissionsQueryHandler(
var result = new Dictionary<long, (string[] roles, string[] permissions)>();
foreach (var userId in userIds)
{
// 5. 聚合用户角色与权限编码
var rolesForUser = userRoleRelations.Where(ur => ur.UserId == userId).Select(ur => ur.RoleId).Distinct().ToArray();
var roleCodes = rolesForUser
.Select(rid => roleCodeMap.GetValueOrDefault(rid))

View File

@@ -16,6 +16,7 @@ public sealed class UpdatePermissionCommandHandler(
{
public async Task<PermissionDto?> Handle(UpdatePermissionCommand request, CancellationToken cancellationToken)
{
// 1. 获取租户上下文并查询权限
var tenantId = tenantProvider.GetCurrentTenantId();
var permission = await permissionRepository.FindByIdAsync(request.PermissionId, tenantId, cancellationToken);
if (permission == null)
@@ -23,12 +24,15 @@ public sealed class UpdatePermissionCommandHandler(
return null;
}
// 2. 更新字段
permission.Name = request.Name;
permission.Description = request.Description;
// 3. 持久化
await permissionRepository.UpdateAsync(permission, cancellationToken);
await permissionRepository.SaveChangesAsync(cancellationToken);
// 4. 返回 DTO
return new PermissionDto
{
Id = permission.Id,

View File

@@ -16,6 +16,7 @@ public sealed class UpdateRoleCommandHandler(
{
public async Task<RoleDto?> Handle(UpdateRoleCommand request, CancellationToken cancellationToken)
{
// 1. 获取租户上下文并查询角色
var tenantId = tenantProvider.GetCurrentTenantId();
var role = await roleRepository.FindByIdAsync(request.RoleId, tenantId, cancellationToken);
if (role == null)
@@ -23,12 +24,15 @@ public sealed class UpdateRoleCommandHandler(
return null;
}
// 2. 更新字段
role.Name = request.Name;
role.Description = request.Description;
// 3. 持久化
await roleRepository.UpdateAsync(role, cancellationToken);
await roleRepository.SaveChangesAsync(cancellationToken);
// 4. 返回 DTO
return new RoleDto
{
Id = role.Id,