diff --git a/extra/reset-password.js b/extra/reset-password.js index 3b40e93e..b87d90f1 100644 --- a/extra/reset-password.js +++ b/extra/reset-password.js @@ -8,6 +8,7 @@ const User = require("../server/model/user"); const { io } = require("socket.io-client"); const { localWebSocketURL } = require("../server/config"); const args = require("args-parser")(process.argv); + const rl = readline.createInterface({ input: process.stdin, output: process.stdout @@ -19,10 +20,10 @@ const main = async () => { } console.log("Connecting the database"); - Database.initDataDir(args); - await Database.connect(false, false, true); try { + Database.initDataDir(args); + await Database.connect(false, false, true); // No need to actually reset the password for testing, just make sure no connection problem. It is ok for now. if (!process.env.TEST_BACKEND) { const user = await R.findOne("user"); diff --git a/server/model/monitor.js b/server/model/monitor.js index 8f3aef8c..1667b83a 100644 --- a/server/model/monitor.js +++ b/server/model/monitor.js @@ -328,9 +328,9 @@ class Monitor extends BeanModel { /** * Start monitor * @param {Server} io Socket server instance - * @returns {void} + * @returns {Promise} */ - start(io) { + async start(io) { let previousBeat = null; let retries = 0; @@ -1102,9 +1102,9 @@ class Monitor extends BeanModel { /** * Stop monitor - * @returns {void} + * @returns {Promise} */ - stop() { + async stop() { clearTimeout(this.heartbeatInterval); this.isStop = true; diff --git a/server/monitor-types/monitor-type.js b/server/monitor-types/monitor-type.js index 782bedd5..eb75307b 100644 --- a/server/monitor-types/monitor-type.js +++ b/server/monitor-types/monitor-type.js @@ -1,5 +1,4 @@ class MonitorType { - name = undefined; /** diff --git a/server/monitor-types/mqtt.js b/server/monitor-types/mqtt.js index cff5c93d..9b2db43d 100644 --- a/server/monitor-types/mqtt.js +++ b/server/monitor-types/mqtt.js @@ -81,7 +81,8 @@ class MqttMonitorType extends MonitorType { let client = mqtt.connect(mqttUrl, { username, - password + password, + clientId: "uptime-kuma_" + Math.random().toString(16).substr(2, 8) }); client.on("connect", () => { diff --git a/server/notification-providers/alerta.js b/server/notification-providers/alerta.js index 62092178..f9a273b4 100644 --- a/server/notification-providers/alerta.js +++ b/server/notification-providers/alerta.js @@ -3,17 +3,15 @@ const { DOWN, UP } = require("../../src/util"); const axios = require("axios"); class Alerta extends NotificationProvider { - name = "alerta"; /** * @inheritdoc */ async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { - let okMsg = "Sent Successfully."; + const okMsg = "Sent Successfully."; try { - let alertaUrl = `${notification.alertaApiEndpoint}`; let config = { headers: { "Content-Type": "application/json;charset=UTF-8", @@ -40,7 +38,7 @@ class Alerta extends NotificationProvider { resource: "Message", }, data); - await axios.post(alertaUrl, postData, config); + await axios.post(notification.alertaApiEndpoint, postData, config); } else { let datadup = Object.assign( { correlate: [ "service_up", "service_down" ], @@ -52,11 +50,11 @@ class Alerta extends NotificationProvider { if (heartbeatJSON["status"] === DOWN) { datadup.severity = notification.alertaAlertState; // critical datadup.text = "Service " + monitorJSON["type"] + " is down."; - await axios.post(alertaUrl, datadup, config); + await axios.post(notification.alertaApiEndpoint, datadup, config); } else if (heartbeatJSON["status"] === UP) { datadup.severity = notification.alertaRecoverState; // cleaned datadup.text = "Service " + monitorJSON["type"] + " is up."; - await axios.post(alertaUrl, datadup, config); + await axios.post(notification.alertaApiEndpoint, datadup, config); } } return okMsg; diff --git a/server/notification-providers/alertnow.js b/server/notification-providers/alertnow.js index 1206b72e..4257ca9c 100644 --- a/server/notification-providers/alertnow.js +++ b/server/notification-providers/alertnow.js @@ -4,14 +4,14 @@ const { setting } = require("../util-server"); const { getMonitorRelativeURL, UP, DOWN } = require("../../src/util"); class AlertNow extends NotificationProvider { - name = "AlertNow"; /** * @inheritdoc */ async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { - let okMsg = "Sent Successfully."; + const okMsg = "Sent Successfully."; + try { let textMsg = ""; let status = "open"; diff --git a/server/notification-providers/aliyun-sms.js b/server/notification-providers/aliyun-sms.js index 28156bdf..ff38bd0d 100644 --- a/server/notification-providers/aliyun-sms.js +++ b/server/notification-providers/aliyun-sms.js @@ -11,7 +11,7 @@ class AliyunSMS extends NotificationProvider { * @inheritdoc */ async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { - let okMsg = "Sent Successfully."; + const okMsg = "Sent Successfully."; try { if (heartbeatJSON != null) { diff --git a/server/notification-providers/apprise.js b/server/notification-providers/apprise.js index 5e4d23c3..0f698214 100644 --- a/server/notification-providers/apprise.js +++ b/server/notification-providers/apprise.js @@ -2,13 +2,14 @@ const NotificationProvider = require("./notification-provider"); const childProcessAsync = require("promisify-child-process"); class Apprise extends NotificationProvider { - name = "apprise"; /** * @inheritdoc */ async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { + const okMsg = "Sent Successfully."; + const args = [ "-vv", "-b", msg, notification.appriseURL ]; if (notification.title) { args.push("-t"); @@ -23,7 +24,7 @@ class Apprise extends NotificationProvider { if (output) { if (! output.includes("ERROR")) { - return "Sent Successfully"; + return okMsg; } throw new Error(output); diff --git a/server/notification-providers/bark.js b/server/notification-providers/bark.js index a248afd8..0907d5f1 100644 --- a/server/notification-providers/bark.js +++ b/server/notification-providers/bark.js @@ -46,29 +46,29 @@ class Bark extends NotificationProvider { } /** - * Add additional parameter for Bark v1 endpoints + * Add additional parameter for Bark v1 endpoints. + * Leads to better on device styles (iOS 15 optimized) * @param {BeanModel} notification Notification to send - * @param {string} postUrl URL to append parameters to * @returns {string} Additional URL parameters */ - appendAdditionalParameters(notification, postUrl) { + additionalParameters(notification) { // set icon to uptime kuma icon, 11kb should be fine - postUrl += "?icon=" + barkNotificationAvatar; + let params = "?icon=" + barkNotificationAvatar; // grouping all our notifications if (notification.barkGroup != null) { - postUrl += "&group=" + notification.barkGroup; + params += "&group=" + notification.barkGroup; } else { // default name - postUrl += "&group=" + "UptimeKuma"; + params += "&group=" + "UptimeKuma"; } // picked a sound, this should follow system's mute status when arrival if (notification.barkSound != null) { - postUrl += "&sound=" + notification.barkSound; + params += "&sound=" + notification.barkSound; } else { // default sound - postUrl += "&sound=" + "telegraph"; + params += "&sound=" + "telegraph"; } - return postUrl; + return params; } /** @@ -100,9 +100,8 @@ class Bark extends NotificationProvider { // url encode title and subtitle title = encodeURIComponent(title); subtitle = encodeURIComponent(subtitle); - let postUrl = endpoint + "/" + title + "/" + subtitle; - postUrl = this.appendAdditionalParameters(notification, postUrl); - result = await axios.get(postUrl); + const params = this.additionalParameters(notification); + result = await axios.get(`${endpoint}/${title}/${subtitle}${params}`); } else { result = await axios.post(`${endpoint}/push`, { title, diff --git a/server/notification-providers/clicksendsms.js b/server/notification-providers/clicksendsms.js index 5539a6a4..c090b7f3 100644 --- a/server/notification-providers/clicksendsms.js +++ b/server/notification-providers/clicksendsms.js @@ -2,14 +2,15 @@ const NotificationProvider = require("./notification-provider"); const axios = require("axios"); class ClickSendSMS extends NotificationProvider { - name = "clicksendsms"; /** * @inheritdoc */ async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { - let okMsg = "Sent Successfully."; + const okMsg = "Sent Successfully."; + const url = "https://rest.clicksend.com/v3/sms/send"; + try { let config = { headers: { @@ -28,7 +29,7 @@ class ClickSendSMS extends NotificationProvider { } ] }; - let resp = await axios.post("https://rest.clicksend.com/v3/sms/send", data, config); + let resp = await axios.post(url, data, config); if (resp.data.data.messages[0].status !== "SUCCESS") { let error = "Something gone wrong. Api returned " + resp.data.data.messages[0].status + "."; this.throwGeneralAxiosError(error); diff --git a/server/notification-providers/dingding.js b/server/notification-providers/dingding.js index 7e7a953c..5e7f030b 100644 --- a/server/notification-providers/dingding.js +++ b/server/notification-providers/dingding.js @@ -10,7 +10,7 @@ class DingDing extends NotificationProvider { * @inheritdoc */ async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { - let okMsg = "Sent Successfully."; + const okMsg = "Sent Successfully."; try { if (heartbeatJSON != null) { diff --git a/server/notification-providers/discord.js b/server/notification-providers/discord.js index f24cd616..f24d4725 100644 --- a/server/notification-providers/discord.js +++ b/server/notification-providers/discord.js @@ -3,14 +3,13 @@ const axios = require("axios"); const { DOWN, UP } = require("../../src/util"); class Discord extends NotificationProvider { - name = "discord"; /** * @inheritdoc */ async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { - let okMsg = "Sent Successfully."; + const okMsg = "Sent Successfully."; try { const discordDisplayName = notification.discordUsername || "Uptime Kuma"; diff --git a/server/notification-providers/feishu.js b/server/notification-providers/feishu.js index dd5ce295..23af6911 100644 --- a/server/notification-providers/feishu.js +++ b/server/notification-providers/feishu.js @@ -9,8 +9,7 @@ class Feishu extends NotificationProvider { * @inheritdoc */ async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { - let okMsg = "Sent Successfully."; - let feishuWebHookUrl = notification.feishuWebHookUrl; + const okMsg = "Sent Successfully."; try { if (heartbeatJSON == null) { @@ -20,7 +19,7 @@ class Feishu extends NotificationProvider { text: msg, }, }; - await axios.post(feishuWebHookUrl, testdata); + await axios.post(notification.feishuWebHookUrl, testdata); return okMsg; } @@ -46,7 +45,7 @@ class Feishu extends NotificationProvider { }, }, }; - await axios.post(feishuWebHookUrl, downdata); + await axios.post(notification.feishuWebHookUrl, downdata); return okMsg; } @@ -72,7 +71,7 @@ class Feishu extends NotificationProvider { }, }, }; - await axios.post(feishuWebHookUrl, updata); + await axios.post(notification.feishuWebHookUrl, updata); return okMsg; } } catch (error) { diff --git a/server/notification-providers/freemobile.js b/server/notification-providers/freemobile.js index 44c55bfd..4de45acd 100644 --- a/server/notification-providers/freemobile.js +++ b/server/notification-providers/freemobile.js @@ -2,14 +2,14 @@ const NotificationProvider = require("./notification-provider"); const axios = require("axios"); class FreeMobile extends NotificationProvider { - name = "FreeMobile"; /** * @inheritdoc */ async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { - let okMsg = "Sent Successfully."; + const okMsg = "Sent Successfully."; + try { await axios.post(`https://smsapi.free-mobile.fr/sendmsg?msg=${encodeURIComponent(msg.replace("🔴", "⛔️"))}`, { "user": notification.freemobileUser, diff --git a/server/notification-providers/goalert.js b/server/notification-providers/goalert.js index abf77924..847c6a00 100644 --- a/server/notification-providers/goalert.js +++ b/server/notification-providers/goalert.js @@ -3,21 +3,20 @@ const axios = require("axios"); const { UP } = require("../../src/util"); class GoAlert extends NotificationProvider { - name = "GoAlert"; /** * @inheritdoc */ async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { - let okMsg = "Sent Successfully."; + const okMsg = "Sent Successfully."; + try { - let closeAction = "close"; let data = { summary: msg, }; if (heartbeatJSON != null && heartbeatJSON["status"] === UP) { - data["action"] = closeAction; + data["action"] = "close"; } let headers = { "Content-Type": "multipart/form-data", @@ -27,7 +26,6 @@ class GoAlert extends NotificationProvider { }; await axios.post(`${notification.goAlertBaseURL}/api/v2/generic/incoming?token=${notification.goAlertToken}`, data, config); return okMsg; - } catch (error) { let msg = (error.response.data) ? error.response.data : "Error without response"; throw new Error(msg); diff --git a/server/notification-providers/google-chat.js b/server/notification-providers/google-chat.js index 413fde26..9f1b53b7 100644 --- a/server/notification-providers/google-chat.js +++ b/server/notification-providers/google-chat.js @@ -5,14 +5,14 @@ const { getMonitorRelativeURL } = require("../../src/util"); const { DOWN, UP } = require("../../src/util"); class GoogleChat extends NotificationProvider { - name = "GoogleChat"; /** * @inheritdoc */ async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { - let okMsg = "Sent Successfully."; + const okMsg = "Sent Successfully."; + try { // Google Chat message formatting: https://developers.google.com/chat/api/guides/message-formats/basic diff --git a/server/notification-providers/gorush.js b/server/notification-providers/gorush.js index 28f03ab9..ba9d470f 100644 --- a/server/notification-providers/gorush.js +++ b/server/notification-providers/gorush.js @@ -2,14 +2,13 @@ const NotificationProvider = require("./notification-provider"); const axios = require("axios"); class Gorush extends NotificationProvider { - name = "gorush"; /** * @inheritdoc */ async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { - let okMsg = "Sent Successfully."; + const okMsg = "Sent Successfully."; let platformMapping = { "ios": 1, diff --git a/server/notification-providers/gotify.js b/server/notification-providers/gotify.js index 3e99b3d1..a52ef511 100644 --- a/server/notification-providers/gotify.js +++ b/server/notification-providers/gotify.js @@ -2,14 +2,14 @@ const NotificationProvider = require("./notification-provider"); const axios = require("axios"); class Gotify extends NotificationProvider { - name = "gotify"; /** * @inheritdoc */ async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { - let okMsg = "Sent Successfully."; + const okMsg = "Sent Successfully."; + try { if (notification.gotifyserverurl && notification.gotifyserverurl.endsWith("/")) { notification.gotifyserverurl = notification.gotifyserverurl.slice(0, -1); diff --git a/server/notification-providers/grafana-oncall.js b/server/notification-providers/grafana-oncall.js index ee1bfd47..e93c77cd 100644 --- a/server/notification-providers/grafana-oncall.js +++ b/server/notification-providers/grafana-oncall.js @@ -3,19 +3,18 @@ const axios = require("axios"); const { DOWN, UP } = require("../../src/util"); class GrafanaOncall extends NotificationProvider { - name = "GrafanaOncall"; /** * @inheritdoc */ async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { + const okMsg = "Sent Successfully."; if (!notification.GrafanaOncallURL) { throw new Error("GrafanaOncallURL cannot be empty"); } - let okMsg = "Sent Successfully."; try { if (heartbeatJSON === null) { let grafanaupdata = { @@ -23,10 +22,7 @@ class GrafanaOncall extends NotificationProvider { message: msg, state: "alerting", }; - await axios.post( - notification.GrafanaOncallURL, - grafanaupdata - ); + await axios.post(notification.GrafanaOncallURL, grafanaupdata); return okMsg; } else if (heartbeatJSON["status"] === DOWN) { let grafanadowndata = { @@ -34,10 +30,7 @@ class GrafanaOncall extends NotificationProvider { message: heartbeatJSON["msg"], state: "alerting", }; - await axios.post( - notification.GrafanaOncallURL, - grafanadowndata - ); + await axios.post(notification.GrafanaOncallURL, grafanadowndata); return okMsg; } else if (heartbeatJSON["status"] === UP) { let grafanaupdata = { @@ -45,10 +38,7 @@ class GrafanaOncall extends NotificationProvider { message: heartbeatJSON["msg"], state: "ok", }; - await axios.post( - notification.GrafanaOncallURL, - grafanaupdata - ); + await axios.post(notification.GrafanaOncallURL, grafanaupdata); return okMsg; } } catch (error) { diff --git a/server/notification-providers/heii-oncall.js b/server/notification-providers/heii-oncall.js new file mode 100644 index 00000000..20b53e6a --- /dev/null +++ b/server/notification-providers/heii-oncall.js @@ -0,0 +1,52 @@ +const { UP, DOWN, getMonitorRelativeURL } = require("../../src/util"); +const { setting } = require("../util-server"); + +const NotificationProvider = require("./notification-provider"); +const axios = require("axios"); +class HeiiOnCall extends NotificationProvider { + name = "HeiiOnCall"; + + /** + * @inheritdoc + */ + async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { + const okMsg = "Sent Successfully."; + const payload = heartbeatJSON || {}; + + const baseURL = await setting("primaryBaseURL"); + if (baseURL && monitorJSON) { + payload["url"] = baseURL + getMonitorRelativeURL(monitorJSON.id); + } + + const config = { + headers: { + Accept: "application/json", + "Content-Type": "application/json", + Authorization: "Bearer " + notification.heiiOnCallApiKey, + }, + }; + const heiiUrl = `https://heiioncall.com/triggers/${notification.heiiOnCallTriggerId}/`; + // docs https://heiioncall.com/docs#manual-triggers + try { + if (!heartbeatJSON) { + // Testing or general notification like certificate expiry + payload["msg"] = msg; + await axios.post(heiiUrl + "alert", payload, config); + return okMsg; + } + + if (heartbeatJSON.status === DOWN) { + await axios.post(heiiUrl + "alert", payload, config); + return okMsg; + } + if (heartbeatJSON.status === UP) { + await axios.post(heiiUrl + "resolve", payload, config); + return okMsg; + } + } catch (error) { + this.throwGeneralAxiosError(error); + } + } +} + +module.exports = HeiiOnCall; diff --git a/server/notification-providers/home-assistant.js b/server/notification-providers/home-assistant.js index 292fc3e6..ee95ba0b 100644 --- a/server/notification-providers/home-assistant.js +++ b/server/notification-providers/home-assistant.js @@ -9,7 +9,9 @@ class HomeAssistant extends NotificationProvider { /** * @inheritdoc */ - async send(notification, message, monitor = null, heartbeat = null) { + async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { + const okMsg = "Sent Successfully."; + const notificationService = notification?.notificationService || defaultNotificationService; try { @@ -17,10 +19,10 @@ class HomeAssistant extends NotificationProvider { `${notification.homeAssistantUrl.trim().replace(/\/*$/, "")}/api/services/notify/${notificationService}`, { title: "Uptime Kuma", - message, + message: msg, ...(notificationService !== "persistent_notification" && { data: { - name: monitor?.name, - status: heartbeat?.status, + name: monitorJSON?.name, + status: heartbeatJSON?.status, } }), }, { @@ -31,7 +33,7 @@ class HomeAssistant extends NotificationProvider { } ); - return "Sent Successfully."; + return okMsg; } catch (error) { this.throwGeneralAxiosError(error); } diff --git a/server/notification-providers/kook.js b/server/notification-providers/kook.js index b9b68f43..dab19513 100644 --- a/server/notification-providers/kook.js +++ b/server/notification-providers/kook.js @@ -2,15 +2,15 @@ const NotificationProvider = require("./notification-provider"); const axios = require("axios"); class Kook extends NotificationProvider { - name = "Kook"; /** * @inheritdoc */ async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { - let okMsg = "Sent Successfully."; - let url = "https://www.kookapp.cn/api/v3/message/create"; + const okMsg = "Sent Successfully."; + const url = "https://www.kookapp.cn/api/v3/message/create"; + let data = { target_id: notification.kookGuildID, content: msg, diff --git a/server/notification-providers/line.js b/server/notification-providers/line.js index 73dc962f..57dc87e7 100644 --- a/server/notification-providers/line.js +++ b/server/notification-providers/line.js @@ -3,16 +3,16 @@ const axios = require("axios"); const { DOWN, UP } = require("../../src/util"); class Line extends NotificationProvider { - name = "line"; /** * @inheritdoc */ async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { - let okMsg = "Sent Successfully."; + const okMsg = "Sent Successfully."; + const url = "https://api.line.me/v2/bot/message/push"; + try { - let lineAPIUrl = "https://api.line.me/v2/bot/message/push"; let config = { headers: { "Content-Type": "application/json", @@ -29,7 +29,7 @@ class Line extends NotificationProvider { } ] }; - await axios.post(lineAPIUrl, testMessage, config); + await axios.post(url, testMessage, config); } else if (heartbeatJSON["status"] === DOWN) { let downMessage = { "to": notification.lineUserID, @@ -43,7 +43,7 @@ class Line extends NotificationProvider { } ] }; - await axios.post(lineAPIUrl, downMessage, config); + await axios.post(url, downMessage, config); } else if (heartbeatJSON["status"] === UP) { let upMessage = { "to": notification.lineUserID, @@ -57,7 +57,7 @@ class Line extends NotificationProvider { } ] }; - await axios.post(lineAPIUrl, upMessage, config); + await axios.post(url, upMessage, config); } return okMsg; } catch (error) { diff --git a/server/notification-providers/linenotify.js b/server/notification-providers/linenotify.js index dfe7e598..2622e3f1 100644 --- a/server/notification-providers/linenotify.js +++ b/server/notification-providers/linenotify.js @@ -4,16 +4,16 @@ const qs = require("qs"); const { DOWN, UP } = require("../../src/util"); class LineNotify extends NotificationProvider { - name = "LineNotify"; /** * @inheritdoc */ async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { - let okMsg = "Sent Successfully."; + const okMsg = "Sent Successfully."; + const url = "https://notify-api.line.me/api/notify"; + try { - let lineAPIUrl = "https://notify-api.line.me/api/notify"; let config = { headers: { "Content-Type": "application/x-www-form-urlencoded", @@ -24,7 +24,7 @@ class LineNotify extends NotificationProvider { let testMessage = { "message": msg, }; - await axios.post(lineAPIUrl, qs.stringify(testMessage), config); + await axios.post(url, qs.stringify(testMessage), config); } else if (heartbeatJSON["status"] === DOWN) { let downMessage = { "message": "\n[🔴 Down]\n" + @@ -32,7 +32,7 @@ class LineNotify extends NotificationProvider { heartbeatJSON["msg"] + "\n" + `Time (${heartbeatJSON["timezone"]}): ${heartbeatJSON["localDateTime"]}` }; - await axios.post(lineAPIUrl, qs.stringify(downMessage), config); + await axios.post(url, qs.stringify(downMessage), config); } else if (heartbeatJSON["status"] === UP) { let upMessage = { "message": "\n[✅ Up]\n" + @@ -40,7 +40,7 @@ class LineNotify extends NotificationProvider { heartbeatJSON["msg"] + "\n" + `Time (${heartbeatJSON["timezone"]}): ${heartbeatJSON["localDateTime"]}` }; - await axios.post(lineAPIUrl, qs.stringify(upMessage), config); + await axios.post(url, qs.stringify(upMessage), config); } return okMsg; } catch (error) { diff --git a/server/notification-providers/lunasea.js b/server/notification-providers/lunasea.js index 3729b0fe..787a704a 100644 --- a/server/notification-providers/lunasea.js +++ b/server/notification-providers/lunasea.js @@ -3,28 +3,23 @@ const axios = require("axios"); const { DOWN, UP } = require("../../src/util"); class LunaSea extends NotificationProvider { - name = "lunasea"; /** * @inheritdoc */ async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { - let okMsg = "Sent Successfully."; - let lunaseaurl = ""; - if (notification.lunaseaTarget === "user") { - lunaseaurl = "https://notify.lunasea.app/v1/custom/user/" + notification.lunaseaUserID; - } else { - lunaseaurl = "https://notify.lunasea.app/v1/custom/device/" + notification.lunaseaDevice; - } + const okMsg = "Sent Successfully."; + const url = "https://notify.lunasea.app/v1"; try { + const target = this.getTarget(notification); if (heartbeatJSON == null) { let testdata = { "title": "Uptime Kuma Alert", "body": msg, }; - await axios.post(lunaseaurl, testdata); + await axios.post(`${url}/custom/${target}`, testdata); return okMsg; } @@ -35,7 +30,7 @@ class LunaSea extends NotificationProvider { heartbeatJSON["msg"] + `\nTime (${heartbeatJSON["timezone"]}): ${heartbeatJSON["localDateTime"]}` }; - await axios.post(lunaseaurl, downdata); + await axios.post(`${url}/custom/${target}`, downdata); return okMsg; } @@ -46,13 +41,25 @@ class LunaSea extends NotificationProvider { heartbeatJSON["msg"] + `\nTime (${heartbeatJSON["timezone"]}): ${heartbeatJSON["localDateTime"]}` }; - await axios.post(lunaseaurl, updata); + await axios.post(`${url}/custom/${target}`, updata); return okMsg; } } catch (error) { this.throwGeneralAxiosError(error); } + } + + /** + * Generates the lunasea target to send the notification to + * @param {BeanModel} notification Notification details + * @returns {string} The target to send the notification to + */ + getTarget(notification) { + if (notification.lunaseaTarget === "user") { + return "user/" + notification.lunaseaUserID; + } + return "device/" + notification.lunaseaDevice; } } diff --git a/server/notification-providers/matrix.js b/server/notification-providers/matrix.js index c9baf48b..805a4947 100644 --- a/server/notification-providers/matrix.js +++ b/server/notification-providers/matrix.js @@ -10,7 +10,7 @@ class Matrix extends NotificationProvider { * @inheritdoc */ async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { - let okMsg = "Sent Successfully."; + const okMsg = "Sent Successfully."; const size = 20; const randomString = encodeURIComponent( diff --git a/server/notification-providers/mattermost.js b/server/notification-providers/mattermost.js index 5a6a8e2c..9946d02b 100644 --- a/server/notification-providers/mattermost.js +++ b/server/notification-providers/mattermost.js @@ -3,14 +3,14 @@ const axios = require("axios"); const { DOWN, UP } = require("../../src/util"); class Mattermost extends NotificationProvider { - name = "mattermost"; /** * @inheritdoc */ async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { - let okMsg = "Sent Successfully."; + const okMsg = "Sent Successfully."; + try { const mattermostUserName = notification.mattermostusername || "Uptime Kuma"; // If heartbeatJSON is null, assume non monitoring notification (Certificate warning) or testing. @@ -98,10 +98,7 @@ class Mattermost extends NotificationProvider { }, ], }; - await axios.post( - notification.mattermostWebhookUrl, - mattermostdata - ); + await axios.post(notification.mattermostWebhookUrl, mattermostdata); return okMsg; } catch (error) { this.throwGeneralAxiosError(error); diff --git a/server/notification-providers/ntfy.js b/server/notification-providers/ntfy.js index 86fc0e08..ad1d39f8 100644 --- a/server/notification-providers/ntfy.js +++ b/server/notification-providers/ntfy.js @@ -3,14 +3,14 @@ const axios = require("axios"); const { DOWN, UP } = require("../../src/util"); class Ntfy extends NotificationProvider { - name = "ntfy"; /** * @inheritdoc */ async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { - let okMsg = "Sent Successfully."; + const okMsg = "Sent Successfully."; + try { let headers = {}; if (notification.ntfyAuthenticationMethod === "usernamePassword") { @@ -31,7 +31,7 @@ class Ntfy extends NotificationProvider { "priority": notification.ntfyPriority, "tags": [ "test_tube" ], }; - await axios.post(`${notification.ntfyserverurl}`, ntfyTestData, { headers: headers }); + await axios.post(notification.ntfyserverurl, ntfyTestData, { headers: headers }); return okMsg; } let tags = []; @@ -54,20 +54,23 @@ class Ntfy extends NotificationProvider { "priority": priority, "title": monitorJSON.name + " " + status + " [Uptime-Kuma]", "tags": tags, - "actions": [ + }; + + if (monitorJSON.url && monitorJSON.url !== "https://") { + data.actions = [ { "action": "view", "label": "Open " + monitorJSON.name, "url": monitorJSON.url, - } - ] - }; + }, + ]; + } if (notification.ntfyIcon) { data.icon = notification.ntfyIcon; } - await axios.post(`${notification.ntfyserverurl}`, data, { headers: headers }); + await axios.post(notification.ntfyserverurl, data, { headers: headers }); return okMsg; diff --git a/server/notification-providers/octopush.js b/server/notification-providers/octopush.js index ec62cd3a..7576e0ad 100644 --- a/server/notification-providers/octopush.js +++ b/server/notification-providers/octopush.js @@ -2,14 +2,15 @@ const NotificationProvider = require("./notification-provider"); const axios = require("axios"); class Octopush extends NotificationProvider { - name = "octopush"; /** * @inheritdoc */ async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { - let okMsg = "Sent Successfully."; + const okMsg = "Sent Successfully."; + const urlV2 = "https://api.octopush.com/v1/public/sms-campaign/send"; + const urlV1 = "https://www.octopush-dm.com/api/sms/json"; try { // Default - V2 @@ -33,7 +34,7 @@ class Octopush extends NotificationProvider { "purpose": "alert", "sender": notification.octopushSenderName }; - await axios.post("https://api.octopush.com/v1/public/sms-campaign/send", data, config); + await axios.post(urlV2, data, config); } else if (notification.octopushVersion === "1") { let data = { "user_login": notification.octopushDMLogin, @@ -55,7 +56,7 @@ class Octopush extends NotificationProvider { // V1 API returns 200 even on error so we must check // response data - let response = await axios.post("https://www.octopush-dm.com/api/sms/json", {}, config); + let response = await axios.post(urlV1, {}, config); if ("error_code" in response.data) { if (response.data.error_code !== "000") { this.throwGeneralAxiosError(`Octopush error ${JSON.stringify(response.data)}`); diff --git a/server/notification-providers/onebot.js b/server/notification-providers/onebot.js index ec7fc46d..b04794de 100644 --- a/server/notification-providers/onebot.js +++ b/server/notification-providers/onebot.js @@ -2,23 +2,23 @@ const NotificationProvider = require("./notification-provider"); const axios = require("axios"); class OneBot extends NotificationProvider { - name = "OneBot"; /** * @inheritdoc */ async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { - let okMsg = "Sent Successfully."; + const okMsg = "Sent Successfully."; + try { - let httpAddr = notification.httpAddr; - if (!httpAddr.startsWith("http")) { - httpAddr = "http://" + httpAddr; + let url = notification.httpAddr; + if (!url.startsWith("http")) { + url = "http://" + url; } - if (!httpAddr.endsWith("/")) { - httpAddr += "/"; + if (!url.endsWith("/")) { + url += "/"; } - let onebotAPIUrl = httpAddr + "send_msg"; + url += "send_msg"; let config = { headers: { "Content-Type": "application/json", @@ -37,7 +37,7 @@ class OneBot extends NotificationProvider { data["message_type"] = "private"; data["user_id"] = notification.recieverId; } - await axios.post(onebotAPIUrl, data, config); + await axios.post(url, data, config); return okMsg; } catch (error) { this.throwGeneralAxiosError(error); diff --git a/server/notification-providers/opsgenie.js b/server/notification-providers/opsgenie.js index e2dc38a7..59a79705 100644 --- a/server/notification-providers/opsgenie.js +++ b/server/notification-providers/opsgenie.js @@ -4,10 +4,9 @@ const { UP, DOWN } = require("../../src/util"); const opsgenieAlertsUrlEU = "https://api.eu.opsgenie.com/v2/alerts"; const opsgenieAlertsUrlUS = "https://api.opsgenie.com/v2/alerts"; -let okMsg = "Sent Successfully."; +const okMsg = "Sent Successfully."; class Opsgenie extends NotificationProvider { - name = "Opsgenie"; /** diff --git a/server/notification-providers/promosms.js b/server/notification-providers/promosms.js index 7ec91971..05334e90 100644 --- a/server/notification-providers/promosms.js +++ b/server/notification-providers/promosms.js @@ -2,14 +2,14 @@ const NotificationProvider = require("./notification-provider"); const axios = require("axios"); class PromoSMS extends NotificationProvider { - name = "promosms"; /** * @inheritdoc */ async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { - let okMsg = "Sent Successfully."; + const okMsg = "Sent Successfully."; + const url = "https://promosms.com/api/rest/v3_2/sms"; if (notification.promosmsAllowLongSMS === undefined) { notification.promosmsAllowLongSMS = false; @@ -36,7 +36,7 @@ class PromoSMS extends NotificationProvider { "sender": notification.promosmsSenderName }; - let resp = await axios.post("https://promosms.com/api/rest/v3_2/sms", data, config); + let resp = await axios.post(url, data, config); if (resp.data.response.status !== 0) { let error = "Something gone wrong. Api returned " + resp.data.response.status + "."; diff --git a/server/notification-providers/pushbullet.js b/server/notification-providers/pushbullet.js index 9fbd4d4c..0b730310 100644 --- a/server/notification-providers/pushbullet.js +++ b/server/notification-providers/pushbullet.js @@ -4,17 +4,16 @@ const axios = require("axios"); const { DOWN, UP } = require("../../src/util"); class Pushbullet extends NotificationProvider { - name = "pushbullet"; /** * @inheritdoc */ async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { - let okMsg = "Sent Successfully."; + const okMsg = "Sent Successfully."; + const url = "https://api.pushbullet.com/v2/pushes"; try { - let pushbulletUrl = "https://api.pushbullet.com/v2/pushes"; let config = { headers: { "Access-Token": notification.pushbulletAccessToken, @@ -27,7 +26,7 @@ class Pushbullet extends NotificationProvider { "title": "Uptime Kuma Alert", "body": msg, }; - await axios.post(pushbulletUrl, data, config); + await axios.post(url, data, config); } else if (heartbeatJSON["status"] === DOWN) { let downData = { "type": "note", @@ -36,7 +35,7 @@ class Pushbullet extends NotificationProvider { heartbeatJSON["msg"] + `\nTime (${heartbeatJSON["timezone"]}): ${heartbeatJSON["localDateTime"]}`, }; - await axios.post(pushbulletUrl, downData, config); + await axios.post(url, downData, config); } else if (heartbeatJSON["status"] === UP) { let upData = { "type": "note", @@ -45,7 +44,7 @@ class Pushbullet extends NotificationProvider { heartbeatJSON["msg"] + `\nTime (${heartbeatJSON["timezone"]}): ${heartbeatJSON["localDateTime"]}`, }; - await axios.post(pushbulletUrl, upData, config); + await axios.post(url, upData, config); } return okMsg; } catch (error) { diff --git a/server/notification-providers/pushdeer.js b/server/notification-providers/pushdeer.js index 78525a54..276c2f47 100644 --- a/server/notification-providers/pushdeer.js +++ b/server/notification-providers/pushdeer.js @@ -3,17 +3,15 @@ const axios = require("axios"); const { DOWN, UP } = require("../../src/util"); class PushDeer extends NotificationProvider { - name = "PushDeer"; /** * @inheritdoc */ async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { - let okMsg = "Sent Successfully."; - let endpoint = "/message/push"; - let serverUrl = notification.pushdeerServer || "https://api2.pushdeer.com"; - let pushdeerlink = `${serverUrl.trim().replace(/\/*$/, "")}${endpoint}`; + const okMsg = "Sent Successfully."; + const serverUrl = notification.pushdeerServer || "https://api2.pushdeer.com"; + const url = `${serverUrl.trim().replace(/\/*$/, "")}/message/push`; let valid = msg != null && monitorJSON != null && heartbeatJSON != null; @@ -34,7 +32,7 @@ class PushDeer extends NotificationProvider { }; try { - let res = await axios.post(pushdeerlink, data); + let res = await axios.post(url, data); if ("error" in res.data) { let error = res.data.error; diff --git a/server/notification-providers/pushover.js b/server/notification-providers/pushover.js index 31f8d885..304aa351 100644 --- a/server/notification-providers/pushover.js +++ b/server/notification-providers/pushover.js @@ -2,15 +2,14 @@ const NotificationProvider = require("./notification-provider"); const axios = require("axios"); class Pushover extends NotificationProvider { - name = "pushover"; /** * @inheritdoc */ async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { - let okMsg = "Sent Successfully."; - let pushoverlink = "https://api.pushover.net/1/messages.json"; + const okMsg = "Sent Successfully."; + const url = "https://api.pushover.net/1/messages.json"; let data = { "message": msg, @@ -33,11 +32,11 @@ class Pushover extends NotificationProvider { try { if (heartbeatJSON == null) { - await axios.post(pushoverlink, data); + await axios.post(url, data); return okMsg; } else { data.message += `\nTime (${heartbeatJSON["timezone"]}):${heartbeatJSON["localDateTime"]}`; - await axios.post(pushoverlink, data); + await axios.post(url, data); return okMsg; } } catch (error) { diff --git a/server/notification-providers/pushy.js b/server/notification-providers/pushy.js index afb9e617..cb700229 100644 --- a/server/notification-providers/pushy.js +++ b/server/notification-providers/pushy.js @@ -2,14 +2,13 @@ const NotificationProvider = require("./notification-provider"); const axios = require("axios"); class Pushy extends NotificationProvider { - name = "pushy"; /** * @inheritdoc */ async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { - let okMsg = "Sent Successfully."; + const okMsg = "Sent Successfully."; try { await axios.post(`https://api.pushy.me/push?api_key=${notification.pushyAPIKey}`, { diff --git a/server/notification-providers/rocket-chat.js b/server/notification-providers/rocket-chat.js index 13b39cde..690e33a8 100644 --- a/server/notification-providers/rocket-chat.js +++ b/server/notification-providers/rocket-chat.js @@ -5,14 +5,14 @@ const { setting } = require("../util-server"); const { getMonitorRelativeURL, DOWN } = require("../../src/util"); class RocketChat extends NotificationProvider { - name = "rocket.chat"; /** * @inheritdoc */ async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { - let okMsg = "Sent Successfully."; + const okMsg = "Sent Successfully."; + try { if (heartbeatJSON == null) { let data = { diff --git a/server/notification-providers/serverchan.js b/server/notification-providers/serverchan.js index 2315e1c3..cefe61f1 100644 --- a/server/notification-providers/serverchan.js +++ b/server/notification-providers/serverchan.js @@ -3,14 +3,14 @@ const axios = require("axios"); const { DOWN, UP } = require("../../src/util"); class ServerChan extends NotificationProvider { - name = "ServerChan"; /** * @inheritdoc */ async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { - let okMsg = "Sent Successfully."; + const okMsg = "Sent Successfully."; + try { await axios.post(`https://sctapi.ftqq.com/${notification.serverChanSendKey}.send`, { "title": this.checkStatus(heartbeatJSON, monitorJSON), diff --git a/server/notification-providers/serwersms.js b/server/notification-providers/serwersms.js index 76e1ef2c..f7c8644a 100644 --- a/server/notification-providers/serwersms.js +++ b/server/notification-providers/serwersms.js @@ -2,14 +2,14 @@ const NotificationProvider = require("./notification-provider"); const axios = require("axios"); class SerwerSMS extends NotificationProvider { - name = "serwersms"; /** * @inheritdoc */ async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { - let okMsg = "Sent Successfully."; + const okMsg = "Sent Successfully."; + const url = "https://api2.serwersms.pl/messages/send_sms"; try { let config = { @@ -25,7 +25,7 @@ class SerwerSMS extends NotificationProvider { "sender": notification.serwersmsSenderName, }; - let resp = await axios.post("https://api2.serwersms.pl/messages/send_sms", data, config); + let resp = await axios.post(url, data, config); if (!resp.data.success) { if (resp.data.error) { diff --git a/server/notification-providers/signal.js b/server/notification-providers/signal.js index c445ee82..9702d06b 100644 --- a/server/notification-providers/signal.js +++ b/server/notification-providers/signal.js @@ -2,14 +2,13 @@ const NotificationProvider = require("./notification-provider"); const axios = require("axios"); class Signal extends NotificationProvider { - name = "signal"; /** * @inheritdoc */ async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { - let okMsg = "Sent Successfully."; + const okMsg = "Sent Successfully."; try { let data = { diff --git a/server/notification-providers/slack.js b/server/notification-providers/slack.js index d512a7cd..9347b07c 100644 --- a/server/notification-providers/slack.js +++ b/server/notification-providers/slack.js @@ -4,7 +4,6 @@ const { setSettings, setting } = require("../util-server"); const { getMonitorRelativeURL, UP } = require("../../src/util"); class Slack extends NotificationProvider { - name = "slack"; /** @@ -31,7 +30,7 @@ class Slack extends NotificationProvider { * @inheritdoc */ async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { - let okMsg = "Sent Successfully."; + const okMsg = "Sent Successfully."; if (notification.slackchannelnotify) { msg += " "; diff --git a/server/notification-providers/smsc.js b/server/notification-providers/smsc.js index 34d9c8fa..89f01d01 100644 --- a/server/notification-providers/smsc.js +++ b/server/notification-providers/smsc.js @@ -8,7 +8,9 @@ class SMSC extends NotificationProvider { * @inheritdoc */ async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { - let okMsg = "Sent Successfully."; + const okMsg = "Sent Successfully."; + const url = "https://smsc.kz/sys/send.php?"; + try { let config = { headers: { @@ -29,7 +31,7 @@ class SMSC extends NotificationProvider { getArray.push("sender=" + notification.smscSenderName); } - let resp = await axios.get("https://smsc.kz/sys/send.php?" + getArray.join("&"), config); + let resp = await axios.get(url + getArray.join("&"), config); if (resp.data.id === undefined) { let error = `Something gone wrong. Api returned code ${resp.data.error_code}: ${resp.data.error}`; this.throwGeneralAxiosError(error); diff --git a/server/notification-providers/smseagle.js b/server/notification-providers/smseagle.js index 988f17fd..4e897006 100644 --- a/server/notification-providers/smseagle.js +++ b/server/notification-providers/smseagle.js @@ -2,14 +2,13 @@ const NotificationProvider = require("./notification-provider"); const axios = require("axios"); class SMSEagle extends NotificationProvider { - name = "SMSEagle"; /** * @inheritdoc */ async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { - let okMsg = "Sent Successfully."; + const okMsg = "Sent Successfully."; try { let config = { diff --git a/server/notification-providers/smsmanager.js b/server/notification-providers/smsmanager.js index 7d55d410..d01285d8 100644 --- a/server/notification-providers/smsmanager.js +++ b/server/notification-providers/smsmanager.js @@ -2,23 +2,24 @@ const NotificationProvider = require("./notification-provider"); const axios = require("axios"); class SMSManager extends NotificationProvider { - name = "SMSManager"; /** * @inheritdoc */ async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { + const okMsg = "Sent Successfully."; + const url = "https://http-api.smsmanager.cz/Send"; + try { let data = { apikey: notification.smsmanagerApiKey, - endpoint: "https://http-api.smsmanager.cz/Send", message: msg.replace(/[^\x00-\x7F]/g, ""), - to: notification.numbers, - messageType: notification.messageType, + number: notification.numbers, + gateway: notification.messageType, }; - await axios.get(`${data.endpoint}?apikey=${data.apikey}&message=${data.message}&number=${data.to}&gateway=${data.messageType}`); - return "SMS sent sucessfully."; + await axios.get(`${url}?apikey=${data.apikey}&message=${data.message}&number=${data.number}&gateway=${data.messageType}`); + return okMsg; } catch (error) { this.throwGeneralAxiosError(error); } diff --git a/server/notification-providers/smtp.js b/server/notification-providers/smtp.js index 0e761bc0..b403117b 100644 --- a/server/notification-providers/smtp.js +++ b/server/notification-providers/smtp.js @@ -4,13 +4,13 @@ const { DOWN } = require("../../src/util"); const { Liquid } = require("liquidjs"); class SMTP extends NotificationProvider { - name = "smtp"; /** * @inheritdoc */ async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { + const okMsg = "Sent Successfully."; const config = { host: notification.smtpHost, @@ -76,7 +76,7 @@ class SMTP extends NotificationProvider { text: body, }); - return "Sent Successfully."; + return okMsg; } /** diff --git a/server/notification-providers/squadcast.js b/server/notification-providers/squadcast.js index 0b60503d..1c653d14 100644 --- a/server/notification-providers/squadcast.js +++ b/server/notification-providers/squadcast.js @@ -3,14 +3,13 @@ const axios = require("axios"); const { DOWN } = require("../../src/util"); class Squadcast extends NotificationProvider { - name = "squadcast"; /** * @inheritdoc */ async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { - let okMsg = "Sent Successfully."; + const okMsg = "Sent Successfully."; try { diff --git a/server/notification-providers/stackfield.js b/server/notification-providers/stackfield.js index 26c038ea..65a92459 100644 --- a/server/notification-providers/stackfield.js +++ b/server/notification-providers/stackfield.js @@ -4,14 +4,14 @@ const { setting } = require("../util-server"); const { getMonitorRelativeURL } = require("../../src/util"); class Stackfield extends NotificationProvider { - name = "stackfield"; /** * @inheritdoc */ - async send(notification, msg, monitorJSON = null) { - let okMsg = "Sent Successfully."; + async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { + const okMsg = "Sent Successfully."; + try { // Stackfield message formatting: https://www.stackfield.com/help/formatting-messages-2001 diff --git a/server/notification-providers/teams.js b/server/notification-providers/teams.js index 30976cf5..f34ba1ce 100644 --- a/server/notification-providers/teams.js +++ b/server/notification-providers/teams.js @@ -1,6 +1,7 @@ const NotificationProvider = require("./notification-provider"); const axios = require("axios"); -const { DOWN, UP } = require("../../src/util"); +const { setting } = require("../util-server"); +const { DOWN, UP, getMonitorRelativeURL } = require("../../src/util"); class Teams extends NotificationProvider { name = "teams"; @@ -9,89 +10,172 @@ class Teams extends NotificationProvider { * Generate the message to send * @param {const} status The status constant * @param {string} monitorName Name of monitor + * @param {boolean} withStatusSymbol If the status should be prepended as symbol * @returns {string} Status message */ - _statusMessageFactory = (status, monitorName) => { + _statusMessageFactory = (status, monitorName, withStatusSymbol) => { if (status === DOWN) { - return `🔴 Application [${monitorName}] went down`; + return (withStatusSymbol ? "🔴 " : "") + `[${monitorName}] went down`; } else if (status === UP) { - return `✅ Application [${monitorName}] is back online`; + return (withStatusSymbol ? "✅ " : "") + `[${monitorName}] is back online`; } return "Notification"; }; /** - * Select theme color to use based on status + * Select the style to use based on status * @param {const} status The status constant - * @returns {string} Selected color in hex RGB format + * @returns {string} Selected style for adaptive cards */ - _getThemeColor = (status) => { + _getStyle = (status) => { if (status === DOWN) { - return "ff0000"; + return "attention"; } if (status === UP) { - return "00e804"; + return "good"; } - return "008cff"; + return "emphasis"; }; /** * Generate payload for notification * @param {object} args Method arguments - * @param {const} args.status The status of the monitor - * @param {string} args.monitorMessage Message to send - * @param {string} args.monitorName Name of monitor affected - * @param {string} args.monitorUrl URL of monitor affected + * @param {object} args.heartbeatJSON Heartbeat details + * @param {string} args.monitorName Name of the monitor affected + * @param {string} args.monitorUrl URL of the monitor affected + * @param {string} args.dashboardUrl URL of the dashboard affected * @returns {object} Notification payload */ _notificationPayloadFactory = ({ - status, - monitorMessage, + heartbeatJSON, monitorName, monitorUrl, + dashboardUrl, }) => { - const notificationMessage = this._statusMessageFactory( - status, - monitorName - ); - + const status = heartbeatJSON?.status; const facts = []; + const actions = []; + + if (dashboardUrl) { + actions.push({ + "type": "Action.OpenUrl", + "title": "Visit Uptime Kuma", + "url": dashboardUrl + }); + } + + if (heartbeatJSON?.msg) { + facts.push({ + title: "Description", + value: heartbeatJSON.msg, + }); + } if (monitorName) { facts.push({ - name: "Monitor", + title: "Monitor", value: monitorName, }); } if (monitorUrl && monitorUrl !== "https://") { facts.push({ - name: "URL", - value: monitorUrl, + title: "URL", + // format URL as markdown syntax, to be clickable + value: `[${monitorUrl}](${monitorUrl})`, + }); + actions.push({ + "type": "Action.OpenUrl", + "title": "Visit Monitor URL", + "url": monitorUrl }); } - return { - "@context": "https://schema.org/extensions", - "@type": "MessageCard", - themeColor: this._getThemeColor(status), - summary: notificationMessage, - sections: [ - { - activityImage: - "https://raw.githubusercontent.com/louislam/uptime-kuma/master/public/icon.png", - activityTitle: "**Uptime Kuma**", - }, - { - activityTitle: notificationMessage, - }, + if (heartbeatJSON?.localDateTime) { + facts.push({ + title: "Time", + value: heartbeatJSON.localDateTime + (heartbeatJSON.timezone ? ` (${heartbeatJSON.timezone})` : ""), + }); + } + + const payload = { + "type": "message", + // message with status prefix as notification text + "summary": this._statusMessageFactory(status, monitorName, true), + "attachments": [ { - activityTitle: "**Description**", - text: monitorMessage, - facts, - }, - ], + "contentType": "application/vnd.microsoft.card.adaptive", + "contentUrl": "", + "content": { + "type": "AdaptiveCard", + "body": [ + { + "type": "Container", + "verticalContentAlignment": "Center", + "items": [ + { + "type": "ColumnSet", + "style": this._getStyle(status), + "columns": [ + { + "type": "Column", + "width": "auto", + "verticalContentAlignment": "Center", + "items": [ + { + "type": "Image", + "width": "32px", + "style": "Person", + "url": "https://raw.githubusercontent.com/louislam/uptime-kuma/master/public/icon.png", + "altText": "Uptime Kuma Logo" + } + ] + }, + { + "type": "Column", + "width": "stretch", + "items": [ + { + "type": "TextBlock", + "size": "Medium", + "weight": "Bolder", + "text": `**${this._statusMessageFactory(status, monitorName, false)}**`, + }, + { + "type": "TextBlock", + "size": "Small", + "weight": "Default", + "text": "Uptime Kuma Alert", + "isSubtle": true, + "spacing": "None" + } + ] + } + ] + } + ] + }, + { + "type": "FactSet", + "separator": false, + "facts": facts + } + ], + "$schema": "http://adaptivecards.io/schemas/adaptive-card.json", + "version": "1.5" + } + } + ] }; + + if (actions) { + payload.attachments[0].content.body.push({ + "type": "ActionSet", + "actions": actions, + }); + } + + return payload; }; /** @@ -112,7 +196,9 @@ class Teams extends NotificationProvider { */ _handleGeneralNotification = (webhookUrl, msg) => { const payload = this._notificationPayloadFactory({ - monitorMessage: msg + heartbeatJSON: { + msg: msg + } }); return this._sendNotification(webhookUrl, payload); @@ -122,7 +208,7 @@ class Teams extends NotificationProvider { * @inheritdoc */ async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { - let okMsg = "Sent Successfully."; + const okMsg = "Sent Successfully."; try { if (heartbeatJSON == null) { @@ -130,26 +216,32 @@ class Teams extends NotificationProvider { return okMsg; } - let url; + let monitorUrl; switch (monitorJSON["type"]) { case "http": case "keywork": - url = monitorJSON["url"]; + monitorUrl = monitorJSON["url"]; break; case "docker": - url = monitorJSON["docker_host"]; + monitorUrl = monitorJSON["docker_host"]; break; default: - url = monitorJSON["hostname"]; + monitorUrl = monitorJSON["hostname"]; break; } + const baseURL = await setting("primaryBaseURL"); + let dashboardUrl; + if (baseURL) { + dashboardUrl = baseURL + getMonitorRelativeURL(monitorJSON.id); + } + const payload = this._notificationPayloadFactory({ - monitorMessage: heartbeatJSON.msg, + heartbeatJSON: heartbeatJSON, monitorName: monitorJSON.name, - monitorUrl: url, - status: heartbeatJSON.status, + monitorUrl: monitorUrl, + dashboardUrl: dashboardUrl, }); await this._sendNotification(notification.webhookUrl, payload); diff --git a/server/notification-providers/techulus-push.js b/server/notification-providers/techulus-push.js index bfd9503b..230897f3 100644 --- a/server/notification-providers/techulus-push.js +++ b/server/notification-providers/techulus-push.js @@ -2,14 +2,13 @@ const NotificationProvider = require("./notification-provider"); const axios = require("axios"); class TechulusPush extends NotificationProvider { - name = "PushByTechulus"; /** * @inheritdoc */ async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { - let okMsg = "Sent Successfully."; + const okMsg = "Sent Successfully."; try { await axios.post(`https://push.techulus.com/api/v1/notify/${notification.pushAPIKey}`, { diff --git a/server/notification-providers/telegram.js b/server/notification-providers/telegram.js index 896b9e08..c5bbb190 100644 --- a/server/notification-providers/telegram.js +++ b/server/notification-providers/telegram.js @@ -2,14 +2,14 @@ const NotificationProvider = require("./notification-provider"); const axios = require("axios"); class Telegram extends NotificationProvider { - name = "telegram"; /** * @inheritdoc */ async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { - let okMsg = "Sent Successfully."; + const okMsg = "Sent Successfully."; + const url = "https://api.telegram.org"; try { let params = { @@ -22,7 +22,7 @@ class Telegram extends NotificationProvider { params.message_thread_id = notification.telegramMessageThreadID; } - await axios.get(`https://api.telegram.org/bot${notification.telegramBotToken}/sendMessage`, { + await axios.get(`${url}/bot${notification.telegramBotToken}/sendMessage`, { params: params, }); return okMsg; diff --git a/server/notification-providers/twilio.js b/server/notification-providers/twilio.js index 2abb38b9..c38a6d7e 100644 --- a/server/notification-providers/twilio.js +++ b/server/notification-providers/twilio.js @@ -2,26 +2,21 @@ const NotificationProvider = require("./notification-provider"); const axios = require("axios"); class Twilio extends NotificationProvider { - name = "twilio"; /** * @inheritdoc */ async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { + const okMsg = "Sent Successfully."; - let okMsg = "Sent Successfully."; - - let accountSID = notification.twilioAccountSID; - let apiKey = notification.twilioApiKey ? notification.twilioApiKey : accountSID; - let authToken = notification.twilioAuthToken; + let apiKey = notification.twilioApiKey ? notification.twilioApiKey : notification.twilioAccountSID; try { - let config = { headers: { "Content-Type": "application/x-www-form-urlencoded;charset=utf-8", - "Authorization": "Basic " + Buffer.from(apiKey + ":" + authToken).toString("base64"), + "Authorization": "Basic " + Buffer.from(apiKey + ":" + notification.twilioAuthToken).toString("base64"), } }; @@ -30,9 +25,7 @@ class Twilio extends NotificationProvider { data.append("From", notification.twilioFromNumber); data.append("Body", msg); - let url = "https://api.twilio.com/2010-04-01/Accounts/" + accountSID + "/Messages.json"; - - await axios.post(url, data, config); + await axios.post(`https://api.twilio.com/2010-04-01/Accounts/${(notification.twilioAccountSID)}/Messages.json`, data, config); return okMsg; } catch (error) { diff --git a/server/notification-providers/webhook.js b/server/notification-providers/webhook.js index 597ef846..986986d4 100644 --- a/server/notification-providers/webhook.js +++ b/server/notification-providers/webhook.js @@ -4,14 +4,13 @@ const FormData = require("form-data"); const { Liquid } = require("liquidjs"); class Webhook extends NotificationProvider { - name = "webhook"; /** * @inheritdoc */ async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { - let okMsg = "Sent Successfully."; + const okMsg = "Sent Successfully."; try { let data = { diff --git a/server/notification-providers/wecom.js b/server/notification-providers/wecom.js index ea30b26d..03fa7c18 100644 --- a/server/notification-providers/wecom.js +++ b/server/notification-providers/wecom.js @@ -3,24 +3,22 @@ const axios = require("axios"); const { DOWN, UP } = require("../../src/util"); class WeCom extends NotificationProvider { - name = "WeCom"; /** * @inheritdoc */ async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { - let okMsg = "Sent Successfully."; + const okMsg = "Sent Successfully."; try { - let WeComUrl = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=" + notification.weComBotKey; let config = { headers: { "Content-Type": "application/json" } }; let body = this.composeMessage(heartbeatJSON, msg); - await axios.post(WeComUrl, body, config); + await axios.post(`https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=${notification.weComBotKey}`, body, config); return okMsg; } catch (error) { this.throwGeneralAxiosError(error); diff --git a/server/notification-providers/zoho-cliq.js b/server/notification-providers/zoho-cliq.js index 08653e3d..10381c81 100644 --- a/server/notification-providers/zoho-cliq.js +++ b/server/notification-providers/zoho-cliq.js @@ -3,7 +3,6 @@ const axios = require("axios"); const { DOWN, UP } = require("../../src/util"); class ZohoCliq extends NotificationProvider { - name = "ZohoCliq"; /** @@ -80,7 +79,7 @@ class ZohoCliq extends NotificationProvider { * @inheritdoc */ async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { - let okMsg = "Sent Successfully."; + const okMsg = "Sent Successfully."; try { if (heartbeatJSON == null) { diff --git a/server/notification.js b/server/notification.js index 5e76d6eb..5a412c6e 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"); @@ -87,6 +88,7 @@ class Notification { new Gotify(), new GrafanaOncall(), new HomeAssistant(), + new HeiiOnCall(), new Kook(), new Line(), new LineNotify(), diff --git a/server/server.js b/server/server.js index b41eb198..45732471 100644 --- a/server/server.js +++ b/server/server.js @@ -986,7 +986,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]; } @@ -1703,11 +1703,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); } /** @@ -1737,7 +1737,7 @@ async function pauseMonitor(userID, monitorID) { ]); if (monitorID in server.monitorList) { - server.monitorList[monitorID].stop(); + await server.monitorList[monitorID].stop(); server.monitorList[monitorID].active = 0; } } @@ -1754,7 +1754,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)); } @@ -1775,7 +1775,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(); diff --git a/src/components/NotificationDialog.vue b/src/components/NotificationDialog.vue index 57a2fdf2..56580fbf 100644 --- a/src/components/NotificationDialog.vue +++ b/src/components/NotificationDialog.vue @@ -120,6 +120,7 @@ export default { "gorush": "Gorush", "gotify": "Gotify", "GrafanaOncall": "Grafana Oncall", + "HeiiOnCall": "Heii On-Call", "HomeAssistant": "Home Assistant", "Kook": "Kook", "line": "LINE Messenger", diff --git a/src/components/notifications/HeiiOnCall.vue b/src/components/notifications/HeiiOnCall.vue new file mode 100644 index 00000000..a61c1c32 --- /dev/null +++ b/src/components/notifications/HeiiOnCall.vue @@ -0,0 +1,34 @@ + + + diff --git a/src/components/notifications/Line.vue b/src/components/notifications/Line.vue index dcd6142b..8ab6a048 100644 --- a/src/components/notifications/Line.vue +++ b/src/components/notifications/Line.vue @@ -1,17 +1,17 @@