PartnerScopeHelper.cs 4.91 KB
using FoodLabeling.Application.Services.DbModels;
using SqlSugar;
using Volo.Abp.Users;
using Yi.Framework.SqlSugarCore.Abstractions;

namespace FoodLabeling.Application.Helpers;

/// <summary>
/// 合作伙伴(公司)数据范围:管理员可见全部;非管理员仅可见其 <c>userlocation</c> 绑定门店所属公司。
/// </summary>
public static class PartnerScopeHelper
{
    /// <summary>
    /// <see cref="IsUnrestricted"/> 为 true 时不限制;
    /// 否则仅 <see cref="AllowedPartnerIds"/> 中的公司 Id(<c>fl_partner.Id</c>)可见;无绑定时为空列表。
    /// </summary>
    public sealed class PartnerScopeFilter
    {
        public bool IsUnrestricted { get; init; }

        public IReadOnlyList<string> AllowedPartnerIds { get; init; } = Array.Empty<string>();
    }

    /// <summary>
    /// 解析当前登录用户可查询的合作伙伴 Id 范围。
    /// </summary>
    public static async Task<PartnerScopeFilter> ResolvePartnerScopeAsync(
        ICurrentUser currentUser,
        ISqlSugarDbContext dbContext)
    {
        if (ReportsRoleHelper.IsAdminRole(currentUser))
        {
            return new PartnerScopeFilter { IsUnrestricted = true };
        }

        if (currentUser.Id is null)
        {
            return new PartnerScopeFilter();
        }

        var db = dbContext.SqlSugarClient;
        var locationIds = await LocationScopeBindingHelper.ResolveBoundLocationIdsForUserAsync(
            db, currentUser.Id.Value);
        if (locationIds.Count == 0)
        {
            return new PartnerScopeFilter();
        }

        var allowedIds = await LocationScopeBindingHelper.ResolvePartnerIdsFromLocationIdsAsync(
            db, locationIds);
        return new PartnerScopeFilter { AllowedPartnerIds = allowedIds };
    }

    /// <summary>
    /// 将数据范围应用到合作伙伴查询(须在其它 Where 之前或之后均可,建议在 IsDeleted 之后)。
    /// </summary>
    public static ISugarQueryable<FlPartnerDbEntity> ApplyPartnerScope(
        ISugarQueryable<FlPartnerDbEntity> query,
        PartnerScopeFilter scope)
    {
        if (scope.IsUnrestricted)
        {
            return query;
        }

        var ids = scope.AllowedPartnerIds;
        if (ids.Count == 0)
        {
            return query.Where(_ => false);
        }

        if (ids.Count == 1)
        {
            var single = ids[0];
            return query.Where(x => x.Id == single);
        }

        return query.In(x => x.Id, ids.ToList());
    }

    /// <summary>
    /// 组织(fl_group)数据范围(供 auth-scope 等复用);列表请优先用 <see cref="GroupListScopeHelper"/>。
    /// </summary>
    public sealed class GroupScopeFilter
    {
        public bool IsUnrestricted { get; init; }

        public IReadOnlyList<string> AllowedGroupIds { get; init; } = Array.Empty<string>();
    }

    /// <summary>
    /// 解析当前登录用户可查询的组织 Id 范围。
    /// </summary>
    public static async Task<GroupScopeFilter> ResolveGroupScopeAsync(
        ICurrentUser currentUser,
        ISqlSugarDbContext dbContext)
    {
        var scope = await GroupListScopeHelper.ResolveAsync(currentUser, dbContext);
        if (scope.IsUnrestricted)
        {
            return new GroupScopeFilter { IsUnrestricted = true };
        }

        if (scope.AllowedPartnerIds.Count > 0)
        {
            var db = dbContext.SqlSugarClient;
            var groupIds = await LocationScopeBindingHelper.ResolveGroupIdsFromPartnerIdsAsync(
                db, scope.AllowedPartnerIds);
            return new GroupScopeFilter { AllowedGroupIds = groupIds };
        }

        return new GroupScopeFilter { AllowedGroupIds = scope.AllowedGroupIds.ToList() };
    }

    /// <summary>
    /// 将组织数据范围应用到 fl_group 单表查询。
    /// </summary>
    public static ISugarQueryable<FlGroupDbEntity> ApplyGroupScope(
        ISugarQueryable<FlGroupDbEntity> query,
        GroupScopeFilter scope) =>
        GroupListScopeHelper.ApplyToQuery(query, GroupListScopeHelper.FromGroupScopeFilter(scope));

    /// <summary>
    /// 将组织数据范围应用到 fl_group 联表查询。
    /// </summary>
    public static ISugarQueryable<FlGroupDbEntity, FlPartnerDbEntity> ApplyGroupScope(
        ISugarQueryable<FlGroupDbEntity, FlPartnerDbEntity> query,
        GroupScopeFilter scope)
    {
        if (scope.IsUnrestricted)
        {
            return query;
        }

        var ids = scope.AllowedGroupIds
            .Where(x => !string.IsNullOrWhiteSpace(x))
            .Select(x => x.Trim())
            .Distinct(StringComparer.OrdinalIgnoreCase)
            .ToList();
        if (ids.Count == 0)
        {
            return query.Where((g, p) => false);
        }

        if (ids.Count == 1)
        {
            var single = ids[0];
            return query.Where((g, p) => g.Id == single);
        }

        return query.In((g, p) => g.Id, ids);
    }
}