fix:修复注释错误
This commit is contained in:
@@ -36,7 +36,7 @@ public sealed class BatchIdentityUserOperationCommandHandler(
|
||||
var operatorProfile = await adminAuthService.GetProfileAsync(currentUserAccessor.UserId, cancellationToken);
|
||||
var isSuperAdmin = IdentityUserAccess.IsSuperAdmin(operatorProfile);
|
||||
|
||||
// 2. (空行后) 校验跨租户访问权限
|
||||
// 2. 校验跨租户访问权限
|
||||
if (!isSuperAdmin && request.TenantId.HasValue && request.TenantId.Value != currentTenantId)
|
||||
{
|
||||
throw new BusinessException(ErrorCodes.Forbidden, "禁止跨租户批量操作用户");
|
||||
@@ -47,7 +47,7 @@ public sealed class BatchIdentityUserOperationCommandHandler(
|
||||
throw new BusinessException(ErrorCodes.BadRequest, "批量操作必须指定租户");
|
||||
}
|
||||
|
||||
// 3. (空行后) 解析用户 ID 列表
|
||||
// 3. 解析用户 ID 列表
|
||||
var tenantId = request.TenantId ?? currentTenantId;
|
||||
var userIds = ParseIds(request.UserIds, "用户");
|
||||
if (userIds.Length == 0)
|
||||
@@ -61,12 +61,12 @@ public sealed class BatchIdentityUserOperationCommandHandler(
|
||||
};
|
||||
}
|
||||
|
||||
// 4. (空行后) 查询目标用户集合
|
||||
// 4. 查询目标用户集合
|
||||
var includeDeleted = request.Operation == IdentityUserBatchOperation.Restore;
|
||||
var users = await identityUserRepository.GetForUpdateByIdsAsync(tenantId, userIds, includeDeleted, isSuperAdmin, cancellationToken);
|
||||
var usersById = users.ToDictionary(user => user.Id, user => user, EqualityComparer<long>.Default);
|
||||
|
||||
// 5. (空行后) 预计算租户管理员约束
|
||||
// 5. 预计算租户管理员约束
|
||||
var tenantAdminRole = await roleRepository.FindByCodeAsync("tenant-admin", tenantId, cancellationToken);
|
||||
var tenantAdminUserIds = tenantAdminRole == null
|
||||
? Array.Empty<long>()
|
||||
@@ -88,7 +88,7 @@ public sealed class BatchIdentityUserOperationCommandHandler(
|
||||
}, isSuperAdmin, cancellationToken)).Total;
|
||||
var remainingActiveAdmins = activeAdminCount;
|
||||
|
||||
// 6. (空行后) 执行批量操作
|
||||
// 6. 执行批量操作
|
||||
var failures = new List<BatchIdentityUserFailureItem>();
|
||||
var successCount = 0;
|
||||
var exportItems = new List<UserListItemDto>();
|
||||
@@ -185,7 +185,7 @@ public sealed class BatchIdentityUserOperationCommandHandler(
|
||||
});
|
||||
}
|
||||
}
|
||||
// 6.1 (空行后) 处理导出数据
|
||||
// 6.1 处理导出数据
|
||||
if (request.Operation == IdentityUserBatchOperation.Export)
|
||||
{
|
||||
var roleCodesLookup = await ResolveRoleCodesAsync(users, userRoleRepository, roleRepository, cancellationToken);
|
||||
@@ -208,7 +208,7 @@ public sealed class BatchIdentityUserOperationCommandHandler(
|
||||
}));
|
||||
}
|
||||
|
||||
// 7. (空行后) 构建操作日志消息
|
||||
// 7. 构建操作日志消息
|
||||
var operatorName = string.IsNullOrWhiteSpace(operatorProfile.DisplayName)
|
||||
? operatorProfile.Account
|
||||
: operatorProfile.DisplayName;
|
||||
@@ -229,7 +229,7 @@ public sealed class BatchIdentityUserOperationCommandHandler(
|
||||
Success = failures.Count == 0
|
||||
};
|
||||
|
||||
// 8. (空行后) 写入 Outbox 并保存变更
|
||||
// 8. 写入 Outbox 并保存变更
|
||||
await operationLogPublisher.PublishAsync(logMessage, cancellationToken);
|
||||
await identityUserRepository.SaveChangesAsync(cancellationToken);
|
||||
|
||||
@@ -250,7 +250,7 @@ public sealed class BatchIdentityUserOperationCommandHandler(
|
||||
return Array.Empty<long>();
|
||||
}
|
||||
|
||||
// 2. (空行后) 解析并去重
|
||||
// 2. 解析并去重
|
||||
var ids = new List<long>(values.Length);
|
||||
foreach (var value in values)
|
||||
{
|
||||
@@ -262,7 +262,7 @@ public sealed class BatchIdentityUserOperationCommandHandler(
|
||||
ids.Add(id);
|
||||
}
|
||||
|
||||
// 3. (空行后) 返回去重结果
|
||||
// 3. 返回去重结果
|
||||
return ids.Distinct().ToArray();
|
||||
}
|
||||
|
||||
@@ -275,7 +275,7 @@ public sealed class BatchIdentityUserOperationCommandHandler(
|
||||
// 1. 预分配字典容量
|
||||
var result = new Dictionary<long, string[]>(users.Count);
|
||||
|
||||
// 2. (空行后) 按租户分组,降低角色查询次数
|
||||
// 2. 按租户分组,降低角色查询次数
|
||||
foreach (var group in users.GroupBy(user => user.TenantId))
|
||||
{
|
||||
var tenantId = group.Key;
|
||||
@@ -285,21 +285,21 @@ public sealed class BatchIdentityUserOperationCommandHandler(
|
||||
continue;
|
||||
}
|
||||
|
||||
// 3. (空行后) 查询用户角色映射
|
||||
// 3. 查询用户角色映射
|
||||
var relations = await userRoleRepository.GetByUserIdsAsync(tenantId, userIds, cancellationToken);
|
||||
if (relations.Count == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// 4. (空行后) 查询角色并构建映射
|
||||
// 4. 查询角色并构建映射
|
||||
var roleIds = relations.Select(x => x.RoleId).Distinct().ToArray();
|
||||
var roles = roleIds.Length == 0
|
||||
? Array.Empty<Role>()
|
||||
: await roleRepository.GetByIdsAsync(tenantId, roleIds, cancellationToken);
|
||||
var roleCodeMap = roles.ToDictionary(role => role.Id, role => role.Code, EqualityComparer<long>.Default);
|
||||
|
||||
// 5. (空行后) 组装用户角色编码列表
|
||||
// 5. 组装用户角色编码列表
|
||||
foreach (var relationGroup in relations.GroupBy(x => x.UserId))
|
||||
{
|
||||
var codes = relationGroup
|
||||
|
||||
@@ -33,13 +33,13 @@ public sealed class ChangeIdentityUserStatusCommandHandler(
|
||||
var operatorProfile = await adminAuthService.GetProfileAsync(currentUserAccessor.UserId, cancellationToken);
|
||||
var isSuperAdmin = IdentityUserAccess.IsSuperAdmin(operatorProfile);
|
||||
|
||||
// 2. (空行后) 校验跨租户访问权限
|
||||
// 2. 校验跨租户访问权限
|
||||
if (!isSuperAdmin && request.TenantId.HasValue && request.TenantId.Value != currentTenantId)
|
||||
{
|
||||
throw new BusinessException(ErrorCodes.Forbidden, "禁止跨租户修改用户状态");
|
||||
}
|
||||
|
||||
// 3. (空行后) 查询用户实体
|
||||
// 3. 查询用户实体
|
||||
var user = isSuperAdmin
|
||||
? await identityUserRepository.GetForUpdateIgnoringTenantAsync(request.UserId, cancellationToken)
|
||||
: await identityUserRepository.GetForUpdateAsync(request.UserId, cancellationToken);
|
||||
@@ -53,13 +53,13 @@ public sealed class ChangeIdentityUserStatusCommandHandler(
|
||||
return false;
|
||||
}
|
||||
|
||||
// 4. (空行后) 校验租户管理员保留规则
|
||||
// 4. 校验租户管理员保留规则
|
||||
if (request.Status == IdentityUserStatus.Disabled && user.Status == IdentityUserStatus.Active)
|
||||
{
|
||||
await EnsureNotLastActiveTenantAdminAsync(user.TenantId, user.Id, isSuperAdmin, cancellationToken);
|
||||
}
|
||||
|
||||
// 5. (空行后) 更新状态
|
||||
// 5. 更新状态
|
||||
var previousStatus = user.Status;
|
||||
switch (request.Status)
|
||||
{
|
||||
@@ -80,7 +80,7 @@ public sealed class ChangeIdentityUserStatusCommandHandler(
|
||||
throw new BusinessException(ErrorCodes.BadRequest, "无效的用户状态");
|
||||
}
|
||||
|
||||
// 6. (空行后) 构建操作日志消息
|
||||
// 6. 构建操作日志消息
|
||||
var operatorName = string.IsNullOrWhiteSpace(operatorProfile.DisplayName)
|
||||
? operatorProfile.Account
|
||||
: operatorProfile.DisplayName;
|
||||
@@ -107,7 +107,7 @@ public sealed class ChangeIdentityUserStatusCommandHandler(
|
||||
Success = true
|
||||
};
|
||||
|
||||
// 7. (空行后) 写入 Outbox 并保存变更
|
||||
// 7. 写入 Outbox 并保存变更
|
||||
await operationLogPublisher.PublishAsync(logMessage, cancellationToken);
|
||||
await identityUserRepository.SaveChangesAsync(cancellationToken);
|
||||
|
||||
@@ -123,14 +123,14 @@ public sealed class ChangeIdentityUserStatusCommandHandler(
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. (空行后) 判断用户是否为租户管理员
|
||||
// 2. 判断用户是否为租户管理员
|
||||
var relations = await userRoleRepository.GetByUserIdAsync(tenantId, userId, cancellationToken);
|
||||
if (!relations.Any(x => x.RoleId == tenantAdminRole.Id))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 3. (空行后) 统计活跃管理员数量
|
||||
// 3. 统计活跃管理员数量
|
||||
var filter = new IdentityUserSearchFilter
|
||||
{
|
||||
TenantId = tenantId,
|
||||
|
||||
@@ -41,13 +41,13 @@ public sealed class CreateIdentityUserCommandHandler(
|
||||
var operatorProfile = await adminAuthService.GetProfileAsync(currentUserAccessor.UserId, cancellationToken);
|
||||
var isSuperAdmin = IdentityUserAccess.IsSuperAdmin(operatorProfile);
|
||||
|
||||
// 2. (空行后) 校验跨租户访问权限
|
||||
// 2. 校验跨租户访问权限
|
||||
if (!isSuperAdmin && request.TenantId.HasValue && request.TenantId.Value != currentTenantId)
|
||||
{
|
||||
throw new BusinessException(ErrorCodes.Forbidden, "禁止跨租户创建用户");
|
||||
}
|
||||
|
||||
// 3. (空行后) 规范化输入并准备校验
|
||||
// 3. 规范化输入并准备校验
|
||||
var tenantId = isSuperAdmin ? request.TenantId ?? currentTenantId : currentTenantId;
|
||||
var account = request.Account.Trim();
|
||||
var displayName = request.DisplayName.Trim();
|
||||
@@ -55,7 +55,7 @@ public sealed class CreateIdentityUserCommandHandler(
|
||||
var email = string.IsNullOrWhiteSpace(request.Email) ? null : request.Email.Trim();
|
||||
var roleIds = ParseIds(request.RoleIds, "角色");
|
||||
|
||||
// 4. (空行后) 唯一性校验
|
||||
// 4. 唯一性校验
|
||||
if (await identityUserRepository.ExistsByAccountAsync(tenantId, account, null, cancellationToken))
|
||||
{
|
||||
throw new BusinessException(ErrorCodes.Conflict, "账号已存在");
|
||||
@@ -73,7 +73,7 @@ public sealed class CreateIdentityUserCommandHandler(
|
||||
throw new BusinessException(ErrorCodes.Conflict, "邮箱已存在");
|
||||
}
|
||||
|
||||
// 5. (空行后) 校验角色合法性
|
||||
// 5. 校验角色合法性
|
||||
if (roleIds.Length > 0)
|
||||
{
|
||||
var roles = await roleRepository.GetByIdsAsync(tenantId, roleIds, cancellationToken);
|
||||
@@ -83,7 +83,7 @@ public sealed class CreateIdentityUserCommandHandler(
|
||||
}
|
||||
}
|
||||
|
||||
// 6. (空行后) 创建用户实体
|
||||
// 6. 创建用户实体
|
||||
var user = new IdentityUser
|
||||
{
|
||||
Id = idGenerator.NextId(),
|
||||
@@ -102,7 +102,7 @@ public sealed class CreateIdentityUserCommandHandler(
|
||||
};
|
||||
user.PasswordHash = passwordHasher.HashPassword(user, request.Password);
|
||||
|
||||
// 7. (空行后) 构建操作日志消息
|
||||
// 7. 构建操作日志消息
|
||||
var operatorName = string.IsNullOrWhiteSpace(operatorProfile.DisplayName)
|
||||
? operatorProfile.Account
|
||||
: operatorProfile.DisplayName;
|
||||
@@ -131,18 +131,18 @@ public sealed class CreateIdentityUserCommandHandler(
|
||||
Success = true
|
||||
};
|
||||
|
||||
// 8. (空行后) 持久化用户并写入 Outbox
|
||||
// 8. 持久化用户并写入 Outbox
|
||||
await identityUserRepository.AddAsync(user, cancellationToken);
|
||||
await operationLogPublisher.PublishAsync(logMessage, cancellationToken);
|
||||
await identityUserRepository.SaveChangesAsync(cancellationToken);
|
||||
|
||||
// 9. (空行后) 绑定角色
|
||||
// 9. 绑定角色
|
||||
if (roleIds.Length > 0)
|
||||
{
|
||||
await userRoleRepository.ReplaceUserRolesAsync(tenantId, user.Id, roleIds, cancellationToken);
|
||||
}
|
||||
|
||||
// 10. (空行后) 返回用户详情
|
||||
// 10. 返回用户详情
|
||||
var detail = await mediator.Send(new GetIdentityUserDetailQuery { UserId = user.Id }, cancellationToken);
|
||||
return detail ?? new UserDetailDto
|
||||
{
|
||||
@@ -173,7 +173,7 @@ public sealed class CreateIdentityUserCommandHandler(
|
||||
return Array.Empty<long>();
|
||||
}
|
||||
|
||||
// 2. (空行后) 解析并去重
|
||||
// 2. 解析并去重
|
||||
var ids = new List<long>(values.Length);
|
||||
foreach (var value in values)
|
||||
{
|
||||
@@ -185,7 +185,7 @@ public sealed class CreateIdentityUserCommandHandler(
|
||||
ids.Add(id);
|
||||
}
|
||||
|
||||
// 3. (空行后) 返回去重结果
|
||||
// 3. 返回去重结果
|
||||
return ids.Distinct().ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,13 +33,13 @@ public sealed class DeleteIdentityUserCommandHandler(
|
||||
var operatorProfile = await adminAuthService.GetProfileAsync(currentUserAccessor.UserId, cancellationToken);
|
||||
var isSuperAdmin = IdentityUserAccess.IsSuperAdmin(operatorProfile);
|
||||
|
||||
// 2. (空行后) 校验跨租户访问权限
|
||||
// 2. 校验跨租户访问权限
|
||||
if (!isSuperAdmin && request.TenantId.HasValue && request.TenantId.Value != currentTenantId)
|
||||
{
|
||||
throw new BusinessException(ErrorCodes.Forbidden, "禁止跨租户删除用户");
|
||||
}
|
||||
|
||||
// 3. (空行后) 查询用户实体
|
||||
// 3. 查询用户实体
|
||||
var user = isSuperAdmin
|
||||
? await identityUserRepository.GetForUpdateIgnoringTenantAsync(request.UserId, cancellationToken)
|
||||
: await identityUserRepository.GetForUpdateAsync(request.UserId, cancellationToken);
|
||||
@@ -53,13 +53,13 @@ public sealed class DeleteIdentityUserCommandHandler(
|
||||
return false;
|
||||
}
|
||||
|
||||
// 4. (空行后) 校验租户管理员保留规则
|
||||
// 4. 校验租户管理员保留规则
|
||||
if (user.Status == IdentityUserStatus.Active)
|
||||
{
|
||||
await EnsureNotLastActiveTenantAdminAsync(user.TenantId, user.Id, isSuperAdmin, cancellationToken);
|
||||
}
|
||||
|
||||
// 5. (空行后) 构建操作日志消息
|
||||
// 5. 构建操作日志消息
|
||||
var operatorName = string.IsNullOrWhiteSpace(operatorProfile.DisplayName)
|
||||
? operatorProfile.Account
|
||||
: operatorProfile.DisplayName;
|
||||
@@ -80,7 +80,7 @@ public sealed class DeleteIdentityUserCommandHandler(
|
||||
Success = true
|
||||
};
|
||||
|
||||
// 6. (空行后) 软删除用户并写入 Outbox
|
||||
// 6. 软删除用户并写入 Outbox
|
||||
await identityUserRepository.RemoveAsync(user, cancellationToken);
|
||||
await operationLogPublisher.PublishAsync(logMessage, cancellationToken);
|
||||
await identityUserRepository.SaveChangesAsync(cancellationToken);
|
||||
@@ -97,14 +97,14 @@ public sealed class DeleteIdentityUserCommandHandler(
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. (空行后) 判断用户是否为租户管理员
|
||||
// 2. 判断用户是否为租户管理员
|
||||
var relations = await userRoleRepository.GetByUserIdAsync(tenantId, userId, cancellationToken);
|
||||
if (!relations.Any(x => x.RoleId == tenantAdminRole.Id))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 3. (空行后) 统计活跃管理员数量
|
||||
// 3. 统计活跃管理员数量
|
||||
var filter = new IdentityUserSearchFilter
|
||||
{
|
||||
TenantId = tenantId,
|
||||
|
||||
@@ -32,7 +32,7 @@ public sealed class GetIdentityUserDetailQueryHandler(
|
||||
var operatorProfile = await adminAuthService.GetProfileAsync(currentUserAccessor.UserId, cancellationToken);
|
||||
var isSuperAdmin = IdentityUserAccess.IsSuperAdmin(operatorProfile);
|
||||
|
||||
// 2. (空行后) 查询用户实体
|
||||
// 2. 查询用户实体
|
||||
IdentityUser? user;
|
||||
if (request.IncludeDeleted)
|
||||
{
|
||||
@@ -55,7 +55,7 @@ public sealed class GetIdentityUserDetailQueryHandler(
|
||||
return null;
|
||||
}
|
||||
|
||||
// 3. (空行后) 加载角色与权限
|
||||
// 3. 加载角色与权限
|
||||
var roleRelations = await userRoleRepository.GetByUserIdAsync(user.TenantId, user.Id, cancellationToken);
|
||||
var roleIds = roleRelations.Select(x => x.RoleId).Distinct().ToArray();
|
||||
var roles = roleIds.Length == 0
|
||||
@@ -79,7 +79,7 @@ public sealed class GetIdentityUserDetailQueryHandler(
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.ToArray();
|
||||
|
||||
// 4. (空行后) 组装详情 DTO
|
||||
// 4. 组装详情 DTO
|
||||
var now = DateTime.UtcNow;
|
||||
return new UserDetailDto
|
||||
{
|
||||
|
||||
@@ -40,14 +40,14 @@ public sealed class ResetAdminPasswordByTokenCommandHandler(
|
||||
throw new BusinessException(ErrorCodes.BadRequest, "新密码长度需为 6~32 位");
|
||||
}
|
||||
|
||||
// 2. (空行后) 校验并消费令牌
|
||||
// 2. 校验并消费令牌
|
||||
var userId = await tokenStore.ConsumeAsync(token, cancellationToken);
|
||||
if (!userId.HasValue || userId.Value == 0)
|
||||
{
|
||||
throw new BusinessException(ErrorCodes.BadRequest, "重置链接无效或已过期");
|
||||
}
|
||||
|
||||
// 3. (空行后) 获取用户(可更新,忽略租户过滤器)并写入新密码哈希
|
||||
// 3. 获取用户(可更新,忽略租户过滤器)并写入新密码哈希
|
||||
var user = await userRepository.GetForUpdateIgnoringTenantAsync(userId.Value, cancellationToken)
|
||||
?? throw new BusinessException(ErrorCodes.NotFound, "用户不存在");
|
||||
|
||||
|
||||
@@ -33,13 +33,13 @@ public sealed class ResetIdentityUserPasswordCommandHandler(
|
||||
var operatorProfile = await adminAuthService.GetProfileAsync(currentUserAccessor.UserId, cancellationToken);
|
||||
var isSuperAdmin = IdentityUserAccess.IsSuperAdmin(operatorProfile);
|
||||
|
||||
// 2. (空行后) 校验跨租户访问权限
|
||||
// 2. 校验跨租户访问权限
|
||||
if (!isSuperAdmin && request.TenantId.HasValue && request.TenantId.Value != currentTenantId)
|
||||
{
|
||||
throw new BusinessException(ErrorCodes.Forbidden, "禁止跨租户重置密码");
|
||||
}
|
||||
|
||||
// 3. (空行后) 查询用户实体
|
||||
// 3. 查询用户实体
|
||||
var user = isSuperAdmin
|
||||
? await identityUserRepository.GetForUpdateIgnoringTenantAsync(request.UserId, cancellationToken)
|
||||
: await identityUserRepository.GetForUpdateAsync(request.UserId, cancellationToken);
|
||||
@@ -53,11 +53,11 @@ public sealed class ResetIdentityUserPasswordCommandHandler(
|
||||
throw new BusinessException(ErrorCodes.Forbidden, "禁止跨租户重置密码");
|
||||
}
|
||||
|
||||
// 4. (空行后) 签发重置令牌(1 小时有效)
|
||||
// 4. 签发重置令牌(1 小时有效)
|
||||
var expiresAt = DateTime.UtcNow.AddHours(1);
|
||||
var token = await tokenStore.IssueAsync(user.Id, expiresAt, cancellationToken);
|
||||
|
||||
// 5. (空行后) 标记用户需重置密码
|
||||
// 5. 标记用户需重置密码
|
||||
user.MustChangePassword = true;
|
||||
user.FailedLoginCount = 0;
|
||||
user.LockedUntil = null;
|
||||
@@ -66,7 +66,7 @@ public sealed class ResetIdentityUserPasswordCommandHandler(
|
||||
user.Status = IdentityUserStatus.Active;
|
||||
}
|
||||
|
||||
// 6. (空行后) 构建操作日志消息
|
||||
// 6. 构建操作日志消息
|
||||
var operatorName = string.IsNullOrWhiteSpace(operatorProfile.DisplayName)
|
||||
? operatorProfile.Account
|
||||
: operatorProfile.DisplayName;
|
||||
@@ -87,7 +87,7 @@ public sealed class ResetIdentityUserPasswordCommandHandler(
|
||||
Success = true
|
||||
};
|
||||
|
||||
// 7. (空行后) 写入 Outbox 并保存变更
|
||||
// 7. 写入 Outbox 并保存变更
|
||||
await operationLogPublisher.PublishAsync(logMessage, cancellationToken);
|
||||
await identityUserRepository.SaveChangesAsync(cancellationToken);
|
||||
|
||||
|
||||
@@ -30,13 +30,13 @@ public sealed class RestoreIdentityUserCommandHandler(
|
||||
var operatorProfile = await adminAuthService.GetProfileAsync(currentUserAccessor.UserId, cancellationToken);
|
||||
var isSuperAdmin = IdentityUserAccess.IsSuperAdmin(operatorProfile);
|
||||
|
||||
// 2. (空行后) 校验跨租户访问权限
|
||||
// 2. 校验跨租户访问权限
|
||||
if (!isSuperAdmin && request.TenantId.HasValue && request.TenantId.Value != currentTenantId)
|
||||
{
|
||||
throw new BusinessException(ErrorCodes.Forbidden, "禁止跨租户恢复用户");
|
||||
}
|
||||
|
||||
// 3. (空行后) 查询用户实体(包含已删除)
|
||||
// 3. 查询用户实体(包含已删除)
|
||||
var user = await identityUserRepository.GetForUpdateIncludingDeletedAsync(currentTenantId, request.UserId, isSuperAdmin, cancellationToken);
|
||||
if (user == null)
|
||||
{
|
||||
@@ -53,7 +53,7 @@ public sealed class RestoreIdentityUserCommandHandler(
|
||||
return false;
|
||||
}
|
||||
|
||||
// 4. (空行后) 构建操作日志消息
|
||||
// 4. 构建操作日志消息
|
||||
var operatorName = string.IsNullOrWhiteSpace(operatorProfile.DisplayName)
|
||||
? operatorProfile.Account
|
||||
: operatorProfile.DisplayName;
|
||||
@@ -74,7 +74,7 @@ public sealed class RestoreIdentityUserCommandHandler(
|
||||
Success = true
|
||||
};
|
||||
|
||||
// 5. (空行后) 恢复软删除状态并写入 Outbox
|
||||
// 5. 恢复软删除状态并写入 Outbox
|
||||
user.DeletedAt = null;
|
||||
user.DeletedBy = null;
|
||||
await operationLogPublisher.PublishAsync(logMessage, cancellationToken);
|
||||
|
||||
@@ -33,13 +33,13 @@ public sealed class SearchIdentityUsersQueryHandler(
|
||||
var operatorProfile = await adminAuthService.GetProfileAsync(currentUserAccessor.UserId, cancellationToken);
|
||||
var isSuperAdmin = IdentityUserAccess.IsSuperAdmin(operatorProfile);
|
||||
|
||||
// 2. (空行后) 校验跨租户访问权限
|
||||
// 2. 校验跨租户访问权限
|
||||
if (!isSuperAdmin && request.TenantId.HasValue && request.TenantId.Value != currentTenantId)
|
||||
{
|
||||
throw new BusinessException(ErrorCodes.Forbidden, "禁止跨租户查询用户");
|
||||
}
|
||||
|
||||
// 3. (空行后) 组装查询过滤条件
|
||||
// 3. 组装查询过滤条件
|
||||
var filter = new IdentityUserSearchFilter
|
||||
{
|
||||
TenantId = isSuperAdmin ? request.TenantId : currentTenantId,
|
||||
@@ -57,17 +57,17 @@ public sealed class SearchIdentityUsersQueryHandler(
|
||||
SortDescending = request.SortDescending
|
||||
};
|
||||
|
||||
// 4. (空行后) 执行分页查询
|
||||
// 4. 执行分页查询
|
||||
var (items, total) = await identityUserRepository.SearchPagedAsync(filter, isSuperAdmin, cancellationToken);
|
||||
if (items.Count == 0)
|
||||
{
|
||||
return new PagedResult<UserListItemDto>(Array.Empty<UserListItemDto>(), request.Page, request.PageSize, total);
|
||||
}
|
||||
|
||||
// 5. (空行后) 加载角色编码映射
|
||||
// 5. 加载角色编码映射
|
||||
var roleCodesLookup = await ResolveRoleCodesAsync(items, userRoleRepository, roleRepository, cancellationToken);
|
||||
|
||||
// 6. (空行后) 组装 DTO
|
||||
// 6. 组装 DTO
|
||||
var now = DateTime.UtcNow;
|
||||
var dtos = items.Select(user => new UserListItemDto
|
||||
{
|
||||
@@ -86,7 +86,7 @@ public sealed class SearchIdentityUsersQueryHandler(
|
||||
LastLoginAt = user.LastLoginAt
|
||||
}).ToList();
|
||||
|
||||
// 7. (空行后) 返回分页结果
|
||||
// 7. 返回分页结果
|
||||
return new PagedResult<UserListItemDto>(dtos, request.Page, request.PageSize, total);
|
||||
}
|
||||
|
||||
@@ -103,7 +103,7 @@ public sealed class SearchIdentityUsersQueryHandler(
|
||||
// 1. 预分配字典容量
|
||||
var result = new Dictionary<long, string[]>(users.Count);
|
||||
|
||||
// 2. (空行后) 按租户分组,降低角色查询次数
|
||||
// 2. 按租户分组,降低角色查询次数
|
||||
foreach (var group in users.GroupBy(user => user.TenantId))
|
||||
{
|
||||
var tenantId = group.Key;
|
||||
@@ -113,21 +113,21 @@ public sealed class SearchIdentityUsersQueryHandler(
|
||||
continue;
|
||||
}
|
||||
|
||||
// 3. (空行后) 查询用户角色映射
|
||||
// 3. 查询用户角色映射
|
||||
var relations = await userRoleRepository.GetByUserIdsAsync(tenantId, userIds, cancellationToken);
|
||||
if (relations.Count == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// 4. (空行后) 查询角色并构建映射
|
||||
// 4. 查询角色并构建映射
|
||||
var roleIds = relations.Select(x => x.RoleId).Distinct().ToArray();
|
||||
var roles = roleIds.Length == 0
|
||||
? Array.Empty<Role>()
|
||||
: await roleRepository.GetByIdsAsync(tenantId, roleIds, cancellationToken);
|
||||
var roleCodeMap = roles.ToDictionary(role => role.Id, role => role.Code, EqualityComparer<long>.Default);
|
||||
|
||||
// 5. (空行后) 组装用户角色编码列表
|
||||
// 5. 组装用户角色编码列表
|
||||
foreach (var relationGroup in relations.GroupBy(x => x.UserId))
|
||||
{
|
||||
var codes = relationGroup
|
||||
|
||||
@@ -36,13 +36,13 @@ public sealed class UpdateIdentityUserCommandHandler(
|
||||
var operatorProfile = await adminAuthService.GetProfileAsync(currentUserAccessor.UserId, cancellationToken);
|
||||
var isSuperAdmin = IdentityUserAccess.IsSuperAdmin(operatorProfile);
|
||||
|
||||
// 2. (空行后) 校验跨租户访问权限
|
||||
// 2. 校验跨租户访问权限
|
||||
if (!isSuperAdmin && request.TenantId.HasValue && request.TenantId.Value != currentTenantId)
|
||||
{
|
||||
throw new BusinessException(ErrorCodes.Forbidden, "禁止跨租户更新用户");
|
||||
}
|
||||
|
||||
// 3. (空行后) 获取用户实体
|
||||
// 3. 获取用户实体
|
||||
var user = isSuperAdmin
|
||||
? await identityUserRepository.GetForUpdateIgnoringTenantAsync(request.UserId, cancellationToken)
|
||||
: await identityUserRepository.GetForUpdateAsync(request.UserId, cancellationToken);
|
||||
@@ -56,7 +56,7 @@ public sealed class UpdateIdentityUserCommandHandler(
|
||||
return null;
|
||||
}
|
||||
|
||||
// 4. (空行后) 规范化输入并校验唯一性
|
||||
// 4. 规范化输入并校验唯一性
|
||||
var displayName = request.DisplayName.Trim();
|
||||
var phone = string.IsNullOrWhiteSpace(request.Phone) ? null : request.Phone.Trim();
|
||||
var email = string.IsNullOrWhiteSpace(request.Email) ? null : request.Email.Trim();
|
||||
@@ -85,14 +85,14 @@ public sealed class UpdateIdentityUserCommandHandler(
|
||||
}
|
||||
}
|
||||
|
||||
// 5. (空行后) 更新用户字段
|
||||
// 5. 更新用户字段
|
||||
user.DisplayName = displayName;
|
||||
user.Phone = phone;
|
||||
user.Email = email;
|
||||
user.Avatar = string.IsNullOrWhiteSpace(request.Avatar) ? null : request.Avatar.Trim();
|
||||
user.RowVersion = request.RowVersion;
|
||||
|
||||
// 6. (空行后) 构建操作日志消息
|
||||
// 6. 构建操作日志消息
|
||||
var operatorName = string.IsNullOrWhiteSpace(operatorProfile.DisplayName)
|
||||
? operatorProfile.Account
|
||||
: operatorProfile.DisplayName;
|
||||
@@ -120,7 +120,7 @@ public sealed class UpdateIdentityUserCommandHandler(
|
||||
Success = true
|
||||
};
|
||||
|
||||
// 7. (空行后) 持久化用户更新并写入 Outbox
|
||||
// 7. 持久化用户更新并写入 Outbox
|
||||
try
|
||||
{
|
||||
await operationLogPublisher.PublishAsync(logMessage, cancellationToken);
|
||||
@@ -131,13 +131,13 @@ public sealed class UpdateIdentityUserCommandHandler(
|
||||
throw new BusinessException(ErrorCodes.Conflict, "用户数据已被修改,请刷新后重试");
|
||||
}
|
||||
|
||||
// 8. (空行后) 覆盖角色绑定(仅当显式传入时)
|
||||
// 8. 覆盖角色绑定(仅当显式传入时)
|
||||
if (roleIds != null)
|
||||
{
|
||||
await userRoleRepository.ReplaceUserRolesAsync(user.TenantId, user.Id, roleIds, cancellationToken);
|
||||
}
|
||||
|
||||
// 9. (空行后) 返回用户详情
|
||||
// 9. 返回用户详情
|
||||
return await mediator.Send(new GetIdentityUserDetailQuery { UserId = user.Id }, cancellationToken);
|
||||
}
|
||||
|
||||
@@ -149,7 +149,7 @@ public sealed class UpdateIdentityUserCommandHandler(
|
||||
return Array.Empty<long>();
|
||||
}
|
||||
|
||||
// 2. (空行后) 解析并去重
|
||||
// 2. 解析并去重
|
||||
var ids = new List<long>(values.Length);
|
||||
foreach (var value in values)
|
||||
{
|
||||
@@ -161,7 +161,7 @@ public sealed class UpdateIdentityUserCommandHandler(
|
||||
ids.Add(id);
|
||||
}
|
||||
|
||||
// 3. (空行后) 返回去重结果
|
||||
// 3. 返回去重结果
|
||||
return ids.Distinct().ToArray();
|
||||
}
|
||||
|
||||
|
||||
@@ -81,10 +81,10 @@ public sealed class AdminAuthService(
|
||||
throw new BusinessException(ErrorCodes.Unauthorized, "账号或密码错误");
|
||||
}
|
||||
|
||||
// 4. (空行后) 更新登录成功状态
|
||||
// 4. 更新登录成功状态
|
||||
await UpdateLoginSuccessAsync(user.Id, now, cancellationToken);
|
||||
|
||||
// 5. (空行后) 构建用户档案并生成令牌
|
||||
// 5. 构建用户档案并生成令牌
|
||||
var profile = await BuildProfileAsync(user, cancellationToken);
|
||||
return await jwtTokenService.CreateTokensAsync(profile, false, cancellationToken);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user