From fce824f5a8ca062e4bd4361081468542915f8260 Mon Sep 17 00:00:00 2001 From: Harry <innerpeace.zhai@gmail.com> Date: Fri, 14 Mar 2025 09:40:13 +0800 Subject: [PATCH 1/2] feat: Support YZJ notification provider (#5686) Co-authored-by: Frank Elsinga <frank@elsinga.de> --- server/notification-providers/yzj.js | 57 +++++++++++++++++++++++++++ server/notification.js | 4 +- src/components/NotificationDialog.vue | 1 + src/components/notifications/YZJ.vue | 19 +++++++++ src/components/notifications/index.js | 2 + src/lang/en.json | 4 +- 6 files changed, 85 insertions(+), 2 deletions(-) create mode 100644 server/notification-providers/yzj.js create mode 100644 src/components/notifications/YZJ.vue diff --git a/server/notification-providers/yzj.js b/server/notification-providers/yzj.js new file mode 100644 index 000000000..6bd3cba51 --- /dev/null +++ b/server/notification-providers/yzj.js @@ -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; diff --git a/server/notification.js b/server/notification.js index e7977eb4a..7ed62ffec 100644 --- a/server/notification.js +++ b/server/notification.js @@ -69,6 +69,7 @@ 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 { @@ -154,7 +155,8 @@ class Notification { new GtxMessaging(), new Cellsynt(), new Wpush(), - new SendGrid() + new SendGrid(), + new YZJ() ]; for (let item of list) { if (! item.name) { diff --git a/src/components/NotificationDialog.vue b/src/components/NotificationDialog.vue index f6d728029..8a2c6269d 100644 --- a/src/components/NotificationDialog.vue +++ b/src/components/NotificationDialog.vue @@ -183,6 +183,7 @@ export default { "ServerChan": "ServerChan (Server酱)", "smsc": "SMSC", "WPush": "WPush(wpush.cn)", + "YZJ": "YZJ (云之家自定义机器人)" }; // Sort by notification name diff --git a/src/components/notifications/YZJ.vue b/src/components/notifications/YZJ.vue new file mode 100644 index 000000000..63bc4c530 --- /dev/null +++ b/src/components/notifications/YZJ.vue @@ -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> diff --git a/src/components/notifications/index.js b/src/components/notifications/index.js index efa2af5c4..3bf9affd3 100644 --- a/src/components/notifications/index.js +++ b/src/components/notifications/index.js @@ -67,6 +67,7 @@ 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. @@ -142,6 +143,7 @@ const NotificationFormList = { "Cellsynt": Cellsynt, "WPush": WPush, "SendGrid": SendGrid, + "YZJ": YZJ, }; export default NotificationFormList; diff --git a/src/lang/en.json b/src/lang/en.json index e215f1031..64958cdc6 100644 --- a/src/lang/en.json +++ b/src/lang/en.json @@ -1051,5 +1051,7 @@ "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", + "YZJ Webhook URL": "YZJ Webhook URL", + "YZJ Robot Token": "YZJ Robot token" } From 9857770cc71fb5e01d05d6f6396f3fad925c94b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergio=20Conde=20G=C3=B3mez?= <skgsergio@gmail.com> Date: Fri, 14 Mar 2025 12:51:07 +0100 Subject: [PATCH 2/2] feat: rework notification templating and add support for telegram (#5637) --- .../notification-provider.js | 47 +++++++++++ server/notification-providers/smtp.js | 47 +---------- server/notification-providers/telegram.js | 8 ++ server/notification-providers/webhook.js | 13 +-- src/components/TemplatedInput.vue | 75 +++++++++++++++++ src/components/TemplatedTextarea.vue | 80 +++++++++++++++++++ src/components/notifications/SMTP.vue | 20 ++--- src/components/notifications/Telegram.vue | 54 +++++++++++++ src/components/notifications/Webhook.vue | 20 ++--- src/lang/en.json | 14 +++- 10 files changed, 290 insertions(+), 88 deletions(-) create mode 100644 src/components/TemplatedInput.vue create mode 100644 src/components/TemplatedTextarea.vue diff --git a/server/notification-providers/notification-provider.js b/server/notification-providers/notification-provider.js index b9fb3d863..42e8e616d 100644 --- a/server/notification-providers/notification-provider.js +++ b/server/notification-providers/notification-provider.js @@ -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 diff --git a/server/notification-providers/smtp.js b/server/notification-providers/smtp.js index 9f3defa5e..980c7dfd3 100644 --- a/server/notification-providers/smtp.js +++ b/server/notification-providers/smtp.js @@ -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; diff --git a/server/notification-providers/telegram.js b/server/notification-providers/telegram.js index c5bbb1909..62263db07 100644 --- a/server/notification-providers/telegram.js +++ b/server/notification-providers/telegram.js @@ -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, }); diff --git a/server/notification-providers/webhook.js b/server/notification-providers/webhook.js index 986986d44..537f94bd5 100644 --- a/server/notification-providers/webhook.js +++ b/server/notification-providers/webhook.js @@ -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) { diff --git a/src/components/TemplatedInput.vue b/src/components/TemplatedInput.vue new file mode 100644 index 000000000..43c5382e0 --- /dev/null +++ b/src/components/TemplatedInput.vue @@ -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> diff --git a/src/components/TemplatedTextarea.vue b/src/components/TemplatedTextarea.vue new file mode 100644 index 000000000..ff0c0f9fb --- /dev/null +++ b/src/components/TemplatedTextarea.vue @@ -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> diff --git a/src/components/notifications/SMTP.vue b/src/components/notifications/SMTP.vue index 003f90556..4e0fb4b57 100644 --- a/src/components/notifications/SMTP.vue +++ b/src/components/notifications/SMTP.vue @@ -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: { diff --git a/src/components/notifications/Telegram.vue b/src/components/notifications/Telegram.vue index a072c3ed3..7f04e44c8 100644 --- a/src/components/notifications/Telegram.vue +++ b/src/components/notifications/Telegram.vue @@ -32,7 +32,42 @@ <label for="message_thread_id" class="form-label">{{ $t("telegramMessageThreadID") }}</label> <input id="message_thread_id" v-model="$parent.notification.telegramMessageThreadID" type="text" class="form-control"> <p class="form-text">{{ $t("telegramMessageThreadIDDescription") }}</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> @@ -57,11 +92,24 @@ <script> import HiddenInput from "../HiddenInput.vue"; +import TemplatedTextarea from "../TemplatedTextarea.vue"; import axios from "axios"; export default { components: { HiddenInput, + TemplatedTextarea, + }, + computed: { + telegramTemplatedTextareaPlaceholder() { + return this.$t("Example:", [ + ` +Uptime Kuma Alert{% if monitorJSON %} - {{ monitorJSON['name'] }}{% endif %} + +{{ msg }} + `, + ]); + } }, methods: { /** @@ -115,3 +163,9 @@ export default { } }; </script> + +<style lang="scss" scoped> +textarea { + min-height: 150px; +} +</style> diff --git a/src/components/notifications/Webhook.vue b/src/components/notifications/Webhook.vue index 8c67a2745..7775a3fdd 100644 --- a/src/components/notifications/Webhook.vue +++ b/src/components/notifications/Webhook.vue @@ -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, diff --git a/src/lang/en.json b/src/lang/en.json index 64958cdc6..118dd7fc8 100644 --- a/src/lang/en.json +++ b/src/lang/en.json @@ -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:", "YOUR BOT TOKEN HERE": "YOUR BOT TOKEN HERE", @@ -519,9 +525,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,8 @@ "SendGrid API Key": "SendGrid API Key", "Separate multiple email addresses with commas": "Separate multiple email addresses with commas", "YZJ Webhook URL": "YZJ Webhook URL", - "YZJ Robot Token": "YZJ Robot token" + "YZJ Robot Token": "YZJ Robot token", + "Plain Text": "Plain Text", + "Message Template": "Message Template", + "Template Format": "Template Format" }