hasAnyRole(['super-admin', 'admin', 'amministratore']); } public function mount(ProgramAclService $acl): void { $actor = Auth::user(); if (! $actor instanceof User) { abort(403); } $roles = $acl->manageableRolesFor($actor); $users = $acl->manageableUserOptions($actor); $selectedRole = $this->resolveRequestedRole($acl, $actor, $roles); $selectedUserId = $this->resolveRequestedUserId($acl, $actor, $users); $this->getSchema('form')?->fill([ 'selected_role' => $selectedRole, 'role_allow' => $selectedRole ? $acl->roleRules($selectedRole)['allow'] : [], 'role_deny' => $selectedRole ? $acl->roleRules($selectedRole)['deny'] : [], 'selected_user_id' => $selectedUserId, 'user_allow' => $selectedUserId ? $acl->userRules((int) $selectedUserId)['allow'] : [], 'user_deny' => $selectedUserId ? $acl->userRules((int) $selectedUserId)['deny'] : [], ]); } public function form(Schema $schema): Schema { /** @var User|null $actor */ $actor = Auth::user(); $acl = app(ProgramAclService::class); $programOptions = $acl->programOptions(); $roleList = $acl->manageableRolesFor($actor instanceof User ? $actor : new User()); $roleOptions = array_combine($roleList, $roleList) ?: []; $userOptions = $actor instanceof User ? $acl->manageableUserOptions($actor) : []; return $schema ->statePath('data') ->components([ Section::make('Regole globali per ruolo') ->description('Il super admin gestisce i default globali. L amministratore puo operare solo sui collaboratori.') ->schema([ Select::make('selected_role') ->label('Ruolo') ->options($roleOptions) ->native(false), Placeholder::make('role_hint') ->label('Note') ->content('Le regole ruolo valgono come default. Gli override utente hanno precedenza.'), CheckboxList::make('role_allow') ->label('Programmi esplicitamente visibili') ->options($programOptions) ->columns(1), CheckboxList::make('role_deny') ->label('Programmi esplicitamente nascosti') ->options($programOptions) ->columns(1), ]), Section::make('Override per singolo utente') ->description('Usa gli override per eccezioni puntuali senza cambiare il default del gruppo.') ->schema([ Select::make('selected_user_id') ->label('Utente') ->options($userOptions) ->searchable() ->native(false), Placeholder::make('user_hint') ->label('Perimetro') ->content($actor instanceof User && $actor->hasRole('amministratore') ? 'Puoi modificare solo i collaboratori collegati al tuo amministratore.' : 'Puoi applicare override puntuali agli utenti gestibili dal tuo profilo.'), CheckboxList::make('user_allow') ->label('Programmi resi visibili per questo utente') ->options($programOptions) ->columns(1), CheckboxList::make('user_deny') ->label('Programmi nascosti per questo utente') ->options($programOptions) ->columns(1), ]), ]); } /** @param array $roles */ private function resolveRequestedRole(ProgramAclService $acl, User $actor, array $roles): ?string { $requestedRole = trim((string) request()->query('selected_role', '')); if ($requestedRole !== '' && $acl->canManageRole($actor, $requestedRole)) { return $requestedRole; } return $roles[0] ?? null; } /** @param array $users */ private function resolveRequestedUserId(ProgramAclService $acl, User $actor, array $users): ?int { $requestedUserId = (int) request()->query('selected_user_id', 0); if ($requestedUserId > 0) { $target = User::query()->find($requestedUserId); if ($target instanceof User && $acl->canManageUser($actor, $target)) { return (int) $target->id; } } $firstKey = array_key_first($users); return is_numeric($firstKey) ? (int) $firstKey : null; } public function loadRoleRules(ProgramAclService $acl): void { $state = $this->normalizedState(); $role = (string) ($state['selected_role'] ?? ''); $actor = Auth::user(); if (! $actor instanceof User || $role === '' || ! $acl->canManageRole($actor, $role)) { Notification::make()->title('Ruolo non gestibile')->danger()->send(); return; } $rules = $acl->roleRules($role); $this->fillState(array_merge($state, [ 'role_allow' => $rules['allow'], 'role_deny' => $rules['deny'], ])); } public function saveRoleRules(ProgramAclService $acl): void { $state = $this->normalizedState(); $role = (string) ($state['selected_role'] ?? ''); $actor = Auth::user(); if (! $actor instanceof User || $role === '' || ! $acl->canManageRole($actor, $role)) { Notification::make()->title('Ruolo non gestibile')->danger()->send(); return; } $acl->replaceRoleRules( $role, is_array($state['role_allow'] ?? null) ? $state['role_allow'] : [], is_array($state['role_deny'] ?? null) ? $state['role_deny'] : [], ); Notification::make()->title('ACL ruolo salvata')->success()->send(); $this->loadRoleRules($acl); } public function loadUserRules(ProgramAclService $acl): void { $state = $this->normalizedState(); $userId = (int) ($state['selected_user_id'] ?? 0); $actor = Auth::user(); $target = $userId > 0 ? User::query()->find($userId) : null; if (! $actor instanceof User || ! $target instanceof User || ! $acl->canManageUser($actor, $target)) { Notification::make()->title('Utente non gestibile')->danger()->send(); return; } $rules = $acl->userRules((int) $target->id); $this->fillState(array_merge($state, [ 'user_allow' => $rules['allow'], 'user_deny' => $rules['deny'], ])); } public function saveUserRules(ProgramAclService $acl): void { $state = $this->normalizedState(); $userId = (int) ($state['selected_user_id'] ?? 0); $actor = Auth::user(); $target = $userId > 0 ? User::query()->find($userId) : null; if (! $actor instanceof User || ! $target instanceof User || ! $acl->canManageUser($actor, $target)) { Notification::make()->title('Utente non gestibile')->danger()->send(); return; } $acl->replaceUserRules( (int) $target->id, is_array($state['user_allow'] ?? null) ? $state['user_allow'] : [], is_array($state['user_deny'] ?? null) ? $state['user_deny'] : [], ); Notification::make()->title('ACL utente salvata')->success()->send(); $this->loadUserRules($acl); } /** @return array */ public function manageableRoles(): array { $actor = Auth::user(); return $actor instanceof User ? app(ProgramAclService::class)->manageableRolesFor($actor) : []; } /** @return array{roles: array, programs: array>} */ public function roleMatrixData(): array { $acl = app(ProgramAclService::class); $roles = $this->manageableRoles(); $rows = []; foreach ($acl->catalog() as $programKey => $definition) { $label = trim((string) ($definition['label'] ?? $programKey)); $description = trim((string) ($definition['description'] ?? '')); $defaultRoles = array_values(array_filter(array_map('strval', (array) ($definition['default_roles'] ?? [])))); $states = []; foreach ($roles as $role) { $rules = $acl->roleRules($role); $source = 'default'; $isVisible = in_array($role, $defaultRoles, true); if (in_array($programKey, $rules['deny'], true)) { $source = 'deny'; $isVisible = false; } elseif (in_array($programKey, $rules['allow'], true)) { $source = 'allow'; $isVisible = true; } $states[$role] = [ 'visible' => $isVisible, 'source' => $source, ]; } $rows[] = [ 'key' => $programKey, 'label' => $label, 'description' => $description, 'default_roles' => $defaultRoles, 'states' => $states, ]; } return [ 'roles' => $roles, 'programs' => $rows, ]; } /** @return array> */ public function rwMatrixData(): array { $roles = $this->manageableRoles(); $configRoles = (array) config('netgescon.user_roles', []); $rows = []; foreach ($configRoles as $role => $definition) { if (! in_array($role, $roles, true)) { continue; } $menus = (array) ($definition['menus'] ?? []); foreach ($menus as $menuKey => $menuValue) { $menuName = is_string($menuKey) ? $menuKey : (string) $menuValue; $actions = is_array($menuValue) ? array_values(array_filter(array_map('strval', $menuValue))) : array_values(array_filter(array_map('strval', (array) ($definition['permissions'] ?? [])))); $rows[] = [ 'role' => $role, 'menu' => $menuName, 'actions' => $actions, ]; } } usort($rows, static function (array $left, array $right): int { $roleCompare = strcmp((string) ($left['role'] ?? ''), (string) ($right['role'] ?? '')); if ($roleCompare !== 0) { return $roleCompare; } return strcmp((string) ($left['menu'] ?? ''), (string) ($right['menu'] ?? '')); }); return $rows; } public function setRoleProgramVisibility(ProgramAclService $acl, string $role, string $programKey, bool $visible): void { $actor = Auth::user(); if (! $actor instanceof User || ! $acl->canManageRole($actor, $role) || ! array_key_exists($programKey, $acl->catalog())) { Notification::make()->title('Regola non gestibile')->danger()->send(); return; } $rules = $acl->roleRules($role); $allow = array_values(array_filter((array) $rules['allow'], static fn(string $key): bool => $key !== $programKey)); $deny = array_values(array_filter((array) $rules['deny'], static fn(string $key): bool => $key !== $programKey)); if ($visible) { $allow[] = $programKey; } else { $deny[] = $programKey; } $acl->replaceRoleRules($role, $allow, $deny); $state = $this->normalizedState(); if ((string) ($state['selected_role'] ?? '') === $role) { $this->fillState(array_merge($state, [ 'role_allow' => array_values(array_unique($allow)), 'role_deny' => array_values(array_unique($deny)), ])); } } public function resetRoleProgramVisibility(ProgramAclService $acl, string $role, string $programKey): void { $actor = Auth::user(); if (! $actor instanceof User || ! $acl->canManageRole($actor, $role) || ! array_key_exists($programKey, $acl->catalog())) { Notification::make()->title('Regola non gestibile')->danger()->send(); return; } $rules = $acl->roleRules($role); $allow = array_values(array_filter((array) $rules['allow'], static fn(string $key): bool => $key !== $programKey)); $deny = array_values(array_filter((array) $rules['deny'], static fn(string $key): bool => $key !== $programKey)); $acl->replaceRoleRules($role, $allow, $deny); $state = $this->normalizedState(); if ((string) ($state['selected_role'] ?? '') === $role) { $this->fillState(array_merge($state, [ 'role_allow' => $allow, 'role_deny' => $deny, ])); } } /** @return array */ private function normalizedState(): array { $state = $this->getSchema('form')?->getState() ?? []; if (is_array($state['data'] ?? null)) { return $state['data']; } return is_array($state) ? $state : (is_array($this->data) ? $this->data : []); } /** @param array $state */ private function fillState(array $state): void { $this->getSchema('form')?->fill($state); } }