Upload via GUI (396 Dateien)
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* Ganzer Weg des E-Mail-Abrufs gegen einen kleinen IMAP-Server (tests/fixtures/fake_imap_server.php), gestartet über den Abruf von Hand:
|
||||
* Aus der Mail wird ein Ticket mit Text (samt Absätzen), HTML-Fassung, eingebettetem Bild und Anhang; die Mail wird als gelesen markiert,
|
||||
* ein zweiter Abruf findet nichts mehr, und der Abruf von Hand lässt sich nicht kurz hintereinander doppelt starten.
|
||||
*/
|
||||
|
||||
if (!function_exists('imap_open')) { echo "Abruf (ganzer Weg): übersprungen, PHP-IMAP fehlt.\n"; exit(0); }
|
||||
|
||||
$tmp = sys_get_temp_dir() . '/deskhub-e2e-' . bin2hex(random_bytes(4));
|
||||
mkdir($tmp . '/uploads', 0755, true);
|
||||
putenv('DESKHUB_TESTING=1');
|
||||
putenv('DESKHUB_SQLITE_PATH=:memory:');
|
||||
putenv('DESKHUB_CONFIG_JSON=' . json_encode(['uploads' => ['path' => $tmp . '/uploads', 'max_size_bytes' => 100000, 'allowed_extensions' => ['png', 'pdf', 'txt', 'docx']]]));
|
||||
require_once dirname(__DIR__) . '/includes/bootstrap.php';
|
||||
require_once dirname(__DIR__) . '/includes/mail_fetch_manual.php';
|
||||
|
||||
$failures = [];
|
||||
$check = function (bool $ok, string $what) use (&$failures): void {
|
||||
if (!$ok) $failures[] = $what;
|
||||
};
|
||||
$pdo = get_db();
|
||||
|
||||
$docx = random_bytes(700);
|
||||
$png = base64_decode('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg==');
|
||||
$html = '<html><body><p>Hallo Team</p><p>Zweiter Absatz mit <b>fett</b></p><img src="cid:logo1@example.de" alt="Logo"></body></html>';
|
||||
$mail = "From: Olaf Andresen <olaf@example.de>\r\nTo: einsendungen@example.org\r\nSubject: Neue Geschichte Teil 12\r\nMessage-ID: <e2e1@example.de>\r\nDate: Mon, 03 Nov 2026 00:39:00 +0100\r\nMIME-Version: 1.0\r\n"
|
||||
. "Content-Type: multipart/mixed; boundary=\"BND1\"\r\n\r\n"
|
||||
. "--BND1\r\nContent-Type: multipart/related; boundary=\"BND2\"\r\n\r\n"
|
||||
. "--BND2\r\nContent-Type: multipart/alternative; boundary=\"BND3\"\r\n\r\n"
|
||||
. "--BND3\r\nContent-Type: text/plain; charset=utf-8\r\nContent-Transfer-Encoding: 8bit\r\n\r\nHallo Team\r\n\r\nZweiter Absatz mit fett\r\n"
|
||||
. "--BND3\r\nContent-Type: text/html; charset=utf-8\r\nContent-Transfer-Encoding: base64\r\n\r\n" . chunk_split(base64_encode($html))
|
||||
. "--BND3--\r\n"
|
||||
. "--BND2\r\nContent-Type: image/png; name=\"logo.png\"\r\nContent-Disposition: inline; filename=\"logo.png\"\r\nContent-ID: <logo1@example.de>\r\nContent-Transfer-Encoding: base64\r\n\r\n" . chunk_split(base64_encode($png))
|
||||
. "--BND2--\r\n"
|
||||
. "--BND1\r\nContent-Type: application/vnd.openxmlformats-officedocument.wordprocessingml.document; name=\"Teil 12.docx\"\r\nContent-Disposition: attachment; filename=\"Teil 12.docx\"\r\nContent-Transfer-Encoding: base64\r\n\r\n" . chunk_split(base64_encode($docx))
|
||||
. "--BND1--\r\n";
|
||||
file_put_contents($tmp . '/mail.eml', $mail);
|
||||
|
||||
$port = 0;
|
||||
for ($try = 0; $try < 20 && !$port; $try++) {
|
||||
$p = random_int(20000, 60000);
|
||||
$s = @stream_socket_server('tcp://127.0.0.1:' . $p);
|
||||
if ($s) { fclose($s); $port = $p; }
|
||||
}
|
||||
$proc = proc_open([PHP_BINARY, __DIR__ . '/fixtures/fake_imap_server.php', (string) $port, $tmp . '/mail.eml', $tmp . '/imap.log'], [0 => ['file', 'php://stdin', 'r'], 1 => ['file', $tmp . '/srv.out', 'w'], 2 => ['file', $tmp . '/srv.err', 'w']], $pipes);
|
||||
for ($i = 0; $i < 50; $i++) {
|
||||
$c = @fsockopen('127.0.0.1', $port, $en, $es, 0.2);
|
||||
if ($c) { fclose($c); break; }
|
||||
usleep(100000);
|
||||
}
|
||||
|
||||
try {
|
||||
$deptId = (int) $pdo->query('SELECT id FROM departments ORDER BY id LIMIT 1')->fetchColumn();
|
||||
$pdo->prepare("INSERT INTO imap_accounts (label, host, port, encryption, username, password_enc, folder, after_fetch, department_id, priority_id, is_active) VALUES ('Test','127.0.0.1',?,'none','u',?,'INBOX','seen',?,2,1)")
|
||||
->execute([$port, encrypt_secret('geheim'), $deptId]);
|
||||
|
||||
$r = mail_fetch_manual($pdo);
|
||||
$check($r['ok'] && $r['processed'] === 1 && $r['new_tickets'] === 1, 'Abruf von Hand: 1 neues Ticket: ' . json_encode($r) . ' | ' . @file_get_contents($tmp . '/srv.err'));
|
||||
$t = $pdo->query("SELECT * FROM tickets WHERE subject = 'Neue Geschichte Teil 12'")->fetch(PDO::FETCH_ASSOC);
|
||||
$check((bool) $t && $t['source'] === 'email' && $t['requester_email'] === 'olaf@example.de', 'Ticket aus der Mail angelegt');
|
||||
$th = $t ? $pdo->query('SELECT * FROM ticket_threads WHERE ticket_id = ' . (int) $t['id'])->fetch(PDO::FETCH_ASSOC) : [];
|
||||
$check(($th['message'] ?? '') === "Hallo Team\n\nZweiter Absatz mit fett", 'Text mit Absatz: ' . json_encode($th['message'] ?? null));
|
||||
$check(str_contains((string) ($th['message_html'] ?? ''), '<b>fett</b>') && str_contains((string) ($th['message_html'] ?? ''), 'cid:logo1@example.de'), 'HTML-Fassung gespeichert');
|
||||
$att = $th ? $pdo->query('SELECT * FROM ticket_attachments WHERE thread_id = ' . (int) $th['id'] . ' ORDER BY is_inline')->fetchAll(PDO::FETCH_ASSOC) : [];
|
||||
$check(count($att) === 2 && $att[0]['original_name'] === 'Teil 12.docx' && (int) $att[1]['is_inline'] === 1 && $att[1]['content_id'] === 'logo1@example.de', 'Anhang und eingebettetes Bild gespeichert: ' . json_encode(array_column($att, 'original_name')));
|
||||
$check($att && file_get_contents($tmp . '/uploads/' . $att[0]['stored_name']) === $docx, 'Inhalt des Anhangs stimmt');
|
||||
$src = $t ? $pdo->query('SELECT * FROM ticket_email_sources WHERE ticket_id = ' . (int) $t['id'])->fetch(PDO::FETCH_ASSOC) : false;
|
||||
$check((bool) $src && $src['message_id'] === '<e2e1@example.de>' && (int) $src['message_uid'] === 7, 'Herkunft der Mail (UID, Message-ID) ist vermerkt');
|
||||
|
||||
// Direkt danach: gesperrt
|
||||
$r2 = mail_fetch_manual($pdo);
|
||||
$check(!$r2['ok'] && str_contains($r2['message'], 'gerade eben'), 'zweiter Klick direkt danach wird abgewiesen');
|
||||
// Nach der Sperrzeit: nichts Neues (Mail ist als gelesen markiert)
|
||||
$pdo->prepare("UPDATE settings SET setting_value = ? WHERE setting_key = 'cron_fetch_emails_last_run'")->execute([date('Y-m-d H:i:s', time() - 120)]);
|
||||
$r3 = mail_fetch_manual($pdo);
|
||||
$check($r3['ok'] && $r3['processed'] === 0 && str_contains($r3['message'], 'Keine neuen E-Mails'), 'zweiter Abruf findet nichts mehr: ' . json_encode($r3));
|
||||
$check((int) $pdo->query("SELECT COUNT(*) FROM tickets WHERE subject = 'Neue Geschichte Teil 12'")->fetchColumn() === 1, 'es gibt weiterhin genau ein Ticket');
|
||||
} finally {
|
||||
if (is_resource($proc)) { proc_terminate($proc); proc_close($proc); }
|
||||
}
|
||||
|
||||
$logTxt = (string) @file_get_contents($tmp . '/imap.log');
|
||||
$rm = function (string $d) use (&$rm) {
|
||||
foreach (scandir($d) ?: [] as $e) { if ($e === '.' || $e === '..') continue; is_dir("$d/$e") ? $rm("$d/$e") : @unlink("$d/$e"); }
|
||||
@rmdir($d);
|
||||
};
|
||||
if ($failures) $failures[] = 'IMAP-Protokoll (Ende): ' . substr($logTxt, -1200);
|
||||
$rm($tmp);
|
||||
|
||||
if ($failures) {
|
||||
fwrite(STDERR, "Fehlgeschlagen:\n - " . implode("\n - ", $failures) . "\n");
|
||||
exit(1);
|
||||
}
|
||||
echo "Mail fetch end-to-end checks passed.\n";
|
||||
Reference in New Issue
Block a user