diff --git a/create_ticket_api.php b/create_ticket_api.php index c15ab4a..4e26fa4 100644 --- a/create_ticket_api.php +++ b/create_ticket_api.php @@ -104,9 +104,15 @@ if (!is_array($data) || empty($data['title'])) { function generateTicketHash($data) { $title = (string)($data['title'] ?? ''); + // Prefer explicit serial from payload; fall back to extracting device path from title + // for backwards compatibility with older hwmonDaemon versions. + $serial = isset($data['serial']) && $data['serial'] !== null && $data['serial'] !== '' + ? (string)$data['serial'] + : null; + // Extract device name if present (matches /dev/sdX, /dev/nvmeXnY patterns) preg_match('/\/dev\/(sd[a-z]+|nvme\d+n\d+)/', $title, $deviceMatches); - $isDriveTicket = !empty($deviceMatches); + $isDriveTicket = !empty($deviceMatches) || $serial !== null; // Extract first bracketed tag as hostname/source preg_match('/^\[([^\]]+)\]/', $title, $hostMatches); @@ -168,9 +174,11 @@ function generateTicketHash($data) { $stableComponents['hostname'] = $hostname; } - // Include device path for drive-specific tickets + // Include drive identifier for drive-specific tickets. + // Use serial when available (stable across reboots/reshuffles); fall back to + // device path for tickets created before serial was added to the payload. if ($isDriveTicket) { - $stableComponents['device'] = $deviceMatches[0]; + $stableComponents['drive'] = $serial ?? ($deviceMatches[0] ?? ''); } sort($stableComponents['environment_tags']); @@ -190,22 +198,90 @@ $ticketHash = generateTicketHash($data); $auditLog = new AuditLogModel($conn); // Look up any existing ticket with this hash (open OR closed) -$checkStmt = $conn->prepare("SELECT ticket_id, status FROM tickets WHERE hash = ? ORDER BY created_at DESC LIMIT 1"); +$checkStmt = $conn->prepare("SELECT ticket_id, status, title, priority FROM tickets WHERE hash = ? ORDER BY created_at DESC LIMIT 1"); $checkStmt->bind_param("s", $ticketHash); $checkStmt->execute(); $existing = $checkStmt->get_result()->fetch_assoc(); $checkStmt->close(); if ($existing) { - $existingId = $existing['ticket_id']; - $existingStatus = $existing['status']; + $existingId = $existing['ticket_id']; + $existingStatus = $existing['status']; + $existingTitle = $existing['title']; + $existingPriority = (int)$existing['priority']; + $newPriority = (int)$priority; if ($existingStatus !== 'Closed') { - // Ticket is still active — do not create a duplicate + // Ticket is still active — update title and escalate priority if the new + // report is more severe (lower number = higher severity). + $changes = []; + $updateSql = "UPDATE tickets SET updated_at = NOW(), updated_by = ?"; + $bindTypes = "i"; + $bindVals = [$userId]; + + if ($title !== $existingTitle) { + $updateSql .= ", title = ?"; + $bindTypes .= "s"; + $bindVals[] = $title; + $changes['title'] = ['from' => $existingTitle, 'to' => $title]; + } + + if ($newPriority < $existingPriority) { + $updateSql .= ", priority = ?"; + $bindTypes .= "i"; + $bindVals[] = $newPriority; + $changes['priority'] = ['from' => $existingPriority, 'to' => $newPriority]; + } + + if (!empty($changes)) { + $updateSql .= " WHERE ticket_id = ?"; + $bindTypes .= "s"; + $bindVals[] = $existingId; + + $updStmt = $conn->prepare($updateSql); + $updStmt->bind_param($bindTypes, ...$bindVals); + $updStmt->execute(); + $updStmt->close(); + + // Comment summarising what changed + $changeLines = []; + if (isset($changes['title'])) { + $changeLines[] = "- **Title updated** to reflect current issue"; + } + if (isset($changes['priority'])) { + $changeLines[] = "- **Priority escalated** from P{$changes['priority']['from']} to P{$changes['priority']['to']}"; + } + $commentText = "**hwmonDaemon reported a worsened condition — ticket updated automatically.**\n\n" . + implode("\n", $changeLines) . "\n\nLatest report:\n\n" . $description; + $commentStmt = $conn->prepare( + "INSERT INTO ticket_comments (ticket_id, user_id, user_name, comment_text, markdown_enabled) VALUES (?, ?, 'hwmonDaemon', ?, 1)" + ); + $commentStmt->bind_param("sis", $existingId, $userId, $commentText); + $commentStmt->execute(); + $commentStmt->close(); + + $auditLog->log($userId, 'update', 'ticket', $existingId, array_merge( + $changes, + ['reason' => 'auto-updated by hwmonDaemon (condition worsened)'] + )); + + require_once __DIR__ . '/helpers/NotificationHelper.php'; + NotificationHelper::sendTicketNotification($existingId, [ + 'title' => $title, + 'priority' => $newPriority < $existingPriority ? $newPriority : $existingPriority, + 'category' => $category, + 'type' => $type, + 'status' => $existingStatus, + ], 'automated'); + } + + $conn->close(); echo json_encode([ - 'success' => false, - 'error' => 'Duplicate ticket', - 'existing_ticket_id' => $existingId, + 'success' => true, + 'ticket_id' => $existingId, + 'message' => empty($changes) ? 'Duplicate — no change' : 'Existing ticket updated', + 'action' => empty($changes) ? 'deduplicated' : 'updated', + 'changes' => $changes, ]); exit; }