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; } } }