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" },