using Dpz.Core.Public.Entity.Auth;
using Dpz.Core.Service.Mediator.Features.Auth.Contracts;

namespace Dpz.Core.Service.Mediator.Features.Auth.Queries;

public class SearchUserAuthorizationsQueryHandler(
    IRepository<DpzAuthorization> authorizationRepository,
    IRepository<DpzApplication> applicationRepository
) : IRequestHandler<SearchUserAuthorizationsQuery, PagedListWarp<AuthAuthorizationPageItem>>
{
    public async ValueTask<PagedListWarp<AuthAuthorizationPageItem>> Handle(
        SearchUserAuthorizationsQuery request,
        CancellationToken cancellationToken
    )
    {
        if (string.IsNullOrWhiteSpace(request.Account))
        {
            return new PagedListWarp<AuthAuthorizationPageItem>(request.Page, request.Limit, 0, []);
        }

        var query = authorizationRepository.SearchFor(x => x.Subject == request.Account);

        if (
            !string.IsNullOrWhiteSpace(request.ApplicationId)
            && ObjectId.TryParse(request.ApplicationId, out var appId)
        )
        {
            query = query.Where(x => x.ApplicationId == appId);
        }

        if (!string.IsNullOrWhiteSpace(request.Status))
        {
            query = query.Where(x => x.Status == request.Status);
        }

        if (!string.IsNullOrWhiteSpace(request.Type))
        {
            query = query.Where(x => x.Type == request.Type);
        }

        if (!string.IsNullOrWhiteSpace(request.Keyword))
        {
            var keyword = request.Keyword.Trim();
            query = query.Where(x =>
                (x.Status != null && x.Status.Contains(keyword))
                || (x.Type != null && x.Type.Contains(keyword))
                || (x.Scopes != null && x.Scopes.Any(scope => scope.Contains(keyword)))
            );
        }

        var pagedList = await query
            .OrderByDescending(x => x.CreationDate)
            .ToPagedListAsync(request.Page, request.Limit, cancellationToken);

        var applicationIds = pagedList.Select(x => x.ApplicationId).ToHashSet();
        var applications = await applicationRepository
            .SearchFor(Builders<DpzApplication>.Filter.In(x => x.Id, applicationIds))
            .ToListAsync(cancellationToken);

        var items = pagedList
            .Select(x =>
            {
                var app = applications.FirstOrDefault(y => y.Id == x.ApplicationId);
                return new AuthAuthorizationPageItem
                {
                    Id = x.Id.ToString(),
                    ApplicationId = x.ApplicationId.ToString(),
                    ApplicationName = app?.DisplayName ?? string.Empty,
                    Status = x.Status,
                    Type = x.Type,
                    CreationDate = x.CreationDate,
                    Scopes = x.Scopes?.ToList() ?? [],
                };
            })
            .ToList();

        return new PagedListWarp<AuthAuthorizationPageItem>(
            pagedList.CurrentPageIndex,
            pagedList.PageSize,
            pagedList.TotalItemCount,
            items
        );
    }
}
⚠⚠    以下内容为AI分析的结果,请根据实际情况进行判断。

代码解释

这是一个基于 MediatR 模式的查询处理器(Query Handler),用于搜索和分页获取用户的授权信息。

核心功能

处理 SearchUserAuthorizationsQuery 请求,返回分页的授权列表 PagedListWarp<AuthAuthorizationPageItem>

主要流程

1. 依赖注入

IRepository<DpzAuthorization> authorizationRepository  // 授权数据仓储
IRepository<DpzApplication> applicationRepository      // 应用数据仓储

2. 参数验证

if (string.IsNullOrWhiteSpace(request.Account))
    return new PagedListWarp<AuthAuthorizationPageItem>(request.Page, request.Limit, 0, []);

如果账号为空,直接返回空结果集。

3. 构建查询条件

基础查询:根据用户账号(Subject)查询

var query = authorizationRepository.SearchFor(x => x.Subject == request.Account);

可选过滤条件

  • 应用ID过滤:如果提供了有效的 ApplicationId
  • 状态过滤:根据 Status 字段
  • 类型过滤:根据 Type 字段
  • 关键词搜索:在 Status、Type、Scopes 中模糊匹配
query = query.Where(x =>
    (x.Status != null && x.Status.Contains(keyword))
    || (x.Type != null && x.Type.Contains(keyword))
    || (x.Scopes != null && x.Scopes.Any(scope => scope.Contains(keyword)))
);

4. 分页查询

var pagedList = await query
    .OrderByDescending(x => x.CreationDate)  // 按创建时间倒序
    .ToPagedListAsync(request.Page, request.Limit, cancellationToken);

5. 关联应用信息

// 提取所有应用ID
var applicationIds = pagedList.Select(x => x.ApplicationId).ToHashSet();

// 批量查询应用信息(避免 N+1 查询问题)
var applications = await applicationRepository
    .SearchFor(Builders<DpzApplication>.Filter.In(x => x.Id, applicationIds))
    .ToListAsync(cancellationToken);

6. 数据映射

将授权实体转换为展示对象,并关联应用名称:

var items = pagedList.Select(x =>
{
    var app = applications.FirstOrDefault(y => y.Id == x.ApplicationId);
    return new AuthAuthorizationPageItem
    {
        Id = x.Id.ToString(),
        ApplicationId = x.ApplicationId.ToString(),
        ApplicationName = app?.DisplayName ?? string.Empty,  // 关联应用名称
        Status = x.Status,
        Type = x.Type,
        CreationDate = x.CreationDate,
        Scopes = x.Scopes?.ToList() ?? [],
    };
}).ToList();

7. 返回分页结果

return new PagedListWarp<AuthAuthorizationPageItem>(
    pagedList.CurrentPageIndex,
    pagedList.PageSize,
    pagedList.TotalItemCount,
    items
);

设计亮点

  1. 性能优化:使用 HashSet 去重应用ID,批量查询避免N+1问题
  2. 灵活过滤:支持多条件组合查询
  3. 空安全:使用 ???. 运算符处理空值
  4. 关注点分离:使用 MediatR 模式解耦业务逻辑
  5. 异步编程:全程使用异步方法提高并发性能

典型应用场景

在管理后台查询某个用户在不同应用下的授权记录,支持按状态、类型、关键词等条件筛选。

评论加载中...