> Rollen-ID => angehakte Berechtigungen */ public array $granted = []; public string $newRole = ''; public function mount(): void { abort_unless(Gate::allows('staff.manage'), 403); $this->loadGrants(); } public function save(int $roleId): void { $this->authorize('staff.manage'); $role = $this->role($roleId); if ($role->name === 'Owner') { $this->addError('granted.'.$roleId, __('roles.owner_locked')); return; } // Nur bekannte Namen: die Liste kommt aus dem Browser. $wanted = array_values(array_intersect( $this->granted[$roleId] ?? [], $this->allPermissions(), )); $role->syncPermissions($wanted); // Spatie hält die Rechte in einem Zwischenspeicher. Ohne das hier // gölte die Änderung erst, wenn der Zwischenspeicher von selbst // abläuft — und die Seite zeigte währenddessen das Neue an, während // das Alte wirkt. app(PermissionRegistrar::class)->forgetCachedPermissions(); $this->loadGrants(); $this->dispatch('notify', message: __('roles.saved', ['role' => $role->name])); } public function create(): void { $this->authorize('staff.manage'); $this->validate(['newRole' => ['required', 'string', 'max:64', 'regex:/^[\pL][\pL\pN \-]*$/u']]); Role::findOrCreate(trim($this->newRole), self::GUARD); app(PermissionRegistrar::class)->forgetCachedPermissions(); $this->newRole = ''; $this->loadGrants(); $this->dispatch('notify', message: __('roles.created')); } public function delete(int $roleId): void { $this->authorize('staff.manage'); $role = $this->role($roleId); if ($role->name === 'Owner') { $this->addError('newRole', __('roles.owner_locked')); return; } // Eine Rolle zu löschen, die jemand hält, nähme diesem Menschen // wortlos jeden Zugang — er stünde beim nächsten Anmelden ohne Rolle // da und käme in die Konsole nicht mehr hinein. if ($role->users()->exists()) { $this->addError('newRole', __('roles.in_use', ['role' => $role->name])); return; } $role->delete(); app(PermissionRegistrar::class)->forgetCachedPermissions(); $this->loadGrants(); $this->dispatch('notify', message: __('roles.deleted')); } private function role(int $roleId): Role { return Role::query() ->where('guard_name', self::GUARD) ->findOr($roleId, fn () => abort(404)); } /** @return array */ private function allPermissions(): array { return Permission::query() ->where('guard_name', self::GUARD) ->orderBy('name') ->pluck('name') ->all(); } private function loadGrants(): void { $this->granted = Role::query() ->where('guard_name', self::GUARD) ->with('permissions') ->get() ->mapWithKeys(fn (Role $role) => [$role->id => $role->permissions->pluck('name')->all()]) ->all(); } public function render() { return view('livewire.admin.roles', [ 'roles' => Role::query() ->where('guard_name', self::GUARD) ->withCount('users') ->orderBy('name') ->get(), // Nach dem Präfix gruppiert — die Namen tragen ihre Ordnung längst // in sich (`billing.`, `customers.`, `provisioning.`), und // einundzwanzig Kästchen flach untereinander sind eine Wand, in // der niemand das eine findet, das er sucht. 'groups' => collect($this->allPermissions()) ->groupBy(fn (string $name) => str_contains($name, '.') ? strtok($name, '.') : 'sonstiges') ->sortKeys(), 'permissions' => $this->allPermissions(), // Wie viele Menschen an dieser Rolle hängen — damit niemand blind // etwas wegnimmt, das gerade sechs Leute benutzen. 'protectedRole' => 'Owner', 'ownRoles' => Operator::find(auth('operator')->id())?->roles->pluck('name')->all() ?? [], ]); } }