Add Flashduty notification (#3475)

* feat: add FlashDuty notification channel

* refactor: #3475 nofify with Up or Down;
refactor code;
add en zh-hk zh-tw lang

* refactor: default select Info

* refactor: add space in word

* refactor the flashduty notification code

* refactor:compatible when Test flashduty nofication

* refactor: add function param description

* refactor: revert zh-hk zh-tw changes of flashduty
pull/3318/head^2
Damon 1 year ago committed by GitHub
parent ae2867e305
commit 587d9e4781
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -0,0 +1,98 @@
const NotificationProvider = require("./notification-provider");
const axios = require("axios");
const { UP, DOWN, getMonitorRelativeURL } = require("../../src/util");
const { setting } = require("../util-server");
const successMessage = "Sent Successfully.";
class FlashDuty extends NotificationProvider {
name = "FlashDuty";
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
try {
if (heartbeatJSON == null) {
const title = "Uptime Kuma Alert";
const monitor = {
type: "ping",
url: msg,
name: "https://flashcat.cloud"
};
return this.postNotification(notification, title, msg, monitor);
}
if (heartbeatJSON.status === UP) {
const title = "Uptime Kuma Monitor ✅ Up";
return this.postNotification(notification, title, heartbeatJSON.msg, monitorJSON, "Ok");
}
if (heartbeatJSON.status === DOWN) {
const title = "Uptime Kuma Monitor 🔴 Down";
return this.postNotification(notification, title, heartbeatJSON.msg, monitorJSON, notification.flashdutySeverity);
}
} catch (error) {
this.throwGeneralAxiosError(error);
}
}
/**
* Generate a monitor url from the monitors infomation
* @param {Object} monitorInfo Monitor details
* @returns {string|undefined}
*/
genMonitorUrl(monitorInfo) {
if (monitorInfo.type === "port" && monitorInfo.port) {
return monitorInfo.hostname + ":" + monitorInfo.port;
}
if (monitorInfo.hostname != null) {
return monitorInfo.hostname;
}
return monitorInfo.url;
}
/**
* Send the message
* @param {BeanModel} notification Message title
* @param {string} title Message
* @param {string} body Message
* @param {Object} monitorInfo Monitor details
* @param {string} eventStatus Monitor status (Info, Warning, Critical, Ok)
* @returns {string}
*/
async postNotification(notification, title, body, monitorInfo, eventStatus) {
const options = {
method: "POST",
url: "https://api.flashcat.cloud/event/push/alert/standard?integration_key=" + notification.flashdutyIntegrationKey,
headers: { "Content-Type": "application/json" },
data: {
description: `[${title}] [${monitorInfo.name}] ${body}`,
title,
event_status: eventStatus || "Info",
alert_key: String(monitorInfo.id) || Math.random().toString(36).substring(7),
labels: monitorInfo?.tags?.reduce((acc, item) => ({ ...acc,
[item.name]: item.value
}), { resource: this.genMonitorUrl(monitorInfo) }),
}
};
const baseURL = await setting("primaryBaseURL");
if (baseURL && monitorInfo) {
options.client = "Uptime Kuma";
options.client_url = baseURL + getMonitorRelativeURL(monitorInfo.id);
}
let result = await axios.request(options);
if (result.status == null) {
throw new Error("FlashDuty notification failed with invalid response!");
}
if (result.status < 200 || result.status >= 300) {
throw new Error("FlashDuty notification failed with status code " + result.status);
}
if (result.statusText != null) {
return "FlashDuty notification succeed: " + result.statusText;
}
return successMessage;
}
}
module.exports = FlashDuty;

@ -27,6 +27,7 @@ const Octopush = require("./notification-providers/octopush");
const OneBot = require("./notification-providers/onebot"); const OneBot = require("./notification-providers/onebot");
const Opsgenie = require("./notification-providers/opsgenie"); const Opsgenie = require("./notification-providers/opsgenie");
const PagerDuty = require("./notification-providers/pagerduty"); const PagerDuty = require("./notification-providers/pagerduty");
const FlashDuty = require("./notification-providers/flashduty");
const PagerTree = require("./notification-providers/pagertree"); const PagerTree = require("./notification-providers/pagertree");
const PromoSMS = require("./notification-providers/promosms"); const PromoSMS = require("./notification-providers/promosms");
const Pushbullet = require("./notification-providers/pushbullet"); const Pushbullet = require("./notification-providers/pushbullet");
@ -91,6 +92,7 @@ class Notification {
new OneBot(), new OneBot(),
new Opsgenie(), new Opsgenie(),
new PagerDuty(), new PagerDuty(),
new FlashDuty(),
new PagerTree(), new PagerTree(),
new PromoSMS(), new PromoSMS(),
new Pushbullet(), new Pushbullet(),
@ -117,7 +119,6 @@ class Notification {
new GoAlert(), new GoAlert(),
new ZohoCliq() new ZohoCliq()
]; ];
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");

@ -158,6 +158,7 @@ export default {
"AliyunSMS": "AliyunSMS (阿里云短信服务)", "AliyunSMS": "AliyunSMS (阿里云短信服务)",
"DingDing": "DingDing (钉钉自定义机器人)", "DingDing": "DingDing (钉钉自定义机器人)",
"Feishu": "Feishu (飞书)", "Feishu": "Feishu (飞书)",
"FlashDuty": "FlashDuty (快猫星云)",
"FreeMobile": "FreeMobile (mobile.free.fr)", "FreeMobile": "FreeMobile (mobile.free.fr)",
"PushDeer": "PushDeer", "PushDeer": "PushDeer",
"promosms": "PromoSMS", "promosms": "PromoSMS",

@ -0,0 +1,29 @@
<template>
<div class="mb-3">
<label for="flashduty-integration-url" class="form-label">Integration Key</label>
<HiddenInput id="flashduty-integration-url" v-model="$parent.notification.flashdutyIntegrationKey" autocomplete="false"></HiddenInput>
<i18n-t tag="div" keypath="wayToGetFlashDutyKey" class="form-text">
<a href="https://flashcat.cloud/product/flashduty?from=kuma" target="_blank">{{ $t("here") }}</a>
</i18n-t>
</div>
<div class="mb-3">
<label for="flashduty-severity" class="form-label">{{ $t("FlashDuty Severity") }}</label>
<select id="flashduty-severity" v-model="$parent.notification.flashdutySeverity" class="form-select" :required="true">
<option value="Info" selected>Info</option>
<option value="Warning" selected>Warning</option>
<option value="Critical">Critical</option>
</select>
</div>
</template>
<script>
import HiddenInput from "../HiddenInput.vue";
export default {
components: {
HiddenInput,
},
mounted() {
}
};
</script>

@ -25,6 +25,7 @@ import Octopush from "./Octopush.vue";
import OneBot from "./OneBot.vue"; import OneBot from "./OneBot.vue";
import Opsgenie from "./Opsgenie.vue"; import Opsgenie from "./Opsgenie.vue";
import PagerDuty from "./PagerDuty.vue"; import PagerDuty from "./PagerDuty.vue";
import FlashDuty from "./FlashDuty.vue";
import PagerTree from "./PagerTree.vue"; import PagerTree from "./PagerTree.vue";
import PromoSMS from "./PromoSMS.vue"; import PromoSMS from "./PromoSMS.vue";
import Pushbullet from "./Pushbullet.vue"; import Pushbullet from "./Pushbullet.vue";
@ -84,6 +85,7 @@ const NotificationFormList = {
"OneBot": OneBot, "OneBot": OneBot,
"Opsgenie": Opsgenie, "Opsgenie": Opsgenie,
"PagerDuty": PagerDuty, "PagerDuty": PagerDuty,
"FlashDuty": FlashDuty,
"PagerTree": PagerTree, "PagerTree": PagerTree,
"promosms": PromoSMS, "promosms": PromoSMS,
"pushbullet": Pushbullet, "pushbullet": Pushbullet,

@ -791,6 +791,8 @@
"noGroupMonitorMsg": "Not Available. Create a Group Monitor First.", "noGroupMonitorMsg": "Not Available. Create a Group Monitor First.",
"Close": "Close", "Close": "Close",
"Request Body": "Request Body", "Request Body": "Request Body",
"wayToGetFlashDutyKey":"You can go to Channel -> (Select a Channel) -> Integrations -> Add a new integration' page, add a 'Custom Event' to get a push address, copy the Integration Key in the address. For more information, please visit",
"FlashDuty Severity":"Severity",
"nostrRelays": "Nostr relays", "nostrRelays": "Nostr relays",
"nostrRelaysHelp": "One relay URL per line", "nostrRelaysHelp": "One relay URL per line",
"nostrSender": "Sender Private Key (nsec)", "nostrSender": "Sender Private Key (nsec)",

@ -98,5 +98,7 @@
"Heartbeat Interval": "檢查間距", "Heartbeat Interval": "檢查間距",
"Add New Monitor": "新增監測器", "Add New Monitor": "新增監測器",
"Quick Stats": "綜合數據", "Quick Stats": "綜合數據",
"markdownSupported": "可以用 Markdown" "markdownSupported": "可以用 Markdown",
"wayToGetFlashDutyKey": "您可以进入 协作空间 -> (选择一个 协作空间) -> 集成数据 -> 新增一个集成 页面,添加“自定义事件”获得一个推送地址,复制地址中的 Integration Key更多信息前往{0}",
"FlashDuty Severity":"严重程度"
} }

@ -413,6 +413,7 @@
"smtpDkimheaderFieldNames": "包含在哈希计算对象内的 Header 列表(可选)", "smtpDkimheaderFieldNames": "包含在哈希计算对象内的 Header 列表(可选)",
"smtpDkimskipFields": "不包含在哈希计算对象内的 Header 列表(可选)", "smtpDkimskipFields": "不包含在哈希计算对象内的 Header 列表(可选)",
"wayToGetPagerDutyKey": "您可以在 Service -> Service Directory -> (选择一个 Service) -> Integrations -> Add integration 页面中搜索“Events API V2”以获取此 Integration Key更多信息请看{0}", "wayToGetPagerDutyKey": "您可以在 Service -> Service Directory -> (选择一个 Service) -> Integrations -> Add integration 页面中搜索“Events API V2”以获取此 Integration Key更多信息请看{0}",
"wayToGetFlashDutyKey": "您可以进入 协作空间 -> (选择一个 协作空间) -> 集成数据 -> 新增一个集成 页面,添加“自定义事件”获得一个推送地址,复制地址中的 Integration Key更多信息前往{0}",
"Integration Key": "集成密钥", "Integration Key": "集成密钥",
"Integration URL": "集成网址", "Integration URL": "集成网址",
"Auto resolve or acknowledged": "自动标记为已解决或已读", "Auto resolve or acknowledged": "自动标记为已解决或已读",
@ -784,5 +785,6 @@
"Edit Maintenance": "编辑维护计划", "Edit Maintenance": "编辑维护计划",
"Home": "首页", "Home": "首页",
"noGroupMonitorMsg": "暂无可用,请先创建一个监控项组。", "noGroupMonitorMsg": "暂无可用,请先创建一个监控项组。",
"Close": "关闭" "Close": "关闭",
"FlashDuty Severity":"严重程度"
} }

Loading…
Cancel
Save