$p[3]); $all = array_keys(permission_labels()); $roleRow = fn(string $name) => $pdo->query("SELECT * FROM roles WHERE LOWER(name) = LOWER(" . $pdo->quote($name) . ")")->fetch(); $perms = fn(string $key): array => $presets[$key][2]; // ── Angelegt durch die Migration ──────────────────────────────────────────────── $check(count($seeded) >= 10, 'Es gibt mindestens 10 vordefinierte Rollen (' . count($seeded) . ')'); $check((int) $pdo->query("SELECT COUNT(*) FROM schema_migrations WHERE migration = 'php_0076_default_roles'")->fetchColumn() === 1, 'Migration 0076 ist eingetragen'); $names = array_map(fn($p) => mb_strtolower($p[0]), $presets); $check(count($names) === count(array_unique($names)), 'Namen der Vorlagen sind eindeutig'); foreach ($seeded as $key => [$name, $desc, $p, $seed]) { $r = $roleRow($name); $check($r !== false && (int) $r['is_active'] === 1, "Rolle „{$name}“ ist angelegt und aktiv"); if (!$r) continue; $stored = json_decode((string) $r['permissions'], true) ?: []; $check($stored == $p && count($stored) === count($all), "Rolle „{$name}“ hat genau die Rechte der Vorlage (alle " . count($all) . ' Rechte gespeichert)'); $check(str_starts_with((string) $r['notes'], 'Vordefinierte Rolle') && str_contains((string) $r['notes'], $desc), "Rolle „{$name}“ hat die Beschreibung als Notiz"); } $check($roleRow('Mitarbeiter') === false, '„Mitarbeiter“ ist nur eine Vorlage im Formular, keine Rolle (das sind die Standardrechte)'); $check((int) $pdo->query('SELECT COUNT(*) FROM roles')->fetchColumn() === count($seeded), 'Genau so viele Rollen wie vordefinierte'); // ── Sinnvolle Rechte je Vorlage ───────────────────────────────────────────────── $check(count(array_filter($perms('co_admin'))) === count($all), 'Co-Administrator: alle Rechte'); $check(!$perms('support_1')['close_ticket'] && !$perms('support_1')['transfer_ticket'] && !$perms('support_1')['merge_split_ticket'] && !$perms('support_1')['manage_banlist'] && $perms('support_1')['reply_ticket'] && $perms('support_1')['assign_ticket'], 'Support 1st Level: antworten und zuweisen, aber nicht schließen, verschieben, zusammenführen, sperren'); $check($perms('support_2')['close_ticket'] && $perms('support_2')['manage_problems'] && !$perms('support_2')['delete_ticket'] && !$perms('support_2')['manage_staff'], 'Support 2nd Level: bearbeiten und Probleme, aber kein Löschen und keine Mitarbeiter'); $check($perms('it')['manage_email_addresses'] && $perms('it')['view_mail_queue'] && $perms('it')['view_login_guard'] && !$perms('it')['manage_staff'] && !$perms('it')['manage_roles'] && !$perms('it')['delete_ticket'], 'IT: Postfächer, Warteschlange, Anmelde-Wächter; keine Mitarbeiter/Rollen/Löschen'); $check($perms('teamleitung')['delete_ticket'] && $perms('teamleitung')['manage_teams'] && !$perms('teamleitung')['manage_staff'] && !$perms('teamleitung')['manage_departments'], 'Teamleitung: Löschen und Teams, aber nicht Mitarbeiter und Abteilungen'); $check($perms('support_manager')['manage_staff'] && $perms('support_manager')['manage_departments'] && !$perms('support_manager')['manage_roles'] && !$perms('support_manager')['manage_languages'], 'Support-Manager: Mitarbeiter und Einrichtung, aber nicht Rollen'); $check($perms('redaktion')['manage_kb'] && $perms('redaktion')['manage_site_pages'] && !$perms('redaktion')['close_ticket'] && !$perms('redaktion')['assign_ticket'], 'Redaktion: Inhalte pflegen, Tickets nicht verwalten'); $check(!$perms('auswertung')['reply_ticket'] && !$perms('auswertung')['post_note'] && $perms('auswertung')['view_reports'] && $perms('auswertung')['export_tickets'] && $perms('auswertung')['schedule_reports'], 'Auswertung: nur Zahlen, keine Tickets bearbeiten'); $check($perms('teamverwaltung')['manage_staff'] && $perms('teamverwaltung')['manage_availability'] && !$perms('teamverwaltung')['reply_ticket'] && !$perms('teamverwaltung')['manage_roles'], 'Teamverwaltung: Personal, aber keine Tickets und keine Rollen'); $check($perms('aushilfe')['reply_ticket'] && !$perms('aushilfe')['close_ticket'] && !$perms('aushilfe')['assign_ticket'] && !$perms('aushilfe')['create_ticket'] && !$perms('aushilfe')['fetch_mail'], 'Aushilfe: nur antworten und notieren'); $check(!$perms('nur_lesen')['reply_ticket'] && !$perms('nur_lesen')['post_note'] && !$perms('nur_lesen')['close_ticket'] && $perms('nur_lesen')['view_reports'], 'Nur lesen: ändert nichts'); // Wer darf Rollen verwalten, Einstellungen sind nie delegierbar: Nur Co-Administrator darf Rollen verwalten $withRoles = array_keys(array_filter($presets, fn($p) => $p[2]['manage_roles'])); $check($withRoles === ['co_admin'], 'Nur der Co-Administrator darf Rollen verwalten (' . implode(',', $withRoles) . ')'); $withDelete = array_keys(array_filter($presets, fn($p) => $p[2]['delete_ticket'])); sort($withDelete); $check($withDelete === ['co_admin', 'support_manager', 'teamleitung'], 'Löschen dürfen nur Co-Administrator, Support-Manager und Teamleitung (' . implode(',', $withDelete) . ')'); // ── Nie überschreiben ─────────────────────────────────────────────────────────── $check(permission_seed_default_roles($pdo) === [], 'Nochmal anlegen: nichts Neues (idempotent)'); $check(permission_missing_default_roles($pdo) === [], 'Es fehlt keine vordefinierte Rolle'); $pdo->prepare("UPDATE roles SET permissions = ?, notes = ?, name = ? WHERE LOWER(name) = LOWER(?)")->execute([json_encode(['reply_ticket' => true]), 'Meine Notiz', 'IT / TECHNIK', 'IT / Technik']); $pdo->exec("DELETE FROM roles WHERE name = 'Aushilfe / Praktikant'"); $check(permission_missing_default_roles($pdo) === ['Aushilfe / Praktikant'], 'Eine gelöschte Rolle gilt als fehlend; eine umbenannte nur in der Schreibweise nicht'); $made = permission_seed_default_roles($pdo); $check($made === ['Aushilfe / Praktikant'], 'Nur die fehlende Rolle wird nachgelegt (' . implode(',', $made) . ')'); $it = $pdo->query("SELECT permissions, notes, name FROM roles WHERE LOWER(name) = LOWER('IT / Technik')")->fetch(); $check($it && $it['notes'] === 'Meine Notiz' && json_decode($it['permissions'], true) === ['reply_ticket' => true], 'Eine geänderte Rolle bleibt unverändert'); $check((int) $pdo->query("SELECT COUNT(*) FROM roles WHERE LOWER(name) = LOWER('IT / Technik')")->fetchColumn() === 1, 'Keine Doppelte bei anderer Schreibweise'); // ── Update einer bestehenden Installation: eigene Rollen bleiben, Namen kollidieren nicht ─────── $pdo->exec("DELETE FROM roles"); $pdo->prepare('INSERT INTO roles (name, permissions, is_active, created_at, updated_at) VALUES (?,?,1,?,?)')->execute(['Teamleitung', json_encode(['reply_ticket' => true]), date('Y-m-d H:i:s'), date('Y-m-d H:i:s')]); $pdo->exec("DELETE FROM schema_migrations WHERE migration = 'php_0076_default_roles'"); $res = run_migrations($pdo, false); $check(($res['errors'] ?? []) === [], 'Migration läuft ohne Fehler: ' . json_encode($res['errors'] ?? [])); $tl = $pdo->query("SELECT permissions FROM roles WHERE name = 'Teamleitung'")->fetchAll(PDO::FETCH_COLUMN); $check(count($tl) === 1 && json_decode($tl[0], true) === ['reply_ticket' => true], 'Update: eine schon vorhandene „Teamleitung“ bleibt unverändert und wird nicht doppelt angelegt'); $check((int) $pdo->query('SELECT COUNT(*) FROM roles')->fetchColumn() === count($seeded), 'Update: alle anderen vordefinierten Rollen kommen dazu'); $check((int) $pdo->query("SELECT COUNT(*) FROM schema_migrations WHERE migration = 'php_0076_default_roles'")->fetchColumn() === 1, 'Update: Migration ist wieder eingetragen'); $before = (int) $pdo->query('SELECT COUNT(*) FROM roles')->fetchColumn(); run_migrations($pdo, false); $check((int) $pdo->query('SELECT COUNT(*) FROM roles')->fetchColumn() === $before, 'Die Migration läuft nur einmal'); // Rolle wirkt wirklich: Mitarbeiter mit „Support 1st Level“ $pdo->exec('DELETE FROM staff'); $dept = (int) $pdo->query('SELECT id FROM departments ORDER BY id LIMIT 1')->fetchColumn(); $rid = (int) $pdo->query("SELECT id FROM roles WHERE name = 'Support 1st Level'")->fetchColumn(); $pdo->prepare('INSERT INTO staff (name, email, password_hash, role, role_id, department_id, is_active, created_at) VALUES (?,?,?,?,?,?,1,?)')->execute(['Neu', 'neu@test.de', 'x', 'agent', $rid, $dept, date('Y-m-d H:i:s')]); $st = $pdo->query('SELECT * FROM staff WHERE email = \'neu@test.de\'')->fetch(); $check(has_permission($st, 'reply_ticket') && has_permission($st, 'assign_ticket') && !has_permission($st, 'close_ticket') && !has_permission($st, 'manage_banlist') && !has_permission($st, 'manage_custom_fields'), 'Ein Mitarbeiter mit „Support 1st Level“ hat genau diese Rechte'); echo $failures ? "FEHLGESCHLAGEN:\n - " . implode("\n - ", $failures) . "\n" : ''; echo "Vordefinierte-Rollen-Test: " . ($total - count($failures)) . " von {$total} Prüfungen in Ordnung.\n"; exit($failures ? 1 : 0);