From 3d88ae213295c16ba0e3bb08590062727fa59587 Mon Sep 17 00:00:00 2001 From: Andy Dixon Date: Mon, 26 Jan 2026 13:12:15 +0000 Subject: [PATCH] Added JSON parsing --- parsers/grafana.php | 422 ++++++++++++++++++++++++++++++++++++++++++++ parsers/json.php | 315 +++++++++++++++++++++++++++++++++ 2 files changed, 737 insertions(+) create mode 100644 parsers/grafana.php create mode 100644 parsers/json.php diff --git a/parsers/grafana.php b/parsers/grafana.php new file mode 100644 index 0000000..5e1e047 --- /dev/null +++ b/parsers/grafana.php @@ -0,0 +1,422 @@ + +
Alert Summary
+
+ + + +HTML; + + if ($truncatedAlerts > 0) { + $alertSummary .= << + + +
+HTML; + } + + if ($externalURL) { + $externalURLSafe = htmlspecialchars($externalURL, ENT_QUOTES, 'UTF-8'); + $alertSummary .= << +
Alertmanager URL
+
$externalURLSafe
+ +HTML; + } + + $alertSummary .= << + +HTML; + + // Build common labels section + $labelsContent = ''; + if (!empty($groupLabels) || !empty($commonLabels)) { + $labelsContent .= '
Labels
'; + + if (!empty($groupLabels)) { + $labelsContent .= '
Group Labels
+HTML; + } + $labelsContent .= '
'; + } + + if (!empty($commonLabels)) { + $labelsContent .= '
Common Labels
'; + foreach ($commonLabels as $key => $value) { + $keySafe = htmlspecialchars($key, ENT_QUOTES, 'UTF-8'); + $valueSafe = htmlspecialchars($value, ENT_QUOTES, 'UTF-8'); + $labelsContent .= << + + +
+HTML; + } + $labelsContent .= ''; + } + + $labelsContent .= ''; + } + + // Build common annotations section + $annotationsContent = ''; + if (!empty($commonAnnotations)) { + $annotationsContent .= '
Common Annotations
+HTML; + } + $annotationsContent .= '
'; + } + + // Build individual alerts section + $alertsContent = ''; + if (!empty($alerts)) { + $alertsContent .= '
Alerts
'; + + foreach ($alerts as $index => $alert) { + $alertStatus = $alert['status'] ?? 'unknown'; + $alertLabels = $alert['labels'] ?? []; + $alertAnnotations = $alert['annotations'] ?? []; + $startsAt = $alert['startsAt'] ?? null; + $endsAt = $alert['endsAt'] ?? null; + $generatorURL = $alert['generatorURL'] ?? null; + $fingerprint = $alert['fingerprint'] ?? null; + + $alertStatusSafe = htmlspecialchars($alertStatus, ENT_QUOTES, 'UTF-8'); + $alertNumber = $index + 1; + + // Choose alert icon + $alertIcon = '🔔'; + $alertColor = '#666666'; + if ($alertStatus === 'firing') { + $alertIcon = '🔥'; + $alertColor = '#dc3545'; + } elseif ($alertStatus === 'resolved') { + $alertIcon = '✅'; + $alertColor = '#28a745'; + } + + $alertsContent .= << +
$alertIcon Alert $alertNumber - $alertStatusSafe
+
Labels
+HTML; + } + $alertsContent .= '
'; + } + + // Add alert annotations + if (!empty($alertAnnotations)) { + $alertsContent .= '
Annotations
'; + foreach ($alertAnnotations as $key => $value) { + $keySafe = htmlspecialchars($key, ENT_QUOTES, 'UTF-8'); + $valueSafe = htmlspecialchars($value, ENT_QUOTES, 'UTF-8'); + $alertsContent .= << + + +
+HTML; + } + $alertsContent .= '
'; + } + + // Add timing and metadata + if ($startsAt) { + $startsAtSafe = htmlspecialchars($startsAt, ENT_QUOTES, 'UTF-8'); + $alertsContent .= << + + +
+HTML; + } + + if ($endsAt) { + $endsAtSafe = htmlspecialchars($endsAt, ENT_QUOTES, 'UTF-8'); + $alertsContent .= << +
Ended At
+
$endsAtSafe
+ +HTML; + } + + if ($generatorURL) { + $generatorURLSafe = htmlspecialchars($generatorURL, ENT_QUOTES, 'UTF-8'); + $alertsContent .= << +
Generator URL
+
$generatorURLSafe
+ +HTML; + } + + if ($fingerprint) { + $fingerprintSafe = htmlspecialchars($fingerprint, ENT_QUOTES, 'UTF-8'); + $alertsContent .= << +
Fingerprint
+
$fingerprintSafe
+ +HTML; + } + + $alertsContent .= ''; + } + + $alertsContent .= ''; + } + + $html = << + + + + + Grafana Alert - $statusSafe + + + +
+
+

$statusIcon Grafana Alert: $statusSafe

+

$dateSafe

+
+ + $alertSummary + + $labelsContent + + $annotationsContent + + $alertsContent + +
+
📋 Request Information
+ +
+ + +
+ + +HTML; + + // Create subject line + $alertCountText = $alertCount === 1 ? '1 alert' : "$alertCount alerts"; + $subject = "$statusIcon Grafana Alert: $statusSafe - $alertCountText"; + + return [ + 'html' => $html, + 'subject' => $subject + ]; +} diff --git a/parsers/json.php b/parsers/json.php new file mode 100644 index 0000000..c10b1d9 --- /dev/null +++ b/parsers/json.php @@ -0,0 +1,315 @@ + + + + + + JSON Webhook Data + + + +
+
+

📊 JSON Webhook Data

+

$dateSafe

+
+ +
+
📋 Request Information
+ +
+ +
+
📦 JSON Data
+ +HTML; + + // Process the JSON data + $html .= renderJsonData($payload); + + $html .= << + + +
+ + +HTML; + + $subject = "📊 JSON Webhook - " . $metadata['date']; + + return [ + 'html' => $html, + 'subject' => $subject + ]; +} + +/** + * Recursively render JSON data as tables + * Sub-arrays are extracted into separate tables with path-based titles + * + * @param mixed $data The data to render + * @param string $path The current path (e.g., "Foo->Bar->Baz") + * @return string HTML representation + */ +function renderJsonData($data, $path = '') { + $html = ''; + + if (!is_array($data)) { + $safe = htmlspecialchars((string)$data, ENT_QUOTES, 'UTF-8'); + return ""; + } + + // Check if it's an indexed array (numeric keys in sequence) + $isIndexedArray = array_keys($data) === range(0, count($data) - 1); + + if ($isIndexedArray && count($data) > 0) { + // It's an array of items + foreach ($data as $index => $item) { + $itemPath = $path ? $path . '->[' . $index . ']' : '[' . $index . ']'; + + if (is_array($item)) { + // Check if this item has any sub-arrays + $subArrays = []; + $simpleData = []; + + foreach ($item as $key => $value) { + if (is_array($value)) { + $subArrays[$key] = $value; + } else { + $simpleData[$key] = $value; + } + } + + // Render simple data for this item + if (!empty($simpleData)) { + if ($path) { + $html .= '
' . htmlspecialchars($itemPath, ENT_QUOTES, 'UTF-8') . '
'; + } + + $html .= '
'; + $html .= '
Item ' . ($index + 1) . '
'; + $html .= ''; + $html .= '
'; + } + + // Recursively render sub-arrays as separate tables + foreach ($subArrays as $key => $value) { + $subPath = $itemPath . '->' . $key; + $html .= renderJsonData($value, $subPath); + } + } else { + // Simple value in array + $valueSafe = htmlspecialchars((string)$item, ENT_QUOTES, 'UTF-8'); + $html .= ''; + } + } + } else { + // It's an associative array (object-like) + // Separate simple values from arrays + $subArrays = []; + $simpleData = []; + + foreach ($data as $key => $value) { + if (is_array($value)) { + $subArrays[$key] = $value; + } else { + $simpleData[$key] = $value; + } + } + + // Render simple key-value pairs + if (!empty($simpleData)) { + if ($path) { + $html .= '
' . htmlspecialchars($path, ENT_QUOTES, 'UTF-8') . '
'; + } + + $html .= ''; + } + + // Recursively render sub-arrays as separate tables with path titles + foreach ($subArrays as $key => $value) { + $subPath = $path ? $path . '->' . $key : $key; + $html .= renderJsonData($value, $subPath); + } + } + + return $html; +}