From dde54a4e4540a9b057780779c617322cba3fee10 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Mon, 19 Jan 2026 22:18:17 +0000 Subject: [PATCH] remove old service --- server/src/config/services.ts | 7 - .../infrastructure/notificationService.js | 128 ----------- .../infrastructure/notificationUtils.js | 205 ------------------ 3 files changed, 340 deletions(-) delete mode 100644 server/src/service/infrastructure/notificationService.js delete mode 100644 server/src/service/infrastructure/notificationUtils.js diff --git a/server/src/config/services.ts b/server/src/config/services.ts index 953fc5a1a..9ae5ecb12 100644 --- a/server/src/config/services.ts +++ b/server/src/config/services.ts @@ -5,7 +5,6 @@ import MongoDB from "../db/MongoDB.js"; import NetworkService from "../service/infrastructure/networkService.js"; import EmailService from "../service/infrastructure/emailService.js"; import BufferService from "../service/infrastructure/bufferService.js"; -import NotificationUtils from "../service/infrastructure/notificationUtils.js"; import { NotificationsService, StatusService, @@ -222,12 +221,6 @@ export const initializeServices = async ({ const statusService = new StatusService({ db, logger, buffer: bufferService, monitorsRepository }); - const notificationUtils = new NotificationUtils({ - stringService, - emailService, - settingsService, - }); - const webhookProvider = new WebhookProvider(logger); const slackProvider = new SlackProvider(logger); const emailProvider = new EmailProvider(emailService, logger); diff --git a/server/src/service/infrastructure/notificationService.js b/server/src/service/infrastructure/notificationService.js deleted file mode 100644 index 8c6fb063f..000000000 --- a/server/src/service/infrastructure/notificationService.js +++ /dev/null @@ -1,128 +0,0 @@ -const SERVICE_NAME = "NotificationService"; -import Matrix from "./notificationProviders/matrix.js"; - -class NotificationService { - static SERVICE_NAME = SERVICE_NAME; - - constructor({ emailService, db, logger, networkService, stringService, notificationUtils }) { - this.emailService = emailService; - this.db = db; - this.logger = logger; - this.networkService = networkService; - this.stringService = stringService; - this.notificationUtils = notificationUtils; - } - - get serviceName() { - return NotificationService.SERVICE_NAME; - } - - sendNotification = async ({ notification, subject, content, html, discordContent = null, webhookBody = null }) => { - const { type, address } = notification; - - if (type === "email") { - const messageId = await this.emailService.sendEmail(address, subject, html); - if (!messageId) return false; - return true; - } - - // Create a body for webhooks - let body = { text: content }; - if (type === "discord") { - body = !discordContent ? { content } : discordContent; - } - if (type === "webhook") { - body = !webhookBody ? { content } : webhookBody; - } - if (type === "slack" || type === "discord" || type === "webhook") { - const response = await this.networkService.requestWebhook(type, address, body); - return response.status; - } - if (type === "pager_duty") { - const response = await this.networkService.requestPagerDuty({ - message: content, - monitorUrl: subject, - routingKey: address, - }); - - return response; - } - if (type === "matrix") { - const { friendlyName, homeserverUrl, accessToken, roomId } = notification; - const monitorName = subject; - const message = content; - const matrix = new Matrix({ networkService: this.networkService, logger: this.logger }); - const success = await matrix.send({ friendlyName, homeserverUrl, accessToken, roomId, message, monitorName }); - return success; - } - }; - - async handleNotifications(networkResponse) { - const { monitor, statusChanged, prevStatus } = networkResponse; - const { type } = monitor; - if (type !== "hardware" && statusChanged === false) return false; - // if prevStatus is undefined, monitor is resuming, we're done - if (type !== "hardware" && prevStatus === undefined) return false; - - const notificationIDs = networkResponse.monitor?.notifications ?? []; - if (notificationIDs.length === 0) return false; - if (networkResponse.monitor.type === "hardware") { - const thresholds = networkResponse?.monitor?.thresholds; - - if (thresholds === undefined) return false; // No thresholds set, we're done - const metrics = networkResponse?.payload?.data ?? null; - if (metrics === null) return false; // No metrics, we're done - - const [alerts, discordContent] = await this.notificationUtils.buildHardwareAlerts(networkResponse); - if (alerts.length === 0) return false; - - const { subject, html } = await this.notificationUtils.buildHardwareEmail(networkResponse, alerts); - const content = await this.notificationUtils.buildHardwareNotificationMessage(alerts, monitor); - const webhookBody = await this.notificationUtils.buildHardwareWebhookBody(alerts, monitor); - const success = await this.notifyAll({ notificationIDs, subject, html, content, discordContent, webhookBody }); - return success; - } - - // Status monitors - const { subject, html } = await this.notificationUtils.buildStatusEmail(networkResponse); - const [content, discordContent] = await this.notificationUtils.buildWebhookMessage(networkResponse); - const success = this.notifyAll({ notificationIDs, subject, html, content, discordContent }); - return success; - } - - async notifyAll({ notificationIDs, subject, html, content, discordContent = null, webhookBody = null }) { - const notifications = await this.db.notificationModule.getNotificationsByIds(notificationIDs); - // Map each notification to a test promise - const promises = notifications.map(async (notification) => { - try { - await this.sendNotification({ notification, subject, content, html, discordContent, webhookBody }); - return true; - } catch (err) { - return false; - } - }); - - const results = await Promise.all(promises); - return results.every((r) => r === true); - } - - async getTestNotification() { - const html = await this.notificationUtils.buildTestEmail(); - const content = "This is a test notification"; - const subject = "Test Notification"; - return { subject, html, content }; - } - - async testAllNotifications(notificationIDs) { - const { subject, html, content } = await this.getTestNotification(); - return this.notifyAll({ notificationIDs, subject, html, content }); - } - - async sendTestNotification(notification) { - const { subject, html, content } = await this.getTestNotification(); - const success = await this.sendNotification({ notification, subject, content, html }); - return success; - } -} - -export default NotificationService; diff --git a/server/src/service/infrastructure/notificationUtils.js b/server/src/service/infrastructure/notificationUtils.js deleted file mode 100644 index 106c8f349..000000000 --- a/server/src/service/infrastructure/notificationUtils.js +++ /dev/null @@ -1,205 +0,0 @@ -const SERVICE_NAME = "NotificationUtils"; - -class NotificationUtils { - static SERVICE_NAME = SERVICE_NAME; - - constructor({ stringService, emailService, settingsService }) { - this.stringService = stringService; - this.emailService = emailService; - this.settingsService = settingsService; - } - - get serviceName() { - return NotificationUtils.SERVICE_NAME; - } - - buildTestEmail = async () => { - const context = { testName: "Monitoring System" }; - const html = await this.emailService.buildEmail("testEmailTemplate", context); - return html; - }; - - buildStatusEmail = async (networkResponse) => { - const { monitor, status, prevStatus } = networkResponse; - const template = prevStatus === false ? "serverIsUpTemplate" : "serverIsDownTemplate"; - const context = { monitor: monitor.name, url: monitor.url }; - const subject = `Monitor ${monitor.name} is ${status === true ? "up" : "down"}`; - const html = await this.emailService.buildEmail(template, context); - return { subject, html }; - }; - - buildWebhookMessage = (networkResponse) => { - const { monitor, status, code, timestamp } = networkResponse; - // Format timestamp using the local system timezone - const formatTime = (timestamp) => { - const date = new Date(timestamp); - - // Get timezone abbreviation and format the date - const timeZoneAbbr = date.toLocaleTimeString("en-US", { timeZoneName: "short" }).split(" ").pop(); - - // Format the date with readable format - return ( - date - .toLocaleString("en-US", { - year: "numeric", - month: "2-digit", - day: "2-digit", - hour: "2-digit", - minute: "2-digit", - second: "2-digit", - hour12: false, - }) - .replace(/(\d+)\/(\d+)\/(\d+),\s/, "$3-$1-$2 ") + - " " + - timeZoneAbbr - ); - }; - - // Get formatted time - const formattedTime = timestamp ? formatTime(timestamp) : formatTime(new Date().getTime()); - - // Create different messages based on status with extra spacing - let messageText; - if (status === true) { - messageText = this.stringService.monitorUpAlert - .replace("{monitorName}", monitor.name) - .replace("{time}", formattedTime) - .replace("{code}", code || "Unknown"); - } else { - messageText = this.stringService.monitorDownAlert - .replace("{monitorName}", monitor.name) - .replace("{time}", formattedTime) - .replace("{code}", code || "Unknown"); - } - const dn = this.stringService.discordNotification; - let discordMessageText = { - embeds: [ - { - title: status - ? dn.uptimeAlert.replace("{monitorName}", monitor?.name ?? dn.unknown) - : dn.downtimeAlert.replace("{monitorName}", monitor?.name ?? dn.unknown), - color: status ? 5763719 : 15548997, - - fields: [ - { name: dn.monitor, value: monitor?.name ?? dn.unknown, inline: true }, - { name: dn.status, value: status ? dn.up : dn.down, inline: true }, - { name: dn.statusCode, value: String(code ?? dn.unknown), inline: true }, - { name: dn.time, value: formattedTime, inline: true }, - { name: dn.url, value: monitor?.url ?? dn.unknown, inline: false }, - ], - footer: { text: dn.checkmate }, - }, - ], - }; - return [messageText, discordMessageText]; - }; - - buildHardwareAlerts = async (networkResponse) => { - const monitor = networkResponse?.monitor; - const thresholds = networkResponse?.monitor?.thresholds; - const { usage_cpu: cpuThreshold = -1, usage_memory: memoryThreshold = -1, usage_disk: diskThreshold = -1 } = thresholds; - - const metrics = networkResponse?.payload?.data; - const { cpu: { usage_percent: cpuUsage = -1 } = {}, memory: { usage_percent: memoryUsage = -1 } = {}, disk = [] } = metrics; - - const { clientHost } = this.settingsService.getSettings(); - - const alerts = { - cpu: cpuThreshold !== -1 && cpuUsage > cpuThreshold ? true : false, - memory: memoryThreshold !== -1 && memoryUsage > memoryThreshold ? true : false, - disk: disk?.some((d) => diskThreshold !== -1 && typeof d?.usage_percent === "number" && d?.usage_percent > diskThreshold) ?? false, - }; - - const alertsToSend = []; - const discordEmbeds = []; - const monitorInfoFields = [ - { name: "Monitor", value: monitor.name, inline: true }, - { name: "URL", value: monitor.url, inline: false }, - ]; - const goToIncidentField = { name: `Go to incident`, value: `${clientHost}/infrastructure/${monitor._id}` }; - const formatDiscordAlert = { - cpu: () => ({ - title: "CPU alert", - description: `Your current CPU usage (${(cpuUsage * 100).toFixed(0)}%) is above your threshold (${(cpuThreshold * 100).toFixed(0)}%)`, - color: 15548997, - fields: [...monitorInfoFields, goToIncidentField], - footer: { text: "Checkmate" }, - }), - - memory: () => ({ - title: "Memory alert", - description: `Your current memory usage (${(memoryUsage * 100).toFixed(0)}%) is above your threshold (${(memoryThreshold * 100).toFixed(0)}%)`, - color: 15548997, - fields: [...monitorInfoFields, goToIncidentField], - footer: { text: "Checkmate" }, - }), - - disk: () => ({ - title: "Disk alert", - description: `Your current disk usage is above your threshold (${(diskThreshold * 100).toFixed(0)}%)`, - color: 15548997, - footer: { text: "Checkmate" }, - fields: [ - ...monitorInfoFields, - ...(Array.isArray(disk) ? disk : []).map((d, idx) => ({ - name: `Disk ${idx}`, - value: `${(d?.usage_percent * 100).toFixed(0)}%`, - inline: true, - })), - goToIncidentField, - ], - }), - }; - const alertTypes = ["cpu", "memory", "disk"]; - for (const type of alertTypes) { - // Iterate over each alert type to see if any need to be decremented - if (alerts[type] === true) { - monitor[`${type}AlertThreshold`]--; // Decrement threshold if an alert is triggered - - if (monitor[`${type}AlertThreshold`] <= 0) { - // If threshold drops below 0, reset and send notification - monitor[`${type}AlertThreshold`] = monitor.alertThreshold; - - const formatAlert = { - cpu: () => `Your current CPU usage (${(cpuUsage * 100).toFixed(0)}%) is above your threshold (${(cpuThreshold * 100).toFixed(0)}%)`, - memory: () => - `Your current memory usage (${(memoryUsage * 100).toFixed(0)}%) is above your threshold (${(memoryThreshold * 100).toFixed(0)}%)`, - disk: () => - `Your current disk usage: ${disk - .map((d, idx) => `(Disk${idx}: ${(d.usage_percent * 100).toFixed(0)}%)`) - .join(", ")} is above your threshold (${(diskThreshold * 100).toFixed(0)}%)`, - }; - alertsToSend.push(formatAlert[type]()); - discordEmbeds.push(formatDiscordAlert[type]()); - } - } - } - await monitor.save(); - const discordPayload = discordEmbeds.length ? { embeds: discordEmbeds } : null; - return [alertsToSend, discordPayload]; - }; - - buildHardwareEmail = async (networkResponse, alerts) => { - const { monitor } = networkResponse; - const template = "hardwareIncidentTemplate"; - const context = { monitor: monitor.name, url: monitor.url, alerts }; - const subject = `Monitor ${monitor.name} infrastructure alerts`; - const html = await this.emailService.buildEmail(template, context); - return { subject, html }; - }; - - buildHardwareNotificationMessage = (alerts, monitor) => { - const { clientHost } = this.settingsService.getSettings(); - const alertsHeader = [`Monitor: ${monitor.name}`, `URL: ${monitor.url}`]; - const alertFooter = [`Go to incident: ${clientHost}/infrastructure/${monitor._id}`]; - const alertText = alerts.length > 0 ? [...alertsHeader, ...alerts, ...alertFooter] : []; - return alertText.map((alert) => alert).join("\n"); - }; - buildHardwareWebhookBody = (alerts, monitor) => { - const content = alerts.map((alert) => alert).join("\n"); - const body = { text: content, name: monitor.name, url: monitor.url }; - return body; - }; -} - -export default NotificationUtils;