diff --git a/internal/notifications/notifications.go b/internal/notifications/notifications.go index 02b19380d..e8c26a93e 100644 --- a/internal/notifications/notifications.go +++ b/internal/notifications/notifications.go @@ -625,8 +625,62 @@ func (n *NotificationManager) sendWebhookRequest(webhook WebhookConfig, jsonData // Set headers req.Header.Set("Content-Type", "application/json") req.Header.Set("User-Agent", "Pulse-Monitoring/2.0") + + // Special handling for ntfy service - add dynamic headers based on alert level + if webhook.Service == "ntfy" { + // Set Content-Type for ntfy (plain text) + req.Header.Set("Content-Type", "text/plain") + + // Set dynamic headers based on alert level + title := fmt.Sprintf("%s: %s", + func() string { + switch alert.Level { + case alerts.AlertLevelCritical: + return "🔴 CRITICAL" + case alerts.AlertLevelWarning: + return "🟡 WARNING" + default: + return "🟢 INFO" + } + }(), + alert.ResourceName, + ) + req.Header.Set("Title", title) + + priority := func() string { + switch alert.Level { + case alerts.AlertLevelCritical: + return "urgent" + case alerts.AlertLevelWarning: + return "high" + default: + return "default" + } + }() + req.Header.Set("Priority", priority) + + tags := fmt.Sprintf("%s,pulse,%s", + func() string { + switch alert.Level { + case alerts.AlertLevelCritical: + return "rotating_light" + case alerts.AlertLevelWarning: + return "warning" + default: + return "white_check_mark" + } + }(), + alert.Type, + ) + req.Header.Set("Tags", tags) + } + + // Apply any custom headers from webhook config (these override defaults) for key, value := range webhook.Headers { - req.Header.Set(key, value) + // Skip template-like headers (those with {{) + if !strings.Contains(value, "{{") { + req.Header.Set(key, value) + } } // Debug log the payload for Telegram and Gotify webhooks diff --git a/internal/notifications/webhook_templates.go b/internal/notifications/webhook_templates.go index 87a65fefe..3ca8d6fa1 100644 --- a/internal/notifications/webhook_templates.go +++ b/internal/notifications/webhook_templates.go @@ -284,9 +284,8 @@ func GetWebhookTemplates() []WebhookTemplate { Method: "POST", Headers: map[string]string{ "Content-Type": "text/plain", - "Title": "{{if eq .Level \"critical\"}}🔴 CRITICAL{{else if eq .Level \"warning\"}}🟡 WARNING{{else}}🟢 INFO{{end}}: {{.ResourceName}}", - "Priority": "{{if eq .Level \"critical\"}}urgent{{else if eq .Level \"warning\"}}high{{else}}default{{end}}", - "Tags": "{{if eq .Level \"critical\"}}rotating_light{{else if eq .Level \"warning\"}}warning{{else}}white_check_mark{{end}},pulse,{{.Type}}", + // Note: Title, Priority, and Tags headers should be added dynamically based on alert level + // For now, we'll use static reasonable defaults that won't break }, PayloadTemplate: `{{if eq .Level "critical"}}🔴 CRITICAL{{else if eq .Level "warning"}}🟡 WARNING{{else}}🟢 INFO{{end}}: {{.ResourceName}} on {{.Node}}