['label' => $label, 'hint' => $hint, 'agent' => $agent, 'area' => $area]; return [ 'tickets' => ['title' => 'Tickets bearbeiten', 'items' => [ 'reply_ticket' => $p('Tickets beantworten', 'Antworten, Antworten einplanen, Anhänge aus E-Mails nachladen', true), 'post_note' => $p('Interne Notizen schreiben', 'Notizen, die nur das Team sieht', true), 'close_ticket' => $p('Tickets schließen/lösen', 'Status auf Gelöst oder Geschlossen setzen, als Spam markieren', true), 'assign_ticket' => $p('Tickets zuweisen (Mitarbeiter/Team)', 'Bearbeiter oder Team ändern', true), 'transfer_ticket' => $p('Tickets übertragen (Abteilung ändern)', 'Ticket in eine andere Abteilung verschieben', true), 'create_ticket' => $p('Tickets im Namen von Kunden erstellen', 'Neues Ticket anlegen', true), 'merge_split_ticket' => $p('Tickets zusammenführen und teilen', 'Doppelte Tickets vereinen, Nachrichten abspalten', true), 'link_tickets' => $p('Tickets verknüpfen', 'Verwandt, doppelt oder blockiert', true), 'delete_ticket' => $p('Tickets löschen', 'Endgültig löschen, auch per Sammelaktion', false), ]], 'customers' => ['title' => 'Kunden und Sperren', 'items' => [ 'view_customers' => $p('Kundenprofile ansehen', 'Profil eines Kunden mit allen seinen Tickets', true), 'manage_customers' => $p('Kundenverzeichnis verwalten', 'Alle Kunden-Konten ansehen und Organisationen zuordnen', false, true), 'manage_organizations' => $p('Organisationen verwalten', 'Mehrere Kunden zu einer Firma bündeln', false, true), 'manage_banlist' => $p('Sperrliste und Absender sperren', 'Adressen und Domains blockieren', true), ]], 'reports' => ['title' => 'Auswertung und Export', 'items' => [ 'view_reports' => $p('Berichte einsehen', 'Übersicht, Berichte, Bericht-Baukasten (nur eigene Abteilungen)', true), 'schedule_reports' => $p('Berichte per E-Mail versenden', 'Zeitpläne im Bericht-Baukasten (externe Empfänger nur Administratoren)', true), 'export_tickets' => $p('Tickets als CSV exportieren', 'Ticketliste für Excel herunterladen', false), 'view_time_entries' => $p('Zeiterfassung einsehen', 'Auswertung der erfassten Zeiten', false, true), 'view_audit_log' => $p('Admin-Protokoll einsehen', 'Wer hat was geändert', false, true), ]], 'mail' => ['title' => 'E-Mail', 'items' => [ 'fetch_mail' => $p('E-Mails jetzt abrufen', 'Den Abruf per Knopf auslösen', true), 'manage_email_addresses' => $p('E-Mail-Adressen und Postfächer verwalten', 'Absender, Eingang, SMTP und IMAP je Adresse', false, true), 'manage_email_templates' => $p('E-Mail-Vorlagen verwalten', 'Texte der automatischen Mails', false, true), 'view_mail_queue' => $p('Mail-Warteschlange verwalten', 'Nicht zugestellte Mails ansehen, erneut senden, löschen', false, true), ]], 'content' => ['title' => 'Inhalte und Vorlagen', 'items' => [ 'manage_canned' => $p('Textbausteine verwalten', 'Vorlagen für Antworten', false, true), 'manage_ticket_templates' => $p('Ticket-Vorlagen verwalten', 'Vorgefüllte Tickets für Mitarbeiter und Kunden', false, true), 'manage_kb' => $p('Wissensdatenbank verwalten', 'Artikel und Kategorien', false, true), 'manage_assistant' => $p('Digitalen Assistenten verwalten', 'Antworten, Fragen-Log, Einstellungen', false, true), 'manage_site_pages' => $p('Seiten im Kundenportal verwalten', 'Impressum, AGB und weitere Seiten', false, true), 'manage_languages' => $p('Sprachen verwalten', 'Sprachpakete und Standardsprache', false, true), 'manage_status_page' => $p('Statusseite verwalten', 'Dienste und Störungsmeldungen', false, true), 'share_views' => $p('Ansichten mit dem Team teilen', 'Gespeicherte Filter für alle sichtbar machen', true), ]], 'setup' => ['title' => 'Einrichtung', 'items' => [ 'manage_departments' => $p('Abteilungen verwalten', 'Abteilungen, Formulare, automatische Zuweisung', false, true), 'manage_priorities' => $p('Prioritäten / SLA verwalten', 'Prioritäten und SLA-Pläne', false, true), 'manage_help_topics' => $p('Hilfethemen verwalten', 'Auswahl für Kunden beim Ticket-Erstellen', false, true), 'manage_custom_fields' => $p('Ticket-Felder und Listen verwalten', 'Zusatzfelder und Auswahllisten', false, true), 'manage_automation' => $p('Ticket-Regeln und wiederkehrende Tickets verwalten', 'Automatische Aktionen bei neuen Tickets, regelmäßige Tickets', false, true), 'manage_escalations' => $p('Eskalationsregeln verwalten', 'Aktionen bei überfälligen oder liegengebliebenen Tickets', false, true), 'manage_business_hours' => $p('Geschäftszeiten verwalten', 'Zeitfenster und Feiertage für die SLA', false, true), 'manage_problems' => $p('Problemmanagement', 'Probleme erfassen und mit Tickets verknüpfen', false, true), ]], 'team' => ['title' => 'Team und Sicherheit', 'items' => [ 'manage_staff' => $p('Mitarbeiter verwalten', 'Konten, Sperre aufheben, Überall abmelden, Passkeys entfernen', false, true), 'manage_teams' => $p('Teams verwalten', 'Gruppen von Mitarbeitern', false, true), 'manage_roles' => $p('Rollen verwalten', 'Rechte vergeben', false, true), 'manage_availability' => $p('Status und Schichten der Kollegen ändern', 'Status anderer Mitarbeiter setzen, automatisches Offline einstellen', false, true), 'view_login_guard' => $p('Anmelde-Wächter ansehen', 'Anmeldeprotokoll und gesperrte Konten; Einstellungen bleiben Administratoren', false, true), 'view_help' => $p('Hilfe und Handbuch', 'Hilfe-Seite mit dem Handbuch (PDF)', false, true), ]], ]; } /** Alle Rechte als schlüssel => Beschriftung (Reihenfolge wie im Katalog). */ function permission_labels(): array { $out = []; foreach (permission_catalog() as $g) foreach ($g['items'] as $k => $i) $out[$k] = $i['label']; return $out; } /** Rechte für Adminportal-Bereiche („Co-Admin“): schlüssel => Beschriftung. */ function admin_section_permissions(): array { $out = []; foreach (permission_catalog() as $g) foreach ($g['items'] as $k => $i) if ($i['area']) $out[$k] = $i['label']; return $out; } /** Standardrechte: Administrator alles, Mitarbeiter die Standardwerte des Katalogs. */ function default_permissions(string $role): array { $out = []; foreach (permission_catalog() as $g) foreach ($g['items'] as $k => $i) $out[$k] = $role === 'admin' ? true : (bool) $i['agent']; return $out; } /** * Vorlagen für Rollen: Schlüssel => [Name, Beschreibung, Rechte, als Rolle anlegen?]. * Die Vorlagen mit „true“ werden bei der Installation und beim Update als echte Rollen angelegt (siehe permission_seed_default_roles()); sie lassen sich danach * wie jede andere Rolle ändern oder löschen. „Mitarbeiter“ ist nur eine Vorlage im Formular, weil das die Standardrechte ohne Rolle sind. */ function permission_presets(): array { $all = array_keys(permission_labels()); $on = fn(array $keys) => array_fill_keys($keys, true) + array_fill_keys($all, false); $agent = array_keys(array_filter(default_permissions('agent'))); $lead = array_merge($agent, ['delete_ticket', 'export_tickets', 'view_time_entries', 'manage_canned', 'manage_kb', 'manage_teams', 'manage_availability']); return [ 'mitarbeiter' => ['Mitarbeiter', 'Die Standardrechte ohne Rolle: Tickets bearbeiten, Berichte der eigenen Abteilungen.', $on($agent), false], 'co_admin' => ['Co-Administrator', 'Alle Rechte, die sich vergeben lassen. Nur Einstellungen, Backup, System-Update, Plugins, API-Schlüssel, Webhooks, Import und Sicherheitsprüfung bleiben echten Administratoren.', $on($all), true], 'support_manager' => ['Support-Manager', 'Leitet den Support: Tickets, Einrichtung (Abteilungen, Prioritäten, Themen, Regeln, Felder), Mitarbeiter, Teams, Protokolle und Mail-Warteschlange.', $on(array_merge($lead, [ 'manage_departments', 'manage_priorities', 'manage_help_topics', 'manage_custom_fields', 'manage_automation', 'manage_escalations', 'manage_business_hours', 'manage_problems', 'manage_ticket_templates', 'manage_staff', 'view_audit_log', 'view_login_guard', 'view_mail_queue', 'manage_customers', 'manage_organizations', 'manage_email_templates', 'view_help'])), true], 'it' => ['IT / Technik', 'Betrieb und Technik: Tickets bearbeiten, dazu Postfächer und E-Mail-Adressen, Mail-Warteschlange, Anmelde-Wächter, Statusseite, Regeln, Eskalationen, Protokoll und Hilfe.', $on(array_merge($agent, [ 'manage_email_addresses', 'view_mail_queue', 'view_login_guard', 'manage_status_page', 'manage_automation', 'manage_escalations', 'view_audit_log', 'manage_problems', 'manage_custom_fields', 'view_help'])), true], 'teamleitung' => ['Teamleitung', 'Führt ein Team: wie Mitarbeiter, dazu Löschen, Export, Zeiterfassung, Textbausteine, Wissensdatenbank, Teams und Schichten.', $on($lead), true], 'support_2' => ['Support 2nd Level', 'Erfahrene Mitarbeiter: Tickets bearbeiten, Probleme verwalten, Export und Zeiterfassung.', $on(array_merge($agent, ['manage_problems', 'export_tickets', 'view_time_entries'])), true], 'support_1' => ['Support 1st Level', 'Einstieg: antworten, Notizen, zuweisen, Tickets anlegen und verknüpfen, E-Mails abrufen. Kein Schließen, Verschieben, Zusammenführen oder Sperren.', $on(['reply_ticket', 'post_note', 'assign_ticket', 'create_ticket', 'link_tickets', 'view_customers', 'fetch_mail']), true], 'redaktion' => ['Redaktion (Wissen und Inhalte)', 'Pflegt Inhalte: Wissensdatenbank, digitaler Assistent, Textbausteine, Ticket- und E-Mail-Vorlagen, Seiten und Sprachen.', $on(['reply_ticket', 'post_note', 'view_customers', 'manage_kb', 'manage_assistant', 'manage_canned', 'manage_ticket_templates', 'manage_email_templates', 'manage_site_pages', 'manage_languages']), true], 'auswertung' => ['Auswertung / Controlling', 'Zahlen und Berichte: Berichte (auch per E-Mail), Export, Zeiterfassung, Protokoll, Ansichten teilen. Kann keine Tickets bearbeiten.', $on(['view_reports', 'schedule_reports', 'export_tickets', 'view_time_entries', 'view_audit_log', 'share_views', 'view_customers']), true], 'teamverwaltung' => ['Teamverwaltung / Schichtplanung', 'Verwaltet Personal: Mitarbeiter, Teams, Status und Schichten, Geschäftszeiten, Anmelde-Wächter ansehen.', $on(['view_reports', 'manage_staff', 'manage_teams', 'manage_availability', 'manage_business_hours', 'view_login_guard', 'view_audit_log']), true], 'aushilfe' => ['Aushilfe / Praktikant', 'Nur das Nötigste: antworten und Notizen schreiben, Kundenprofile ansehen.', $on(['reply_ticket', 'post_note', 'view_customers']), true], 'nur_lesen' => ['Nur lesen', 'Tickets, Kundenprofile und Berichte ansehen, nichts ändern.', $on(['view_customers', 'view_reports']), true], ]; } /** * Legt die vordefinierten Rollen an, die es noch nicht gibt (Vergleich über den Namen, Groß-/Kleinschreibung egal). Vorhandene Rollen werden nie verändert. * @return list Namen der neu angelegten Rollen */ function permission_seed_default_roles(PDO $pdo): array { $created = []; $exists = $pdo->prepare('SELECT COUNT(*) FROM roles WHERE LOWER(name) = LOWER(?)'); $now = date('Y-m-d H:i:s'); foreach (permission_presets() as [$name, $desc, $perms, $seed]) { if (!$seed) continue; $exists->execute([$name]); if ((int) $exists->fetchColumn() > 0) continue; $pdo->prepare('INSERT INTO roles (name, permissions, is_active, notes, created_at, updated_at) VALUES (?,?,1,?,?,?)') ->execute([$name, json_encode($perms), 'Vordefinierte Rolle – frei änderbar. ' . $desc, $now, $now]); $created[] = $name; } return $created; } /** Namen der vordefinierten Rollen, die auf dieser Installation fehlen. @return list */ function permission_missing_default_roles(PDO $pdo): array { $have = array_map('mb_strtolower', $pdo->query('SELECT name FROM roles')->fetchAll(PDO::FETCH_COLUMN)); $missing = []; foreach (permission_presets() as [$name, , , $seed]) if ($seed && !in_array(mb_strtolower($name), $have, true)) $missing[] = $name; return $missing; } /** * Rechte, die es schon vor dem Katalog gab. Fehlt eines davon in einer gespeicherten Rolle, gilt wie bisher „nein“; bei allen neueren Rechten gilt * der Standardwert des Katalogs (so behalten bestehende Rollen, was bisher für alle offen war, und neue Adminbereiche bleiben aus). */ function permission_legacy_keys(): array { return ['reply_ticket', 'close_ticket', 'delete_ticket', 'transfer_ticket', 'post_note', 'assign_ticket', 'manage_canned', 'view_reports', 'manage_kb', 'create_ticket', 'manage_departments', 'manage_priorities', 'manage_help_topics', 'manage_email_addresses', 'manage_email_templates', 'manage_organizations', 'manage_teams', 'manage_roles', 'manage_staff', 'view_audit_log', 'manage_escalations', 'view_time_entries', 'manage_business_hours', 'manage_assistant']; } /** Wirksame Rechte einer gespeicherten Rolle (so, wie has_permission() sie auswertet): fehlende alte Rechte = nein, fehlende neuere = Standardwert. */ function permission_effective(array $rolePerms): array { $defaults = default_permissions('agent'); $legacy = permission_legacy_keys(); $out = []; foreach (array_keys($defaults) as $k) { $out[$k] = array_key_exists($k, $rolePerms) ? (bool) $rolePerms[$k] : (!in_array($k, $legacy, true) && $defaults[$k]); } return $out; }