admin/src/Oms.Application/Rbac/InternalUserRepository.cs
xiaolipro 09ca1c96d7
Some checks failed
Build and Deploy / deploy (push) Failing after 15s
fix
2026-10-13 16:25:22 +08:00

175 lines
5.7 KiB
C#

using Fake.DependencyInjection;
using Fake.Rbac.Infrastructure;
using Fake.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using Oms.Application.Dtos.Rbac;
namespace Oms.Application.Rbac;
public class InternalUserRepository(FakeRbacDbContext dbContext) : IScopedDependency
{
private static readonly string InternalUserFilter = $$"""
(
NOT EXISTS (SELECT 1 FROM `{{FakeTables.UserRole}}` ur0 WHERE ur0.`UserId` = u.`Id`)
OR EXISTS (
SELECT 1
FROM `{{FakeTables.UserRole}}` ur
INNER JOIN `{{FakeTables.Role}}` r ON r.`Id` = ur.`RoleId` AND r.`IsDeleted` = 0
WHERE ur.`UserId` = u.`Id`
AND r.`Code` <> 'Customer'
AND r.`Code` NOT LIKE 'CustomerSub\_%'
)
)
""";
public async Task<InternalUserListResultDto> GetInternalUsersAsync(
string? keyword,
Guid? organizationId,
int page,
int pageSize,
CancellationToken cancellationToken = default)
{
var where = $"WHERE u.`IsDeleted` = 0 AND {InternalUserFilter}";
var args = new List<object>();
if (!string.IsNullOrWhiteSpace(keyword))
{
var pattern = $"%{keyword.Trim()}%";
where += $" AND (u.`Name` LIKE {{{args.Count}}} OR u.`Account` LIKE {{{args.Count + 1}}})";
args.Add(pattern);
args.Add(pattern);
}
if (organizationId.HasValue && organizationId.Value != Guid.Empty)
{
where += $" AND u.`OrganizationId` = {{{args.Count}}}";
args.Add(organizationId.Value.ToString());
}
var countSql = $$"""
SELECT COUNT(*) AS `Value`
FROM `{{FakeTables.User}}` u
{where}
""";
var total = await dbContext.Database.SqlQueryRaw<long>(countSql, args.ToArray())
.FirstAsync(cancellationToken);
var offset = Math.Max(page - 1, 0) * pageSize;
var listSql = $$"""
SELECT
u.`Id` AS `Id`,
u.`Name` AS `Name`,
u.`Account` AS `Account`,
u.`Email` AS `Email`,
u.`Avatar` AS `Avatar`,
u.`Phone` AS `Phone`,
u.`EmployeeNo` AS `EmployeeNo`,
u.`WechatId` AS `WechatId`,
u.`OrganizationId` AS `OrganizationId`,
o.`Name` AS `OrganizationName`,
u.`CreateTime` AS `CreatedAt`
FROM `{{FakeTables.User}}` u
LEFT JOIN `{{FakeTables.Organization}}` o ON o.`Id` = u.`OrganizationId` AND o.`IsDeleted` = 0
{where}
ORDER BY u.`CreateTime` DESC
LIMIT {pageSize} OFFSET {offset}
""";
var rows = await dbContext.Database.SqlQueryRaw<InternalUserRow>(listSql, args.ToArray())
.ToListAsync(cancellationToken);
if (rows.Count == 0)
{
return new InternalUserListResultDto { Total = total, Items = [] };
}
var userIds = rows.Select(x => x.Id).Distinct().ToList();
var roleMap = await LoadRolesByUserIdsAsync(userIds, cancellationToken);
var items = rows.Select(row => new InternalUserListItemDto
{
Id = row.Id.ToString(),
Name = row.Name,
Account = row.Account,
Email = row.Email,
Avatar = row.Avatar,
Phone = row.Phone,
EmployeeNo = row.EmployeeNo,
WechatId = row.WechatId,
OrganizationId = row.OrganizationId?.ToString(),
OrganizationName = row.OrganizationName,
CreatedAt = row.CreatedAt,
Roles = roleMap.TryGetValue(row.Id, out var roles) ? roles : []
}).ToList();
return new InternalUserListResultDto { Total = total, Items = items };
}
private async Task<Dictionary<Guid, List<InternalUserRoleDto>>> LoadRolesByUserIdsAsync(
IReadOnlyList<Guid> userIds,
CancellationToken cancellationToken)
{
if (userIds.Count == 0)
{
return [];
}
var inClause = string.Join(",", userIds.Select(x => $"'{x}'"));
var sql = $$"""
SELECT
ur.`UserId` AS `UserId`,
r.`Id` AS `RoleId`,
r.`Name` AS `RoleName`,
r.`Code` AS `RoleCode`
FROM `{{FakeTables.UserRole}}` ur
INNER JOIN `{{FakeTables.Role}}` r ON r.`Id` = ur.`RoleId` AND r.`IsDeleted` = 0
WHERE ur.`UserId` IN ({inClause})
ORDER BY r.`Name`
""";
var roleRows = await dbContext.Database.SqlQueryRaw<UserRoleRow>(sql).ToListAsync(cancellationToken);
return roleRows
.GroupBy(x => x.UserId)
.ToDictionary(
g => g.Key,
g => g.Select(x => new InternalUserRoleDto
{
Id = x.RoleId.ToString(),
Name = x.RoleName,
Code = x.RoleCode
}).ToList());
}
private sealed class InternalUserRow
{
public Guid Id { get; set; }
public string? Name { get; set; }
public string? Account { get; set; }
public string? Email { get; set; }
public string? Avatar { get; set; }
public string? Phone { get; set; }
public string? EmployeeNo { get; set; }
public string? WechatId { get; set; }
public Guid? OrganizationId { get; set; }
public string? OrganizationName { get; set; }
public DateTime? CreatedAt { get; set; }
}
private sealed class UserRoleRow
{
public Guid UserId { get; set; }
public Guid RoleId { get; set; }
public string? RoleName { get; set; }
public string? RoleCode { get; set; }
}
}