Fix API correctness: external API stub/collision, recurring dates, CSV, audit
- create_ticket_api.php: remove the wrong CREATE TABLE stub that broke a fresh DB; generate collision-safe ticket_ids so a genuine id collision isn't misreported as a duplicate and a hw alert dropped; stop leaking raw DB errors; correct a reopen comment that falsely claimed refreshed sensor data - manage_recurring.php: fix next-run so create/edit no longer skips the current period (monthly day-of-month this month, daily today if time not passed, correct ISO weekday, month-length clamp); only recompute on schedule changes to avoid double-fire - export_tickets.php, audit_log.php: neutralize CSV formula injection - revoke_api_key.php, generate_api_key.php: correct HTTP status codes and stop the catch clobbering specific 4xx codes - health.php: stop leaking PHP version / extension names / paths to unauthenticated callers - watch_ticket.php: define $data before use - manage_templates/recurring/custom_fields: add audit logging for CRUD; add recurring_ticket + custom_field to the audit entity whitelist Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+38
-20
@@ -73,18 +73,6 @@ try {
|
||||
|
||||
$userId = $systemUser['user_id'];
|
||||
|
||||
// Create tickets table with hash column if not exists
|
||||
$createTableSQL = "CREATE TABLE IF NOT EXISTS tickets (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
ticket_id VARCHAR(9) NOT NULL,
|
||||
title VARCHAR(255) NOT NULL,
|
||||
hash VARCHAR(64) NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
UNIQUE KEY unique_hash (hash)
|
||||
)";
|
||||
|
||||
$conn->query($createTableSQL);
|
||||
|
||||
// Parse input regardless of content-type header
|
||||
$rawInput = file_get_contents('php://input');
|
||||
$data = json_decode($rawInput, true);
|
||||
@@ -371,7 +359,8 @@ if ($existing) {
|
||||
$reopenStmt->close();
|
||||
|
||||
$commentText = "**Issue recurred — ticket reopened automatically.**\n\n" .
|
||||
"hwmonDaemon detected this condition again. Current sensor data is in the ticket description above.";
|
||||
"hwmonDaemon detected this condition again. The ticket description reflects the "
|
||||
. "original report; see this comment's timestamp for when the issue recurred.";
|
||||
$commentStmt = $conn->prepare(
|
||||
"INSERT INTO ticket_comments (ticket_id, user_id, user_name, comment_text, markdown_enabled) VALUES (?, ?, 'hwmonDaemon', ?, 1)"
|
||||
);
|
||||
@@ -404,13 +393,40 @@ if ($existing) {
|
||||
exit;
|
||||
}
|
||||
|
||||
// No existing ticket — create a new one
|
||||
// Use random_int range 100000000-999999999 to avoid leading-zero IDs
|
||||
try {
|
||||
$ticket_id = (string)random_int(100000000, 999999999);
|
||||
} catch (Exception $e) {
|
||||
$ticket_id = (string)mt_rand(100000000, 999999999);
|
||||
// No existing ticket — create a new one.
|
||||
// Generate a collision-safe unique ticket_id with a pre-check + retry loop (same
|
||||
// approach as TicketModel::createTicket) so a ticket_id clash cannot happen. That
|
||||
// way a 1062 on INSERT below can only be the unique_hash (dedup) key racing, and
|
||||
// is correctly reported as a duplicate rather than a dropped hardware alert.
|
||||
$ticket_id = null;
|
||||
$maxAttempts = 50;
|
||||
$attempts = 0;
|
||||
do {
|
||||
try {
|
||||
$candidateId = sprintf('%09d', random_int(100000000, 999999999));
|
||||
} catch (Exception $e) {
|
||||
$candidateId = sprintf('%09d', mt_rand(100000000, 999999999));
|
||||
}
|
||||
|
||||
$idCheckStmt = $conn->prepare("SELECT ticket_id FROM tickets WHERE ticket_id = ? LIMIT 1");
|
||||
$idCheckStmt->bind_param("s", $candidateId);
|
||||
$idCheckStmt->execute();
|
||||
$idExists = $idCheckStmt->get_result()->num_rows > 0;
|
||||
$idCheckStmt->close();
|
||||
|
||||
if (!$idExists) {
|
||||
$ticket_id = $candidateId;
|
||||
}
|
||||
$attempts++;
|
||||
} while ($ticket_id === null && $attempts < $maxAttempts);
|
||||
|
||||
if ($ticket_id === null) {
|
||||
error_log('create_ticket_api: failed to generate a unique ticket_id after ' . $maxAttempts . ' attempts');
|
||||
http_response_code(500);
|
||||
echo json_encode(['success' => false, 'error' => 'Internal server error']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$insertStmt = $conn->prepare(
|
||||
"INSERT INTO tickets (ticket_id, title, description, status, priority, category, type, hash, created_by)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"
|
||||
@@ -469,5 +485,7 @@ if ($inserted) {
|
||||
'message' => 'Ticket created successfully',
|
||||
]);
|
||||
} else {
|
||||
echo json_encode(['success' => false, 'error' => $conn->error]);
|
||||
error_log('create_ticket_api: ticket insert reported failure: ' . $conn->error);
|
||||
http_response_code(500);
|
||||
echo json_encode(['success' => false, 'error' => 'Internal server error']);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user