Replace Discord webhook notifications with Matrix (hookshot)

- Add helpers/NotificationHelper.php: shared Matrix webhook sender
  that reads MATRIX_WEBHOOK_URL and MATRIX_NOTIFY_USERS from config
- Remove sendDiscordWebhook() from TicketController; call
  NotificationHelper::sendTicketNotification() instead
- Replace 60-line Discord embed block in create_ticket_api.php
  with a single NotificationHelper call
- config/config.php: DISCORD_WEBHOOK_URL → MATRIX_WEBHOOK_URL +
  new MATRIX_NOTIFY_USERS key (comma-separated Matrix user IDs)
- .env.example: updated env var names and comments

Payload sent to hookshot includes notify_users array so the
JS transform can build proper @mention links for each user.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-21 19:17:46 -05:00
parent 13f0fab138
commit f59913910f
5 changed files with 83 additions and 172 deletions

View File

@@ -7,6 +7,7 @@ require_once dirname(__DIR__) . '/models/UserModel.php';
require_once dirname(__DIR__) . '/models/WorkflowModel.php';
require_once dirname(__DIR__) . '/models/TemplateModel.php';
require_once dirname(__DIR__) . '/helpers/UrlHelper.php';
require_once dirname(__DIR__) . '/helpers/NotificationHelper.php';
class TicketController {
private $ticketModel;
@@ -110,8 +111,8 @@ class TicketController {
$GLOBALS['auditLog']->logTicketCreate($userId, $result['ticket_id'], $ticketData);
}
// Send Discord webhook notification for new ticket
$this->sendDiscordWebhook($result['ticket_id'], $ticketData);
// Send Matrix notification for new ticket
NotificationHelper::sendTicketNotification($result['ticket_id'], $ticketData, 'manual');
// Redirect to the new ticket
header("Location: " . $GLOBALS['config']['BASE_URL'] . "/ticket/" . $result['ticket_id']);
@@ -195,107 +196,5 @@ class TicketController {
}
}
private function sendDiscordWebhook($ticketId, $ticketData) {
$webhookUrl = $GLOBALS['config']['DISCORD_WEBHOOK_URL'] ?? null;
if (empty($webhookUrl)) {
error_log("Discord webhook URL not configured, skipping webhook for ticket creation");
return;
}
// Create ticket URL using validated host
$ticketUrl = UrlHelper::ticketUrl($ticketId);
// Map priorities to Discord colors (matching API endpoint)
$priorityColors = [
1 => 0xDC3545, // P1 Critical - Red
2 => 0xFD7E14, // P2 High - Orange
3 => 0x0DCAF0, // P3 Medium - Cyan
4 => 0x198754, // P4 Low - Green
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);
$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 = [
'title' => 'New Ticket Created',
'description' => "**#{$ticketId}** - {$title}",
'url' => $ticketUrl,
'color' => $color,
'fields' => [
[
'name' => 'Priority',
'value' => $priorityLabel,
'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 | Manual Entry'
],
'timestamp' => date('c')
];
$payload = [
'embeds' => [$embed]
];
// Send webhook
$ch = curl_init($webhookUrl);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
$webhookResult = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$curlError = curl_error($ch);
curl_close($ch);
if ($curlError) {
error_log("Discord webhook cURL error: {$curlError}");
} elseif ($httpCode !== 204 && $httpCode !== 200) {
error_log("Discord webhook failed for ticket #{$ticketId}. HTTP Code: {$httpCode}");
}
}
}
?>