menu_action.permission_code */ public static function delegationMenuActionCodesForAgent(AgentNode $agent): array { if ($agent->isRoot()) { return DB::table('admin_menu_actions')->where('status', 1)->pluck('permission_code')->all(); } return DB::table('agent_delegation_grants as g') ->join('admin_menu_actions as ma', 'ma.id', '=', 'g.menu_action_id') ->where('g.child_agent_id', $agent->id) ->where('ma.status', 1) ->pluck('ma.permission_code') ->all(); } /** * @return list prd.* */ public static function delegationLegacySlugsForAgent(AgentNode $agent): array { $codes = self::delegationMenuActionCodesForAgent($agent); return AdminPermissionBridge::legacySlugsGrantedByMenuActionCodes($codes); } /** * @return list prd.* */ public static function delegationLegacySlugsForAdminUser(AdminUser $admin): array { if ($admin->isSuperAdmin()) { return AdminPermissionBridge::allLegacySlugs(); } $node = $admin->primaryAgentNode(); if ($node === null) { return []; } return self::delegationLegacySlugsForAgent($node); } public static function childIsManageableBy(AdminUser $admin, AgentNode $child): bool { if ($admin->isSuperAdmin()) { return true; } if (! AdminAgentScope::nodeVisibleTo($admin, $child)) { return false; } $parentId = $child->parent_id; if ($parentId === null) { return false; } $actor = AdminAgentScope::primaryAgentNode($admin); if ($actor === null) { return false; } return (int) $parentId === (int) $actor->id || AdminAgentScope::nodeManageableBy($admin, AgentNode::query()->find($parentId) ?? $child); } /** * @param list $grants */ public static function assertGrantsAllowed(AdminUser $actor, AgentNode $child, array $grants): void { if ($actor->isSuperAdmin()) { return; } if (! self::childIsManageableBy($actor, $child)) { throw ValidationException::withMessages(['child_agent_id' => ['not_manageable']]); } $actorCodes = $actor->effectiveMenuActionPermissionCodes(); $actorCodeSet = array_fill_keys($actorCodes, true); $parent = $child->parent; if ($parent === null && $child->parent_id !== null) { $parent = AgentNode::query()->find($child->parent_id); } $parentCeiling = $parent !== null ? self::delegationMenuActionCodesForAgent($parent) : $actorCodes; if ($parent !== null && ! $parent->isRoot() && $parentCeiling === []) { $parentCeiling = $actorCodes; } $parentCeilingSet = array_fill_keys($parentCeiling, true); foreach ($grants as $grant) { $actionId = (int) ($grant['menu_action_id'] ?? 0); $code = DB::table('admin_menu_actions')->where('id', $actionId)->value('permission_code'); if (! is_string($code) || $code === '') { throw ValidationException::withMessages(['grants' => ['invalid_menu_action']]); } if (! isset($actorCodeSet[$code])) { throw ValidationException::withMessages(['grants' => ['exceeds_actor: '.$code]]); } if ($parent !== null && ! $parent->isRoot() && ! isset($parentCeilingSet[$code])) { throw ValidationException::withMessages(['grants' => ['exceeds_parent_ceiling: '.$code]]); } } } /** * @param list $permissionSlugs */ public static function assertRoleSlugsWithinAgentCeiling( AgentNode $ownerAgent, array $permissionSlugs, AdminUser $actor, ): void { $ceiling = self::delegationLegacySlugsForAgent($ownerAgent); if ($ceiling === []) { // 尚未配置下放上限:与 P2 一致,仅校验操作者自身权限 AgentRoleAuthorization::assertSlugsWithinActor($actor, $permissionSlugs); return; } $invalid = array_values(array_diff($permissionSlugs, $ceiling)); if ($invalid !== []) { throw ValidationException::withMessages([ 'permission_slugs' => ['exceeds_delegation_ceiling: '.implode(', ', $invalid)], ]); } } }