Compare commits

..

3 commits

Author SHA1 Message Date
Sophie Hirn
6d85ba6fb0
Merge 216f39d556 into 03beef8006 2025-01-22 18:03:54 +00:00
DayShift
03beef8006
BugFix:Regular Expression in parseDuration Function (#5563)
Some checks failed
CodeQL / Analyze (push) Has been cancelled
Auto Test / armv7-simple-test (18, ARMv7) (push) Has been cancelled
Auto Test / armv7-simple-test (20, ARMv7) (push) Has been cancelled
Auto Test / check-linters (push) Has been cancelled
Auto Test / e2e-test (push) Has been cancelled
Merge Conflict Labeler / Labeling (push) Has been cancelled
validate / json-yaml-validate (push) Has been cancelled
validate / validate (push) Has been cancelled
Auto Test / auto-test (18, ARM64) (push) Has been cancelled
Auto Test / auto-test (18, macos-latest) (push) Has been cancelled
Auto Test / auto-test (18, ubuntu-latest) (push) Has been cancelled
Auto Test / auto-test (18, windows-latest) (push) Has been cancelled
Auto Test / auto-test (20, ARM64) (push) Has been cancelled
Auto Test / auto-test (20, macos-latest) (push) Has been cancelled
Auto Test / auto-test (20, ubuntu-latest) (push) Has been cancelled
Auto Test / auto-test (20, windows-latest) (push) Has been cancelled
Co-authored-by: Frank Elsinga <frank@elsinga.de>
2025-01-22 19:03:38 +01:00
Louis Lam
223cde831f
Fix push examples cannot be loaded (Docker only) (#5490)
Some checks failed
Auto Test / e2e-test (push) Has been cancelled
Auto Test / armv7-simple-test (18, ARMv7) (push) Has been cancelled
Auto Test / armv7-simple-test (20, ARMv7) (push) Has been cancelled
Auto Test / check-linters (push) Has been cancelled
CodeQL / Analyze (push) Has been cancelled
Merge Conflict Labeler / Labeling (push) Has been cancelled
validate / json-yaml-validate (push) Has been cancelled
validate / validate (push) Has been cancelled
Auto Test / auto-test (18, ARM64) (push) Has been cancelled
Auto Test / auto-test (18, macos-latest) (push) Has been cancelled
Auto Test / auto-test (18, ubuntu-latest) (push) Has been cancelled
Auto Test / auto-test (18, windows-latest) (push) Has been cancelled
Auto Test / auto-test (20, ARM64) (push) Has been cancelled
Auto Test / auto-test (20, macos-latest) (push) Has been cancelled
Auto Test / auto-test (20, ubuntu-latest) (push) Has been cancelled
Auto Test / auto-test (20, windows-latest) (push) Has been cancelled
2025-01-18 23:35:40 +08:00
14 changed files with 91 additions and 235 deletions

View file

@ -32,7 +32,6 @@ tsconfig.json
/extra/healthcheck.exe /extra/healthcheck.exe
/extra/healthcheck /extra/healthcheck
/extra/exe-builder /extra/exe-builder
/extra/push-examples
/extra/uptime-kuma-push /extra/uptime-kuma-push
# Comment the following line if you want to rebuild the healthcheck binary # Comment the following line if you want to rebuild the healthcheck binary

View file

@ -485,7 +485,7 @@ function ApiCache() {
} }
if (typeof duration === "string") { if (typeof duration === "string") {
let split = duration.match(/^([\d\.,]+)\s?(\w+)$/); let split = duration.match(/^([\d\.,]+)\s?([a-zA-Z]+)$/);
if (split.length === 3) { if (split.length === 3) {
let len = parseFloat(split[1]); let len = parseFloat(split[1]);

View file

@ -44,7 +44,7 @@ class Alerta extends NotificationProvider {
correlate: [ "service_up", "service_down" ], correlate: [ "service_up", "service_down" ],
event: monitorJSON["type"], event: monitorJSON["type"],
group: "uptimekuma-" + monitorJSON["type"], group: "uptimekuma-" + monitorJSON["type"],
resource: monitorJSON["name"], resource: monitorJSON["pathName"],
}, data ); }, data );
if (heartbeatJSON["status"] === DOWN) { if (heartbeatJSON["status"] === DOWN) {

View file

@ -1,34 +0,0 @@
const NotificationProvider = require("./notification-provider");
const axios = require("axios");
class Bale extends NotificationProvider {
name = "bale";
/**
* @inheritdoc
*/
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
const okMsg = "Sent Successfully.";
const url = "https://tapi.bale.ai";
try {
await axios.post(
`${url}/bot${notification.baleBotToken}/sendMessage`,
{
chat_id: notification.baleChatID,
text: msg
},
{
headers: {
"content-type": "application/json",
},
}
);
return okMsg;
} catch (error) {
this.throwGeneralAxiosError(error);
}
}
}
module.exports = Bale;

View file

@ -70,7 +70,7 @@ class Mattermost extends NotificationProvider {
} }
let mattermostdata = { let mattermostdata = {
username: monitorJSON.name + " " + mattermostUserName, username: monitorJSON.pathName + " " + mattermostUserName,
channel: mattermostChannel, channel: mattermostChannel,
icon_emoji: iconEmoji, icon_emoji: iconEmoji,
icon_url: mattermostIconUrl, icon_url: mattermostIconUrl,

View file

@ -60,7 +60,7 @@ class Ntfy extends NotificationProvider {
data.actions = [ data.actions = [
{ {
"action": "view", "action": "view",
"label": "Open " + monitorJSON.name, "label": "Open " + monitorJSON.pathName,
"url": monitorJSON.url, "url": monitorJSON.url,
}, },
]; ];

View file

@ -44,7 +44,7 @@ class Opsgenie extends NotificationProvider {
if (heartbeatJSON.status === DOWN) { if (heartbeatJSON.status === DOWN) {
let data = { let data = {
"message": monitorJSON ? textMsg + `: ${monitorJSON.pathName}` : textMsg, "message": monitorJSON ? textMsg + `: ${monitorJSON.pathName}` : textMsg,
"alias": monitorJSON.name, "alias": monitorJSON.pathName,
"description": msg, "description": msg,
"source": "Uptime Kuma", "source": "Uptime Kuma",
"priority": `P${priority}` "priority": `P${priority}`
@ -54,7 +54,7 @@ class Opsgenie extends NotificationProvider {
} }
if (heartbeatJSON.status === UP) { if (heartbeatJSON.status === UP) {
let opsgenieAlertsCloseUrl = `${opsgenieAlertsUrl}/${encodeURIComponent(monitorJSON.name)}/close?identifierType=alias`; let opsgenieAlertsCloseUrl = `${opsgenieAlertsUrl}/${encodeURIComponent(monitorJSON.pathName)}/close?identifierType=alias`;
let data = { let data = {
"source": "Uptime Kuma", "source": "Uptime Kuma",
}; };

View file

@ -224,7 +224,7 @@ class Teams extends NotificationProvider {
const payload = this._notificationPayloadFactory({ const payload = this._notificationPayloadFactory({
heartbeatJSON: heartbeatJSON, heartbeatJSON: heartbeatJSON,
monitorName: monitorJSON.name, monitorName: monitorJSON.pathName,
monitorUrl: this.extractAddress(monitorJSON), monitorUrl: this.extractAddress(monitorJSON),
dashboardUrl: dashboardUrl, dashboardUrl: dashboardUrl,
}); });

View file

@ -84,7 +84,7 @@ class ZohoCliq extends NotificationProvider {
const payload = this._notificationPayloadFactory({ const payload = this._notificationPayloadFactory({
monitorMessage: heartbeatJSON.msg, monitorMessage: heartbeatJSON.msg,
monitorName: monitorJSON.name, monitorName: monitorJSON.pathName,
monitorUrl: this.extractAddress(monitorJSON), monitorUrl: this.extractAddress(monitorJSON),
status: heartbeatJSON.status status: heartbeatJSON.status
}); });

View file

@ -4,7 +4,6 @@ const Alerta = require("./notification-providers/alerta");
const AlertNow = require("./notification-providers/alertnow"); const AlertNow = require("./notification-providers/alertnow");
const AliyunSms = require("./notification-providers/aliyun-sms"); const AliyunSms = require("./notification-providers/aliyun-sms");
const Apprise = require("./notification-providers/apprise"); const Apprise = require("./notification-providers/apprise");
const Bale = require("./notification-providers/bale");
const Bark = require("./notification-providers/bark"); const Bark = require("./notification-providers/bark");
const Bitrix24 = require("./notification-providers/bitrix24"); const Bitrix24 = require("./notification-providers/bitrix24");
const ClickSendSMS = require("./notification-providers/clicksendsms"); const ClickSendSMS = require("./notification-providers/clicksendsms");
@ -72,6 +71,7 @@ const Wpush = require("./notification-providers/wpush");
const SendGrid = require("./notification-providers/send-grid"); const SendGrid = require("./notification-providers/send-grid");
class Notification { class Notification {
providerList = {}; providerList = {};
/** /**
@ -90,7 +90,6 @@ class Notification {
new AlertNow(), new AlertNow(),
new AliyunSms(), new AliyunSms(),
new Apprise(), new Apprise(),
new Bale(),
new Bark(), new Bark(),
new Bitrix24(), new Bitrix24(),
new ClickSendSMS(), new ClickSendSMS(),
@ -155,10 +154,10 @@ class Notification {
new GtxMessaging(), new GtxMessaging(),
new Cellsynt(), new Cellsynt(),
new Wpush(), new Wpush(),
new SendGrid(), new SendGrid()
]; ];
for (let item of list) { for (let item of list) {
if (!item.name) { if (! item.name) {
throw new Error("Notification provider without name"); throw new Error("Notification provider without name");
} }
@ -178,19 +177,9 @@ class Notification {
* @returns {Promise<string>} Successful msg * @returns {Promise<string>} Successful msg
* @throws Error with fail msg * @throws Error with fail msg
*/ */
static async send( static async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
notification,
msg,
monitorJSON = null,
heartbeatJSON = null
) {
if (this.providerList[notification.type]) { if (this.providerList[notification.type]) {
return this.providerList[notification.type].send( return this.providerList[notification.type].send(notification, msg, monitorJSON, heartbeatJSON);
notification,
msg,
monitorJSON,
heartbeatJSON
);
} else { } else {
throw new Error("Notification type is not supported"); throw new Error("Notification type is not supported");
} }
@ -212,9 +201,10 @@ class Notification {
userID, userID,
]); ]);
if (!bean) { if (! bean) {
throw new Error("notification not found"); throw new Error("notification not found");
} }
} else { } else {
bean = R.dispense("notification"); bean = R.dispense("notification");
} }
@ -244,7 +234,7 @@ class Notification {
userID, userID,
]); ]);
if (!bean) { if (! bean) {
throw new Error("notification not found"); throw new Error("notification not found");
} }
@ -260,6 +250,7 @@ class Notification {
let exists = commandExistsSync("apprise"); let exists = commandExistsSync("apprise");
return exists; return exists;
} }
} }
/** /**
@ -270,17 +261,16 @@ class Notification {
*/ */
async function applyNotificationEveryMonitor(notificationID, userID) { async function applyNotificationEveryMonitor(notificationID, userID) {
let monitors = await R.getAll("SELECT id FROM monitor WHERE user_id = ?", [ let monitors = await R.getAll("SELECT id FROM monitor WHERE user_id = ?", [
userID, userID
]); ]);
for (let i = 0; i < monitors.length; i++) { for (let i = 0; i < monitors.length; i++) {
let checkNotification = await R.findOne( let checkNotification = await R.findOne("monitor_notification", " monitor_id = ? AND notification_id = ? ", [
"monitor_notification", monitors[i].id,
" monitor_id = ? AND notification_id = ? ", notificationID,
[ monitors[i].id, notificationID ] ]);
);
if (!checkNotification) { if (! checkNotification) {
let relation = R.dispense("monitor_notification"); let relation = R.dispense("monitor_notification");
relation.monitor_id = monitors[i].id; relation.monitor_id = monitors[i].id;
relation.notification_id = notificationID; relation.notification_id = notificationID;

View file

@ -113,7 +113,6 @@ export default {
"alerta": "Alerta", "alerta": "Alerta",
"AlertNow": "AlertNow", "AlertNow": "AlertNow",
"apprise": this.$t("apprise"), "apprise": this.$t("apprise"),
"bale": "Bale",
"Bark": "Bark", "Bark": "Bark",
"Bitrix24": "Bitrix24", "Bitrix24": "Bitrix24",
"clicksendsms": "ClickSend SMS", "clicksendsms": "ClickSend SMS",

View file

@ -1,93 +0,0 @@
<template>
<div class="mb-3">
<label for="bale-bot-token" class="form-label">{{ $t("Bot Token") }}</label>
<HiddenInput id="bale-bot-token" v-model="$parent.notification.baleBotToken" :required="true" autocomplete="new-password"></HiddenInput>
<i18n-t tag="div" keypath="wayToGetBaleToken" class="form-text">
<a href="https://ble.ir/BotFather" target="_blank">https://ble.ir/BotFather</a>
</i18n-t>
</div>
<div class="mb-3">
<label for="bale-chat-id" class="form-label">{{ $t("Chat ID") }}</label>
<div class="input-group mb-3">
<input id="bale-chat-id" v-model="$parent.notification.baleChatID" type="text" class="form-control" required>
<button v-if="$parent.notification.baleBotToken" class="btn btn-outline-secondary" type="button" @click="autoGetBaleChatID">
{{ $t("Auto Get") }}
</button>
</div>
<div class="form-text">
{{ $t("supportBaleChatID") }}
<p style="margin-top: 8px;">
{{ $t("wayToGetBaleChatID") }}
</p>
<p style="margin-top: 8px;">
<a :href="baleGetUpdatesURL('withToken')" target="_blank" style="word-break: break-word;">{{ baleGetUpdatesURL("masked") }}</a>
</p>
</div>
</div>
</template>
<script>
import HiddenInput from "../HiddenInput.vue";
import axios from "axios";
export default {
components: {
HiddenInput,
},
methods: {
/**
* Get the URL for bale updates
* @param {string} mode Should the token be masked?
* @returns {string} formatted URL
*/
baleGetUpdatesURL(mode = "masked") {
let token = `<${this.$t("YOUR BOT TOKEN HERE")}>`;
if (this.$parent.notification.baleBotToken) {
if (mode === "withToken") {
token = this.$parent.notification.baleBotToken;
} else if (mode === "masked") {
token = "*".repeat(this.$parent.notification.baleBotToken.length);
}
}
return `https://tapi.bale.ai/bot${token}/getUpdates`;
},
/**
* Get the bale chat ID
* @returns {Promise<void>}
* @throws The chat ID could not be found
*/
async autoGetBaleChatID() {
try {
let res = await axios.get(this.baleGetUpdatesURL("withToken"));
if (res.data.result.length >= 1) {
let update = res.data.result[res.data.result.length - 1];
if (update.channel_post) {
this.$parent.notification.baleChatID = update.channel_post.chat.id;
} else if (update.message) {
this.$parent.notification.baleChatID = update.message.chat.id;
} else {
throw new Error(this.$t("chatIDNotFound"));
}
} else {
throw new Error(this.$t("chatIDNotFound"));
}
} catch (error) {
this.$root.toastError(error.message);
}
},
}
};
</script>

View file

@ -2,7 +2,6 @@ import Alerta from "./Alerta.vue";
import AlertNow from "./AlertNow.vue"; import AlertNow from "./AlertNow.vue";
import AliyunSMS from "./AliyunSms.vue"; import AliyunSMS from "./AliyunSms.vue";
import Apprise from "./Apprise.vue"; import Apprise from "./Apprise.vue";
import Bale from "./Bale.vue";
import Bark from "./Bark.vue"; import Bark from "./Bark.vue";
import Bitrix24 from "./Bitrix24.vue"; import Bitrix24 from "./Bitrix24.vue";
import ClickSendSMS from "./ClickSendSMS.vue"; import ClickSendSMS from "./ClickSendSMS.vue";
@ -74,76 +73,75 @@ import SendGrid from "./SendGrid.vue";
* @type { Record<string, any> } * @type { Record<string, any> }
*/ */
const NotificationFormList = { const NotificationFormList = {
alerta: Alerta, "alerta": Alerta,
AlertNow: AlertNow, "AlertNow": AlertNow,
AliyunSMS: AliyunSMS, "AliyunSMS": AliyunSMS,
apprise: Apprise, "apprise": Apprise,
bale: Bale, "Bark": Bark,
Bark: Bark, "Bitrix24": Bitrix24,
Bitrix24: Bitrix24, "clicksendsms": ClickSendSMS,
clicksendsms: ClickSendSMS, "CallMeBot": CallMeBot,
CallMeBot: CallMeBot, "smsc": SMSC,
smsc: SMSC, "DingDing": DingDing,
DingDing: DingDing, "discord": Discord,
discord: Discord, "Elks": Elks,
Elks: Elks, "Feishu": Feishu,
Feishu: Feishu, "FreeMobile": FreeMobile,
FreeMobile: FreeMobile, "GoogleChat": GoogleChat,
GoogleChat: GoogleChat, "gorush": Gorush,
gorush: Gorush, "gotify": Gotify,
gotify: Gotify, "GrafanaOncall": GrafanaOncall,
GrafanaOncall: GrafanaOncall, "HomeAssistant": HomeAssistant,
HomeAssistant: HomeAssistant, "HeiiOnCall": HeiiOnCall,
HeiiOnCall: HeiiOnCall, "Keep": Keep,
Keep: Keep, "Kook": Kook,
Kook: Kook, "line": Line,
line: Line, "LineNotify": LineNotify,
LineNotify: LineNotify, "lunasea": LunaSea,
lunasea: LunaSea, "matrix": Matrix,
matrix: Matrix, "mattermost": Mattermost,
mattermost: Mattermost, "nostr": Nostr,
nostr: Nostr, "ntfy": Ntfy,
ntfy: Ntfy, "octopush": Octopush,
octopush: Octopush, "OneBot": OneBot,
OneBot: OneBot, "Onesender": Onesender,
Onesender: Onesender, "Opsgenie": Opsgenie,
Opsgenie: Opsgenie, "PagerDuty": PagerDuty,
PagerDuty: PagerDuty, "FlashDuty": FlashDuty,
FlashDuty: FlashDuty, "PagerTree": PagerTree,
PagerTree: PagerTree, "promosms": PromoSMS,
promosms: PromoSMS, "pushbullet": Pushbullet,
pushbullet: Pushbullet, "PushByTechulus": TechulusPush,
PushByTechulus: TechulusPush, "PushDeer": PushDeer,
PushDeer: PushDeer, "pushover": Pushover,
pushover: Pushover, "pushy": Pushy,
pushy: Pushy,
"rocket.chat": RocketChat, "rocket.chat": RocketChat,
serwersms: SerwerSMS, "serwersms": SerwerSMS,
signal: Signal, "signal": Signal,
SIGNL4: SIGNL4, "SIGNL4": SIGNL4,
SMSManager: SMSManager, "SMSManager": SMSManager,
SMSPartner: SMSPartner, "SMSPartner": SMSPartner,
slack: Slack, "slack": Slack,
squadcast: Squadcast, "squadcast": Squadcast,
SMSEagle: SMSEagle, "SMSEagle": SMSEagle,
smtp: STMP, "smtp": STMP,
stackfield: Stackfield, "stackfield": Stackfield,
teams: Teams, "teams": Teams,
telegram: Telegram, "telegram": Telegram,
threema: Threema, "threema": Threema,
twilio: Twilio, "twilio": Twilio,
Splunk: Splunk, "Splunk": Splunk,
webhook: Webhook, "webhook": Webhook,
WeCom: WeCom, "WeCom": WeCom,
GoAlert: GoAlert, "GoAlert": GoAlert,
ServerChan: ServerChan, "ServerChan": ServerChan,
ZohoCliq: ZohoCliq, "ZohoCliq": ZohoCliq,
SevenIO: SevenIO, "SevenIO": SevenIO,
whapi: Whapi, "whapi": Whapi,
gtxmessaging: GtxMessaging, "gtxmessaging": GtxMessaging,
Cellsynt: Cellsynt, "Cellsynt": Cellsynt,
WPush: WPush, "WPush": WPush,
SendGrid: SendGrid, "SendGrid": SendGrid,
}; };
export default NotificationFormList; export default NotificationFormList;

View file

@ -429,9 +429,6 @@
"trustProxyDescription": "Trust 'X-Forwarded-*' headers. If you want to get the correct client IP and your Uptime Kuma is behind a proxy such as Nginx or Apache, you should enable this.", "trustProxyDescription": "Trust 'X-Forwarded-*' headers. If you want to get the correct client IP and your Uptime Kuma is behind a proxy such as Nginx or Apache, you should enable this.",
"wayToGetLineNotifyToken": "You can get an access token from {0}", "wayToGetLineNotifyToken": "You can get an access token from {0}",
"Examples": "Examples", "Examples": "Examples",
"supportBaleChatID": "Support Direct Chat / Group / Channel's Chat ID",
"wayToGetBaleChatID": "You can get your chat ID by sending a message to the bot and going to this URL to view the chat_id:",
"wayToGetBaleToken": "You can get a token from {0}.",
"Home Assistant URL": "Home Assistant URL", "Home Assistant URL": "Home Assistant URL",
"Long-Lived Access Token": "Long-Lived Access Token", "Long-Lived Access Token": "Long-Lived Access Token",
"Long-Lived Access Token can be created by clicking on your profile name (bottom left) and scrolling to the bottom then click Create Token. ": "Long-Lived Access Token can be created by clicking on your profile name (bottom left) and scrolling to the bottom then click Create Token. ", "Long-Lived Access Token can be created by clicking on your profile name (bottom left) and scrolling to the bottom then click Create Token. ": "Long-Lived Access Token can be created by clicking on your profile name (bottom left) and scrolling to the bottom then click Create Token. ",