mirror of
https://github.com/louislam/uptime-kuma.git
synced 2025-04-02 06:22:20 +00:00
Merge branch 'master' into telegram-custom-server
# Conflicts: # src/components/notifications/Telegram.vue
This commit is contained in:
commit
6dd37e1ab1
19 changed files with 465 additions and 91 deletions
|
@ -41,7 +41,7 @@
|
|||
"build-docker-pr-test": "docker buildx build -f docker/dockerfile --platform linux/amd64,linux/arm64 -t louislam/uptime-kuma:pr-test2 --target pr-test2 . --push",
|
||||
"upload-artifacts": "node extra/release/upload-artifacts.mjs",
|
||||
"upload-artifacts-beta": "node extra/release/upload-artifacts-beta.mjs",
|
||||
"setup": "git checkout 1.23.16 && npm ci --production && npm run download-dist",
|
||||
"setup": "git checkout 1.23.16 && npm ci --omit dev && npm run download-dist",
|
||||
"download-dist": "node extra/download-dist.js",
|
||||
"mark-as-nightly": "node extra/mark-as-nightly.js",
|
||||
"reset-password": "node extra/reset-password.js",
|
||||
|
|
|
@ -1434,7 +1434,7 @@ class Monitor extends BeanModel {
|
|||
for (let notification of notificationList) {
|
||||
try {
|
||||
log.debug("monitor", "Sending to " + notification.name);
|
||||
await Notification.send(JSON.parse(notification.config), `[${this.name}][${this.url}] ${certType} certificate ${certCN} will be expired in ${daysRemaining} days`);
|
||||
await Notification.send(JSON.parse(notification.config), `[${this.name}][${this.url}] ${certType} certificate ${certCN} will expire in ${daysRemaining} days`);
|
||||
sent = true;
|
||||
} catch (e) {
|
||||
log.error("monitor", "Cannot send cert notification to " + notification.name);
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
const { Liquid } = require("liquidjs");
|
||||
const { DOWN } = require("../../src/util");
|
||||
|
||||
class NotificationProvider {
|
||||
|
||||
/**
|
||||
|
@ -49,6 +52,50 @@ class NotificationProvider {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a message template with notification context
|
||||
* @param {string} template the template
|
||||
* @param {string} msg the message that will be included in the context
|
||||
* @param {?object} monitorJSON Monitor details (For Up/Down/Cert-Expiry only)
|
||||
* @param {?object} heartbeatJSON Heartbeat details (For Up/Down only)
|
||||
* @returns {Promise<string>} rendered template
|
||||
*/
|
||||
async renderTemplate(template, msg, monitorJSON, heartbeatJSON) {
|
||||
const engine = new Liquid();
|
||||
const parsedTpl = engine.parse(template);
|
||||
|
||||
// Let's start with dummy values to simplify code
|
||||
let monitorName = "Monitor Name not available";
|
||||
let monitorHostnameOrURL = "testing.hostname";
|
||||
|
||||
if (monitorJSON !== null) {
|
||||
monitorName = monitorJSON["name"];
|
||||
monitorHostnameOrURL = this.extractAddress(monitorJSON);
|
||||
}
|
||||
|
||||
let serviceStatus = "⚠️ Test";
|
||||
if (heartbeatJSON !== null) {
|
||||
serviceStatus = (heartbeatJSON["status"] === DOWN) ? "🔴 Down" : "✅ Up";
|
||||
}
|
||||
|
||||
const context = {
|
||||
// for v1 compatibility, to be removed in v3
|
||||
"STATUS": serviceStatus,
|
||||
"NAME": monitorName,
|
||||
"HOSTNAME_OR_URL": monitorHostnameOrURL,
|
||||
|
||||
// variables which are officially supported
|
||||
"status": serviceStatus,
|
||||
"name": monitorName,
|
||||
"hostnameOrURL": monitorHostnameOrURL,
|
||||
monitorJSON,
|
||||
heartbeatJSON,
|
||||
msg,
|
||||
};
|
||||
|
||||
return engine.render(parsedTpl, context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws an error
|
||||
* @param {any} error The error to throw
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
const nodemailer = require("nodemailer");
|
||||
const NotificationProvider = require("./notification-provider");
|
||||
const { DOWN } = require("../../src/util");
|
||||
const { Liquid } = require("liquidjs");
|
||||
|
||||
class SMTP extends NotificationProvider {
|
||||
name = "smtp";
|
||||
|
@ -53,15 +51,11 @@ class SMTP extends NotificationProvider {
|
|||
const customSubject = notification.customSubject?.trim() || "";
|
||||
const customBody = notification.customBody?.trim() || "";
|
||||
|
||||
const context = this.generateContext(msg, monitorJSON, heartbeatJSON);
|
||||
const engine = new Liquid();
|
||||
if (customSubject !== "") {
|
||||
const tpl = engine.parse(customSubject);
|
||||
subject = await engine.render(tpl, context);
|
||||
subject = await this.renderTemplate(customSubject, msg, monitorJSON, heartbeatJSON);
|
||||
}
|
||||
if (customBody !== "") {
|
||||
const tpl = engine.parse(customBody);
|
||||
body = await engine.render(tpl, context);
|
||||
body = await this.renderTemplate(customBody, msg, monitorJSON, heartbeatJSON);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -78,43 +72,6 @@ class SMTP extends NotificationProvider {
|
|||
|
||||
return okMsg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate context for LiquidJS
|
||||
* @param {string} msg the message that will be included in the context
|
||||
* @param {?object} monitorJSON Monitor details (For Up/Down/Cert-Expiry only)
|
||||
* @param {?object} heartbeatJSON Heartbeat details (For Up/Down only)
|
||||
* @returns {{STATUS: string, status: string, HOSTNAME_OR_URL: string, hostnameOrUrl: string, NAME: string, name: string, monitorJSON: ?object, heartbeatJSON: ?object, msg: string}} the context
|
||||
*/
|
||||
generateContext(msg, monitorJSON, heartbeatJSON) {
|
||||
// Let's start with dummy values to simplify code
|
||||
let monitorName = "Monitor Name not available";
|
||||
let monitorHostnameOrURL = "testing.hostname";
|
||||
|
||||
if (monitorJSON !== null) {
|
||||
monitorName = monitorJSON["name"];
|
||||
monitorHostnameOrURL = this.extractAddress(monitorJSON);
|
||||
}
|
||||
|
||||
let serviceStatus = "⚠️ Test";
|
||||
if (heartbeatJSON !== null) {
|
||||
serviceStatus = (heartbeatJSON["status"] === DOWN) ? "🔴 Down" : "✅ Up";
|
||||
}
|
||||
return {
|
||||
// for v1 compatibility, to be removed in v3
|
||||
"STATUS": serviceStatus,
|
||||
"NAME": monitorName,
|
||||
"HOSTNAME_OR_URL": monitorHostnameOrURL,
|
||||
|
||||
// variables which are officially supported
|
||||
"status": serviceStatus,
|
||||
"name": monitorName,
|
||||
"hostnameOrURL": monitorHostnameOrURL,
|
||||
monitorJSON,
|
||||
heartbeatJSON,
|
||||
msg,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = SMTP;
|
||||
|
|
|
@ -22,6 +22,14 @@ class Telegram extends NotificationProvider {
|
|||
params.message_thread_id = notification.telegramMessageThreadID;
|
||||
}
|
||||
|
||||
if (notification.telegramUseTemplate) {
|
||||
params.text = await this.renderTemplate(notification.telegramTemplate, msg, monitorJSON, heartbeatJSON);
|
||||
|
||||
if (notification.telegramTemplateParseMode !== "plain") {
|
||||
params.parse_mode = notification.telegramTemplateParseMode;
|
||||
}
|
||||
}
|
||||
|
||||
await axios.get(`${url}/bot${notification.telegramBotToken}/sendMessage`, {
|
||||
params: params,
|
||||
});
|
||||
|
|
40
server/notification-providers/waha.js
Normal file
40
server/notification-providers/waha.js
Normal file
|
@ -0,0 +1,40 @@
|
|||
const NotificationProvider = require("./notification-provider");
|
||||
const axios = require("axios");
|
||||
|
||||
class WAHA extends NotificationProvider {
|
||||
name = "waha";
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
||||
const okMsg = "Sent Successfully.";
|
||||
|
||||
try {
|
||||
const config = {
|
||||
headers: {
|
||||
"Accept": "application/json",
|
||||
"Content-Type": "application/json",
|
||||
"X-Api-Key": notification.wahaApiKey,
|
||||
}
|
||||
};
|
||||
|
||||
let data = {
|
||||
"session": notification.wahaSession,
|
||||
"chatId": notification.wahaChatId,
|
||||
"text": msg,
|
||||
};
|
||||
|
||||
let url = notification.wahaApiUrl.replace(/([^/])\/+$/, "$1") + "/api/sendText";
|
||||
|
||||
await axios.post(url, data, config);
|
||||
|
||||
return okMsg;
|
||||
} catch (error) {
|
||||
this.throwGeneralAxiosError(error);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = WAHA;
|
|
@ -1,7 +1,6 @@
|
|||
const NotificationProvider = require("./notification-provider");
|
||||
const axios = require("axios");
|
||||
const FormData = require("form-data");
|
||||
const { Liquid } = require("liquidjs");
|
||||
|
||||
class Webhook extends NotificationProvider {
|
||||
name = "webhook";
|
||||
|
@ -28,17 +27,7 @@ class Webhook extends NotificationProvider {
|
|||
config.headers = formData.getHeaders();
|
||||
data = formData;
|
||||
} else if (notification.webhookContentType === "custom") {
|
||||
// Initialize LiquidJS and parse the custom Body Template
|
||||
const engine = new Liquid();
|
||||
const tpl = engine.parse(notification.webhookCustomBody);
|
||||
|
||||
// Insert templated values into Body
|
||||
data = await engine.render(tpl,
|
||||
{
|
||||
msg,
|
||||
heartbeatJSON,
|
||||
monitorJSON
|
||||
});
|
||||
data = await this.renderTemplate(notification.webhookCustomBody, msg, monitorJSON, heartbeatJSON);
|
||||
}
|
||||
|
||||
if (notification.webhookAdditionalHeaders) {
|
||||
|
|
57
server/notification-providers/yzj.js
Normal file
57
server/notification-providers/yzj.js
Normal file
|
@ -0,0 +1,57 @@
|
|||
const NotificationProvider = require("./notification-provider");
|
||||
const { DOWN, UP } = require("../../src/util");
|
||||
const { default: axios } = require("axios");
|
||||
|
||||
class YZJ extends NotificationProvider {
|
||||
name = "YZJ";
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
||||
let okMsg = "Sent Successfully.";
|
||||
|
||||
try {
|
||||
if (heartbeatJSON !== null) {
|
||||
msg = `${this.statusToString(heartbeatJSON["status"])} ${monitorJSON["name"]} \n> ${heartbeatJSON["msg"]}\n> Time (${heartbeatJSON["timezone"]}): ${heartbeatJSON["localDateTime"]}`;
|
||||
}
|
||||
|
||||
const config = {
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
};
|
||||
const params = {
|
||||
content: msg
|
||||
};
|
||||
// yzjtype=0 => general robot
|
||||
const url = `${notification.yzjWebHookUrl}?yzjtype=0&yzjtoken=${notification.yzjToken}`;
|
||||
|
||||
const result = await axios.post(url, params, config);
|
||||
if (!result.data?.success) {
|
||||
throw new Error(result.data?.errmsg ?? "yzj's server did not respond with the expected result");
|
||||
}
|
||||
return okMsg;
|
||||
} catch (error) {
|
||||
this.throwGeneralAxiosError(error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert status constant to string
|
||||
* @param {string} status The status constant
|
||||
* @returns {string} status
|
||||
*/
|
||||
statusToString(status) {
|
||||
switch (status) {
|
||||
case DOWN:
|
||||
return "❌";
|
||||
case UP:
|
||||
return "✅";
|
||||
default:
|
||||
return status;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = YZJ;
|
|
@ -64,11 +64,13 @@ const ServerChan = require("./notification-providers/serverchan");
|
|||
const ZohoCliq = require("./notification-providers/zoho-cliq");
|
||||
const SevenIO = require("./notification-providers/sevenio");
|
||||
const Whapi = require("./notification-providers/whapi");
|
||||
const WAHA = require("./notification-providers/waha");
|
||||
const GtxMessaging = require("./notification-providers/gtx-messaging");
|
||||
const Cellsynt = require("./notification-providers/cellsynt");
|
||||
const Onesender = require("./notification-providers/onesender");
|
||||
const Wpush = require("./notification-providers/wpush");
|
||||
const SendGrid = require("./notification-providers/send-grid");
|
||||
const YZJ = require("./notification-providers/yzj");
|
||||
|
||||
class Notification {
|
||||
|
||||
|
@ -151,10 +153,12 @@ class Notification {
|
|||
new ZohoCliq(),
|
||||
new SevenIO(),
|
||||
new Whapi(),
|
||||
new WAHA(),
|
||||
new GtxMessaging(),
|
||||
new Cellsynt(),
|
||||
new Wpush(),
|
||||
new SendGrid()
|
||||
new SendGrid(),
|
||||
new YZJ()
|
||||
];
|
||||
for (let item of list) {
|
||||
if (! item.name) {
|
||||
|
|
|
@ -163,6 +163,7 @@ export default {
|
|||
"ZohoCliq": "ZohoCliq",
|
||||
"SevenIO": "SevenIO",
|
||||
"whapi": "WhatsApp (Whapi)",
|
||||
"waha": "WhatsApp (WAHA)",
|
||||
"gtxmessaging": "GtxMessaging",
|
||||
"Cellsynt": "Cellsynt",
|
||||
"SendGrid": "SendGrid"
|
||||
|
@ -183,6 +184,7 @@ export default {
|
|||
"ServerChan": "ServerChan (Server酱)",
|
||||
"smsc": "SMSC",
|
||||
"WPush": "WPush(wpush.cn)",
|
||||
"YZJ": "YZJ (云之家自定义机器人)"
|
||||
};
|
||||
|
||||
// Sort by notification name
|
||||
|
|
75
src/components/TemplatedInput.vue
Normal file
75
src/components/TemplatedInput.vue
Normal file
|
@ -0,0 +1,75 @@
|
|||
<template>
|
||||
<div class="form-text mb-2">
|
||||
<i18n-t tag="div" keypath="liquidIntroduction">
|
||||
<a href="https://liquidjs.com/" target="_blank">{{ $t("documentation") }}</a>
|
||||
</i18n-t>
|
||||
|
||||
<code v-pre>{{ msg }}</code>: {{ $t("templateMsg") }}<br />
|
||||
<code v-pre>{{ name }}</code>: {{ $t("templateServiceName") }}<br />
|
||||
<code v-pre>{{ status }}</code>: {{ $t("templateStatus") }}<br />
|
||||
<code v-pre>{{ hostnameOrURL }}</code>: {{ $t("templateHostnameOrURL") }}<br />
|
||||
<code v-pre>{{ heartbeatJSON }}</code>: {{ $t("templateHeartbeatJSON") }} <b>({{ $t("templateLimitedToUpDownNotifications") }})</b><br />
|
||||
<code v-pre>{{ monitorJSON }}</code>: {{ $t("templateMonitorJSON") }} <b>({{ $t("templateLimitedToUpDownCertNotifications") }})</b><br />
|
||||
</div>
|
||||
|
||||
<input
|
||||
:id="id"
|
||||
ref="templatedInput"
|
||||
v-model="model"
|
||||
type="text"
|
||||
class="form-control"
|
||||
:placeholder="placeholder"
|
||||
:required="required"
|
||||
autocomplete="false"
|
||||
>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
/**
|
||||
* The value of the templated input.
|
||||
*/
|
||||
modelValue: {
|
||||
type: String,
|
||||
default: ""
|
||||
},
|
||||
/**
|
||||
* id for the templated input.
|
||||
*/
|
||||
id: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
/**
|
||||
* Whether the templated input is required.
|
||||
* @example true
|
||||
*/
|
||||
required: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
/**
|
||||
* Placeholder text for the templated input.
|
||||
*/
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: ""
|
||||
},
|
||||
},
|
||||
emits: [ "update:modelValue" ],
|
||||
computed: {
|
||||
/**
|
||||
* Send value update to parent on change.
|
||||
*/
|
||||
model: {
|
||||
get() {
|
||||
return this.modelValue;
|
||||
},
|
||||
set(value) {
|
||||
this.$emit("update:modelValue", value);
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
80
src/components/TemplatedTextarea.vue
Normal file
80
src/components/TemplatedTextarea.vue
Normal file
|
@ -0,0 +1,80 @@
|
|||
<template>
|
||||
<div class="form-text mb-2">
|
||||
<i18n-t tag="div" keypath="liquidIntroduction">
|
||||
<a href="https://liquidjs.com/" target="_blank">{{ $t("documentation") }}</a>
|
||||
</i18n-t>
|
||||
|
||||
<code v-pre>{{ msg }}</code>: {{ $t("templateMsg") }}<br />
|
||||
<code v-pre>{{ name }}</code>: {{ $t("templateServiceName") }}<br />
|
||||
<code v-pre>{{ status }}</code>: {{ $t("templateStatus") }}<br />
|
||||
<code v-pre>{{ hostnameOrURL }}</code>: {{ $t("templateHostnameOrURL") }}<br />
|
||||
<code v-pre>{{ heartbeatJSON }}</code>: {{ $t("templateHeartbeatJSON") }} <b>({{ $t("templateLimitedToUpDownNotifications") }})</b><br />
|
||||
<code v-pre>{{ monitorJSON }}</code>: {{ $t("templateMonitorJSON") }} <b>({{ $t("templateLimitedToUpDownCertNotifications") }})</b><br />
|
||||
</div>
|
||||
|
||||
<textarea
|
||||
:id="id"
|
||||
ref="templatedTextarea"
|
||||
v-model="model"
|
||||
class="form-control"
|
||||
:placeholder="placeholder"
|
||||
:required="required"
|
||||
autocomplete="false"
|
||||
></textarea>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
/**
|
||||
* The value of the templated textarea.
|
||||
*/
|
||||
modelValue: {
|
||||
type: String,
|
||||
default: ""
|
||||
},
|
||||
/**
|
||||
* id for the templated textarea.
|
||||
*/
|
||||
id: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
/**
|
||||
* Whether the templated textarea is required.
|
||||
* @example true
|
||||
*/
|
||||
required: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
/**
|
||||
* Placeholder text for the templated textarea.
|
||||
*/
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: ""
|
||||
},
|
||||
},
|
||||
emits: [ "update:modelValue" ],
|
||||
computed: {
|
||||
/**
|
||||
* Send value update to parent on change.
|
||||
*/
|
||||
model: {
|
||||
get() {
|
||||
return this.modelValue;
|
||||
},
|
||||
set(value) {
|
||||
this.$emit("update:modelValue", value);
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
textarea {
|
||||
min-height: 150px;
|
||||
}
|
||||
</style>
|
|
@ -67,25 +67,15 @@
|
|||
<input id="to-bcc" v-model="$parent.notification.smtpBCC" type="text" class="form-control" autocomplete="false" :required="!hasRecipient">
|
||||
</div>
|
||||
|
||||
<p class="form-text">
|
||||
<i18n-t tag="div" keypath="smtpLiquidIntroduction" class="form-text mb-3">
|
||||
<a href="https://liquidjs.com/" target="_blank">{{ $t("documentation") }}</a>
|
||||
</i18n-t>
|
||||
<code v-pre>{{name}}</code>: {{ $t("emailTemplateServiceName") }}<br />
|
||||
<code v-pre>{{msg}}</code>: {{ $t("emailTemplateMsg") }}<br />
|
||||
<code v-pre>{{status}}</code>: {{ $t("emailTemplateStatus") }}<br />
|
||||
<code v-pre>{{heartbeatJSON}}</code>: {{ $t("emailTemplateHeartbeatJSON") }}<b>{{ $t("emailTemplateLimitedToUpDownNotification") }}</b><br />
|
||||
<code v-pre>{{monitorJSON}}</code>: {{ $t("emailTemplateMonitorJSON") }} <b>{{ $t("emailTemplateLimitedToUpDownNotification") }}</b><br />
|
||||
<code v-pre>{{hostnameOrURL}}</code>: {{ $t("emailTemplateHostnameOrURL") }}<br />
|
||||
</p>
|
||||
<div class="mb-3">
|
||||
<label for="subject-email" class="form-label">{{ $t("emailCustomSubject") }}</label>
|
||||
<input id="subject-email" v-model="$parent.notification.customSubject" type="text" class="form-control" autocomplete="false" placeholder="">
|
||||
<TemplatedInput id="subject-email" v-model="$parent.notification.customSubject" :required="false" placeholder=""></TemplatedInput>
|
||||
<div class="form-text">{{ $t("leave blank for default subject") }}</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="body-email" class="form-label">{{ $t("emailCustomBody") }}</label>
|
||||
<textarea id="body-email" v-model="$parent.notification.customBody" type="text" class="form-control" autocomplete="false" placeholder=""></textarea>
|
||||
<TemplatedTextarea id="body-email" v-model="$parent.notification.customBody" :required="false" placeholder=""></TemplatedTextarea>
|
||||
<div class="form-text">{{ $t("leave blank for default body") }}</div>
|
||||
</div>
|
||||
|
||||
|
@ -124,11 +114,15 @@
|
|||
|
||||
<script>
|
||||
import HiddenInput from "../HiddenInput.vue";
|
||||
import TemplatedInput from "../TemplatedInput.vue";
|
||||
import TemplatedTextarea from "../TemplatedTextarea.vue";
|
||||
import ToggleSection from "../ToggleSection.vue";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
HiddenInput,
|
||||
TemplatedInput,
|
||||
TemplatedTextarea,
|
||||
ToggleSection,
|
||||
},
|
||||
computed: {
|
||||
|
|
|
@ -36,7 +36,42 @@
|
|||
<label for="server_url" class="form-label">{{ $t("telegramServerUrl") }}</label>
|
||||
<input id="server_url" v-model="$parent.notification.telegramServerUrl" type="text" class="form-control">
|
||||
<p class="form-text">{{ $t("telegramServerUrlDescription") }}</p>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<div class="form-check form-switch">
|
||||
<input v-model="$parent.notification.telegramUseTemplate" class="form-check-input" type="checkbox">
|
||||
<label class="form-check-label">{{ $t("telegramUseTemplate") }}</label>
|
||||
</div>
|
||||
|
||||
<div class="form-text">
|
||||
{{ $t("telegramUseTemplateDescription") }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template v-if="$parent.notification.telegramUseTemplate">
|
||||
<div class="mb-3">
|
||||
<label class="form-label" for="message_parse_mode">{{ $t("Message Format") }}</label>
|
||||
<select
|
||||
id="message_parse_mode"
|
||||
v-model="$parent.notification.telegramTemplateParseMode"
|
||||
class="form-select"
|
||||
required
|
||||
>
|
||||
<option value="plain">{{ $t("Plain Text") }}</option>
|
||||
<option value="HTML">HTML</option>
|
||||
<option value="MarkdownV2">MarkdownV2</option>
|
||||
</select>
|
||||
<i18n-t tag="p" keypath="telegramTemplateFormatDescription" class="form-text">
|
||||
<a href="https://core.telegram.org/bots/api#formatting-options" target="_blank">{{ $t("documentation") }}</a>
|
||||
</i18n-t>
|
||||
|
||||
<label class="form-label" for="message_template">{{ $t('Message Template') }}</label>
|
||||
<TemplatedTextarea id="message_template" v-model="$parent.notification.telegramTemplate" :required="true" :placeholder="telegramTemplatedTextareaPlaceholder"></TemplatedTextarea>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div class="mb-3">
|
||||
<div class="form-check form-switch">
|
||||
<input v-model="$parent.notification.telegramSendSilently" class="form-check-input" type="checkbox">
|
||||
<label class="form-check-label">{{ $t("telegramSendSilently") }}</label>
|
||||
|
@ -61,15 +96,28 @@
|
|||
|
||||
<script>
|
||||
import HiddenInput from "../HiddenInput.vue";
|
||||
import TemplatedTextarea from "../TemplatedTextarea.vue";
|
||||
import axios from "axios";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
HiddenInput,
|
||||
TemplatedTextarea,
|
||||
},
|
||||
mounted() {
|
||||
this.$parent.notification.telegramServerUrl ||= "https://api.telegram.org";
|
||||
},
|
||||
computed: {
|
||||
telegramTemplatedTextareaPlaceholder() {
|
||||
return this.$t("Example:", [
|
||||
`
|
||||
Uptime Kuma Alert{% if monitorJSON %} - {{ monitorJSON['name'] }}{% endif %}
|
||||
|
||||
{{ msg }}
|
||||
`,
|
||||
]);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* Get the URL for telegram updates
|
||||
|
@ -123,3 +171,9 @@ export default {
|
|||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
textarea {
|
||||
min-height: 150px;
|
||||
}
|
||||
</style>
|
||||
|
|
38
src/components/notifications/WAHA.vue
Normal file
38
src/components/notifications/WAHA.vue
Normal file
|
@ -0,0 +1,38 @@
|
|||
<template>
|
||||
<div class="mb-3">
|
||||
<label for="waha-api-url" class="form-label">{{ $t("API URL") }}</label>
|
||||
<input id="waha-api-url" v-model="$parent.notification.wahaApiUrl" placeholder="http://localhost:3000/" type="url" class="form-control" required>
|
||||
<div class="form-text">{{ $t("wayToGetWahaApiUrl") }}</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="waha-api-key" class="form-label">{{ $t("API Key") }}</label>
|
||||
<HiddenInput id="waha-api-key" v-model="$parent.notification.wahaApiKey" :required="false" autocomplete="new-password"></HiddenInput>
|
||||
<div class="form-text">{{ $t("wayToGetWahaApiKey") }}</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="waha-session" class="form-label">{{ $t("wahaSession") }}</label>
|
||||
<input id="waha-session" v-model="$parent.notification.wahaSession" type="text" placeholder="default" class="form-control" required>
|
||||
<div class="form-text">{{ $t("wayToGetWahaSession") }}</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="waha-chat-id" class="form-label">{{ $t("wahaChatId") }}</label>
|
||||
<input id="waha-chat-id" v-model="$parent.notification.wahaChatId" type="text" pattern="^[\d-]{10,31}$" class="form-control" required>
|
||||
<div class="form-text">{{ $t("wayToWriteWahaChatId", ["00117612345678", "00117612345678@c.us", "123456789012345678@g.us"]) }}</div>
|
||||
</div>
|
||||
|
||||
<i18n-t tag="div" keypath="More info on:" class="mb-3 form-text">
|
||||
<a href="https://waha.devlike.pro/" target="_blank">https://waha.devlike.pro/</a>
|
||||
</i18n-t>
|
||||
</template>
|
||||
<script>
|
||||
import HiddenInput from "../HiddenInput.vue";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
HiddenInput,
|
||||
}
|
||||
};
|
||||
</script>
|
|
@ -32,20 +32,7 @@
|
|||
</template>
|
||||
</i18n-t>
|
||||
<template v-else-if="$parent.notification.webhookContentType == 'custom'">
|
||||
<i18n-t tag="div" keypath="liquidIntroduction" class="form-text">
|
||||
<a href="https://liquidjs.com/" target="_blank">{{ $t("documentation") }}</a>
|
||||
</i18n-t>
|
||||
<code v-pre>{{msg}}</code>: {{ $t("templateMsg") }}<br />
|
||||
<code v-pre>{{heartbeatJSON}}</code>: {{ $t("templateHeartbeatJSON") }} <b>({{ $t("templateLimitedToUpDownNotifications") }})</b><br />
|
||||
<code v-pre>{{monitorJSON}}</code>: {{ $t("templateMonitorJSON") }} <b>({{ $t("templateLimitedToUpDownCertNotifications") }})</b><br />
|
||||
|
||||
<textarea
|
||||
id="customBody"
|
||||
v-model="$parent.notification.webhookCustomBody"
|
||||
class="form-control"
|
||||
:placeholder="customBodyPlaceholder"
|
||||
required
|
||||
></textarea>
|
||||
<TemplatedTextarea id="customBody" v-model="$parent.notification.webhookCustomBody" :required="true" :placeholder="customBodyPlaceholder"></TemplatedTextarea>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
|
@ -67,7 +54,12 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import TemplatedTextarea from "../TemplatedTextarea.vue";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TemplatedTextarea,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
showAdditionalHeadersField: this.$parent.notification.webhookAdditionalHeaders != null,
|
||||
|
|
19
src/components/notifications/YZJ.vue
Normal file
19
src/components/notifications/YZJ.vue
Normal file
|
@ -0,0 +1,19 @@
|
|||
<template>
|
||||
<div class="mb-3">
|
||||
<label for="yzjWebHookUrl" class="form-label">{{ $t("YZJ Webhook URL") }}<span style="color: red;"><sup>*</sup></span></label>
|
||||
<input id="yzjWebHookUrl" v-model="$parent.notification.yzjWebHookUrl" type="url" class="form-control" required />
|
||||
<i18n-t class="form-text" keypath="wayToGetTeamsURL">
|
||||
<a href="https://www.yunzhijia.com/opendocs/docs.html#/tutorial/index/robot" target="_blank">{{ $t("here") }}</a>
|
||||
</i18n-t>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="yzjToken" class="form-label">{{ $t("YZJ Robot Token") }}<span style="color: red;"><sup>*</sup></span></label>
|
||||
<HiddenInput id="yzjToken" v-model="$parent.notification.yzjToken" :required="true" autocomplete="new-password"></HiddenInput>
|
||||
<i18n-t class="form-text" keypath="wayToGetLineNotifyToken">
|
||||
<a href="https://www.yunzhijia.com/opendocs/docs.html#/server-api/im/index?id=%e6%8e%a5%e5%8f%a3%e5%9c%b0%e5%9d%80%e5%92%8c%e6%8e%88%e6%9d%83%e7%a0%81" target="_blank">{{ $t("here") }}</a>
|
||||
</i18n-t>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import HiddenInput from "../HiddenInput.vue";
|
||||
</script>
|
|
@ -63,10 +63,12 @@ import ZohoCliq from "./ZohoCliq.vue";
|
|||
import Splunk from "./Splunk.vue";
|
||||
import SevenIO from "./SevenIO.vue";
|
||||
import Whapi from "./Whapi.vue";
|
||||
import WAHA from "./WAHA.vue";
|
||||
import Cellsynt from "./Cellsynt.vue";
|
||||
import WPush from "./WPush.vue";
|
||||
import SIGNL4 from "./SIGNL4.vue";
|
||||
import SendGrid from "./SendGrid.vue";
|
||||
import YZJ from "./YZJ.vue";
|
||||
|
||||
/**
|
||||
* Manage all notification form.
|
||||
|
@ -138,10 +140,12 @@ const NotificationFormList = {
|
|||
"ZohoCliq": ZohoCliq,
|
||||
"SevenIO": SevenIO,
|
||||
"whapi": Whapi,
|
||||
"waha": WAHA,
|
||||
"gtxmessaging": GtxMessaging,
|
||||
"Cellsynt": Cellsynt,
|
||||
"WPush": WPush,
|
||||
"SendGrid": SendGrid,
|
||||
"YZJ": YZJ,
|
||||
};
|
||||
|
||||
export default NotificationFormList;
|
||||
|
|
|
@ -231,6 +231,9 @@
|
|||
"templateMonitorJSON": "object describing the monitor",
|
||||
"templateLimitedToUpDownCertNotifications": "only available for UP/DOWN/Certificate expiry notifications",
|
||||
"templateLimitedToUpDownNotifications": "only available for UP/DOWN notifications",
|
||||
"templateServiceName": "service name",
|
||||
"templateHostnameOrURL": "hostname or URL",
|
||||
"templateStatus": "status",
|
||||
"webhookAdditionalHeadersTitle": "Additional Headers",
|
||||
"webhookAdditionalHeadersDesc": "Sets additional headers sent with the webhook. Each header should be defined as a JSON key/value.",
|
||||
"webhookBodyPresetOption": "Preset - {0}",
|
||||
|
@ -421,6 +424,9 @@
|
|||
"telegramSendSilentlyDescription": "Sends the message silently. Users will receive a notification with no sound.",
|
||||
"telegramProtectContent": "Protect Forwarding/Saving",
|
||||
"telegramProtectContentDescription": "If enabled, the bot messages in Telegram will be protected from forwarding and saving.",
|
||||
"telegramUseTemplate": "Use custom message template",
|
||||
"telegramUseTemplateDescription": "If enabled, the message will be sent using a custom template.",
|
||||
"telegramTemplateFormatDescription": "Telegram allows using different markup languages for messages, see Telegram {0} for specifc details.",
|
||||
"supportTelegramChatID": "Support Direct Chat / Group / Channel's Chat ID",
|
||||
"wayToGetTelegramChatID": "You can get your chat ID by sending a message to the bot and going to this URL to view the chat_id:",
|
||||
"telegramServerUrl": "(Optional) Server Url",
|
||||
|
@ -521,9 +527,6 @@
|
|||
"leave blank for default subject": "leave blank for default subject",
|
||||
"emailCustomBody": "Custom Body",
|
||||
"leave blank for default body": "leave blank for default body",
|
||||
"emailTemplateServiceName": "Service Name",
|
||||
"emailTemplateHostnameOrURL": "Hostname or URL",
|
||||
"emailTemplateStatus": "Status",
|
||||
"emailTemplateMonitorJSON": "object describing the monitor",
|
||||
"emailTemplateHeartbeatJSON": "object describing the heartbeat",
|
||||
"emailTemplateMsg": "message of the notification",
|
||||
|
@ -1053,5 +1056,16 @@
|
|||
"RabbitMQ Password": "RabbitMQ Password",
|
||||
"rabbitmqHelpText": "To use the monitor, you will need to enable the Management Plugin in your RabbitMQ setup. For more information, please consult the {rabitmq_documentation}.",
|
||||
"SendGrid API Key": "SendGrid API Key",
|
||||
"Separate multiple email addresses with commas": "Separate multiple email addresses with commas"
|
||||
"Separate multiple email addresses with commas": "Separate multiple email addresses with commas",
|
||||
"wahaSession": "Session",
|
||||
"wahaChatId": "Chat ID (Phone Number / Contact ID / Group ID)",
|
||||
"wayToGetWahaApiUrl": "Your WAHA Instance URL.",
|
||||
"wayToGetWahaApiKey": "API Key is WHATSAPP_API_KEY environment variable value you used to run WAHA.",
|
||||
"wayToGetWahaSession": "From this session WAHA sends notifications to Chat ID. You can find it in WAHA Dashboard.",
|
||||
"wayToWriteWahaChatId": "The phone number with the international prefix, but without the plus sign at the start ({0}), the Contact ID ({1}) or the Group ID ({2}). Notifications are sent to this Chat ID from WAHA Session.",
|
||||
"YZJ Webhook URL": "YZJ Webhook URL",
|
||||
"YZJ Robot Token": "YZJ Robot token",
|
||||
"Plain Text": "Plain Text",
|
||||
"Message Template": "Message Template",
|
||||
"Template Format": "Template Format"
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue