diff --git a/.github/workflows/stale-bot.yml b/.github/workflows/stale-bot.yml
deleted file mode 100644
index e4faaa5f8..000000000
--- a/.github/workflows/stale-bot.yml
+++ /dev/null
@@ -1,22 +0,0 @@
-name: 'Automatically close stale issues and PRs'
-on:
- schedule:
- - cron: '0 0 * * *'
-#Run once a day at midnight
-
-jobs:
- stale:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/stale@v4
- with:
- stale-issue-message: 'We are clearing up our old issues and your ticket has been open for 6 months with no activity. Remove stale label or comment or this will be closed in 7 days.'
- stale-pr-message: 'We are clearing up our old Pull Requests and yours has been open for 6 months with no activity. Remove stale label or comment or this will be closed in 7 days.'
- close-issue-message: 'This issue was closed because it has been stalled for 7 days with no activity.'
- close-pr-message: 'This PR was closed because it has been stalled for 7 days with no activity.'
- days-before-stale: 180
- days-before-close: 0
- exempt-issue-labels: 'News,Medium,High,discussion,bug,doc,'
- exempt-pr-labels: 'awaiting-approval,work-in-progress,enhancement,feature-request'
- exempt-issue-assignees: 'louislam'
- exempt-pr-assignees: 'louislam'
diff --git a/server/check-version.js b/server/check-version.js
index a3465ddf0..f3b15e848 100644
--- a/server/check-version.js
+++ b/server/check-version.js
@@ -1,5 +1,6 @@
-const { setSetting } = require("./util-server");
+const { setSetting, setting } = require("./util-server");
const axios = require("axios");
+const compareVersions = require("compare-versions");
exports.version = require("../package.json").version;
exports.latestVersion = null;
@@ -16,6 +17,19 @@ exports.startInterval = () => {
res.data.slow = "1000.0.0";
}
+ if (!await setting("checkUpdate")) {
+ return;
+ }
+
+ let checkBeta = await setting("checkBeta");
+
+ if (checkBeta && res.data.beta) {
+ if (compareVersions.compare(res.data.beta, res.data.beta, ">")) {
+ exports.latestVersion = res.data.beta;
+ return;
+ }
+ }
+
if (res.data.slow) {
exports.latestVersion = res.data.slow;
}
diff --git a/server/notification-providers/alerta.js b/server/notification-providers/alerta.js
new file mode 100644
index 000000000..e692b57ba
--- /dev/null
+++ b/server/notification-providers/alerta.js
@@ -0,0 +1,67 @@
+const NotificationProvider = require("./notification-provider");
+const { DOWN, UP } = require("../../src/util");
+const axios = require("axios");
+
+class Alerta extends NotificationProvider {
+
+ name = "alerta";
+
+ async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
+ let okMsg = "Sent Successfully.";
+
+ try {
+ let alertaUrl = `${notification.alertaApiEndpoint}`;
+ let config = {
+ headers: {
+ "Content-Type": "application/json;charset=UTF-8",
+ "Authorization": "Key " + notification.alertaapiKey,
+ }
+ };
+ let data = {
+ environment: notification.alertaEnvironment,
+ severity: "critical",
+ correlate: [],
+ service: [ "UptimeKuma" ],
+ value: "Timeout",
+ tags: [ "uptimekuma" ],
+ attributes: {},
+ origin: "uptimekuma",
+ type: "exceptionAlert",
+ };
+
+ if (heartbeatJSON == null) {
+ let postData = Object.assign({
+ event: "msg",
+ text: msg,
+ group: "uptimekuma-msg",
+ resource: "Message",
+ }, data);
+
+ await axios.post(alertaUrl, postData, config);
+ } else {
+ let datadup = Object.assign( {
+ correlate: ["service_up", "service_down"],
+ event: monitorJSON["type"],
+ group: "uptimekuma-" + monitorJSON["type"],
+ resource: monitorJSON["name"],
+ }, data );
+
+ if (heartbeatJSON["status"] == DOWN) {
+ datadup.severity = notification.alertaAlertState; // critical
+ datadup.text = "Service " + monitorJSON["type"] + " is down.";
+ await axios.post(alertaUrl, 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);
+ }
+ }
+ return okMsg;
+ } catch (error) {
+ this.throwGeneralAxiosError(error);
+ }
+
+ }
+}
+
+module.exports = Alerta;
diff --git a/server/notification-providers/gorush.js b/server/notification-providers/gorush.js
new file mode 100644
index 000000000..58da5525e
--- /dev/null
+++ b/server/notification-providers/gorush.js
@@ -0,0 +1,42 @@
+const NotificationProvider = require("./notification-provider");
+const axios = require("axios");
+
+class Gorush extends NotificationProvider {
+
+ name = "gorush";
+
+ async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
+ let okMsg = "Sent Successfully.";
+
+ let platformMapping = {
+ "ios": 1,
+ "android": 2,
+ "huawei": 3,
+ };
+
+ try {
+ let data = {
+ "notifications": [
+ {
+ "tokens": [notification.gorushDeviceToken],
+ "platform": platformMapping[notification.gorushPlatform],
+ "message": msg,
+ // Optional
+ "title": notification.gorushTitle,
+ "priority": notification.gorushPriority,
+ "retry": parseInt(notification.gorushRetry) || 0,
+ "topic": notification.gorushTopic,
+ }
+ ]
+ };
+ let config = {};
+
+ await axios.post(`${notification.gorushServerURL}/api/push`, data, config);
+ return okMsg;
+ } catch (error) {
+ this.throwGeneralAxiosError(error);
+ }
+ }
+}
+
+module.exports = Gorush;
diff --git a/server/notification-providers/techulus-push.js b/server/notification-providers/techulus-push.js
new file mode 100644
index 000000000..f844d17ce
--- /dev/null
+++ b/server/notification-providers/techulus-push.js
@@ -0,0 +1,23 @@
+const NotificationProvider = require("./notification-provider");
+const axios = require("axios");
+
+class TechulusPush extends NotificationProvider {
+
+ name = "PushByTechulus";
+
+ async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
+ let okMsg = "Sent Successfully.";
+
+ try {
+ await axios.post(`https://push.techulus.com/api/v1/notify/${notification.pushAPIKey}`, {
+ "title": "Uptime-Kuma",
+ "body": msg,
+ })
+ return okMsg;
+ } catch (error) {
+ this.throwGeneralAxiosError(error)
+ }
+ }
+}
+
+module.exports = TechulusPush;
diff --git a/server/notification.js b/server/notification.js
index 4d72c81c7..30f83b0e0 100644
--- a/server/notification.js
+++ b/server/notification.js
@@ -12,6 +12,7 @@ const ClickSendSMS = require("./notification-providers/clicksendsms");
const Pushbullet = require("./notification-providers/pushbullet");
const Pushover = require("./notification-providers/pushover");
const Pushy = require("./notification-providers/pushy");
+const TechulusPush = require("./notification-providers/techulus-push");
const RocketChat = require("./notification-providers/rocket-chat");
const Signal = require("./notification-providers/signal");
const Slack = require("./notification-providers/slack");
@@ -27,6 +28,8 @@ const SerwerSMS = require("./notification-providers/serwersms");
const Stackfield = require("./notification-providers/stackfield");
const WeCom = require("./notification-providers/wecom");
const GoogleChat = require("./notification-providers/google-chat");
+const Gorush = require("./notification-providers/gorush");
+const Alerta = require("./notification-providers/alerta");
class Notification {
@@ -55,6 +58,7 @@ class Notification {
new Pushbullet(),
new Pushover(),
new Pushy(),
+ new TechulusPush(),
new RocketChat(),
new Signal(),
new Slack(),
@@ -65,7 +69,9 @@ class Notification {
new SerwerSMS(),
new Stackfield(),
new WeCom(),
- new GoogleChat()
+ new GoogleChat(),
+ new Gorush(),
+ new Alerta(),
];
for (let item of list) {
diff --git a/src/assets/app.scss b/src/assets/app.scss
index cec644676..f49ed4f2c 100644
--- a/src/assets/app.scss
+++ b/src/assets/app.scss
@@ -156,8 +156,13 @@ textarea.form-control {
.form-check-input {
background-color: $dark-bg2;
+ border-color: $dark-border-color;
}
+ .form-check-input:checked {
+ border-color: $primary; // Re-apply bootstrap border
+ }
+
.form-switch .form-check-input {
background-color: #232f3b;
}
diff --git a/src/components/NotificationDialog.vue b/src/components/NotificationDialog.vue
index 659f57267..8c03dbbda 100644
--- a/src/components/NotificationDialog.vue
+++ b/src/components/NotificationDialog.vue
@@ -85,7 +85,9 @@ export default {
model: null,
processing: false,
id: null,
- notificationTypes: Object.keys(NotificationFormList),
+ notificationTypes: Object.keys(NotificationFormList).sort((a, b) => {
+ return a.toLowerCase().localeCompare(b.toLowerCase());
+ }),
notification: {
name: "",
/** @type { null | keyof NotificationFormList } */
@@ -143,12 +145,9 @@ export default {
this.id = null;
this.notification = {
name: "",
- type: null,
+ type: "telegram",
isDefault: false,
};
-
- // Set Default value here
- this.notification.type = this.notificationTypes[0];
}
this.modal.show();
diff --git a/src/components/notifications/Alerta.vue b/src/components/notifications/Alerta.vue
new file mode 100644
index 000000000..962267fb6
--- /dev/null
+++ b/src/components/notifications/Alerta.vue
@@ -0,0 +1,14 @@
+
+