86 lines
6.3 KiB
PHP
86 lines
6.3 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
/**
|
|
* Prüft die Zuordnung eingehender Mails zu Tickets (includes/mail_threading.php): Nummer im Betreff, fremde Nummer im Betreff,
|
|
* Kopfzeilen In-Reply-To/References, Absenderprüfung, und dass ausgehende Mails zu einem Ticket eine Message-ID mit der Nummer tragen.
|
|
*/
|
|
|
|
putenv('DESKHUB_TESTING=1');
|
|
putenv('DESKHUB_SQLITE_PATH=:memory:');
|
|
require_once dirname(__DIR__) . '/includes/bootstrap.php';
|
|
|
|
$failures = [];
|
|
$check = function (bool $ok, string $what) use (&$failures): void {
|
|
if (!$ok) $failures[] = $what;
|
|
};
|
|
$pdo = get_db();
|
|
$now = date('Y-m-d H:i:s');
|
|
$mk = function (string $number, string $email) use ($pdo, $now): array {
|
|
$pdo->prepare("INSERT INTO tickets (ticket_number, subject, requester_name, requester_email, department_id, priority_id, status, source, created_at, updated_at) VALUES (?,?,?,?,1,2,'open','email',?,?)")
|
|
->execute([$number, 'Test ' . $number, 'Kunde', $email, $now, $now]);
|
|
$id = (int) $pdo->lastInsertId();
|
|
return $pdo->query("SELECT * FROM tickets WHERE id = {$id}")->fetch(PDO::FETCH_ASSOC);
|
|
};
|
|
$a = $mk('260101-0001', 'olaf@example.de');
|
|
$legacy = $mk('923425', 'olaf@example.de');
|
|
$b = $mk('260101-0002', 'anna@example.de');
|
|
$pdo->prepare('INSERT INTO ticket_email_sources (ticket_id, imap_account_id, message_uid, message_id, current_folder, created_at) VALUES (?,?,?,?,?,?)')
|
|
->execute([(int) $b['id'], 1, 5, '<Orig-Mail-77@Mail.Example.De>', 'INBOX', $now]);
|
|
|
|
// Kopfzeilen lesen
|
|
$raw = "From: x\r\nIn-Reply-To: <abc@x.de>\r\nReferences: <r1@x.de>\r\n <R2@x.de>\r\n\t<r3@x.de>\r\nSubject: s\r\n";
|
|
$ids = mail_reference_ids($raw);
|
|
$check($ids === ['abc@x.de', 'r1@x.de', 'r2@x.de', 'r3@x.de'], 'In-Reply-To und gefaltete References werden gelesen: ' . json_encode($ids));
|
|
$check(mail_reference_ids("Subject: nur\r\n") === [], 'ohne Kopfzeilen keine IDs');
|
|
|
|
// Message-ID mit Ticketnummer: erzeugen und wieder lesen
|
|
$mid = mail_ticket_message_id('Neue Antwort [#260101-0001] Ihr Ticket', 'support.example.de');
|
|
$check($mid !== null && preg_match('/^<deskhub\.260101-0001\.[0-9a-f]{16}@support\.example\.de>$/', $mid) === 1, 'Message-ID mit Nummer: ' . $mid);
|
|
$check(mail_ticket_number_from_message_id(trim((string) $mid, '<>')) === '260101-0001', 'Nummer wird aus der Message-ID gelesen');
|
|
$check(mail_ticket_message_id('Ohne Nummer', 'x.de') === null, 'Betreff ohne Nummer: keine Message-ID');
|
|
$check(mail_ticket_number_from_message_id('irgendwas@mail.example.de') === null, 'fremde Message-ID enthält keine Nummer');
|
|
|
|
// 1. Nummer im Betreff (DeskHub-Format): wie bisher ohne Absenderprüfung
|
|
$r = mail_find_ticket_for_reply($pdo, 'AW: [#260101-0001] Frage', '', 'jemand-anders@example.org');
|
|
$check($r && (int) $r['ticket']['id'] === (int) $a['id'] && $r['via'] === 'subject', 'DeskHub-Nummer im Betreff ordnet zu, wie bisher');
|
|
|
|
// 2. Andere Nummer im Betreff
|
|
$r = mail_find_ticket_for_reply($pdo, 'Aw: AW: [#923425] Haus Ledwin Teil 11', '', 'Olaf@Example.de');
|
|
$check($r && (int) $r['ticket']['id'] === (int) $legacy['id'] && $r['via'] === 'legacy', 'fremde Nummer (923425) ordnet zu, wenn der Absender der Auftraggeber ist: ' . json_encode($r['via'] ?? null));
|
|
$check(mail_find_ticket_for_reply($pdo, 'Aw: [#923425] x', '', 'fremder@example.org') === null, 'fremde Nummer von einem fremden Absender wird nicht zugeordnet');
|
|
$check(mail_find_ticket_for_reply($pdo, 'Aw: [#99999999] x', '', 'olaf@example.de') === null, 'Nummer, die es nicht gibt: neues Ticket');
|
|
|
|
// 3. Kopfzeilen
|
|
$r = mail_find_ticket_for_reply($pdo, 'Betreff geändert', "References: <deskhub.260101-0001.0123456789abcdef@support.example.de>\r\n", 'olaf@example.de');
|
|
$check($r && (int) $r['ticket']['id'] === (int) $a['id'] && $r['via'] === 'header', 'DeskHub-Message-ID in References ordnet zu, auch bei geändertem Betreff');
|
|
$check(mail_find_ticket_for_reply($pdo, 'Betreff geändert', "In-Reply-To: <deskhub.260101-0001.0123456789abcdef@support.example.de>\r\n", 'fremder@example.org') === null, 'DeskHub-Message-ID von fremdem Absender wird nicht zugeordnet');
|
|
$r = mail_find_ticket_for_reply($pdo, 'Neuer Betreff', "In-Reply-To: <orig-mail-77@mail.example.de>\r\n", 'ANNA@example.de');
|
|
$check($r && (int) $r['ticket']['id'] === (int) $b['id'] && $r['via'] === 'header', 'Message-ID einer früher abgerufenen Mail ordnet zu (Groß-/Kleinschreibung egal)');
|
|
$check(mail_find_ticket_for_reply($pdo, 'Neuer Betreff', "In-Reply-To: <orig-mail-77@mail.example.de>\r\n", 'olaf@example.de') === null, 'Mail-ID eines fremden Tickets: Absender passt nicht');
|
|
$check(mail_find_ticket_for_reply($pdo, 'Hallo', '', 'olaf@example.de') === null, 'ohne Nummer und ohne Kopfzeilen: neues Ticket');
|
|
$check(mail_find_ticket_for_reply($pdo, 'Hallo', "In-Reply-To: <unbekannt@x.de>\r\n", 'olaf@example.de') === null, 'unbekannte Message-ID: neues Ticket');
|
|
|
|
// Früherer Verfasser darf antworten
|
|
$pdo->exec("INSERT INTO users (name, email, password_hash, created_at) VALUES ('Kollegin','kollegin@example.de','x','{$now}')");
|
|
$uid = (int) $pdo->lastInsertId();
|
|
$pdo->exec("INSERT INTO ticket_threads (ticket_id, author_type, user_id, message, is_internal_note, created_at) VALUES ({$a['id']},'customer',{$uid},'x',0,'{$now}')");
|
|
$check(mail_sender_belongs_to_ticket($pdo, $a, 'kollegin@example.de'), 'früherer Verfasser einer Kundennachricht gehört zum Ticket');
|
|
$check(!mail_sender_belongs_to_ticket($pdo, $a, ''), 'leerer Absender gehört nirgends hin');
|
|
|
|
// Ausgehende Mail: Header mit Message-ID (nur wenn der Betreff eine Nummer hat)
|
|
require_once dirname(__DIR__) . '/includes/smtp_mailer.php';
|
|
$mailer = new SmtpMailer('localhost', 25, 'none', '', '');
|
|
$m = new ReflectionMethod($mailer, 'buildHeaders');
|
|
$m->setAccessible(true);
|
|
$h1 = (string) $m->invoke($mailer, 'kunde@example.de', 'Support <support@firma.example>', 'Antwort auf Ihr Ticket [#260101-0001]');
|
|
$h2 = (string) $m->invoke($mailer, 'kunde@example.de', 'Support <support@firma.example>', 'Willkommen');
|
|
$check(preg_match('/^Message-ID: <deskhub\.260101-0001\.[0-9a-f]{16}@firma\.example>
|
|
?$/m', $h1) === 1, 'ausgehende Ticketmail trägt Message-ID mit Nummer und Domain des Absenders');
|
|
$check(!str_contains($h2, 'Message-ID'), 'Mail ohne Ticketnummer bekommt keine eigene Message-ID');
|
|
|
|
if ($failures) {
|
|
fwrite(STDERR, "Fehlgeschlagen:\n - " . implode("\n - ", $failures) . "\n");
|
|
exit(1);
|
|
}
|
|
echo "Mail threading checks passed.\n";
|