TeamMemberRoleHelper.cs 5.45 KB
using SqlSugar;
using Volo.Abp.Users;
using Yi.Framework.Rbac.Domain.Shared.Consts;

namespace FoodLabeling.Application.Helpers;

/// <summary>
/// Team Member 角色识别(Company Admin / Partner Admin 等)。
/// </summary>
public static class TeamMemberRoleHelper
{
    /// <summary>
    /// UI 展示为 Company Admin,库内常见为 Partner Admin 或 RoleCode 含 partner / CompanyAdmin。
    /// </summary>
    public static bool IsCompanyAdminRoleName(string? roleName)
    {
        if (string.IsNullOrWhiteSpace(roleName))
        {
            return false;
        }

        if (IsCompanyAdminRoleToken(roleName))
        {
            return true;
        }

        var name = roleName.Trim();
        if (string.Equals(name, "Company Admin", StringComparison.OrdinalIgnoreCase))
        {
            return true;
        }

        if (string.Equals(name, "Partner Admin", StringComparison.OrdinalIgnoreCase))
        {
            return true;
        }

        return name.Contains("partner", StringComparison.OrdinalIgnoreCase) &&
               name.Contains("admin", StringComparison.OrdinalIgnoreCase);
    }

    /// <summary>
    /// 当前登录用户是否为 Company Admin 类角色(JWT 声明 + 库内 Role)。
    /// </summary>
    public static async Task<bool> IsCompanyAdminUserAsync(ISqlSugarClient db, ICurrentUser currentUser)
    {
        if (IsCompanyAdminFromClaims(currentUser))
        {
            return true;
        }

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

        return await IsCompanyAdminUserAsync(db, currentUser.Id.Value);
    }

    /// <summary>
    /// 指定用户是否为 Company Admin 类角色(按库内 Role 判定,用于登录等无 JWT 声明场景)。
    /// </summary>
    public static async Task<bool> IsCompanyAdminUserAsync(ISqlSugarClient db, Guid userId)
    {
        var roleRows = await LoadUserRoleRowsAsync(db, userId);
        return roleRows.Any(r =>
            IsCompanyAdminRoleName(r.RoleName) || IsCompanyAdminRoleToken(r.RoleCode));
    }

    /// <summary>
    /// 是否 Company Admin 类角色(按 RoleId 查库)。
    /// </summary>
    public static async Task<bool> IsCompanyAdminRoleAsync(ISqlSugarClient db, Guid? roleId)
    {
        if (roleId is null)
        {
            return false;
        }

        var roleRows = await db.Ado.SqlQueryAsync<UserRoleNameRow>(
            """
            SELECT RoleCode, RoleName
            FROM Role
            WHERE IsDeleted = 0 AND Id = @RoleId
            LIMIT 1
            """,
            new { RoleId = roleId.Value });

        var role = roleRows.FirstOrDefault();
        if (role is null)
        {
            return false;
        }

        return IsCompanyAdminRoleName(role.RoleName) || IsCompanyAdminRoleToken(role.RoleCode);
    }

    /// <summary>
    /// 读取用户角色(raw SQL,避免 RBAC 数据权限过滤器中 Select 表达式导致 SqlSugar 解析失败)。
    /// </summary>
    private static Task<List<UserRoleNameRow>> LoadUserRoleRowsAsync(ISqlSugarClient db, Guid userId) =>
        db.Ado.SqlQueryAsync<UserRoleNameRow>(
            """
            SELECT r.RoleCode, r.RoleName
            FROM UserRole ur
            INNER JOIN Role r ON ur.RoleId = r.Id
            WHERE ur.UserId = @UserId AND r.IsDeleted = 0 AND r.State = 1
            """,
            new { UserId = userId });

    /// <summary>
    /// 列表/详情出参:Partner Admin → Company Admin(与 Web UI 一致)。
    /// </summary>
    public static string? FormatDisplayRoleName(string? roleName)
    {
        if (IsCompanyAdminRoleName(roleName) &&
            !string.Equals(roleName?.Trim(), "Company Admin", StringComparison.OrdinalIgnoreCase))
        {
            return "Company Admin";
        }

        return roleName;
    }

    /// <summary>
    /// JWT / RoleCode / RoleName 中的 Company Admin 标识(含 <c>CompanyAdmin</c>)。
    /// </summary>
    public static bool IsCompanyAdminRoleToken(string? value)
    {
        if (string.IsNullOrWhiteSpace(value))
        {
            return false;
        }

        var key = NormalizeRoleKey(value);
        if (key == "companyadmin" || key.Contains("companyadmin", StringComparison.Ordinal))
        {
            return true;
        }

        return value.Trim().Contains("partner", StringComparison.OrdinalIgnoreCase);
    }

    private static bool IsCompanyAdminFromClaims(ICurrentUser currentUser)
    {
        if (currentUser.Roles is not null)
        {
            foreach (var r in currentUser.Roles)
            {
                if (IsCompanyAdminRoleToken(r))
                {
                    return true;
                }
            }
        }

        var rolesClaim = currentUser.FindClaims(TokenTypeConst.Roles).Select(x => x.Value).FirstOrDefault();
        if (string.IsNullOrWhiteSpace(rolesClaim))
        {
            return false;
        }

        foreach (var part in rolesClaim.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries))
        {
            if (IsCompanyAdminRoleToken(part))
            {
                return true;
            }
        }

        return false;
    }

    private static string NormalizeRoleKey(string value) =>
        new string(value.Trim().ToLowerInvariant().Where(c => char.IsLetterOrDigit(c)).ToArray());

    private sealed class UserRoleNameRow
    {
        public string? RoleCode { get; set; }

        public string? RoleName { get; set; }
    }
}