From 7f88aacbe735c3632a2d3664888e7a96f2c8e245 Mon Sep 17 00:00:00 2001 From: Thomas Spalinger Date: Thu, 23 Feb 2023 16:16:49 +0000 Subject: [PATCH 01/41] make monitor start() and stop() async --- server/model/monitor.js | 4 ++-- server/server.js | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/server/model/monitor.js b/server/model/monitor.js index 4bb859e9a..c7388607d 100644 --- a/server/model/monitor.js +++ b/server/model/monitor.js @@ -199,7 +199,7 @@ class Monitor extends BeanModel { * Start monitor * @param {Server} io Socket server instance */ - start(io) { + async start(io) { let previousBeat = null; let retries = 0; @@ -836,7 +836,7 @@ class Monitor extends BeanModel { } /** Stop monitor */ - stop() { + async stop() { clearTimeout(this.heartbeatInterval); this.isStop = true; diff --git a/server/server.js b/server/server.js index 18598171e..1dd012afa 100644 --- a/server/server.js +++ b/server/server.js @@ -872,7 +872,7 @@ let needSetup = false; log.info("manage", `Delete Monitor: ${monitorID} User ID: ${socket.userID}`); if (monitorID in server.monitorList) { - server.monitorList[monitorID].stop(); + await server.monitorList[monitorID].stop(); delete server.monitorList[monitorID]; } @@ -1694,11 +1694,11 @@ async function startMonitor(userID, monitorID) { ]); if (monitor.id in server.monitorList) { - server.monitorList[monitor.id].stop(); + await server.monitorList[monitor.id].stop(); } server.monitorList[monitor.id] = monitor; - monitor.start(io); + await monitor.start(io); } /** @@ -1728,7 +1728,7 @@ async function pauseMonitor(userID, monitorID) { ]); if (monitorID in server.monitorList) { - server.monitorList[monitorID].stop(); + await server.monitorList[monitorID].stop(); } } @@ -1741,7 +1741,7 @@ async function startMonitors() { } for (let monitor of list) { - monitor.start(io); + await monitor.start(io); // Give some delays, so all monitors won't make request at the same moment when just start the server. await sleep(getRandomInt(300, 1000)); } @@ -1762,7 +1762,7 @@ async function shutdownFunction(signal) { log.info("server", "Stopping all monitors"); for (let id in server.monitorList) { let monitor = server.monitorList[id]; - monitor.stop(); + await monitor.stop(); } await sleep(2000); await Database.close(); From 20b69acde21a44c202215963a49912f395e84429 Mon Sep 17 00:00:00 2001 From: Philip Klostermann Date: Tue, 23 Jan 2024 10:10:31 -0500 Subject: [PATCH 02/41] [Ntfy] Only include action link if monitor url is defined #3274 --- server/notification-providers/ntfy.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/server/notification-providers/ntfy.js b/server/notification-providers/ntfy.js index 86fc0e081..b51b0f238 100644 --- a/server/notification-providers/ntfy.js +++ b/server/notification-providers/ntfy.js @@ -54,14 +54,17 @@ class Ntfy extends NotificationProvider { "priority": priority, "title": monitorJSON.name + " " + status + " [Uptime-Kuma]", "tags": tags, - "actions": [ + }; + + if (monitorJSON.url) { + data.actions = [ { "action": "view", "label": "Open " + monitorJSON.name, "url": monitorJSON.url, - } - ] - }; + }, + ]; + } if (notification.ntfyIcon) { data.icon = notification.ntfyIcon; From 95125cc4172c2d196f99748fc3dac06a9285bc75 Mon Sep 17 00:00:00 2001 From: Philip Klostermann Date: Tue, 23 Jan 2024 11:16:10 -0500 Subject: [PATCH 03/41] [Ntfy] don't include url action with defaut URL value --- server/notification-providers/ntfy.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/notification-providers/ntfy.js b/server/notification-providers/ntfy.js index b51b0f238..12c9258b8 100644 --- a/server/notification-providers/ntfy.js +++ b/server/notification-providers/ntfy.js @@ -56,7 +56,7 @@ class Ntfy extends NotificationProvider { "tags": tags, }; - if (monitorJSON.url) { + if (monitorJSON.url && monitorJSON.url !== "https://") { data.actions = [ { "action": "view", From dc3abc68f0c90681727c7ea574a35f8588174108 Mon Sep 17 00:00:00 2001 From: Frank Elsinga Date: Tue, 30 Jan 2024 17:54:04 +0100 Subject: [PATCH 04/41] Fixed type anotation --- server/model/monitor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/model/monitor.js b/server/model/monitor.js index 30c631a75..0c322b92c 100644 --- a/server/model/monitor.js +++ b/server/model/monitor.js @@ -324,7 +324,7 @@ class Monitor extends BeanModel { /** * Start monitor * @param {Server} io Socket server instance - * @returns {void} + * @returns {Promise} */ async start(io) { let previousBeat = null; From 93ac212aef23f8bdb8a64968ecb6a6ca5f704407 Mon Sep 17 00:00:00 2001 From: Humberto Evans Date: Mon, 12 Feb 2024 15:58:54 -0800 Subject: [PATCH 05/41] Add Heii On-Call --- server/notification-providers/heii-oncall.js | 68 +++++++++++ server/notification.js | 40 ++++--- src/components/NotificationDialog.vue | 118 +++++++++++++++---- src/components/notifications/HeiiOnCall.vue | 35 ++++++ src/components/notifications/index.js | 108 ++++++++--------- src/lang/en.json | 3 +- 6 files changed, 283 insertions(+), 89 deletions(-) create mode 100644 server/notification-providers/heii-oncall.js create mode 100644 src/components/notifications/HeiiOnCall.vue diff --git a/server/notification-providers/heii-oncall.js b/server/notification-providers/heii-oncall.js new file mode 100644 index 000000000..7babd907e --- /dev/null +++ b/server/notification-providers/heii-oncall.js @@ -0,0 +1,68 @@ +const { UP, DOWN, getMonitorRelativeURL } = require("../../src/util"); +const { setting } = require("../util-server"); + +const NotificationProvider = require("./notification-provider"); +const axios = require("axios"); + +const heiiOnCallBaseUrl = "http://192.168.2.1:3005"; + +class HeiiOnCall extends NotificationProvider { + name = "HeiiOnCall"; + + /** + * @inheritdoc + */ + async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { + // Payload to Heii On-Call is the entire heartbat JSON + const payload = heartbeatJSON ? heartbeatJSON : {}; + + if (!heartbeatJSON) { + // Test button was clicked on Notification Setup, trigger the alert as a test + payload["message"] = "Testing UptimeKuma Trigger"; + return this.postNotification(notification, "alert", payload); + } + + // If we can add url back to mintor to payload + const baseURL = await setting("primaryBaseURL"); + if (baseURL && monitorJSON) { + payload["url"] = baseURL + getMonitorRelativeURL(monitorJSON.id); + } + + if (heartbeatJSON.status === DOWN) { + // Monitor is DOWN, alert on Heii On-Call + return this.postNotification(notification, "alert", payload); + } + + if (heartbeatJSON.status === UP) { + // Monitor is UP, resolve on Heii On-Call + return this.postNotification(notification, "resolve", payload); + } + } + + /** + * Post to Heii On-Call + * @param {BeanModel} notification Message title + * @param {string} action Trigger Action (alert, resovle) + * @param {object} payload Data for Heii On-Call + * @returns {Promise} Success message + */ + async postNotification(notification, action, payload) { + const config = { + headers: { + Accept: "application/json", + "Content-Type": "application/json", + Authorization: "Bearer " + notification.heiiOnCallApiKey, + }, + }; + + // Post to Heii On-Call Trigger https://heiioncall.com/docs#manual-triggers + await axios.post( + `${heiiOnCallBaseUrl}/triggers/${notification.heiiOnCallTriggerId}/${action}`, + payload, + config + ); + return "Sent Successfully."; + } +} + +module.exports = HeiiOnCall; diff --git a/server/notification.js b/server/notification.js index 5e76d6eb1..722cf90c2 100644 --- a/server/notification.js +++ b/server/notification.js @@ -16,6 +16,7 @@ const Gorush = require("./notification-providers/gorush"); const Gotify = require("./notification-providers/gotify"); const GrafanaOncall = require("./notification-providers/grafana-oncall"); const HomeAssistant = require("./notification-providers/home-assistant"); +const HeiiOnCall = require("./notification-providers/heii-oncall"); const Kook = require("./notification-providers/kook"); const Line = require("./notification-providers/line"); const LineNotify = require("./notification-providers/linenotify"); @@ -56,7 +57,6 @@ const ServerChan = require("./notification-providers/serverchan"); const ZohoCliq = require("./notification-providers/zoho-cliq"); class Notification { - providerList = {}; /** @@ -87,6 +87,7 @@ class Notification { new Gotify(), new GrafanaOncall(), new HomeAssistant(), + new HeiiOnCall(), new Kook(), new Line(), new LineNotify(), @@ -124,10 +125,10 @@ class Notification { new Webhook(), new WeCom(), new GoAlert(), - new ZohoCliq() + new ZohoCliq(), ]; for (let item of list) { - if (! item.name) { + if (!item.name) { throw new Error("Notification provider without name"); } @@ -147,9 +148,19 @@ class Notification { * @returns {Promise} Successful msg * @throws Error with fail msg */ - static async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { + static async send( + notification, + msg, + monitorJSON = null, + heartbeatJSON = null + ) { if (this.providerList[notification.type]) { - return this.providerList[notification.type].send(notification, msg, monitorJSON, heartbeatJSON); + return this.providerList[notification.type].send( + notification, + msg, + monitorJSON, + heartbeatJSON + ); } else { throw new Error("Notification type is not supported"); } @@ -171,10 +182,9 @@ class Notification { userID, ]); - if (! bean) { + if (!bean) { throw new Error("notification not found"); } - } else { bean = R.dispense("notification"); } @@ -204,7 +214,7 @@ class Notification { userID, ]); - if (! bean) { + if (!bean) { throw new Error("notification not found"); } @@ -220,7 +230,6 @@ class Notification { let exists = commandExistsSync("apprise"); return exists; } - } /** @@ -231,16 +240,17 @@ class Notification { */ async function applyNotificationEveryMonitor(notificationID, userID) { let monitors = await R.getAll("SELECT id FROM monitor WHERE user_id = ?", [ - userID + userID, ]); for (let i = 0; i < monitors.length; i++) { - let checkNotification = await R.findOne("monitor_notification", " monitor_id = ? AND notification_id = ? ", [ - monitors[i].id, - notificationID, - ]); + let checkNotification = await R.findOne( + "monitor_notification", + " monitor_id = ? AND notification_id = ? ", + [monitors[i].id, notificationID] + ); - if (! checkNotification) { + if (!checkNotification) { let relation = R.dispense("monitor_notification"); relation.monitor_id = monitors[i].id; relation.notification_id = notificationID; diff --git a/src/components/NotificationDialog.vue b/src/components/NotificationDialog.vue index 57a2fdf2d..4a16fdf3e 100644 --- a/src/components/NotificationDialog.vue +++ b/src/components/NotificationDialog.vue @@ -1,62 +1,132 @@ @@ -121,6 +197,7 @@ export default { "gotify": "Gotify", "GrafanaOncall": "Grafana Oncall", "HomeAssistant": "Home Assistant", + "HeiiOnCall": "Heii On-Call", "Kook": "Kook", "line": "LINE Messenger", "LineNotify": "LINE Notify", @@ -330,7 +407,8 @@ export default { @import "../assets/vars.scss"; .dark { - .modal-dialog .form-text, .modal-dialog p { + .modal-dialog .form-text, + .modal-dialog p { color: $dark-font-color; } } diff --git a/src/components/notifications/HeiiOnCall.vue b/src/components/notifications/HeiiOnCall.vue new file mode 100644 index 000000000..f773dbaef --- /dev/null +++ b/src/components/notifications/HeiiOnCall.vue @@ -0,0 +1,35 @@ + + + diff --git a/src/components/notifications/index.js b/src/components/notifications/index.js index 0606d41af..c71736a79 100644 --- a/src/components/notifications/index.js +++ b/src/components/notifications/index.js @@ -14,6 +14,7 @@ import Gorush from "./Gorush.vue"; import Gotify from "./Gotify.vue"; import GrafanaOncall from "./GrafanaOncall.vue"; import HomeAssistant from "./HomeAssistant.vue"; +import HeiiOnCall from "./HeiiOnCall.vue"; import Kook from "./Kook.vue"; import Line from "./Line.vue"; import LineNotify from "./LineNotify.vue"; @@ -58,60 +59,61 @@ import Splunk from "./Splunk.vue"; * @type { Record } */ const NotificationFormList = { - "alerta": Alerta, - "AlertNow": AlertNow, - "AliyunSMS": AliyunSMS, - "apprise": Apprise, - "Bark": Bark, - "clicksendsms": ClickSendSMS, - "smsc": SMSC, - "DingDing": DingDing, - "discord": Discord, - "Feishu": Feishu, - "FreeMobile": FreeMobile, - "GoogleChat": GoogleChat, - "gorush": Gorush, - "gotify": Gotify, - "GrafanaOncall": GrafanaOncall, - "HomeAssistant": HomeAssistant, - "Kook": Kook, - "line": Line, - "LineNotify": LineNotify, - "lunasea": LunaSea, - "matrix": Matrix, - "mattermost": Mattermost, - "nostr": Nostr, - "ntfy": Ntfy, - "octopush": Octopush, - "OneBot": OneBot, - "Opsgenie": Opsgenie, - "PagerDuty": PagerDuty, - "FlashDuty": FlashDuty, - "PagerTree": PagerTree, - "promosms": PromoSMS, - "pushbullet": Pushbullet, - "PushByTechulus": TechulusPush, - "PushDeer": PushDeer, - "pushover": Pushover, - "pushy": Pushy, + alerta: Alerta, + AlertNow: AlertNow, + AliyunSMS: AliyunSMS, + apprise: Apprise, + Bark: Bark, + clicksendsms: ClickSendSMS, + smsc: SMSC, + DingDing: DingDing, + discord: Discord, + Feishu: Feishu, + FreeMobile: FreeMobile, + GoogleChat: GoogleChat, + gorush: Gorush, + gotify: Gotify, + GrafanaOncall: GrafanaOncall, + HomeAssistant: HomeAssistant, + HeiiOnCall: HeiiOnCall, + Kook: Kook, + line: Line, + LineNotify: LineNotify, + lunasea: LunaSea, + matrix: Matrix, + mattermost: Mattermost, + nostr: Nostr, + ntfy: Ntfy, + octopush: Octopush, + OneBot: OneBot, + Opsgenie: Opsgenie, + PagerDuty: PagerDuty, + FlashDuty: FlashDuty, + PagerTree: PagerTree, + promosms: PromoSMS, + pushbullet: Pushbullet, + PushByTechulus: TechulusPush, + PushDeer: PushDeer, + pushover: Pushover, + pushy: Pushy, "rocket.chat": RocketChat, - "serwersms": SerwerSMS, - "signal": Signal, - "SMSManager": SMSManager, - "slack": Slack, - "squadcast": Squadcast, - "SMSEagle": SMSEagle, - "smtp": STMP, - "stackfield": Stackfield, - "teams": Teams, - "telegram": Telegram, - "twilio": Twilio, - "Splunk": Splunk, - "webhook": Webhook, - "WeCom": WeCom, - "GoAlert": GoAlert, - "ServerChan": ServerChan, - "ZohoCliq": ZohoCliq + serwersms: SerwerSMS, + signal: Signal, + SMSManager: SMSManager, + slack: Slack, + squadcast: Squadcast, + SMSEagle: SMSEagle, + smtp: STMP, + stackfield: Stackfield, + teams: Teams, + telegram: Telegram, + twilio: Twilio, + Splunk: Splunk, + webhook: Webhook, + WeCom: WeCom, + GoAlert: GoAlert, + ServerChan: ServerChan, + ZohoCliq: ZohoCliq, }; export default NotificationFormList; diff --git a/src/lang/en.json b/src/lang/en.json index 0f59e62ae..c81403d06 100644 --- a/src/lang/en.json +++ b/src/lang/en.json @@ -883,5 +883,6 @@ "deleteRemoteBrowserMessage": "Are you sure want to delete this Remote Browser for all monitors?", "GrafanaOncallUrl": "Grafana Oncall URL", "Browser Screenshot": "Browser Screenshot", - "What is a Remote Browser?": "What is a Remote Browser?" + "What is a Remote Browser?": "What is a Remote Browser?", + "Trigger ID": "Trigger ID" } From e8fada938675d5b7655291492d0d22382365737b Mon Sep 17 00:00:00 2001 From: Humberto Evans Date: Mon, 12 Feb 2024 16:14:41 -0800 Subject: [PATCH 06/41] set url to heii on call prod --- server/notification-providers/heii-oncall.js | 23 ++++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/server/notification-providers/heii-oncall.js b/server/notification-providers/heii-oncall.js index 7babd907e..6332fee85 100644 --- a/server/notification-providers/heii-oncall.js +++ b/server/notification-providers/heii-oncall.js @@ -4,7 +4,7 @@ const { setting } = require("../util-server"); const NotificationProvider = require("./notification-provider"); const axios = require("axios"); -const heiiOnCallBaseUrl = "http://192.168.2.1:3005"; +const heiiOnCallBaseUrl = "https://heiioncall.com"; class HeiiOnCall extends NotificationProvider { name = "HeiiOnCall"; @@ -22,7 +22,7 @@ class HeiiOnCall extends NotificationProvider { return this.postNotification(notification, "alert", payload); } - // If we can add url back to mintor to payload + // If we can, add url back to mintor to payload const baseURL = await setting("primaryBaseURL"); if (baseURL && monitorJSON) { payload["url"] = baseURL + getMonitorRelativeURL(monitorJSON.id); @@ -42,7 +42,7 @@ class HeiiOnCall extends NotificationProvider { /** * Post to Heii On-Call * @param {BeanModel} notification Message title - * @param {string} action Trigger Action (alert, resovle) + * @param {string} action Trigger action (alert, resovle) * @param {object} payload Data for Heii On-Call * @returns {Promise} Success message */ @@ -56,12 +56,17 @@ class HeiiOnCall extends NotificationProvider { }; // Post to Heii On-Call Trigger https://heiioncall.com/docs#manual-triggers - await axios.post( - `${heiiOnCallBaseUrl}/triggers/${notification.heiiOnCallTriggerId}/${action}`, - payload, - config - ); - return "Sent Successfully."; + try { + await axios.post( + `${heiiOnCallBaseUrl}/triggers/${notification.heiiOnCallTriggerId}/${action}`, + payload, + config + ); + } catch (error) { + this.throwGeneralAxiosError(error); + } + + return "Heii On-Call post sent successfully."; } } From 80bdc455da6cd255ee95d5714ae803dab3bec8a2 Mon Sep 17 00:00:00 2001 From: Humberto Evans Date: Mon, 12 Feb 2024 16:31:58 -0800 Subject: [PATCH 07/41] lint --- server/notification.js | 2 +- src/components/notifications/HeiiOnCall.vue | 12 ++++-------- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/server/notification.js b/server/notification.js index 722cf90c2..71310b000 100644 --- a/server/notification.js +++ b/server/notification.js @@ -247,7 +247,7 @@ async function applyNotificationEveryMonitor(notificationID, userID) { let checkNotification = await R.findOne( "monitor_notification", " monitor_id = ? AND notification_id = ? ", - [monitors[i].id, notificationID] + [ monitors[i].id, notificationID ] ); if (!checkNotification) { diff --git a/src/components/notifications/HeiiOnCall.vue b/src/components/notifications/HeiiOnCall.vue index f773dbaef..64c0a9e09 100644 --- a/src/components/notifications/HeiiOnCall.vue +++ b/src/components/notifications/HeiiOnCall.vue @@ -1,9 +1,7 @@