135 lines
7.8 KiB
PHP
135 lines
7.8 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
/**
|
|
* Prüft, dass Mitarbeiter im Urlaub keine Benachrichtigungen bekommen: E-Mail (neues Ticket, überfällig, Erwähnung, Team, Eskalation),
|
|
* Browser-Push und Android-Push. Mitarbeiter, die zurück sind, bekommen sie wieder.
|
|
*/
|
|
|
|
$db = sys_get_temp_dir() . '/deskhub-vn-' . bin2hex(random_bytes(4)) . '.sqlite';
|
|
putenv('DESKHUB_TESTING=1');
|
|
putenv('DESKHUB_SQLITE_PATH=' . $db);
|
|
require_once dirname(__DIR__) . '/includes/bootstrap.php';
|
|
require_once dirname(__DIR__) . '/includes/push.php';
|
|
|
|
$failures = [];
|
|
$check = function (bool $ok, string $what) use (&$failures): void { if (!$ok) $failures[] = $what; };
|
|
$pdo = get_db();
|
|
$now = db_now();
|
|
$pdo->prepare('INSERT INTO departments (name, email) VALUES (?,?)')->execute(['Support', 'support@firma.example']);
|
|
$dept = (int) $pdo->lastInsertId();
|
|
$person = function (string $name, string $role, int $d) use ($pdo, $now): int {
|
|
$pdo->prepare('INSERT INTO staff (name, email, password_hash, role, department_id, is_active, created_at) VALUES (?,?,?,?,?,1,?)')
|
|
->execute([$name, strtolower($name) . '@firma.example', 'x', $role, $d, $now]);
|
|
return (int) $pdo->lastInsertId();
|
|
};
|
|
$anna = $person('Anna', 'agent', $dept);
|
|
$ben = $person('Ben', 'agent', $dept);
|
|
$chef = $person('Chef', 'admin', $dept);
|
|
$away = fn(int $id, bool $on, ?int $sub = null) => $pdo->prepare('UPDATE staff SET is_on_vacation = ?, vacation_substitute_id = ? WHERE id = ?')->execute([$on ? 1 : 0, $sub, $id]);
|
|
|
|
// Mails über die Warteschlange abfangen: SMTP absichtlich ohne Server, Mails landen in mail_queue
|
|
set_setting('mail_enabled', '1');
|
|
set_setting('smtp_host', '127.0.0.1');
|
|
set_setting('smtp_port', '1');
|
|
set_setting('smtp_encryption', 'none');
|
|
set_setting('smtp_from_email', 'noreply@firma.example');
|
|
$queued = function () use ($pdo): array { return $pdo->query('SELECT to_email FROM mail_queue ORDER BY id')->fetchAll(PDO::FETCH_COLUMN); };
|
|
$reset = fn() => $pdo->exec('DELETE FROM mail_queue');
|
|
$ticket = ['id' => 1, 'ticket_number' => '261030-0001', 'subject' => 'Test', 'requester_name' => 'Kunde', 'requester_email' => 'kunde@x.example', 'department_id' => $dept, 'department_name' => 'Support', 'assigned_staff_id' => null];
|
|
|
|
// 1) Neues Ticket
|
|
$reset();
|
|
notify_staff_new_ticket($ticket);
|
|
$to = $queued(); sort($to);
|
|
$check(in_array('anna@firma.example', $to, true) && in_array('ben@firma.example', $to, true) && in_array('chef@firma.example', $to, true), 'Ohne Urlaub gehen Mails an alle: ' . json_encode($to));
|
|
$reset();
|
|
$away($ben, true);
|
|
notify_staff_new_ticket($ticket);
|
|
$check(!in_array('ben@firma.example', $queued(), true), 'Neues Ticket: Mitarbeiter im Urlaub bekommt keine Mail');
|
|
$away($ben, false);
|
|
|
|
// 2) Überfällig an Admins
|
|
$reset();
|
|
$away($chef, true);
|
|
notify_admins_overdue_ticket($ticket);
|
|
$check(!in_array('chef@firma.example', $queued(), true), 'Überfällig: Administrator im Urlaub bekommt keine Mail');
|
|
$away($chef, false);
|
|
|
|
// 3) SLA-Empfänger: Bearbeiter im Urlaub ohne Vertretung bekommt nichts, mit Vertretung bekommt diese die Mail
|
|
$away($anna, true);
|
|
$r = sla_overdue_recipients($pdo, ['assigned_staff_id' => $anna, 'department_id' => $dept]);
|
|
$check(!in_array('anna@firma.example', $r, true), 'SLA: Bearbeiter im Urlaub ohne Vertretung bekommt keine Mail: ' . json_encode($r));
|
|
$away($anna, true, $ben);
|
|
$r = sla_overdue_recipients($pdo, ['assigned_staff_id' => $anna, 'department_id' => $dept]);
|
|
$check($r === ['ben@firma.example'], 'SLA: mit Vertretung bekommt diese die Mail: ' . json_encode($r));
|
|
$away($anna, false);
|
|
|
|
// 4) Erwähnung per Mail
|
|
$pdo->prepare("INSERT INTO tickets (ticket_number, subject, status, department_id, requester_name, requester_email, priority_id, created_at, updated_at) VALUES (?,?,?,?,?,?,(SELECT MIN(id) FROM priorities),?,?)")
|
|
->execute(['261030-0001', 'Test', 'open', $dept, 'Kunde', 'kunde@x.example', $now, $now]);
|
|
$ticket['id'] = (int) $pdo->lastInsertId();
|
|
$pdo->prepare("INSERT INTO ticket_threads (ticket_id, author_type, message, is_internal_note, created_at) VALUES (?,?,?,0,?)")->execute([$ticket['id'], 'staff', 'x', $now]);
|
|
$threadId = (int) $pdo->lastInsertId();
|
|
$reset();
|
|
$away($ben, true);
|
|
if (true) {
|
|
save_mentions($pdo, (int) $ticket['id'], $threadId, $anna, '@Ben bitte prüfen', $ticket + ['ticket_number' => '261030-0001']);
|
|
$check(!in_array('ben@firma.example', $queued(), true), 'Erwähnung: Mitarbeiter im Urlaub bekommt keine Mail');
|
|
}
|
|
$away($ben, false);
|
|
|
|
// 5) Push-Hilfsfunktion und Abfragen
|
|
$check(staff_is_on_vacation($ben) === false, 'Ben ist zurück');
|
|
$away($ben, true);
|
|
$check(staff_is_on_vacation($ben) === true, 'Ben ist im Urlaub');
|
|
$src = file_get_contents(dirname(__DIR__) . '/includes/push.php') . file_get_contents(dirname(__DIR__) . '/includes/fcm.php');
|
|
$check(str_contains($src, 'vacation_expand_ids') && substr_count($src, 'vacation_expand_ids') >= 3, 'Web-Push und Android-Push ersetzen Mitarbeiter im Urlaub durch die Vertretung');
|
|
$away($ben, false);
|
|
|
|
// 6) Android-Push: Geräte von Mitarbeitern im Urlaub werden übersprungen
|
|
$pdo->prepare('INSERT INTO push_devices (staff_id, token, token_hash, created_at) VALUES (?,?,?,?)')->execute([$anna, str_repeat('a', 40), hash('sha256', 'a'), $now]);
|
|
$pdo->prepare('INSERT INTO push_devices (staff_id, token, token_hash, created_at) VALUES (?,?,?,?)')->execute([$ben, str_repeat('b', 40), hash('sha256', 'b'), $now]);
|
|
$away($ben, true);
|
|
$sel = $pdo->prepare("SELECT d.staff_id FROM push_devices d JOIN staff s ON s.id = d.staff_id WHERE s.is_active = 1 AND s.is_on_vacation = 0 AND d.staff_id IN (?,?)");
|
|
$sel->execute([$anna, $ben]);
|
|
$check($sel->fetchAll(PDO::FETCH_COLUMN) == [$anna], 'Android: nur das Gerät des anwesenden Mitarbeiters bleibt');
|
|
|
|
// 7) Die Vertretung bekommt stattdessen die Benachrichtigung
|
|
$reset();
|
|
$away($ben, true, $anna);
|
|
notify_staff_new_ticket($ticket);
|
|
$to = $queued();
|
|
$check(in_array('anna@firma.example', $to, true) && !in_array('ben@firma.example', $to, true), 'Neues Ticket: die Vertretung bekommt die Mail des Abwesenden: ' . json_encode($to));
|
|
$check(count(array_keys($to, 'anna@firma.example', true)) === 1, 'Die Vertretung bekommt die Mail nur einmal, auch wenn sie selbst Empfänger ist');
|
|
$reset();
|
|
$away($chef, true, $ben);
|
|
$away($ben, true, $anna);
|
|
notify_admins_overdue_ticket($ticket);
|
|
$to = $queued();
|
|
$check(in_array('anna@firma.example', $to, true) && !in_array('chef@firma.example', $to, true) && !in_array('ben@firma.example', $to, true), 'Kette: Admin im Urlaub → Vertretung im Urlaub → deren Vertretung bekommt die Mail: ' . json_encode($to));
|
|
$away($chef, false);
|
|
$away($ben, false);
|
|
// Push: Abos der Abwesenden gehen an die Vertretung
|
|
$sub = fn(int $id, string $ep) => $pdo->prepare('INSERT INTO push_subscriptions (staff_id, endpoint, p256dh, auth, created_at) VALUES (?,?,?,?,?)')->execute([$id, $ep, 'k', 'a', $now]);
|
|
$sub($anna, 'https://push.example/anna');
|
|
$sub($ben, 'https://push.example/ben');
|
|
$endpoints = fn() => array_map(fn($r) => $r['endpoint'], push_subscriptions_for_department($pdo, $dept));
|
|
$check(in_array('https://push.example/ben', $endpoints(), true), 'Ohne Urlaub bekommt Ben das Browser-Push');
|
|
$away($ben, true, $anna);
|
|
$e = $endpoints();
|
|
$check(!in_array('https://push.example/ben', $e, true) && in_array('https://push.example/anna', $e, true), 'Im Urlaub geht das Browser-Push an die Vertretung: ' . json_encode($e));
|
|
$away($ben, true, null);
|
|
$e = $endpoints();
|
|
$check(!in_array('https://push.example/ben', $e, true), 'Ohne Vertretung bekommt der Abwesende nichts');
|
|
$check(vacation_expand_ids($pdo, [$ben]) === [], 'Ohne Vertretung entfällt der Abwesende');
|
|
$away($ben, true, $anna);
|
|
$check(vacation_expand_ids($pdo, [$ben, $anna]) === [$anna], 'Vertretung wird nicht doppelt gezählt');
|
|
$away($ben, false);
|
|
@unlink($db);
|
|
if ($failures) {
|
|
fwrite(STDERR, "Urlaub ohne Benachrichtigungen fehlgeschlagen:\n- " . implode("\n- ", $failures) . "\n");
|
|
exit(1);
|
|
}
|
|
echo "Urlaub ohne Benachrichtigungen bestanden.\n";
|