Files
2026-11-05 21:21:55 +00:00

99 lines
9.7 KiB
PHP

<?php
declare(strict_types=1);
/**
* Prüft die vordefinierten Rollen: Sie werden bei Installation und Update angelegt (Migration 0076), nie überschrieben, nur bei Bedarf einzeln nachgelegt,
* und jede Vorlage gibt genau die Rechte, die ihre Beschreibung verspricht.
*/
putenv('DESKHUB_TESTING=1');
putenv('DESKHUB_SQLITE_PATH=:memory:');
require_once dirname(__DIR__) . '/includes/bootstrap.php';
require_once dirname(__DIR__) . '/database/migrate.php';
$failures = [];
$total = 0;
$check = function (bool $ok, string $what) use (&$failures, &$total): void {
$total++;
if (!$ok) $failures[] = $what;
};
$pdo = get_db();
$presets = permission_presets();
$seeded = array_filter($presets, fn($p) => $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);