From 323d49e13eb5b245d13f8811715d8593dfe035a7 Mon Sep 17 00:00:00 2001 From: M_Viper Date: Sun, 1 Nov 2026 11:16:05 +0000 Subject: [PATCH] Upload via GUI (364 Dateien) --- DeskHub-Webseite/.htaccess | 2 +- DeskHub-Webseite/live_chat.php | 2 +- DeskHub-Webseite/tests/status_plugin_site.php | 75 +++++++++++++++++++ DeskHub-Webseite/tests/ticket_lock_admin.php | 4 +- .../tests/vacation_substitute_access.php | 4 +- .../tests/web_smoke_integration.php | 2 +- 6 files changed, 83 insertions(+), 6 deletions(-) create mode 100644 DeskHub-Webseite/tests/status_plugin_site.php diff --git a/DeskHub-Webseite/.htaccess b/DeskHub-Webseite/.htaccess index ed301e59..fb7d8dcf 100644 --- a/DeskHub-Webseite/.htaccess +++ b/DeskHub-Webseite/.htaccess @@ -13,7 +13,7 @@ RewriteRule ^ - [F,L] # RewriteRule ^ - [F,L] # Clickjacking-Schutz -Header always set X-Frame-Options "SAMEORIGIN" +Header always set X-Frame-Options "DENY" Header always set X-Content-Type-Options "nosniff" # Schützt interne Verzeichnisse vor direktem Web-Zugriff. diff --git a/DeskHub-Webseite/live_chat.php b/DeskHub-Webseite/live_chat.php index 3e90be1b..2788c0c6 100644 --- a/DeskHub-Webseite/live_chat.php +++ b/DeskHub-Webseite/live_chat.php @@ -248,7 +248,7 @@ if ($action !== 'typing') { if ($action === 'typing') { if ($activeTicket && $activeTicket['status'] !== 'closed') { - $pdo->prepare('UPDATE tickets SET typing_customer_until = ? WHERE id = ?') + $pdo->prepare('UPDATE tickets SET typing_customer_until = ?, updated_at = updated_at WHERE id = ?') ->execute([date('Y-m-d H:i:s', time() + 6), $activeTicket['id']]); } chat_json(['ok' => true]); diff --git a/DeskHub-Webseite/tests/status_plugin_site.php b/DeskHub-Webseite/tests/status_plugin_site.php new file mode 100644 index 00000000..701522d1 --- /dev/null +++ b/DeskHub-Webseite/tests/status_plugin_site.php @@ -0,0 +1,75 @@ + $pdo->query("SELECT * FROM status_components WHERE name = " . $pdo->quote($name))->fetch(PDO::FETCH_ASSOC); + +// Ohne offiziellen Katalog gibt es nichts zu prüfen +$check(status_plugin_site_url() === '', 'ohne Katalog keine Prüfadresse'); +status_restore_core_components($pdo); +$check(!$byName('Plugin-Webseite'), 'ohne Katalog wird kein Dienst "Plugin-Webseite" angelegt'); + +// Mit offiziellem Katalog +$GLOBALS['deskhub_catalog_defaults'] = ['plugins_url' => 'https://plugins.example.test/seite/catalog.php?type=plugins', 'themes_url' => '', 'publisher_key' => 'x']; +$check(status_plugin_site_url() === 'https://plugins.example.test/seite/health.php', 'Prüfadresse liegt neben dem Katalog: ' . status_plugin_site_url()); +$check(status_restore_core_components($pdo) >= 1, 'Standarddienste ergänzen den fehlenden Dienst'); +$c = $byName('Plugin-Webseite'); +$check((bool) $c && $c['monitor_type'] === 'plugin_site' && (int) ($c['is_enabled'] ?? 1) === 1, 'Dienst "Plugin-Webseite" ist angelegt und aktiv'); +$t = status_component_monitor_target($pdo, $c); +$check($t && $t['type'] === 'plugin_site' && $t['target'] === 'https://plugins.example.test/seite/health.php', 'Prüfziel ist das health.php der Plugin-Webseite'); +$check(status_restore_core_components($pdo) === 0, 'ein zweiter Durchlauf legt nichts doppelt an'); +$check(isset(status_monitor_types()['plugin_site']) && status_set_component_monitor($pdo, (int) $c['id'], 'plugin_site', ''), 'Prüfart "Plugin-Webseite" lässt sich wählen'); + +// Automatische Erkennung am Namen (Dienst mit anderem Namen, Prüfart "auto") +$id = status_save_component($pdo, null, 'Pluginseite von DeskHub', '', 900, null); +$row = $pdo->query('SELECT * FROM status_components WHERE id = ' . (int) $id)->fetch(PDO::FETCH_ASSOC); +$t = status_component_monitor_target($pdo, $row); +$check($t && $t['type'] === 'plugin_site', 'Name mit "Plugin" und "seite" wird automatisch erkannt'); +$id2 = status_save_component($pdo, null, 'Plugin-Hersteller', '', 910, null); +$row2 = $pdo->query('SELECT * FROM status_components WHERE id = ' . (int) $id2)->fetch(PDO::FETCH_ASSOC); +$check(status_component_monitor_target($pdo, $row2) === null, 'ein anderer Name mit "Plugin" wird nicht fälschlich geprüft'); + +// Intern: wird geprüft, steht aber nicht öffentlich +$check(status_has_internal($pdo), 'Spalte is_internal ist vorhanden'); +$check((int) $byName('Plugin-Webseite')['is_internal'] === 1, 'Plugin-Webseite ist standardmäßig intern'); +$cat = $pdo->query('SELECT name FROM status_categories WHERE id = ' . (int) $byName('Plugin-Webseite')['category_id'])->fetchColumn(); +$check($cat === 'Server & Datenbank', 'Kategorie ist "Server & Datenbank", nicht "Webseite": ' . var_export($cat, true)); +$pub = array_column(status_components($pdo, false, true), 'name'); +$all = array_column(status_components($pdo), 'name'); +$check(!in_array('Plugin-Webseite', $pub, true) && in_array('Plugin-Webseite', $all, true), 'öffentliche Liste ohne den internen Dienst, Mitarbeiterliste mit ihm'); +$check(in_array('plugin_site', array_map(fn($c) => (status_component_monitor_target($pdo, $c)['type'] ?? ''), status_components($pdo)), true), 'interner Dienst wird weiter geprüft'); +// Ausfall eines internen Dienstes ändert den öffentlichen Gesamtzustand nicht +status_set_component($pdo, (int) $byName('Plugin-Webseite')['id'], 'outage'); +$check(status_overall($pdo)['key'] === 'operational', 'Ausfall eines internen Dienstes ändert den öffentlichen Gesamtzustand nicht: ' . status_overall($pdo)['key']); +$check(status_set_component_internal($pdo, (int) $byName('Plugin-Webseite')['id'], false) && in_array('Plugin-Webseite', array_column(status_components($pdo, false, true), 'name'), true), 'als öffentlich markiert erscheint er wieder'); +$check(status_overall($pdo)['key'] === 'outage', 'öffentlich: der Ausfall zählt'); +status_set_component_internal($pdo, (int) $byName('Plugin-Webseite')['id'], true); +status_set_component($pdo, (int) $byName('Plugin-Webseite')['id'], 'operational'); +// Störung an einem internen Dienst erscheint nicht öffentlich +$inc = status_create_incident($pdo, 'Plugin-Webseite langsam', 'x', 'investigating', (int) $byName('Plugin-Webseite')['id'], null, null); +$check(!empty($inc['ok']) && count(status_incidents($pdo, 14)) === 0 && count(status_incidents($pdo, 14, false, true)) === 1, 'Störung an einem internen Dienst steht nicht öffentlich, Mitarbeiter sehen sie'); + +// Eine http-Adresse (ohne https) wird nicht als Prüfadresse verwendet +$GLOBALS['deskhub_catalog_defaults'] = ['plugins_url' => 'http://plugins.example.test/catalog.php', 'themes_url' => '', 'publisher_key' => 'x']; +$check(status_plugin_site_url() === '', 'nur https wird verwendet'); +unset($GLOBALS['deskhub_catalog_defaults']); + +if ($failures) { + fwrite(STDERR, "Fehlgeschlagen:\n - " . implode("\n - ", $failures) . "\n"); + exit(1); +} +echo "Status plugin site checks passed.\n"; diff --git a/DeskHub-Webseite/tests/ticket_lock_admin.php b/DeskHub-Webseite/tests/ticket_lock_admin.php index 7d35cd4c..be6d4782 100644 --- a/DeskHub-Webseite/tests/ticket_lock_admin.php +++ b/DeskHub-Webseite/tests/ticket_lock_admin.php @@ -216,10 +216,10 @@ try { [$s] = $call('GET', '/staff/ticket_view.php?n=T-OPEN-5', null, null, [], $jarChef, ['Sec-Fetch-Mode: navigate']); $check($s === 200 && (int) $assignee('T-OPEN-5') === $ids['Chef'], 'Auch im Browser: Öffnen weist das Ticket zu (HTTP ' . $s . ')'); - // Ticketliste: Spalte mit dem Eingangsdatum + // Ticketliste: Spalte mit der letzten Aktivität (Eingang im Tooltip) [$s, $list] = $call('GET', '/staff/tickets.php', null, null, [], $jarChef, ['Sec-Fetch-Mode: navigate']); $list = is_string($list) ? $list : ''; - $check($s === 200 && str_contains($list, 'Eingang') && str_contains($list, date('d.m.Y ')), 'Ticketliste zeigt die Spalte „Eingang“ mit Datum und Uhrzeit (HTTP ' . $s . ', ' . strlen($list) . ' Zeichen, Tabelle: ' . (str_contains($list, 'Letzte Aktivität') && str_contains($list, date('d.m.Y ')), 'Ticketliste zeigt die Spalte „Letzte Aktivität“ mit Datum und Uhrzeit (HTTP ' . $s . ', ' . strlen($list) . ' Zeichen, Tabelle: ' . (str_contains($list, 'prepare('UPDATE staff SET is_on_vacation = 1, vacation_substitute_id = NUL [$h] = vacation_apply_change($pdo, $ben, [0, null], [1, null], true); $check($h === 0 && $owner($t6) === $ben, 'Ohne Vertretung bleibt alles beim Abwesenden'); // Das Plugin „Urlaub und Vertretung“ hat Vorrang -$pdo->exec('CREATE TABLE IF NOT EXISTS plugin_vertretung_absences (id INTEGER PRIMARY KEY AUTOINCREMENT, staff_id INTEGER, substitute_id INTEGER, start_date TEXT, end_date TEXT, note TEXT, status TEXT, created_by INTEGER, created_at TEXT)'); +$pdo->exec($pdo->getAttribute(PDO::ATTR_DRIVER_NAME) === 'sqlite' + ? 'CREATE TABLE IF NOT EXISTS plugin_vertretung_absences (id INTEGER PRIMARY KEY AUTOINCREMENT, staff_id INTEGER, substitute_id INTEGER, start_date TEXT, end_date TEXT, note TEXT, status TEXT, created_by INTEGER, created_at TEXT)' + : 'CREATE TABLE IF NOT EXISTS plugin_vertretung_absences (id INT AUTO_INCREMENT PRIMARY KEY, staff_id INT, substitute_id INT, start_date VARCHAR(20), end_date VARCHAR(20), note TEXT, status VARCHAR(20), created_by INT, created_at VARCHAR(20))'); $pdo->prepare("INSERT INTO plugin_vertretung_absences (staff_id, substitute_id, start_date, end_date, note, status, created_at) VALUES (?,?,?,?,?,?,?)")->execute([$ben, $anna, '2026-01-01', '2026-12-31', '', 'active', $now]); $pdo->prepare('UPDATE staff SET is_on_vacation = 1, vacation_substitute_id = ? WHERE id = ?')->execute([$anna, $ben]); [$h] = vacation_apply_change($pdo, $ben, [0, null], [1, $anna], true); diff --git a/DeskHub-Webseite/tests/web_smoke_integration.php b/DeskHub-Webseite/tests/web_smoke_integration.php index f170eb6a..9f86d178 100644 --- a/DeskHub-Webseite/tests/web_smoke_integration.php +++ b/DeskHub-Webseite/tests/web_smoke_integration.php @@ -150,7 +150,7 @@ try { '/staff/custom_lists.php' => 'Listen', '/staff/custom_lists.php?new=1' => 'Einträge', '/staff/site_pages.php' => 'Seiten', '/staff/site_pages.php?new=1' => 'Seiteninformationen', '/staff/business_hours.php' => 'Feiertage', '/staff/business_hours.php?tab=holidays' => 'Feiertage', - '/staff/update.php' => 'Datenbank aktualisieren', '/staff/plugins.php' => 'Plugin-Katalog', '/staff/login_log.php' => 'Anmelde-Wächter', '/staff/login_alert.php?t=abc' => 'ungültig, abgelaufen', '/staff/backup.php' => 'Vorhandene Backups', '/staff/security_check.php' => 'Sicherheitsprüfung', '/staff/import_osticket.php' => 'osTicket Import', '/staff/ticket_rules.php' => 'Ticket-Regeln', '/staff/ticket_rules.php?new=1' => 'Regelinformationen', + '/staff/update.php' => 'Datenbank aktualisieren', '/staff/plugins.php' => 'Plugin-Katalog', '/staff/login_log.php' => 'Anmelde-Wächter', '/staff/problems.php' => 'Neues Problem', '/staff/reports.php' => 'Jetzt zu tun', '/staff/reports.php?tab=activity' => 'Ticketaktivität', '/staff/reports.php?tab=analysis' => 'Statistiken', '/staff/problems.php?tab=create' => 'Neues Problem erfassen', '/staff/login_alert.php?t=abc' => 'ungültig, abgelaufen', '/staff/backup.php' => 'Vorhandene Backups', '/staff/security_check.php' => 'Sicherheitsprüfung', '/staff/import_osticket.php' => 'osTicket Import', '/staff/ticket_rules.php' => 'Ticket-Regeln', '/staff/ticket_rules.php?new=1' => 'Regelinformationen', ] as $path => $marker) { $response = browser_request($port, 'GET', $path, $cookies); assert_page($response, $marker);