From c7f79db919e0fe514c301a35c0515cd7b242c215 Mon Sep 17 00:00:00 2001 From: M_Viper Date: Wed, 28 Oct 2026 07:55:02 +0000 Subject: [PATCH] Upload via GUI (346 Dateien) --- DeskHub-Webseite/api/public/v1/tickets.php | 33 +++++++++++++++++++--- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/DeskHub-Webseite/api/public/v1/tickets.php b/DeskHub-Webseite/api/public/v1/tickets.php index 2bfe3ea4..24ca81ff 100644 --- a/DeskHub-Webseite/api/public/v1/tickets.php +++ b/DeskHub-Webseite/api/public/v1/tickets.php @@ -5,6 +5,8 @@ declare(strict_types=1); * * POST /api/public/v1/tickets.php Ticket anlegen (Recht "Tickets anlegen") * JSON: { "name", "email", "subject", "message", "helpTopicId"?, "departmentId"?, "priorityId"? } + * POST /api/public/v1/tickets.php Ticket lösen (Recht "Tickets anlegen") + * JSON: { "action": "resolve", "number", "email", "message"? } nur für Tickets, die über die API angelegt wurden, mit passender E-Mail-Adresse * GET /api/public/v1/tickets.php?number=…&email=… Status + öffentlicher Verlauf (Recht "Tickets lesen") * * Authentifizierung: Header "X-API-Key: dh_…" oder "Authorization: Bearer dh_…". @@ -36,15 +38,38 @@ if (!$apiKey) public_api_fail(401, 'UNAUTHENTICATED', 'Ein gültiger API-Schlüs if ($method === 'POST') { if (!$apiKey['can_create_tickets']) public_api_fail(403, 'FORBIDDEN', 'Dieser Schlüssel darf keine Tickets anlegen.'); + $raw = file_get_contents('php://input') ?: ''; + if (strlen($raw) > 200000) public_api_fail(413, 'TOO_LARGE', 'Die Anfrage ist zu groß.'); + $body = json_decode($raw, true); + if (!is_array($body)) public_api_fail(400, 'INVALID_JSON', 'Der Anfragekörper muss gültiges JSON sein.'); + if (($body['action'] ?? '') === 'resolve') { + // Ein Fremdsystem meldet Entwarnung (zum Beispiel Minecraft-Server wieder erreichbar): Ticket auf „Gelöst“ setzen. + // Nur Tickets, die über die API angelegt wurden, und nur mit der E-Mail-Adresse des Anfragenden. + $number = trim((string) ($body['number'] ?? '')); + $email = strtolower(trim((string) ($body['email'] ?? ''))); + if ($number === '' || $email === '') public_api_fail(422, 'MISSING_PARAMS', 'Die Felder number und email sind erforderlich.'); + $stmt = $pdo->prepare("SELECT * FROM tickets WHERE ticket_number = ? AND LOWER(requester_email) = ? AND source = 'api'"); + $stmt->execute([$number, $email]); + $ticket = $stmt->fetch(); + if (!$ticket) public_api_fail(404, 'NOT_FOUND', 'Ticket nicht gefunden.'); + $note = trim(strip_tags((string) ($body['message'] ?? ''))); + if ($note === '') $note = 'Das Fremdsystem meldet Entwarnung.'; + $note = mb_substr($note, 0, 2000); + if (!in_array($ticket['status'], ['resolved', 'closed'], true)) { + $now = db_now(); + $pdo->prepare("INSERT INTO ticket_threads (ticket_id, author_type, message, is_internal_note, created_at) VALUES (?, 'system', ?, 1, ?)")->execute([$ticket['id'], e($note), $now]); + $pdo->prepare("UPDATE tickets SET status = 'resolved', resolved_at = ?, updated_at = ? WHERE id = ?")->execute([$now, $now, $ticket['id']]); + log_activity($pdo, (int) $ticket['id'], null, 'Über die API gelöst: ' . $note); + try { webhook_dispatch($pdo, 'ticket.status_changed', (int) $ticket['id'], ['previousStatus' => (string) $ticket['status']]); } catch (Throwable $e) { /* nachrangig */ } + } + echo json_encode(['number' => $number, 'status' => 'resolved'], JSON_UNESCAPED_UNICODE); + exit; + } // Schutz vor Überflutung: höchstens 60 über die API angelegte Tickets pro Minute $recent = $pdo->prepare("SELECT COUNT(*) FROM tickets WHERE source = 'api' AND created_at >= ?"); $recent->execute([date('Y-m-d H:i:s', time() - 60)]); if ((int) $recent->fetchColumn() >= 60) public_api_fail(429, 'RATE_LIMITED', 'Zu viele Anfragen. Bitte in einer Minute erneut versuchen.'); - $raw = file_get_contents('php://input') ?: ''; - if (strlen($raw) > 200000) public_api_fail(413, 'TOO_LARGE', 'Die Anfrage ist zu groß.'); - $body = json_decode($raw, true); - if (!is_array($body)) public_api_fail(400, 'INVALID_JSON', 'Der Anfragekörper muss gültiges JSON sein.'); try { $created = public_ticket_create($pdo, $body, client_ip()); } catch (AdminModelException $e) {