diff --git a/server/notification.js b/server/notification.js index 446753ea4..cb77a6190 100644 --- a/server/notification.js +++ b/server/notification.js @@ -279,6 +279,116 @@ class Notification { throwGeneralAxiosError(error) } + } else if (notification.type === "mattermost") { + try { + const mattermostUserName = notification.mattermostusername || "Uptime Kuma"; + // If heartbeatJSON is null, assume we're testing. + if (heartbeatJSON == null) { + let mattermostTestData = { + username: mattermostUserName, + text: msg, + } + await axios.post(notification.mattermostWebhookUrl, mattermostTestData) + return okMsg; + } + + const mattermostChannel = notification.mattermostchannel; + const mattermostIconEmoji = notification.mattermosticonemo; + const mattermostIconUrl = notification.mattermosticonurl; + + if (heartbeatJSON["status"] == 0) { + let mattermostdowndata = { + username: mattermostUserName, + text: "Uptime Kuma Alert", + channel: mattermostChannel, + icon_emoji: mattermostIconEmoji, + icon_url: mattermostIconUrl, + attachments: [ + { + fallback: + "Your " + + monitorJSON["name"] + + " service went down.", + color: "#FF0000", + title: + "❌ " + + monitorJSON["name"] + + " service went down. ❌", + title_link: monitorJSON["url"], + fields: [ + { + short: true, + title: "Service Name", + value: monitorJSON["name"], + }, + { + short: true, + title: "Time (UTC)", + value: heartbeatJSON["time"], + }, + { + short: false, + title: "Error", + value: heartbeatJSON["msg"], + }, + ], + }, + ], + }; + await axios.post( + notification.mattermostWebhookUrl, + mattermostdowndata + ); + return okMsg; + } else if (heartbeatJSON["status"] == 1) { + let mattermostupdata = { + username: mattermostUserName, + text: "Uptime Kuma Alert", + channel: mattermostChannel, + icon_emoji: mattermostIconEmoji, + icon_url: mattermostIconUrl, + attachments: [ + { + fallback: + "Your " + + monitorJSON["name"] + + " service went up!", + color: "#32CD32", + title: + "✅ " + + monitorJSON["name"] + + " service went up! ✅", + title_link: monitorJSON["url"], + fields: [ + { + short: true, + title: "Service Name", + value: monitorJSON["name"], + }, + { + short: true, + title: "Time (UTC)", + value: heartbeatJSON["time"], + }, + { + short: false, + title: "Ping", + value: heartbeatJSON["ping"] + "ms", + }, + ], + }, + ], + }; + await axios.post( + notification.mattermostWebhookUrl, + mattermostupdata + ); + return okMsg; + } + } catch (error) { + throwGeneralAxiosError(error); + } + } else if (notification.type === "pushover") { let pushoverlink = "https://api.pushover.net/1/messages.json" try { diff --git a/src/components/NotificationDialog.vue b/src/components/NotificationDialog.vue index 43b56b2f1..d639e4f23 100644 --- a/src/components/NotificationDialog.vue +++ b/src/components/NotificationDialog.vue @@ -27,6 +27,7 @@ <option value="apprise">Apprise (Support 50+ Notification services)</option> <option value="pushbullet">Pushbullet</option> <option value="line">Line Messenger</option> + <option value="mattermost">Mattermost</option> </select> </div> @@ -238,6 +239,39 @@ </div> </template> + <template v-if="notification.type === 'mattermost'"> + <div class="mb-3"> + <label for="mattermost-webhook-url" class="form-label">Webhook URL<span style="color:red;"><sup>*</sup></span></label> + <input id="mattermost-webhook-url" v-model="notification.mattermostWebhookUrl" type="text" class="form-control" required> + <label for="mattermost-username" class="form-label">Username</label> + <input id="mattermost-username" v-model="notification.mattermostusername" type="text" class="form-control"> + <label for="mattermost-iconurl" class="form-label">Icon URL</label> + <input id="mattermost-iconurl" v-model="notification.mattermosticonurl" type="text" class="form-control"> + <label for="mattermost-iconemo" class="form-label">Icon Emoji</label> + <input id="mattermost-iconemo" v-model="notification.mattermosticonemo" type="text" class="form-control"> + <label for="mattermost-channel" class="form-label">Channel Name</label> + <input id="mattermost-channel-name" v-model="notification.mattermostchannel" type="text" class="form-control"> + <div class="form-text"> + <span style="color:red;"><sup>*</sup></span>Required + <p style="margin-top: 8px;"> + More info about webhooks on: <a href="https://docs.mattermost.com/developer/webhooks-incoming.html" target="_blank">https://docs.mattermost.com/developer/webhooks-incoming.html</a> + </p> + <p style="margin-top: 8px;"> + You can override the default channel that webhook posts to by entering the channel name into "Channel Name" field. This needs to be enabled in Mattermost webhook settings. Ex: #other-channel + </p> + <p style="margin-top: 8px;"> + If you leave the Uptime Kuma URL field blank, it will default to the Project Github page. + </p> + <p style="margin-top: 8px;"> + You can provide a link to a picture in "Icon URL" to override the default profile picture. Will not be used if Icon Emoji is set. + </p> + <p style="margin-top: 8px;"> + Emoji cheat sheet: <a href="https://www.webfx.com/tools/emoji-cheat-sheet/" target="_blank">https://www.webfx.com/tools/emoji-cheat-sheet/</a> Note: emoji takes preference over Icon URL. + </p> + </div> + </div> + </template> + <template v-if="notification.type === 'pushy'"> <div class="mb-3"> <label for="pushy-app-token" class="form-label">API_KEY</label>