*/ public function listForChild(AgentNode $child, ?AdminUser $actor = null): array { $rows = DB::table('agent_delegation_grants as g') ->join('admin_menu_actions as ma', 'ma.id', '=', 'g.menu_action_id') ->where('g.child_agent_id', $child->id) ->where('ma.status', 1) ->orderBy('ma.permission_code') ->get(['g.menu_action_id', 'g.can_delegate', 'ma.permission_code', 'ma.name']); if ($rows->isNotEmpty()) { return $rows->map(static fn ($row): array => [ 'menu_action_id' => (int) $row->menu_action_id, 'permission_code' => (string) $row->permission_code, 'name' => (string) $row->name, 'can_delegate' => (bool) $row->can_delegate, ])->all(); } if ($actor === null) { return []; } $codes = $actor->effectiveMenuActionPermissionCodes(); if ($codes === []) { return []; } return DB::table('admin_menu_actions') ->where('status', 1) ->whereIn('permission_code', $codes) ->orderBy('permission_code') ->get(['id', 'permission_code', 'name']) ->map(static fn ($row): array => [ 'menu_action_id' => (int) $row->id, 'permission_code' => (string) $row->permission_code, 'name' => (string) $row->name, 'can_delegate' => false, ]) ->all(); } /** * @param list $grants * @return list */ public function syncGrants(AdminUser $actor, AgentNode $child, array $grants): array { AgentDelegationAuthorization::assertGrantsAllowed($actor, $child, $grants); $parentId = (int) ($child->parent_id ?? 0); if ($parentId <= 0) { throw new \InvalidArgumentException('Child agent must have parent.'); } $now = Carbon::now(); DB::transaction(function () use ($actor, $child, $grants, $parentId, $now): void { DB::table('agent_delegation_grants') ->where('child_agent_id', $child->id) ->delete(); foreach ($grants as $grant) { DB::table('agent_delegation_grants')->insert([ 'parent_agent_id' => $parentId, 'child_agent_id' => $child->id, 'menu_action_id' => (int) $grant['menu_action_id'], 'can_delegate' => ! empty($grant['can_delegate']), 'granted_by' => $actor->id, 'granted_at' => $now, 'created_at' => $now, 'updated_at' => $now, ]); } }); return $this->listForChild($child->fresh()); } }