using FoodLabeling.Application.Services.DbModels;
using SqlSugar;
using Volo.Abp;
using Volo.Abp.Users;
using Yi.Framework.Rbac.Domain.Shared.Consts;
using Yi.Framework.SqlSugarCore.Abstractions;
namespace FoodLabeling.Application.Helpers;
///
/// Account Management 结构变更权限:平台管理员、Company Admin 角色,或具备 manage_people 访问权限的用户可维护 Region/Location。
///
public static class AccountManagementStructureHelper
{
///
/// 是否可新增/编辑/删除 Region(fl_group)与门店(location)。
///
public static async Task EnsureCanMutateRegionAndLocationAsync(
ICurrentUser currentUser,
ISqlSugarDbContext dbContext)
{
if (await CanMutateRegionAndLocationAsync(currentUser, dbContext))
{
return;
}
throw new UserFriendlyException("You do not have permission to manage regions or locations.");
}
public static async Task CanMutateRegionAndLocationAsync(
ICurrentUser currentUser,
ISqlSugarDbContext dbContext)
{
if (ReportsRoleHelper.IsAdminRole(currentUser))
{
return true;
}
if (IsCompanyAdminFromClaims(currentUser))
{
return true;
}
if (currentUser.Id is null)
{
return false;
}
var db = dbContext.SqlSugarClient;
if (await IsCompanyAdminRoleFromDbAsync(currentUser, db))
{
return true;
}
var accessCodes = await UserRoleAccessPermissionHelper.ResolveMergedAccessPermissionCodesAsync(
db, currentUser.Id.Value);
return UserRoleAccessPermissionHelper.CanManageRegionAndLocationByAccessPermissions(accessCodes);
}
///
/// 非平台管理员仅能在其数据范围内的公司下维护 Region。
///
public static async Task EnsurePartnerIdAllowedForRegionMutationAsync(
ICurrentUser currentUser,
ISqlSugarDbContext dbContext,
string partnerId)
{
if (ReportsRoleHelper.IsAdminRole(currentUser))
{
return;
}
var pid = partnerId?.Trim() ?? string.Empty;
if (string.IsNullOrWhiteSpace(pid))
{
throw new UserFriendlyException("Parent company is required.");
}
var scope = await PartnerScopeHelper.ResolvePartnerScopeAsync(currentUser, dbContext);
if (scope.IsUnrestricted || scope.AllowedPartnerIds.Any(x => string.Equals(x, pid, StringComparison.Ordinal)))
{
return;
}
throw new UserFriendlyException("You can only manage regions for your assigned company.");
}
///
/// 非平台管理员仅能在其数据范围内的公司下维护门店(location.Partner 为公司名称)。
///
public static async Task EnsureLocationPartnerAllowedForMutationAsync(
ICurrentUser currentUser,
ISqlSugarDbContext dbContext,
string? partnerName)
{
if (ReportsRoleHelper.IsAdminRole(currentUser))
{
return;
}
var name = partnerName?.Trim() ?? string.Empty;
if (string.IsNullOrWhiteSpace(name))
{
return;
}
var scope = await PartnerScopeHelper.ResolvePartnerScopeAsync(currentUser, dbContext);
if (scope.IsUnrestricted)
{
return;
}
if (scope.AllowedPartnerIds.Count == 0)
{
throw new UserFriendlyException("You can only manage locations for your assigned company.");
}
var allowedNames = await dbContext.SqlSugarClient.Queryable()
.Where(x => !x.IsDeleted && scope.AllowedPartnerIds.Contains(x.Id))
.Select(x => x.PartnerName)
.ToListAsync();
if (allowedNames.Any(n =>
!string.IsNullOrWhiteSpace(n) &&
string.Equals(n.Trim(), name, StringComparison.OrdinalIgnoreCase)))
{
return;
}
throw new UserFriendlyException("You can only manage locations for your assigned company.");
}
private static async Task IsCompanyAdminRoleFromDbAsync(ICurrentUser currentUser, ISqlSugarClient db)
{
if (currentUser.Id is null)
{
return false;
}
var roleRows = await db.Ado.SqlQueryAsync(
@"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 = currentUser.Id.Value });
return roleRows.Any(r =>
IsCompanyAdminRoleToken(r.RoleCode) || IsCompanyAdminRoleToken(r.RoleName));
}
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))
{
foreach (var part in rolesClaim.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries))
{
if (IsCompanyAdminRoleToken(part))
{
return true;
}
}
}
return false;
}
private 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 string NormalizeRoleKey(string value) =>
new string(value.Trim().ToLowerInvariant().Where(c => char.IsLetterOrDigit(c)).ToArray());
private sealed class CompanyRoleRow
{
public string? RoleCode { get; set; }
public string? RoleName { get; set; }
}
}