$i) { if (isset($all[$k])) $dupes[] = $k; $all[$k] = $i; $check(preg_match('/^[a-z_]+$/', $k) === 1 && $i['label'] !== '' && $i['hint'] !== '' && is_bool($i['agent']) && is_bool($i['area']), "Recht {$k}: Schlüssel, Beschriftung, Hinweis und Flags"); } } $check($dupes === [], 'Kein Recht kommt doppelt vor: ' . implode(',', $dupes)); $check(array_keys(permission_labels()) === array_keys($all), 'permission_labels() entspricht dem Katalog'); // Alle bisherigen Rechte gibt es weiterhin (gespeicherte Rollen bleiben gültig) $old = ['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']; $check(array_diff($old, array_keys($all)) === [], 'Alle bisherigen Rechte sind im Katalog'); $check(count($all) >= 40, 'Der Katalog hat die neuen Rechte (' . count($all) . ')'); // Neue Rechte, die es bisher gar nicht gab foreach (['merge_split_ticket', 'link_tickets', 'manage_banlist', 'export_tickets', 'fetch_mail', 'share_views', 'schedule_reports', 'view_customers', 'manage_customers', 'manage_custom_fields', 'manage_ticket_templates', 'manage_automation', 'manage_site_pages', 'manage_languages', 'manage_status_page', 'view_mail_queue', 'view_login_guard', 'manage_problems', 'manage_availability', 'view_help'] as $k) { $check(isset($all[$k]), "Neues Recht {$k} vorhanden"); } // Adminportal-Bereiche $areas = admin_section_permissions(); $check(isset($areas['manage_canned'], $areas['manage_kb'], $areas['view_help'], $areas['view_login_guard']) && !isset($areas['reply_ticket'], $areas['manage_banlist'], $areas['export_tickets']), 'admin_section_permissions(): Bereiche ja, Ticket-Rechte nein'); foreach (['settings', 'backup', 'update', 'plugins', 'api_keys', 'webhooks', 'import', 'security_check', 'passkeys'] as $needle) { $hit = array_filter(array_keys($all), fn($k) => str_contains($k, $needle)); $check($hit === [], "Nicht delegierbar: kein Recht für {$needle}"); } // ── Standardwerte ────────────────────────────────────────────────────────────── $adm = default_permissions('admin'); $agt = default_permissions('agent'); $check(count(array_filter($adm)) === count($all), 'Administrator: alle Rechte'); foreach (['reply_ticket', 'close_ticket', 'transfer_ticket', 'post_note', 'assign_ticket', 'create_ticket', 'view_reports', 'merge_split_ticket', 'link_tickets', 'manage_banlist', 'fetch_mail', 'share_views', 'schedule_reports', 'view_customers'] as $k) { $check($agt[$k] === true, "Standard-Mitarbeiter darf weiterhin: {$k}"); } foreach (['delete_ticket', 'export_tickets'] as $k) $check($agt[$k] === false, "Standard-Mitarbeiter darf nicht: {$k}"); foreach ($areas as $k => $_l) $check($agt[$k] === false, "Adminportal-Bereich standardmäßig aus: {$k}"); // ── has_permission ───────────────────────────────────────────────────────────── $pdo = get_db(); $now = date('Y-m-d H:i:s'); $dept = (int) $pdo->query('SELECT id FROM departments ORDER BY id LIMIT 1')->fetchColumn(); $pdo->prepare('INSERT INTO departments (name, email, is_active, created_at) VALUES (?,?,1,?)')->execute(['Zweite', 'zweite@test.de', $now]); $dept2 = (int) $pdo->lastInsertId(); $pdo->exec('DELETE FROM staff'); $mkRole = function (string $name, array $perms, int $active = 1) use ($pdo, $now): int { $pdo->prepare('INSERT INTO roles (name, permissions, is_active, created_at, updated_at) VALUES (?,?,?,?,?)')->execute([$name, json_encode($perms), $active, $now, $now]); return (int) $pdo->lastInsertId(); }; $mkStaff = function (string $mail, string $role, ?int $roleId) use ($pdo, $dept, $now): array { $pdo->prepare('INSERT INTO staff (name, email, password_hash, role, role_id, department_id, is_active, created_at) VALUES (?,?,?,?,?,?,1,?)')->execute([$mail, $mail . '@test.de', 'x', $role, $roleId, $dept, $now]); return $pdo->query('SELECT * FROM staff WHERE id = ' . (int) $pdo->lastInsertId())->fetch(); }; $admin = $mkStaff('chef', 'admin', null); $plain = $mkStaff('eva', 'agent', null); $check(has_permission($admin, 'manage_staff') && has_permission($admin, 'gibt_es_nicht'), 'Administrator hat immer alles'); $check(has_permission($plain, 'reply_ticket') && has_permission($plain, 'merge_split_ticket') && !has_permission($plain, 'delete_ticket') && !has_permission($plain, 'manage_custom_fields'), 'Mitarbeiter ohne Rolle: Standardrechte'); $check(!has_permission($plain, 'gibt_es_nicht'), 'Unbekanntes Recht: nein'); // Alte Rolle (gespeichert vor den neuen Rechten): neue Rechte gelten mit dem Standardwert $oldJson = array_fill_keys($old, false); $oldJson['reply_ticket'] = true; $oldJson['manage_departments'] = true; $roleOld = $mkRole('Alt', $oldJson); $s1 = $mkStaff('alt', 'agent', $roleOld); $check(has_permission($s1, 'reply_ticket') && has_permission($s1, 'manage_departments') && !has_permission($s1, 'close_ticket'), 'Alte Rolle: gespeicherte Werte gelten (auch „aus“)'); $check(has_permission($s1, 'merge_split_ticket') && has_permission($s1, 'manage_banlist') && has_permission($s1, 'fetch_mail'), 'Alte Rolle: bisher offene Funktionen bleiben erlaubt (Standardwert)'); $check(!has_permission($s1, 'manage_custom_fields') && !has_permission($s1, 'view_help') && !has_permission($s1, 'export_tickets'), 'Alte Rolle: neue Adminbereiche bleiben aus'); // Altes Recht fehlt in einer gespeicherten Rolle: wie bisher „nein“ $roleGap = $mkRole('Lücke', ['reply_ticket' => true]); $sg = $mkStaff('luecke', 'agent', $roleGap); $check(has_permission($sg, 'reply_ticket') && !has_permission($sg, 'post_note') && !has_permission($sg, 'close_ticket'), 'Fehlendes altes Recht in einer Rolle: nein (wie bisher)'); $check(array_diff(permission_legacy_keys(), array_keys($all)) === [] && count(permission_legacy_keys()) === 24, 'Liste der alten Rechte ist vollständig'); $eff = permission_effective(['reply_ticket' => true]); $check($eff['reply_ticket'] && !$eff['post_note'] && $eff['merge_split_ticket'] && !$eff['manage_custom_fields'] && count($eff) === count($all), 'permission_effective(): wie has_permission() für fehlende Rechte'); // Neue Rolle mit ausdrücklich „aus“ $roleNew = $mkRole('Neu', ['merge_split_ticket' => false, 'manage_custom_fields' => true]); $s2 = $mkStaff('neu', 'agent', $roleNew); $check(!has_permission($s2, 'merge_split_ticket') && has_permission($s2, 'manage_custom_fields'), 'Ausdrücklich gesetzte Werte schlagen den Standard'); // Deaktivierte Rolle $roleOff = $mkRole('Aus', ['reply_ticket' => false, 'manage_custom_fields' => true], 0); $s3 = $mkStaff('aus', 'agent', $roleOff); $check(has_permission($s3, 'reply_ticket') && !has_permission($s3, 'manage_custom_fields'), 'Deaktivierte Rolle: Standardrechte'); // Rolle pro Abteilung $pdo->prepare('INSERT INTO staff_department (staff_id, department_id, notify, role_id) VALUES (?,?,?,?)')->execute([$s1['id'], $dept2, 1, $roleNew]); $check(has_permission($s1, 'manage_custom_fields', $dept2) && !has_permission($s1, 'manage_custom_fields', $dept), 'Rolle pro Abteilung gilt nur in dieser Abteilung'); // ── Vorlagen ─────────────────────────────────────────────────────────────────── $presets = permission_presets(); foreach ($presets as $key => [$name, $desc, $perms]) { $check(array_keys($perms) === array_keys($all) || count(array_diff(array_keys($all), array_keys($perms))) === 0, "Vorlage {$key} nennt jedes Recht"); $check(array_diff(array_keys($perms), array_keys($all)) === [], "Vorlage {$key} nennt keine unbekannten Rechte"); } $check($presets['mitarbeiter'][2] == $agt, 'Vorlage „Mitarbeiter“ entspricht den Standardrechten'); $check(!$presets['nur_lesen'][2]['reply_ticket'] && $presets['nur_lesen'][2]['view_customers'], 'Vorlage „Nur lesen“ darf nicht antworten'); $check($presets['teamleitung'][2]['delete_ticket'] && !$presets['teamleitung'][2]['manage_staff'], 'Vorlage „Teamleitung“: löschen ja, Mitarbeiter verwalten nein'); $check($presets['support_manager'][2]['manage_staff'] && !$presets['support_manager'][2]['manage_roles'], 'Vorlage „Support-Manager“: Mitarbeiter ja, Rollen nein'); echo $failures ? "FEHLGESCHLAGEN:\n - " . implode("\n - ", $failures) . "\n" : ''; echo "Rechte-Test: " . ($total - count($failures)) . " von {$total} Prüfungen in Ordnung.\n"; exit($failures ? 1 : 0);