From 861eab805057002ad9e2e1ba3a4e4dd4b8a4976d Mon Sep 17 00:00:00 2001
From: headlessdev
Date: Wed, 23 Apr 2025 21:34:52 +0200
Subject: [PATCH] Test Notification Processing in agent
---
agent/main.go | 83 +++++++++++++++++++++++++++++
app/dashboard/settings/Settings.tsx | 44 +++++++++++----
components/ui/sonner.tsx | 25 +++++++++
package-lock.json | 26 ++++-----
package.json | 1 +
5 files changed, 154 insertions(+), 25 deletions(-)
create mode 100644 components/ui/sonner.tsx
diff --git a/agent/main.go b/agent/main.go
index db6ec11..d56885c 100644
--- a/agent/main.go
+++ b/agent/main.go
@@ -145,6 +145,16 @@ func main() {
}
}()
+ // Check for test notifications every 10 seconds
+ go func() {
+ testNotifTicker := time.NewTicker(10 * time.Second)
+ defer testNotifTicker.Stop()
+
+ for range testNotifTicker.C {
+ checkAndSendTestNotifications(db)
+ }
+ }()
+
appClient := &http.Client{
Timeout: 4 * time.Second,
}
@@ -735,3 +745,76 @@ func sendPushover(n Notification, message string) {
fmt.Printf("Pushover: ERROR status code: %d\n", resp.StatusCode)
}
}
+
+func checkAndSendTestNotifications(db *sql.DB) {
+ // Query for test notifications
+ rows, err := db.Query(`SELECT tn.id, tn."notificationId" FROM test_notification tn`)
+ if err != nil {
+ fmt.Printf("Error fetching test notifications: %v\n", err)
+ return
+ }
+ defer rows.Close()
+
+ // Process each test notification
+ var testIds []int
+ for rows.Next() {
+ var id, notificationId int
+ if err := rows.Scan(&id, ¬ificationId); err != nil {
+ fmt.Printf("Error scanning test notification: %v\n", err)
+ continue
+ }
+
+ // Add to list of IDs to delete
+ testIds = append(testIds, id)
+
+ // Find the notification configuration
+ notifMutex.RLock()
+ for _, n := range notifications {
+ if n.ID == notificationId {
+ // Send test notification
+ fmt.Printf("Sending test notification to notification ID %d\n", notificationId)
+ sendSpecificNotification(n, "Test notification from CoreControl")
+ }
+ }
+ notifMutex.RUnlock()
+ }
+
+ // Delete processed test notifications
+ if len(testIds) > 0 {
+ for _, id := range testIds {
+ _, err := db.Exec(`DELETE FROM test_notification WHERE id = $1`, id)
+ if err != nil {
+ fmt.Printf("Error deleting test notification (ID: %d): %v\n", id, err)
+ }
+ }
+ }
+}
+
+func sendSpecificNotification(n Notification, message string) {
+ switch n.Type {
+ case "email":
+ if n.SMTPHost.Valid && n.SMTPTo.Valid {
+ sendEmail(n, message)
+ }
+ case "telegram":
+ if n.TelegramToken.Valid && n.TelegramChatID.Valid {
+ sendTelegram(n, message)
+ }
+ case "discord":
+ if n.DiscordWebhook.Valid {
+ sendDiscord(n, message)
+ }
+ case "gotify":
+ if n.GotifyUrl.Valid && n.GotifyToken.Valid {
+ sendGotify(n, message)
+ }
+ case "ntfy":
+ if n.NtfyUrl.Valid && n.NtfyToken.Valid {
+ sendNtfy(n, message)
+ }
+ case "pushover":
+ if n.PushoverUrl.Valid && n.PushoverToken.Valid && n.PushoverUser.Valid {
+ sendPushover(n, message)
+ }
+ }
+}
diff --git a/app/dashboard/settings/Settings.tsx b/app/dashboard/settings/Settings.tsx
index 17bb44e..3d37a72 100644
--- a/app/dashboard/settings/Settings.tsx
+++ b/app/dashboard/settings/Settings.tsx
@@ -19,7 +19,9 @@ import axios from "axios"
import Cookies from "js-cookie"
import { Button } from "@/components/ui/button"
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"
-import { AlertCircle, Check, Palette, User, Bell, AtSign, Send, MessageSquare, Trash2 } from "lucide-react"
+import { AlertCircle, Check, Palette, User, Bell, AtSign, Send, MessageSquare, Trash2, Play } from "lucide-react"
+import { Toaster } from "@/components/ui/sonner"
+import { toast } from "sonner"
import {
AlertDialog,
@@ -254,6 +256,17 @@ export default function Settings() {
getNotificationText()
}, [])
+ const testNotification = async (id: number) => {
+ try {
+ const response = await axios.post("/api/notifications/test", {
+ notificationId: id,
+ })
+ toast.success("Notification will be sent in a few seconds.")
+ } catch (error: any) {
+ toast.error(error.response.data.error)
+ }
+ }
+
return (
@@ -763,15 +776,25 @@ export default function Settings() {
-
+
+
+
+
))
) : (
@@ -789,6 +812,7 @@ export default function Settings() {
)}
+
diff --git a/components/ui/sonner.tsx b/components/ui/sonner.tsx
new file mode 100644
index 0000000..957524e
--- /dev/null
+++ b/components/ui/sonner.tsx
@@ -0,0 +1,25 @@
+"use client"
+
+import { useTheme } from "next-themes"
+import { Toaster as Sonner, ToasterProps } from "sonner"
+
+const Toaster = ({ ...props }: ToasterProps) => {
+ const { theme = "system" } = useTheme()
+
+ return (
+
+ )
+}
+
+export { Toaster }
diff --git a/package-lock.json b/package-lock.json
index cad316a..a5822e9 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -43,6 +43,7 @@
"postcss-loader": "^8.1.1",
"react": "^19.0.0",
"react-dom": "^19.0.0",
+ "sonner": "^2.0.3",
"tailwind-merge": "^3.2.0",
"tw-animate-css": "^1.2.5"
},
@@ -4729,6 +4730,16 @@
"is-arrayish": "^0.3.1"
}
},
+ "node_modules/sonner": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/sonner/-/sonner-2.0.3.tgz",
+ "integrity": "sha512-njQ4Hht92m0sMqqHVDL32V2Oun9W1+PHO9NDv9FHfJjT3JT22IG4Jpo3FPQy+mouRKCXFWO+r67v6MrHX2zeIA==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": "^18.0.0 || ^19.0.0 || ^19.0.0-rc",
+ "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-rc"
+ }
+ },
"node_modules/source-map-js": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
@@ -5062,21 +5073,6 @@
"optional": true
}
}
- },
- "node_modules/@next/swc-win32-x64-msvc": {
- "version": "15.3.0",
- "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.3.0.tgz",
- "integrity": "sha512-vHUQS4YVGJPmpjn7r5lEZuMhK5UQBNBRSB+iGDvJjaNk649pTIcRluDWNb9siunyLLiu/LDPHfvxBtNamyuLTw==",
- "cpu": [
- "x64"
- ],
- "optional": true,
- "os": [
- "win32"
- ],
- "engines": {
- "node": ">= 10"
- }
}
}
}
diff --git a/package.json b/package.json
index 631d38e..400e829 100644
--- a/package.json
+++ b/package.json
@@ -44,6 +44,7 @@
"postcss-loader": "^8.1.1",
"react": "^19.0.0",
"react-dom": "^19.0.0",
+ "sonner": "^2.0.3",
"tailwind-merge": "^3.2.0",
"tw-animate-css": "^1.2.5"
},