Unify Discord webhook notifications between API and manual ticket creation
- Standardized embed format across both ticket creation paths - Added consistent priority colors (P1-P5) with distinct hex values - Added priority labels (e.g., "P1 - Critical" instead of just "1") - Added Source field showing hostname extracted from ticket title - Added Status field to both webhook formats - Added footer distinguishing "Automated Alert" vs "Manual Entry" - Added timestamp to API endpoint webhooks - Added error logging for failed webhook calls - Added timeout (10s) to API endpoint curl calls - Added null check for webhook URL in API endpoint Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -208,63 +208,87 @@ class TicketController {
|
|||||||
error_log("Discord webhook URL not configured, skipping webhook for ticket creation");
|
error_log("Discord webhook URL not configured, skipping webhook for ticket creation");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$webhookUrl = $this->envVars['DISCORD_WEBHOOK_URL'];
|
$webhookUrl = $this->envVars['DISCORD_WEBHOOK_URL'];
|
||||||
|
|
||||||
// Create ticket URL
|
// Create ticket URL
|
||||||
$protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
|
$protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
|
||||||
$host = $_SERVER['HTTP_HOST'] ?? 't.lotusguild.org';
|
$host = $_SERVER['HTTP_HOST'] ?? 't.lotusguild.org';
|
||||||
$ticketUrl = "{$protocol}://{$host}/ticket/{$ticketId}";
|
$ticketUrl = "{$protocol}://{$host}/ticket/{$ticketId}";
|
||||||
|
|
||||||
// Map priorities to Discord colors
|
// Map priorities to Discord colors (matching API endpoint)
|
||||||
$priorityColors = [
|
$priorityColors = [
|
||||||
1 => 0xff4d4d, // Red
|
1 => 0xDC3545, // P1 Critical - Red
|
||||||
2 => 0xffa726, // Orange
|
2 => 0xFD7E14, // P2 High - Orange
|
||||||
3 => 0x42a5f5, // Blue
|
3 => 0x0DCAF0, // P3 Medium - Cyan
|
||||||
4 => 0x66bb6a, // Green
|
4 => 0x198754, // P4 Low - Green
|
||||||
5 => 0x9e9e9e // Gray
|
5 => 0x6C757D // P5 Info - Gray
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// Priority labels for display
|
||||||
|
$priorityLabels = [
|
||||||
|
1 => "P1 - Critical",
|
||||||
|
2 => "P2 - High",
|
||||||
|
3 => "P3 - Medium",
|
||||||
|
4 => "P4 - Low",
|
||||||
|
5 => "P5 - Info"
|
||||||
|
];
|
||||||
|
|
||||||
$priority = (int)($ticketData['priority'] ?? 4);
|
$priority = (int)($ticketData['priority'] ?? 4);
|
||||||
$color = $priorityColors[$priority] ?? 0x3498db;
|
$color = $priorityColors[$priority] ?? 0x6C757D;
|
||||||
|
$priorityLabel = $priorityLabels[$priority] ?? "P{$priority}";
|
||||||
|
|
||||||
|
$title = $ticketData['title'] ?? 'Untitled';
|
||||||
|
$category = $ticketData['category'] ?? 'General';
|
||||||
|
$type = $ticketData['type'] ?? 'Issue';
|
||||||
|
$status = $ticketData['status'] ?? 'Open';
|
||||||
|
|
||||||
|
// Extract hostname from title for cleaner display
|
||||||
|
preg_match('/^\[([^\]]+)\]/', $title, $hostnameMatch);
|
||||||
|
$sourceHost = $hostnameMatch[1] ?? 'Manual';
|
||||||
|
|
||||||
$embed = [
|
$embed = [
|
||||||
'title' => '🎫 New Ticket Created',
|
'title' => 'New Ticket Created',
|
||||||
'description' => "**#{$ticketId}** - " . $ticketData['title'],
|
'description' => "**#{$ticketId}** - {$title}",
|
||||||
'url' => $ticketUrl,
|
'url' => $ticketUrl,
|
||||||
'color' => $color,
|
'color' => $color,
|
||||||
'fields' => [
|
'fields' => [
|
||||||
[
|
[
|
||||||
'name' => 'Priority',
|
'name' => 'Priority',
|
||||||
'value' => 'P' . $priority,
|
'value' => $priorityLabel,
|
||||||
'inline' => true
|
'inline' => true
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'name' => 'Category',
|
'name' => 'Category',
|
||||||
'value' => $ticketData['category'] ?? 'General',
|
'value' => $category,
|
||||||
'inline' => true
|
'inline' => true
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'name' => 'Type',
|
'name' => 'Type',
|
||||||
'value' => $ticketData['type'] ?? 'Issue',
|
'value' => $type,
|
||||||
'inline' => true
|
'inline' => true
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'name' => 'Status',
|
'name' => 'Status',
|
||||||
'value' => $ticketData['status'] ?? 'Open',
|
'value' => $status,
|
||||||
|
'inline' => true
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => 'Source',
|
||||||
|
'value' => $sourceHost,
|
||||||
'inline' => true
|
'inline' => true
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
'footer' => [
|
'footer' => [
|
||||||
'text' => 'Tinker Tickets'
|
'text' => 'Tinker Tickets | Manual Entry'
|
||||||
],
|
],
|
||||||
'timestamp' => date('c')
|
'timestamp' => date('c')
|
||||||
];
|
];
|
||||||
|
|
||||||
$payload = [
|
$payload = [
|
||||||
'embeds' => [$embed]
|
'embeds' => [$embed]
|
||||||
];
|
];
|
||||||
|
|
||||||
// Send webhook
|
// Send webhook
|
||||||
$ch = curl_init($webhookUrl);
|
$ch = curl_init($webhookUrl);
|
||||||
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
|
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
|
||||||
@@ -272,16 +296,16 @@ class TicketController {
|
|||||||
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
|
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
|
||||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||||
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
|
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
|
||||||
|
|
||||||
$webhookResult = curl_exec($ch);
|
$webhookResult = curl_exec($ch);
|
||||||
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||||
$curlError = curl_error($ch);
|
$curlError = curl_error($ch);
|
||||||
curl_close($ch);
|
curl_close($ch);
|
||||||
|
|
||||||
if ($curlError) {
|
if ($curlError) {
|
||||||
error_log("Discord webhook cURL error: $curlError");
|
error_log("Discord webhook cURL error: {$curlError}");
|
||||||
} else {
|
} elseif ($httpCode !== 204 && $httpCode !== 200) {
|
||||||
error_log("Discord webhook sent for new ticket. HTTP Code: $httpCode");
|
error_log("Discord webhook failed for ticket #{$ticketId}. HTTP Code: {$httpCode}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -223,40 +223,67 @@ if ($stmt->execute()) {
|
|||||||
$stmt->close();
|
$stmt->close();
|
||||||
$conn->close();
|
$conn->close();
|
||||||
|
|
||||||
// Discord webhook
|
// Discord webhook notification
|
||||||
$discord_webhook_url = $envVars['DISCORD_WEBHOOK_URL'];
|
if (isset($envVars['DISCORD_WEBHOOK_URL']) && !empty($envVars['DISCORD_WEBHOOK_URL'])) {
|
||||||
|
$discord_webhook_url = $envVars['DISCORD_WEBHOOK_URL'];
|
||||||
|
|
||||||
// Map priorities to Discord colors (decimal format)
|
// Map priorities to Discord colors (decimal format)
|
||||||
$priorityColors = [
|
$priorityColors = [
|
||||||
"1" => 16736589, // --priority-1: #ff4d4d
|
"1" => 0xDC3545, // P1 Critical - Red
|
||||||
"2" => 16753958, // --priority-2: #ffa726
|
"2" => 0xFD7E14, // P2 High - Orange
|
||||||
"3" => 4363509, // --priority-3: #42a5f5
|
"3" => 0x0DCAF0, // P3 Medium - Cyan
|
||||||
"4" => 6736490 // --priority-4: #66bb6a
|
"4" => 0x198754, // P4 Low - Green
|
||||||
];
|
"5" => 0x6C757D // P5 Info - Gray
|
||||||
|
];
|
||||||
|
|
||||||
$protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
|
// Priority labels for display
|
||||||
$host = $_SERVER['HTTP_HOST'] ?? 't.lotusguild.org';
|
$priorityLabels = [
|
||||||
$ticketUrl = "{$protocol}://{$host}/ticket/{$ticket_id}";
|
"1" => "P1 - Critical",
|
||||||
|
"2" => "P2 - High",
|
||||||
|
"3" => "P3 - Medium",
|
||||||
|
"4" => "P4 - Low",
|
||||||
|
"5" => "P5 - Info"
|
||||||
|
];
|
||||||
|
|
||||||
$discord_data = [
|
$protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
|
||||||
"content" => "",
|
$host = $_SERVER['HTTP_HOST'] ?? 't.lotusguild.org';
|
||||||
"embeds" => [[
|
$ticketUrl = "{$protocol}://{$host}/ticket/{$ticket_id}";
|
||||||
"title" => "New Ticket Created: #" . $ticket_id,
|
|
||||||
"description" => $title,
|
|
||||||
"url" => $ticketUrl,
|
|
||||||
"color" => $priorityColors[$priority],
|
|
||||||
"fields" => [
|
|
||||||
["name" => "Priority", "value" => $priority, "inline" => true],
|
|
||||||
["name" => "Category", "value" => $category, "inline" => true],
|
|
||||||
["name" => "Type", "value" => $type, "inline" => true]
|
|
||||||
]
|
|
||||||
]]
|
|
||||||
];
|
|
||||||
|
|
||||||
$ch = curl_init($discord_webhook_url);
|
// Extract hostname from title for cleaner display
|
||||||
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
|
preg_match('/^\[([^\]]+)\]/', $title, $hostnameMatch);
|
||||||
curl_setopt($ch, CURLOPT_POST, 1);
|
$sourceHost = $hostnameMatch[1] ?? 'Unknown';
|
||||||
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($discord_data));
|
|
||||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
$discord_data = [
|
||||||
curl_exec($ch);
|
"embeds" => [[
|
||||||
curl_close($ch);
|
"title" => "New Ticket Created",
|
||||||
|
"description" => "**#{$ticket_id}** - {$title}",
|
||||||
|
"url" => $ticketUrl,
|
||||||
|
"color" => $priorityColors[$priority] ?? 0x6C757D,
|
||||||
|
"fields" => [
|
||||||
|
["name" => "Priority", "value" => $priorityLabels[$priority] ?? "P{$priority}", "inline" => true],
|
||||||
|
["name" => "Category", "value" => $category, "inline" => true],
|
||||||
|
["name" => "Type", "value" => $type, "inline" => true],
|
||||||
|
["name" => "Status", "value" => $status, "inline" => true],
|
||||||
|
["name" => "Source", "value" => $sourceHost, "inline" => true]
|
||||||
|
],
|
||||||
|
"footer" => [
|
||||||
|
"text" => "Tinker Tickets | Automated Alert"
|
||||||
|
],
|
||||||
|
"timestamp" => date('c')
|
||||||
|
]]
|
||||||
|
];
|
||||||
|
|
||||||
|
$ch = curl_init($discord_webhook_url);
|
||||||
|
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
|
||||||
|
curl_setopt($ch, CURLOPT_POST, 1);
|
||||||
|
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($discord_data));
|
||||||
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||||
|
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
|
||||||
|
$webhookResult = curl_exec($ch);
|
||||||
|
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||||
|
curl_close($ch);
|
||||||
|
|
||||||
|
if ($httpCode !== 204 && $httpCode !== 200) {
|
||||||
|
error_log("Discord webhook failed for ticket #{$ticket_id}. HTTP Code: {$httpCode}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user