mirror of
https://github.com/louislam/uptime-kuma.git
synced 2024-11-24 18:36:48 +03:00
Merge branch 'master' into import-export
This commit is contained in:
commit
62712f5cc4
40 changed files with 1082 additions and 785 deletions
|
@ -17,7 +17,8 @@ module.exports = {
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
"camelcase": ["warn", {
|
"camelcase": ["warn", {
|
||||||
"properties": "never"
|
"properties": "never",
|
||||||
|
"ignoreImports": true
|
||||||
}],
|
}],
|
||||||
// override/add rules settings here, such as:
|
// override/add rules settings here, such as:
|
||||||
// 'vue/no-unused-vars': 'error'
|
// 'vue/no-unused-vars': 'error'
|
||||||
|
|
26
server/notification-providers/apprise.js
Normal file
26
server/notification-providers/apprise.js
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
const NotificationProvider = require("./notification-provider");
|
||||||
|
const child_process = require("child_process");
|
||||||
|
|
||||||
|
class Apprise extends NotificationProvider {
|
||||||
|
|
||||||
|
name = "apprise";
|
||||||
|
|
||||||
|
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
||||||
|
let s = child_process.spawnSync("apprise", [ "-vv", "-b", msg, notification.appriseURL])
|
||||||
|
|
||||||
|
let output = (s.stdout) ? s.stdout.toString() : "ERROR: maybe apprise not found";
|
||||||
|
|
||||||
|
if (output) {
|
||||||
|
|
||||||
|
if (! output.includes("ERROR")) {
|
||||||
|
return "Sent Successfully";
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error(output)
|
||||||
|
} else {
|
||||||
|
return "No output from apprise";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Apprise;
|
105
server/notification-providers/discord.js
Normal file
105
server/notification-providers/discord.js
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
const NotificationProvider = require("./notification-provider");
|
||||||
|
const axios = require("axios");
|
||||||
|
const { DOWN, UP } = require("../../src/util");
|
||||||
|
|
||||||
|
class Discord extends NotificationProvider {
|
||||||
|
|
||||||
|
name = "discord";
|
||||||
|
|
||||||
|
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
||||||
|
let okMsg = "Sent Successfully. ";
|
||||||
|
|
||||||
|
try {
|
||||||
|
const discordDisplayName = notification.discordUsername || "Uptime Kuma";
|
||||||
|
|
||||||
|
// If heartbeatJSON is null, assume we're testing.
|
||||||
|
if (heartbeatJSON == null) {
|
||||||
|
let discordtestdata = {
|
||||||
|
username: discordDisplayName,
|
||||||
|
content: msg,
|
||||||
|
}
|
||||||
|
await axios.post(notification.discordWebhookUrl, discordtestdata)
|
||||||
|
return okMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
let url;
|
||||||
|
|
||||||
|
if (monitorJSON["type"] === "port") {
|
||||||
|
url = monitorJSON["hostname"];
|
||||||
|
if (monitorJSON["port"]) {
|
||||||
|
url += ":" + monitorJSON["port"];
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
url = monitorJSON["url"];
|
||||||
|
}
|
||||||
|
|
||||||
|
// If heartbeatJSON is not null, we go into the normal alerting loop.
|
||||||
|
if (heartbeatJSON["status"] == DOWN) {
|
||||||
|
let discorddowndata = {
|
||||||
|
username: discordDisplayName,
|
||||||
|
embeds: [{
|
||||||
|
title: "❌ Your service " + monitorJSON["name"] + " went down. ❌",
|
||||||
|
color: 16711680,
|
||||||
|
timestamp: heartbeatJSON["time"],
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: "Service Name",
|
||||||
|
value: monitorJSON["name"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Service URL",
|
||||||
|
value: url,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Time (UTC)",
|
||||||
|
value: heartbeatJSON["time"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Error",
|
||||||
|
value: heartbeatJSON["msg"],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}],
|
||||||
|
}
|
||||||
|
await axios.post(notification.discordWebhookUrl, discorddowndata)
|
||||||
|
return okMsg;
|
||||||
|
|
||||||
|
} else if (heartbeatJSON["status"] == UP) {
|
||||||
|
let discordupdata = {
|
||||||
|
username: discordDisplayName,
|
||||||
|
embeds: [{
|
||||||
|
title: "✅ Your service " + monitorJSON["name"] + " is up! ✅",
|
||||||
|
color: 65280,
|
||||||
|
timestamp: heartbeatJSON["time"],
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
name: "Service Name",
|
||||||
|
value: monitorJSON["name"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Service URL",
|
||||||
|
value: url.startsWith("http") ? "[Visit Service](" + url + ")" : url,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Time (UTC)",
|
||||||
|
value: heartbeatJSON["time"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Ping",
|
||||||
|
value: heartbeatJSON["ping"] + "ms",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}],
|
||||||
|
}
|
||||||
|
await axios.post(notification.discordWebhookUrl, discordupdata)
|
||||||
|
return okMsg;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
this.throwGeneralAxiosError(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Discord;
|
28
server/notification-providers/gotify.js
Normal file
28
server/notification-providers/gotify.js
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
const NotificationProvider = require("./notification-provider");
|
||||||
|
const axios = require("axios");
|
||||||
|
|
||||||
|
class Gotify extends NotificationProvider {
|
||||||
|
|
||||||
|
name = "gotify";
|
||||||
|
|
||||||
|
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
||||||
|
let okMsg = "Sent Successfully. ";
|
||||||
|
try {
|
||||||
|
if (notification.gotifyserverurl && notification.gotifyserverurl.endsWith("/")) {
|
||||||
|
notification.gotifyserverurl = notification.gotifyserverurl.slice(0, -1);
|
||||||
|
}
|
||||||
|
await axios.post(`${notification.gotifyserverurl}/message?token=${notification.gotifyapplicationToken}`, {
|
||||||
|
"message": msg,
|
||||||
|
"priority": notification.gotifyPriority || 8,
|
||||||
|
"title": "Uptime-Kuma",
|
||||||
|
})
|
||||||
|
|
||||||
|
return okMsg;
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
this.throwGeneralAxiosError(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Gotify;
|
60
server/notification-providers/line.js
Normal file
60
server/notification-providers/line.js
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
const NotificationProvider = require("./notification-provider");
|
||||||
|
const axios = require("axios");
|
||||||
|
const { DOWN, UP } = require("../../src/util");
|
||||||
|
|
||||||
|
class Line extends NotificationProvider {
|
||||||
|
|
||||||
|
name = "line";
|
||||||
|
|
||||||
|
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
||||||
|
let okMsg = "Sent Successfully. ";
|
||||||
|
try {
|
||||||
|
let lineAPIUrl = "https://api.line.me/v2/bot/message/push";
|
||||||
|
let config = {
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"Authorization": "Bearer " + notification.lineChannelAccessToken
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (heartbeatJSON == null) {
|
||||||
|
let testMessage = {
|
||||||
|
"to": notification.lineUserID,
|
||||||
|
"messages": [
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"text": "Test Successful!"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
await axios.post(lineAPIUrl, testMessage, config)
|
||||||
|
} else if (heartbeatJSON["status"] == DOWN) {
|
||||||
|
let downMessage = {
|
||||||
|
"to": notification.lineUserID,
|
||||||
|
"messages": [
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"text": "UptimeKuma Alert: [🔴 Down]\n" + "Name: " + monitorJSON["name"] + " \n" + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
await axios.post(lineAPIUrl, downMessage, config)
|
||||||
|
} else if (heartbeatJSON["status"] == UP) {
|
||||||
|
let upMessage = {
|
||||||
|
"to": notification.lineUserID,
|
||||||
|
"messages": [
|
||||||
|
{
|
||||||
|
"type": "text",
|
||||||
|
"text": "UptimeKuma Alert: [✅ Up]\n" + "Name: " + monitorJSON["name"] + " \n" + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
await axios.post(lineAPIUrl, upMessage, config)
|
||||||
|
}
|
||||||
|
return okMsg;
|
||||||
|
} catch (error) {
|
||||||
|
this.throwGeneralAxiosError(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Line;
|
48
server/notification-providers/lunasea.js
Normal file
48
server/notification-providers/lunasea.js
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
const NotificationProvider = require("./notification-provider");
|
||||||
|
const axios = require("axios");
|
||||||
|
const { DOWN, UP } = require("../../src/util");
|
||||||
|
|
||||||
|
class LunaSea extends NotificationProvider {
|
||||||
|
|
||||||
|
name = "lunasea";
|
||||||
|
|
||||||
|
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
||||||
|
let okMsg = "Sent Successfully. ";
|
||||||
|
let lunaseadevice = "https://notify.lunasea.app/v1/custom/device/" + notification.lunaseaDevice
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (heartbeatJSON == null) {
|
||||||
|
let testdata = {
|
||||||
|
"title": "Uptime Kuma Alert",
|
||||||
|
"body": "Testing Successful.",
|
||||||
|
}
|
||||||
|
await axios.post(lunaseadevice, testdata)
|
||||||
|
return okMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (heartbeatJSON["status"] == DOWN) {
|
||||||
|
let downdata = {
|
||||||
|
"title": "UptimeKuma Alert: " + monitorJSON["name"],
|
||||||
|
"body": "[🔴 Down] " + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"],
|
||||||
|
}
|
||||||
|
await axios.post(lunaseadevice, downdata)
|
||||||
|
return okMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (heartbeatJSON["status"] == UP) {
|
||||||
|
let updata = {
|
||||||
|
"title": "UptimeKuma Alert: " + monitorJSON["name"],
|
||||||
|
"body": "[✅ Up] " + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"],
|
||||||
|
}
|
||||||
|
await axios.post(lunaseadevice, updata)
|
||||||
|
return okMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
this.throwGeneralAxiosError(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = LunaSea;
|
123
server/notification-providers/mattermost.js
Normal file
123
server/notification-providers/mattermost.js
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
const NotificationProvider = require("./notification-provider");
|
||||||
|
const axios = require("axios");
|
||||||
|
const { DOWN, UP } = require("../../src/util");
|
||||||
|
|
||||||
|
class Mattermost extends NotificationProvider {
|
||||||
|
|
||||||
|
name = "mattermost";
|
||||||
|
|
||||||
|
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
||||||
|
let okMsg = "Sent Successfully. ";
|
||||||
|
try {
|
||||||
|
const mattermostUserName = notification.mattermostusername || "Uptime Kuma";
|
||||||
|
// If heartbeatJSON is null, assume we're testing.
|
||||||
|
if (heartbeatJSON == null) {
|
||||||
|
let mattermostTestData = {
|
||||||
|
username: mattermostUserName,
|
||||||
|
text: msg,
|
||||||
|
}
|
||||||
|
await axios.post(notification.mattermostWebhookUrl, mattermostTestData)
|
||||||
|
return okMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
const mattermostChannel = notification.mattermostchannel;
|
||||||
|
const mattermostIconEmoji = notification.mattermosticonemo;
|
||||||
|
const mattermostIconUrl = notification.mattermosticonurl;
|
||||||
|
|
||||||
|
if (heartbeatJSON["status"] == DOWN) {
|
||||||
|
let mattermostdowndata = {
|
||||||
|
username: mattermostUserName,
|
||||||
|
text: "Uptime Kuma Alert",
|
||||||
|
channel: mattermostChannel,
|
||||||
|
icon_emoji: mattermostIconEmoji,
|
||||||
|
icon_url: mattermostIconUrl,
|
||||||
|
attachments: [
|
||||||
|
{
|
||||||
|
fallback:
|
||||||
|
"Your " +
|
||||||
|
monitorJSON["name"] +
|
||||||
|
" service went down.",
|
||||||
|
color: "#FF0000",
|
||||||
|
title:
|
||||||
|
"❌ " +
|
||||||
|
monitorJSON["name"] +
|
||||||
|
" service went down. ❌",
|
||||||
|
title_link: monitorJSON["url"],
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
short: true,
|
||||||
|
title: "Service Name",
|
||||||
|
value: monitorJSON["name"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
short: true,
|
||||||
|
title: "Time (UTC)",
|
||||||
|
value: heartbeatJSON["time"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
short: false,
|
||||||
|
title: "Error",
|
||||||
|
value: heartbeatJSON["msg"],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
await axios.post(
|
||||||
|
notification.mattermostWebhookUrl,
|
||||||
|
mattermostdowndata
|
||||||
|
);
|
||||||
|
return okMsg;
|
||||||
|
} else if (heartbeatJSON["status"] == UP) {
|
||||||
|
let mattermostupdata = {
|
||||||
|
username: mattermostUserName,
|
||||||
|
text: "Uptime Kuma Alert",
|
||||||
|
channel: mattermostChannel,
|
||||||
|
icon_emoji: mattermostIconEmoji,
|
||||||
|
icon_url: mattermostIconUrl,
|
||||||
|
attachments: [
|
||||||
|
{
|
||||||
|
fallback:
|
||||||
|
"Your " +
|
||||||
|
monitorJSON["name"] +
|
||||||
|
" service went up!",
|
||||||
|
color: "#32CD32",
|
||||||
|
title:
|
||||||
|
"✅ " +
|
||||||
|
monitorJSON["name"] +
|
||||||
|
" service went up! ✅",
|
||||||
|
title_link: monitorJSON["url"],
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
short: true,
|
||||||
|
title: "Service Name",
|
||||||
|
value: monitorJSON["name"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
short: true,
|
||||||
|
title: "Time (UTC)",
|
||||||
|
value: heartbeatJSON["time"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
short: false,
|
||||||
|
title: "Ping",
|
||||||
|
value: heartbeatJSON["ping"] + "ms",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
await axios.post(
|
||||||
|
notification.mattermostWebhookUrl,
|
||||||
|
mattermostupdata
|
||||||
|
);
|
||||||
|
return okMsg;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
this.throwGeneralAxiosError(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Mattermost;
|
36
server/notification-providers/notification-provider.js
Normal file
36
server/notification-providers/notification-provider.js
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
class NotificationProvider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notification Provider Name
|
||||||
|
* @type string
|
||||||
|
*/
|
||||||
|
name = undefined;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param notification : BeanModel
|
||||||
|
* @param msg : string General Message
|
||||||
|
* @param monitorJSON : object Monitor details (For Up/Down only)
|
||||||
|
* @param heartbeatJSON : object Heartbeat details (For Up/Down only)
|
||||||
|
* @returns {Promise<string>} Return Successful Message
|
||||||
|
* Throw Error with fail msg
|
||||||
|
*/
|
||||||
|
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
||||||
|
throw new Error("Have to override Notification.send(...)");
|
||||||
|
}
|
||||||
|
|
||||||
|
throwGeneralAxiosError(error) {
|
||||||
|
let msg = "Error: " + error + " ";
|
||||||
|
|
||||||
|
if (error.response && error.response.data) {
|
||||||
|
if (typeof error.response.data === "string") {
|
||||||
|
msg += error.response.data;
|
||||||
|
} else {
|
||||||
|
msg += JSON.stringify(error.response.data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = NotificationProvider;
|
40
server/notification-providers/octopush.js
Normal file
40
server/notification-providers/octopush.js
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
const NotificationProvider = require("./notification-provider");
|
||||||
|
const axios = require("axios");
|
||||||
|
|
||||||
|
class Octopush extends NotificationProvider {
|
||||||
|
|
||||||
|
name = "octopush";
|
||||||
|
|
||||||
|
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
||||||
|
let okMsg = "Sent Successfully. ";
|
||||||
|
|
||||||
|
try {
|
||||||
|
let config = {
|
||||||
|
headers: {
|
||||||
|
"api-key": notification.octopushAPIKey,
|
||||||
|
"api-login": notification.octopushLogin,
|
||||||
|
"cache-control": "no-cache"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let data = {
|
||||||
|
"recipients": [
|
||||||
|
{
|
||||||
|
"phone_number": notification.octopushPhoneNumber
|
||||||
|
}
|
||||||
|
],
|
||||||
|
//octopush not supporting non ascii char
|
||||||
|
"text": msg.replace(/[^\x00-\x7F]/g, ""),
|
||||||
|
"type": notification.octopushSMSType,
|
||||||
|
"purpose": "alert",
|
||||||
|
"sender": notification.octopushSenderName
|
||||||
|
};
|
||||||
|
|
||||||
|
await axios.post("https://api.octopush.com/v1/public/sms-campaign/send", data, config)
|
||||||
|
return okMsg;
|
||||||
|
} catch (error) {
|
||||||
|
this.throwGeneralAxiosError(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Octopush;
|
50
server/notification-providers/pushbullet.js
Normal file
50
server/notification-providers/pushbullet.js
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
const NotificationProvider = require("./notification-provider");
|
||||||
|
const axios = require("axios");
|
||||||
|
|
||||||
|
const { DOWN, UP } = require("../../src/util");
|
||||||
|
|
||||||
|
class Pushbullet extends NotificationProvider {
|
||||||
|
|
||||||
|
name = "pushbullet";
|
||||||
|
|
||||||
|
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
||||||
|
let okMsg = "Sent Successfully. ";
|
||||||
|
|
||||||
|
try {
|
||||||
|
let pushbulletUrl = "https://api.pushbullet.com/v2/pushes";
|
||||||
|
let config = {
|
||||||
|
headers: {
|
||||||
|
"Access-Token": notification.pushbulletAccessToken,
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (heartbeatJSON == null) {
|
||||||
|
let testdata = {
|
||||||
|
"type": "note",
|
||||||
|
"title": "Uptime Kuma Alert",
|
||||||
|
"body": "Testing Successful.",
|
||||||
|
}
|
||||||
|
await axios.post(pushbulletUrl, testdata, config)
|
||||||
|
} else if (heartbeatJSON["status"] == DOWN) {
|
||||||
|
let downdata = {
|
||||||
|
"type": "note",
|
||||||
|
"title": "UptimeKuma Alert: " + monitorJSON["name"],
|
||||||
|
"body": "[🔴 Down] " + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"],
|
||||||
|
}
|
||||||
|
await axios.post(pushbulletUrl, downdata, config)
|
||||||
|
} else if (heartbeatJSON["status"] == UP) {
|
||||||
|
let updata = {
|
||||||
|
"type": "note",
|
||||||
|
"title": "UptimeKuma Alert: " + monitorJSON["name"],
|
||||||
|
"body": "[✅ Up] " + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"],
|
||||||
|
}
|
||||||
|
await axios.post(pushbulletUrl, updata, config)
|
||||||
|
}
|
||||||
|
return okMsg;
|
||||||
|
} catch (error) {
|
||||||
|
this.throwGeneralAxiosError(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Pushbullet;
|
49
server/notification-providers/pushover.js
Normal file
49
server/notification-providers/pushover.js
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
const NotificationProvider = require("./notification-provider");
|
||||||
|
const axios = require("axios");
|
||||||
|
|
||||||
|
class Pushover extends NotificationProvider {
|
||||||
|
|
||||||
|
name = "pushover";
|
||||||
|
|
||||||
|
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
||||||
|
let okMsg = "Sent Successfully. ";
|
||||||
|
let pushoverlink = "https://api.pushover.net/1/messages.json"
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (heartbeatJSON == null) {
|
||||||
|
let data = {
|
||||||
|
"message": "<b>Uptime Kuma Pushover testing successful.</b>",
|
||||||
|
"user": notification.pushoveruserkey,
|
||||||
|
"token": notification.pushoverapptoken,
|
||||||
|
"sound": notification.pushoversounds,
|
||||||
|
"priority": notification.pushoverpriority,
|
||||||
|
"title": notification.pushovertitle,
|
||||||
|
"retry": "30",
|
||||||
|
"expire": "3600",
|
||||||
|
"html": 1,
|
||||||
|
}
|
||||||
|
await axios.post(pushoverlink, data)
|
||||||
|
return okMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
let data = {
|
||||||
|
"message": "<b>Uptime Kuma Alert</b>\n\n<b>Message</b>:" + msg + "\n<b>Time (UTC)</b>:" + heartbeatJSON["time"],
|
||||||
|
"user": notification.pushoveruserkey,
|
||||||
|
"token": notification.pushoverapptoken,
|
||||||
|
"sound": notification.pushoversounds,
|
||||||
|
"priority": notification.pushoverpriority,
|
||||||
|
"title": notification.pushovertitle,
|
||||||
|
"retry": "30",
|
||||||
|
"expire": "3600",
|
||||||
|
"html": 1,
|
||||||
|
}
|
||||||
|
await axios.post(pushoverlink, data)
|
||||||
|
return okMsg;
|
||||||
|
} catch (error) {
|
||||||
|
this.throwGeneralAxiosError(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Pushover;
|
30
server/notification-providers/pushy.js
Normal file
30
server/notification-providers/pushy.js
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
const NotificationProvider = require("./notification-provider");
|
||||||
|
const axios = require("axios");
|
||||||
|
|
||||||
|
class Pushy extends NotificationProvider {
|
||||||
|
|
||||||
|
name = "pushy";
|
||||||
|
|
||||||
|
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
||||||
|
let okMsg = "Sent Successfully. ";
|
||||||
|
|
||||||
|
try {
|
||||||
|
await axios.post(`https://api.pushy.me/push?api_key=${notification.pushyAPIKey}`, {
|
||||||
|
"to": notification.pushyToken,
|
||||||
|
"data": {
|
||||||
|
"message": "Uptime-Kuma"
|
||||||
|
},
|
||||||
|
"notification": {
|
||||||
|
"body": msg,
|
||||||
|
"badge": 1,
|
||||||
|
"sound": "ping.aiff"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return okMsg;
|
||||||
|
} catch (error) {
|
||||||
|
this.throwGeneralAxiosError(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Pushy;
|
46
server/notification-providers/rocket-chat.js
Normal file
46
server/notification-providers/rocket-chat.js
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
const NotificationProvider = require("./notification-provider");
|
||||||
|
const axios = require("axios");
|
||||||
|
|
||||||
|
class RocketChat extends NotificationProvider {
|
||||||
|
|
||||||
|
name = "rocket.chat";
|
||||||
|
|
||||||
|
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
||||||
|
let okMsg = "Sent Successfully. ";
|
||||||
|
try {
|
||||||
|
if (heartbeatJSON == null) {
|
||||||
|
let data = {
|
||||||
|
"text": "Uptime Kuma Rocket.chat testing successful.",
|
||||||
|
"channel": notification.rocketchannel,
|
||||||
|
"username": notification.rocketusername,
|
||||||
|
"icon_emoji": notification.rocketiconemo,
|
||||||
|
}
|
||||||
|
await axios.post(notification.rocketwebhookURL, data)
|
||||||
|
return okMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
const time = heartbeatJSON["time"];
|
||||||
|
let data = {
|
||||||
|
"text": "Uptime Kuma Alert",
|
||||||
|
"channel": notification.rocketchannel,
|
||||||
|
"username": notification.rocketusername,
|
||||||
|
"icon_emoji": notification.rocketiconemo,
|
||||||
|
"attachments": [
|
||||||
|
{
|
||||||
|
"title": "Uptime Kuma Alert *Time (UTC)*\n" + time,
|
||||||
|
"title_link": notification.rocketbutton,
|
||||||
|
"text": "*Message*\n" + msg,
|
||||||
|
"color": "#32cd32"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
await axios.post(notification.rocketwebhookURL, data)
|
||||||
|
return okMsg;
|
||||||
|
} catch (error) {
|
||||||
|
this.throwGeneralAxiosError(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = RocketChat;
|
27
server/notification-providers/signal.js
Normal file
27
server/notification-providers/signal.js
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
const NotificationProvider = require("./notification-provider");
|
||||||
|
const axios = require("axios");
|
||||||
|
|
||||||
|
class Signal extends NotificationProvider {
|
||||||
|
|
||||||
|
name = "signal";
|
||||||
|
|
||||||
|
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
||||||
|
let okMsg = "Sent Successfully. ";
|
||||||
|
|
||||||
|
try {
|
||||||
|
let data = {
|
||||||
|
"message": msg,
|
||||||
|
"number": notification.signalNumber,
|
||||||
|
"recipients": notification.signalRecipients.replace(/\s/g, "").split(","),
|
||||||
|
};
|
||||||
|
let config = {};
|
||||||
|
|
||||||
|
await axios.post(notification.signalURL, data, config)
|
||||||
|
return okMsg;
|
||||||
|
} catch (error) {
|
||||||
|
this.throwGeneralAxiosError(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Signal;
|
70
server/notification-providers/slack.js
Normal file
70
server/notification-providers/slack.js
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
const NotificationProvider = require("./notification-provider");
|
||||||
|
const axios = require("axios");
|
||||||
|
|
||||||
|
class Slack extends NotificationProvider {
|
||||||
|
|
||||||
|
name = "slack";
|
||||||
|
|
||||||
|
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
||||||
|
let okMsg = "Sent Successfully. ";
|
||||||
|
try {
|
||||||
|
if (heartbeatJSON == null) {
|
||||||
|
let data = {
|
||||||
|
"text": "Uptime Kuma Slack testing successful.",
|
||||||
|
"channel": notification.slackchannel,
|
||||||
|
"username": notification.slackusername,
|
||||||
|
"icon_emoji": notification.slackiconemo,
|
||||||
|
}
|
||||||
|
await axios.post(notification.slackwebhookURL, data)
|
||||||
|
return okMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
const time = heartbeatJSON["time"];
|
||||||
|
let data = {
|
||||||
|
"text": "Uptime Kuma Alert",
|
||||||
|
"channel": notification.slackchannel,
|
||||||
|
"username": notification.slackusername,
|
||||||
|
"icon_emoji": notification.slackiconemo,
|
||||||
|
"blocks": [{
|
||||||
|
"type": "header",
|
||||||
|
"text": {
|
||||||
|
"type": "plain_text",
|
||||||
|
"text": "Uptime Kuma Alert",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "section",
|
||||||
|
"fields": [{
|
||||||
|
"type": "mrkdwn",
|
||||||
|
"text": "*Message*\n" + msg,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "mrkdwn",
|
||||||
|
"text": "*Time (UTC)*\n" + time,
|
||||||
|
}],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "actions",
|
||||||
|
"elements": [
|
||||||
|
{
|
||||||
|
"type": "button",
|
||||||
|
"text": {
|
||||||
|
"type": "plain_text",
|
||||||
|
"text": "Visit Uptime Kuma",
|
||||||
|
},
|
||||||
|
"value": "Uptime-Kuma",
|
||||||
|
"url": notification.slackbutton || "https://github.com/louislam/uptime-kuma",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}],
|
||||||
|
}
|
||||||
|
await axios.post(notification.slackwebhookURL, data)
|
||||||
|
return okMsg;
|
||||||
|
} catch (error) {
|
||||||
|
this.throwGeneralAxiosError(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Slack;
|
43
server/notification-providers/smtp.js
Normal file
43
server/notification-providers/smtp.js
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
const nodemailer = require("nodemailer");
|
||||||
|
const NotificationProvider = require("./notification-provider");
|
||||||
|
|
||||||
|
class SMTP extends NotificationProvider {
|
||||||
|
|
||||||
|
name = "smtp";
|
||||||
|
|
||||||
|
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
host: notification.smtpHost,
|
||||||
|
port: notification.smtpPort,
|
||||||
|
secure: notification.smtpSecure,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Should fix the issue in https://github.com/louislam/uptime-kuma/issues/26#issuecomment-896373904
|
||||||
|
if (notification.smtpUsername || notification.smtpPassword) {
|
||||||
|
config.auth = {
|
||||||
|
user: notification.smtpUsername,
|
||||||
|
pass: notification.smtpPassword,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
let transporter = nodemailer.createTransport(config);
|
||||||
|
|
||||||
|
let bodyTextContent = msg;
|
||||||
|
if (heartbeatJSON) {
|
||||||
|
bodyTextContent = `${msg}\nTime (UTC): ${heartbeatJSON["time"]}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// send mail with defined transport object
|
||||||
|
await transporter.sendMail({
|
||||||
|
from: `"Uptime Kuma" <${notification.smtpFrom}>`,
|
||||||
|
to: notification.smtpTo,
|
||||||
|
subject: msg,
|
||||||
|
text: bodyTextContent,
|
||||||
|
});
|
||||||
|
|
||||||
|
return "Sent Successfully.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = SMTP;
|
27
server/notification-providers/telegram.js
Normal file
27
server/notification-providers/telegram.js
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
const NotificationProvider = require("./notification-provider");
|
||||||
|
const axios = require("axios");
|
||||||
|
|
||||||
|
class Telegram extends NotificationProvider {
|
||||||
|
|
||||||
|
name = "telegram";
|
||||||
|
|
||||||
|
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
||||||
|
let okMsg = "Sent Successfully. ";
|
||||||
|
|
||||||
|
try {
|
||||||
|
await axios.get(`https://api.telegram.org/bot${notification.telegramBotToken}/sendMessage`, {
|
||||||
|
params: {
|
||||||
|
chat_id: notification.telegramChatID,
|
||||||
|
text: msg,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
return okMsg;
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
let msg = (error.response.data.description) ? error.response.data.description : "Error without description"
|
||||||
|
throw new Error(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Telegram;
|
44
server/notification-providers/webhook.js
Normal file
44
server/notification-providers/webhook.js
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
const NotificationProvider = require("./notification-provider");
|
||||||
|
const axios = require("axios");
|
||||||
|
const FormData = require("form-data");
|
||||||
|
|
||||||
|
class Webhook extends NotificationProvider {
|
||||||
|
|
||||||
|
name = "webhook";
|
||||||
|
|
||||||
|
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
||||||
|
let okMsg = "Sent Successfully. ";
|
||||||
|
|
||||||
|
try {
|
||||||
|
let data = {
|
||||||
|
heartbeat: heartbeatJSON,
|
||||||
|
monitor: monitorJSON,
|
||||||
|
msg,
|
||||||
|
};
|
||||||
|
let finalData;
|
||||||
|
let config = {};
|
||||||
|
|
||||||
|
if (notification.webhookContentType === "form-data") {
|
||||||
|
finalData = new FormData();
|
||||||
|
finalData.append("data", JSON.stringify(data));
|
||||||
|
|
||||||
|
config = {
|
||||||
|
headers: finalData.getHeaders(),
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
finalData = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
await axios.post(notification.webhookURL, finalData, config)
|
||||||
|
return okMsg;
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
this.throwGeneralAxiosError(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Webhook;
|
|
@ -1,602 +1,75 @@
|
||||||
const axios = require("axios");
|
|
||||||
const { R } = require("redbean-node");
|
const { R } = require("redbean-node");
|
||||||
const FormData = require("form-data");
|
const Apprise = require("./notification-providers/apprise");
|
||||||
const nodemailer = require("nodemailer");
|
const Discord = require("./notification-providers/discord");
|
||||||
const child_process = require("child_process");
|
const Gotify = require("./notification-providers/gotify");
|
||||||
|
const Line = require("./notification-providers/line");
|
||||||
const { UP, DOWN } = require("../src/util");
|
const LunaSea = require("./notification-providers/lunasea");
|
||||||
|
const Mattermost = require("./notification-providers/mattermost");
|
||||||
|
const Octopush = require("./notification-providers/octopush");
|
||||||
|
const Pushbullet = require("./notification-providers/pushbullet");
|
||||||
|
const Pushover = require("./notification-providers/pushover");
|
||||||
|
const Pushy = require("./notification-providers/pushy");
|
||||||
|
const RocketChat = require("./notification-providers/rocket-chat");
|
||||||
|
const Signal = require("./notification-providers/signal");
|
||||||
|
const Slack = require("./notification-providers/slack");
|
||||||
|
const SMTP = require("./notification-providers/smtp");
|
||||||
|
const Telegram = require("./notification-providers/telegram");
|
||||||
|
const Webhook = require("./notification-providers/webhook");
|
||||||
|
|
||||||
class Notification {
|
class Notification {
|
||||||
|
|
||||||
|
providerList = {};
|
||||||
|
|
||||||
|
static init() {
|
||||||
|
console.log("Prepare Notification Providers");
|
||||||
|
|
||||||
|
this.providerList = {};
|
||||||
|
|
||||||
|
const list = [
|
||||||
|
new Apprise(),
|
||||||
|
new Discord(),
|
||||||
|
new Gotify(),
|
||||||
|
new Line(),
|
||||||
|
new LunaSea(),
|
||||||
|
new Mattermost(),
|
||||||
|
new Octopush(),
|
||||||
|
new Pushbullet(),
|
||||||
|
new Pushover(),
|
||||||
|
new Pushy(),
|
||||||
|
new RocketChat(),
|
||||||
|
new Signal(),
|
||||||
|
new Slack(),
|
||||||
|
new SMTP(),
|
||||||
|
new Telegram(),
|
||||||
|
new Webhook(),
|
||||||
|
];
|
||||||
|
|
||||||
|
for (let item of list) {
|
||||||
|
if (! item.name) {
|
||||||
|
throw new Error("Notification provider without name");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.providerList[item.name]) {
|
||||||
|
throw new Error("Duplicate notification provider name");
|
||||||
|
}
|
||||||
|
this.providerList[item.name] = item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param notification
|
* @param notification : BeanModel
|
||||||
* @param msg
|
* @param msg : string General Message
|
||||||
* @param monitorJSON
|
* @param monitorJSON : object Monitor details (For Up/Down only)
|
||||||
* @param heartbeatJSON
|
* @param heartbeatJSON : object Heartbeat details (For Up/Down only)
|
||||||
* @returns {Promise<string>} Successful msg
|
* @returns {Promise<string>} Successful msg
|
||||||
* Throw Error with fail msg
|
* Throw Error with fail msg
|
||||||
*/
|
*/
|
||||||
static async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
static async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
||||||
let okMsg = "Sent Successfully. ";
|
if (this.providerList[notification.type]) {
|
||||||
|
return this.providerList[notification.type].send(notification, msg, monitorJSON, heartbeatJSON);
|
||||||
if (notification.type === "telegram") {
|
|
||||||
try {
|
|
||||||
await axios.get(`https://api.telegram.org/bot${notification.telegramBotToken}/sendMessage`, {
|
|
||||||
params: {
|
|
||||||
chat_id: notification.telegramChatID,
|
|
||||||
text: msg,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
return okMsg;
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
let msg = (error.response.data.description) ? error.response.data.description : "Error without description"
|
|
||||||
throw new Error(msg)
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (notification.type === "gotify") {
|
|
||||||
try {
|
|
||||||
if (notification.gotifyserverurl && notification.gotifyserverurl.endsWith("/")) {
|
|
||||||
notification.gotifyserverurl = notification.gotifyserverurl.slice(0, -1);
|
|
||||||
}
|
|
||||||
await axios.post(`${notification.gotifyserverurl}/message?token=${notification.gotifyapplicationToken}`, {
|
|
||||||
"message": msg,
|
|
||||||
"priority": notification.gotifyPriority || 8,
|
|
||||||
"title": "Uptime-Kuma",
|
|
||||||
})
|
|
||||||
|
|
||||||
return okMsg;
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
throwGeneralAxiosError(error)
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (notification.type === "webhook") {
|
|
||||||
try {
|
|
||||||
let data = {
|
|
||||||
heartbeat: heartbeatJSON,
|
|
||||||
monitor: monitorJSON,
|
|
||||||
msg,
|
|
||||||
};
|
|
||||||
let finalData;
|
|
||||||
let config = {};
|
|
||||||
|
|
||||||
if (notification.webhookContentType === "form-data") {
|
|
||||||
finalData = new FormData();
|
|
||||||
finalData.append("data", JSON.stringify(data));
|
|
||||||
|
|
||||||
config = {
|
|
||||||
headers: finalData.getHeaders(),
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
finalData = data;
|
throw new Error("Notification type is not supported");
|
||||||
}
|
|
||||||
|
|
||||||
await axios.post(notification.webhookURL, finalData, config)
|
|
||||||
return okMsg;
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
throwGeneralAxiosError(error)
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (notification.type === "smtp") {
|
|
||||||
return await Notification.smtp(notification, msg, heartbeatJSON)
|
|
||||||
|
|
||||||
} else if (notification.type === "discord") {
|
|
||||||
try {
|
|
||||||
const discordDisplayName = notification.discordUsername || "Uptime Kuma";
|
|
||||||
|
|
||||||
// If heartbeatJSON is null, assume we're testing.
|
|
||||||
if (heartbeatJSON == null) {
|
|
||||||
let discordtestdata = {
|
|
||||||
username: discordDisplayName,
|
|
||||||
content: msg,
|
|
||||||
}
|
|
||||||
await axios.post(notification.discordWebhookUrl, discordtestdata)
|
|
||||||
return okMsg;
|
|
||||||
}
|
|
||||||
|
|
||||||
let url;
|
|
||||||
|
|
||||||
if (monitorJSON["type"] === "port") {
|
|
||||||
url = monitorJSON["hostname"];
|
|
||||||
if (monitorJSON["port"]) {
|
|
||||||
url += ":" + monitorJSON["port"];
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
url = monitorJSON["url"];
|
|
||||||
}
|
|
||||||
|
|
||||||
// If heartbeatJSON is not null, we go into the normal alerting loop.
|
|
||||||
if (heartbeatJSON["status"] == DOWN) {
|
|
||||||
let discorddowndata = {
|
|
||||||
username: discordDisplayName,
|
|
||||||
embeds: [{
|
|
||||||
title: "❌ Your service " + monitorJSON["name"] + " went down. ❌",
|
|
||||||
color: 16711680,
|
|
||||||
timestamp: heartbeatJSON["time"],
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
name: "Service Name",
|
|
||||||
value: monitorJSON["name"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Service URL",
|
|
||||||
value: url,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Time (UTC)",
|
|
||||||
value: heartbeatJSON["time"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Error",
|
|
||||||
value: heartbeatJSON["msg"],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}],
|
|
||||||
}
|
|
||||||
await axios.post(notification.discordWebhookUrl, discorddowndata)
|
|
||||||
return okMsg;
|
|
||||||
|
|
||||||
} else if (heartbeatJSON["status"] == UP) {
|
|
||||||
let discordupdata = {
|
|
||||||
username: discordDisplayName,
|
|
||||||
embeds: [{
|
|
||||||
title: "✅ Your service " + monitorJSON["name"] + " is up! ✅",
|
|
||||||
color: 65280,
|
|
||||||
timestamp: heartbeatJSON["time"],
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
name: "Service Name",
|
|
||||||
value: monitorJSON["name"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Service URL",
|
|
||||||
value: url.startsWith("http") ? "[Visit Service](" + url + ")" : url,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Time (UTC)",
|
|
||||||
value: heartbeatJSON["time"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Ping",
|
|
||||||
value: heartbeatJSON["ping"] + "ms",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}],
|
|
||||||
}
|
|
||||||
await axios.post(notification.discordWebhookUrl, discordupdata)
|
|
||||||
return okMsg;
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
throwGeneralAxiosError(error)
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (notification.type === "signal") {
|
|
||||||
try {
|
|
||||||
let data = {
|
|
||||||
"message": msg,
|
|
||||||
"number": notification.signalNumber,
|
|
||||||
"recipients": notification.signalRecipients.replace(/\s/g, "").split(","),
|
|
||||||
};
|
|
||||||
let config = {};
|
|
||||||
|
|
||||||
await axios.post(notification.signalURL, data, config)
|
|
||||||
return okMsg;
|
|
||||||
} catch (error) {
|
|
||||||
throwGeneralAxiosError(error)
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (notification.type === "pushy") {
|
|
||||||
try {
|
|
||||||
await axios.post(`https://api.pushy.me/push?api_key=${notification.pushyAPIKey}`, {
|
|
||||||
"to": notification.pushyToken,
|
|
||||||
"data": {
|
|
||||||
"message": "Uptime-Kuma"
|
|
||||||
},
|
|
||||||
"notification": {
|
|
||||||
"body": msg,
|
|
||||||
"badge": 1,
|
|
||||||
"sound": "ping.aiff"
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return true;
|
|
||||||
} catch (error) {
|
|
||||||
console.log(error)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else if (notification.type === "octopush") {
|
|
||||||
try {
|
|
||||||
let config = {
|
|
||||||
headers: {
|
|
||||||
"api-key": notification.octopushAPIKey,
|
|
||||||
"api-login": notification.octopushLogin,
|
|
||||||
"cache-control": "no-cache"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let data = {
|
|
||||||
"recipients": [
|
|
||||||
{
|
|
||||||
"phone_number": notification.octopushPhoneNumber
|
|
||||||
}
|
|
||||||
],
|
|
||||||
//octopush not supporting non ascii char
|
|
||||||
"text": msg.replace(/[^\x00-\x7F]/g, ""),
|
|
||||||
"type": notification.octopushSMSType,
|
|
||||||
"purpose": "alert",
|
|
||||||
"sender": notification.octopushSenderName
|
|
||||||
};
|
|
||||||
|
|
||||||
await axios.post("https://api.octopush.com/v1/public/sms-campaign/send", data, config)
|
|
||||||
return true;
|
|
||||||
} catch (error) {
|
|
||||||
console.log(error)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else if (notification.type === "slack") {
|
|
||||||
try {
|
|
||||||
if (heartbeatJSON == null) {
|
|
||||||
let data = {
|
|
||||||
"text": "Uptime Kuma Slack testing successful.",
|
|
||||||
"channel": notification.slackchannel,
|
|
||||||
"username": notification.slackusername,
|
|
||||||
"icon_emoji": notification.slackiconemo,
|
|
||||||
}
|
|
||||||
await axios.post(notification.slackwebhookURL, data)
|
|
||||||
return okMsg;
|
|
||||||
}
|
|
||||||
|
|
||||||
const time = heartbeatJSON["time"];
|
|
||||||
let data = {
|
|
||||||
"text": "Uptime Kuma Alert",
|
|
||||||
"channel": notification.slackchannel,
|
|
||||||
"username": notification.slackusername,
|
|
||||||
"icon_emoji": notification.slackiconemo,
|
|
||||||
"blocks": [{
|
|
||||||
"type": "header",
|
|
||||||
"text": {
|
|
||||||
"type": "plain_text",
|
|
||||||
"text": "Uptime Kuma Alert",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "section",
|
|
||||||
"fields": [{
|
|
||||||
"type": "mrkdwn",
|
|
||||||
"text": "*Message*\n" + msg,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "mrkdwn",
|
|
||||||
"text": "*Time (UTC)*\n" + time,
|
|
||||||
}],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "actions",
|
|
||||||
"elements": [
|
|
||||||
{
|
|
||||||
"type": "button",
|
|
||||||
"text": {
|
|
||||||
"type": "plain_text",
|
|
||||||
"text": "Visit Uptime Kuma",
|
|
||||||
},
|
|
||||||
"value": "Uptime-Kuma",
|
|
||||||
"url": notification.slackbutton || "https://github.com/louislam/uptime-kuma",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}],
|
|
||||||
}
|
|
||||||
await axios.post(notification.slackwebhookURL, data)
|
|
||||||
return okMsg;
|
|
||||||
} catch (error) {
|
|
||||||
throwGeneralAxiosError(error)
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (notification.type === "rocket.chat") {
|
|
||||||
try {
|
|
||||||
if (heartbeatJSON == null) {
|
|
||||||
let data = {
|
|
||||||
"text": "Uptime Kuma Rocket.chat testing successful.",
|
|
||||||
"channel": notification.rocketchannel,
|
|
||||||
"username": notification.rocketusername,
|
|
||||||
"icon_emoji": notification.rocketiconemo,
|
|
||||||
}
|
|
||||||
await axios.post(notification.rocketwebhookURL, data)
|
|
||||||
return okMsg;
|
|
||||||
}
|
|
||||||
|
|
||||||
const time = heartbeatJSON["time"];
|
|
||||||
let data = {
|
|
||||||
"text": "Uptime Kuma Alert",
|
|
||||||
"channel": notification.rocketchannel,
|
|
||||||
"username": notification.rocketusername,
|
|
||||||
"icon_emoji": notification.rocketiconemo,
|
|
||||||
"attachments": [
|
|
||||||
{
|
|
||||||
"title": "Uptime Kuma Alert *Time (UTC)*\n" + time,
|
|
||||||
"title_link": notification.rocketbutton,
|
|
||||||
"text": "*Message*\n" + msg,
|
|
||||||
"color": "#32cd32"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
await axios.post(notification.rocketwebhookURL, data)
|
|
||||||
return okMsg;
|
|
||||||
} catch (error) {
|
|
||||||
throwGeneralAxiosError(error)
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (notification.type === "mattermost") {
|
|
||||||
try {
|
|
||||||
const mattermostUserName = notification.mattermostusername || "Uptime Kuma";
|
|
||||||
// If heartbeatJSON is null, assume we're testing.
|
|
||||||
if (heartbeatJSON == null) {
|
|
||||||
let mattermostTestData = {
|
|
||||||
username: mattermostUserName,
|
|
||||||
text: msg,
|
|
||||||
}
|
|
||||||
await axios.post(notification.mattermostWebhookUrl, mattermostTestData)
|
|
||||||
return okMsg;
|
|
||||||
}
|
|
||||||
|
|
||||||
const mattermostChannel = notification.mattermostchannel;
|
|
||||||
const mattermostIconEmoji = notification.mattermosticonemo;
|
|
||||||
const mattermostIconUrl = notification.mattermosticonurl;
|
|
||||||
|
|
||||||
if (heartbeatJSON["status"] == DOWN) {
|
|
||||||
let mattermostdowndata = {
|
|
||||||
username: mattermostUserName,
|
|
||||||
text: "Uptime Kuma Alert",
|
|
||||||
channel: mattermostChannel,
|
|
||||||
icon_emoji: mattermostIconEmoji,
|
|
||||||
icon_url: mattermostIconUrl,
|
|
||||||
attachments: [
|
|
||||||
{
|
|
||||||
fallback:
|
|
||||||
"Your " +
|
|
||||||
monitorJSON["name"] +
|
|
||||||
" service went down.",
|
|
||||||
color: "#FF0000",
|
|
||||||
title:
|
|
||||||
"❌ " +
|
|
||||||
monitorJSON["name"] +
|
|
||||||
" service went down. ❌",
|
|
||||||
title_link: monitorJSON["url"],
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
short: true,
|
|
||||||
title: "Service Name",
|
|
||||||
value: monitorJSON["name"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
short: true,
|
|
||||||
title: "Time (UTC)",
|
|
||||||
value: heartbeatJSON["time"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
short: false,
|
|
||||||
title: "Error",
|
|
||||||
value: heartbeatJSON["msg"],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
await axios.post(
|
|
||||||
notification.mattermostWebhookUrl,
|
|
||||||
mattermostdowndata
|
|
||||||
);
|
|
||||||
return okMsg;
|
|
||||||
} else if (heartbeatJSON["status"] == UP) {
|
|
||||||
let mattermostupdata = {
|
|
||||||
username: mattermostUserName,
|
|
||||||
text: "Uptime Kuma Alert",
|
|
||||||
channel: mattermostChannel,
|
|
||||||
icon_emoji: mattermostIconEmoji,
|
|
||||||
icon_url: mattermostIconUrl,
|
|
||||||
attachments: [
|
|
||||||
{
|
|
||||||
fallback:
|
|
||||||
"Your " +
|
|
||||||
monitorJSON["name"] +
|
|
||||||
" service went up!",
|
|
||||||
color: "#32CD32",
|
|
||||||
title:
|
|
||||||
"✅ " +
|
|
||||||
monitorJSON["name"] +
|
|
||||||
" service went up! ✅",
|
|
||||||
title_link: monitorJSON["url"],
|
|
||||||
fields: [
|
|
||||||
{
|
|
||||||
short: true,
|
|
||||||
title: "Service Name",
|
|
||||||
value: monitorJSON["name"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
short: true,
|
|
||||||
title: "Time (UTC)",
|
|
||||||
value: heartbeatJSON["time"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
short: false,
|
|
||||||
title: "Ping",
|
|
||||||
value: heartbeatJSON["ping"] + "ms",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
await axios.post(
|
|
||||||
notification.mattermostWebhookUrl,
|
|
||||||
mattermostupdata
|
|
||||||
);
|
|
||||||
return okMsg;
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
throwGeneralAxiosError(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (notification.type === "pushover") {
|
|
||||||
let pushoverlink = "https://api.pushover.net/1/messages.json"
|
|
||||||
try {
|
|
||||||
if (heartbeatJSON == null) {
|
|
||||||
let data = {
|
|
||||||
"message": "<b>Uptime Kuma Pushover testing successful.</b>",
|
|
||||||
"user": notification.pushoveruserkey,
|
|
||||||
"token": notification.pushoverapptoken,
|
|
||||||
"sound": notification.pushoversounds,
|
|
||||||
"priority": notification.pushoverpriority,
|
|
||||||
"title": notification.pushovertitle,
|
|
||||||
"retry": "30",
|
|
||||||
"expire": "3600",
|
|
||||||
"html": 1,
|
|
||||||
}
|
|
||||||
await axios.post(pushoverlink, data)
|
|
||||||
return okMsg;
|
|
||||||
}
|
|
||||||
|
|
||||||
let data = {
|
|
||||||
"message": "<b>Uptime Kuma Alert</b>\n\n<b>Message</b>:" + msg + "\n<b>Time (UTC)</b>:" + heartbeatJSON["time"],
|
|
||||||
"user": notification.pushoveruserkey,
|
|
||||||
"token": notification.pushoverapptoken,
|
|
||||||
"sound": notification.pushoversounds,
|
|
||||||
"priority": notification.pushoverpriority,
|
|
||||||
"title": notification.pushovertitle,
|
|
||||||
"retry": "30",
|
|
||||||
"expire": "3600",
|
|
||||||
"html": 1,
|
|
||||||
}
|
|
||||||
await axios.post(pushoverlink, data)
|
|
||||||
return okMsg;
|
|
||||||
} catch (error) {
|
|
||||||
throwGeneralAxiosError(error)
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (notification.type === "apprise") {
|
|
||||||
|
|
||||||
return Notification.apprise(notification, msg)
|
|
||||||
|
|
||||||
} else if (notification.type === "lunasea") {
|
|
||||||
let lunaseadevice = "https://notify.lunasea.app/v1/custom/device/" + notification.lunaseaDevice
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (heartbeatJSON == null) {
|
|
||||||
let testdata = {
|
|
||||||
"title": "Uptime Kuma Alert",
|
|
||||||
"body": "Testing Successful.",
|
|
||||||
}
|
|
||||||
await axios.post(lunaseadevice, testdata)
|
|
||||||
return okMsg;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (heartbeatJSON["status"] == DOWN) {
|
|
||||||
let downdata = {
|
|
||||||
"title": "UptimeKuma Alert: " + monitorJSON["name"],
|
|
||||||
"body": "[🔴 Down] " + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"],
|
|
||||||
}
|
|
||||||
await axios.post(lunaseadevice, downdata)
|
|
||||||
return okMsg;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (heartbeatJSON["status"] == UP) {
|
|
||||||
let updata = {
|
|
||||||
"title": "UptimeKuma Alert: " + monitorJSON["name"],
|
|
||||||
"body": "[✅ Up] " + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"],
|
|
||||||
}
|
|
||||||
await axios.post(lunaseadevice, updata)
|
|
||||||
return okMsg;
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
throwGeneralAxiosError(error)
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (notification.type === "pushbullet") {
|
|
||||||
try {
|
|
||||||
let pushbulletUrl = "https://api.pushbullet.com/v2/pushes";
|
|
||||||
let config = {
|
|
||||||
headers: {
|
|
||||||
"Access-Token": notification.pushbulletAccessToken,
|
|
||||||
"Content-Type": "application/json"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if (heartbeatJSON == null) {
|
|
||||||
let testdata = {
|
|
||||||
"type": "note",
|
|
||||||
"title": "Uptime Kuma Alert",
|
|
||||||
"body": "Testing Successful.",
|
|
||||||
}
|
|
||||||
await axios.post(pushbulletUrl, testdata, config)
|
|
||||||
} else if (heartbeatJSON["status"] == DOWN) {
|
|
||||||
let downdata = {
|
|
||||||
"type": "note",
|
|
||||||
"title": "UptimeKuma Alert: " + monitorJSON["name"],
|
|
||||||
"body": "[🔴 Down] " + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"],
|
|
||||||
}
|
|
||||||
await axios.post(pushbulletUrl, downdata, config)
|
|
||||||
} else if (heartbeatJSON["status"] == UP) {
|
|
||||||
let updata = {
|
|
||||||
"type": "note",
|
|
||||||
"title": "UptimeKuma Alert: " + monitorJSON["name"],
|
|
||||||
"body": "[✅ Up] " + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"],
|
|
||||||
}
|
|
||||||
await axios.post(pushbulletUrl, updata, config)
|
|
||||||
}
|
|
||||||
return okMsg;
|
|
||||||
} catch (error) {
|
|
||||||
throwGeneralAxiosError(error)
|
|
||||||
}
|
|
||||||
} else if (notification.type === "line") {
|
|
||||||
try {
|
|
||||||
let lineAPIUrl = "https://api.line.me/v2/bot/message/push";
|
|
||||||
let config = {
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
"Authorization": "Bearer " + notification.lineChannelAccessToken
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if (heartbeatJSON == null) {
|
|
||||||
let testMessage = {
|
|
||||||
"to": notification.lineUserID,
|
|
||||||
"messages": [
|
|
||||||
{
|
|
||||||
"type": "text",
|
|
||||||
"text": "Test Successful!"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
await axios.post(lineAPIUrl, testMessage, config)
|
|
||||||
} else if (heartbeatJSON["status"] == DOWN) {
|
|
||||||
let downMessage = {
|
|
||||||
"to": notification.lineUserID,
|
|
||||||
"messages": [
|
|
||||||
{
|
|
||||||
"type": "text",
|
|
||||||
"text": "UptimeKuma Alert: [🔴 Down]\n" + "Name: " + monitorJSON["name"] + " \n" + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
await axios.post(lineAPIUrl, downMessage, config)
|
|
||||||
} else if (heartbeatJSON["status"] == UP) {
|
|
||||||
let upMessage = {
|
|
||||||
"to": notification.lineUserID,
|
|
||||||
"messages": [
|
|
||||||
{
|
|
||||||
"type": "text",
|
|
||||||
"text": "UptimeKuma Alert: [✅ Up]\n" + "Name: " + monitorJSON["name"] + " \n" + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
await axios.post(lineAPIUrl, upMessage, config)
|
|
||||||
}
|
|
||||||
return okMsg;
|
|
||||||
} catch (error) {
|
|
||||||
throwGeneralAxiosError(error)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw new Error("Notification type is not supported")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -636,57 +109,6 @@ class Notification {
|
||||||
await R.trash(bean)
|
await R.trash(bean)
|
||||||
}
|
}
|
||||||
|
|
||||||
static async smtp(notification, msg, heartbeatJSON = null) {
|
|
||||||
|
|
||||||
const config = {
|
|
||||||
host: notification.smtpHost,
|
|
||||||
port: notification.smtpPort,
|
|
||||||
secure: notification.smtpSecure,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Should fix the issue in https://github.com/louislam/uptime-kuma/issues/26#issuecomment-896373904
|
|
||||||
if (notification.smtpUsername || notification.smtpPassword) {
|
|
||||||
config.auth = {
|
|
||||||
user: notification.smtpUsername,
|
|
||||||
pass: notification.smtpPassword,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
let transporter = nodemailer.createTransport(config);
|
|
||||||
|
|
||||||
let bodyTextContent = msg;
|
|
||||||
if(heartbeatJSON) {
|
|
||||||
bodyTextContent = `${msg}\nTime (UTC): ${heartbeatJSON["time"]}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
// send mail with defined transport object
|
|
||||||
await transporter.sendMail({
|
|
||||||
from: `"Uptime Kuma" <${notification.smtpFrom}>`,
|
|
||||||
to: notification.smtpTo,
|
|
||||||
subject: msg,
|
|
||||||
text: bodyTextContent,
|
|
||||||
});
|
|
||||||
|
|
||||||
return "Sent Successfully.";
|
|
||||||
}
|
|
||||||
|
|
||||||
static async apprise(notification, msg) {
|
|
||||||
let s = child_process.spawnSync("apprise", [ "-vv", "-b", msg, notification.appriseURL])
|
|
||||||
|
|
||||||
let output = (s.stdout) ? s.stdout.toString() : "ERROR: maybe apprise not found";
|
|
||||||
|
|
||||||
if (output) {
|
|
||||||
|
|
||||||
if (! output.includes("ERROR")) {
|
|
||||||
return "Sent Successfully";
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error(output)
|
|
||||||
} else {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static checkApprise() {
|
static checkApprise() {
|
||||||
let commandExistsSync = require("command-exists").sync;
|
let commandExistsSync = require("command-exists").sync;
|
||||||
let exists = commandExistsSync("apprise");
|
let exists = commandExistsSync("apprise");
|
||||||
|
@ -695,20 +117,6 @@ class Notification {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function throwGeneralAxiosError(error) {
|
|
||||||
let msg = "Error: " + error + " ";
|
|
||||||
|
|
||||||
if (error.response && error.response.data) {
|
|
||||||
if (typeof error.response.data === "string") {
|
|
||||||
msg += error.response.data;
|
|
||||||
} else {
|
|
||||||
msg += JSON.stringify(error.response.data)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error(msg)
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
Notification,
|
Notification,
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,8 +27,11 @@ debug("Importing Monitor");
|
||||||
const Monitor = require("./model/monitor");
|
const Monitor = require("./model/monitor");
|
||||||
debug("Importing Settings");
|
debug("Importing Settings");
|
||||||
const { getSettings, setSettings, setting, initJWTSecret } = require("./util-server");
|
const { getSettings, setSettings, setting, initJWTSecret } = require("./util-server");
|
||||||
|
|
||||||
debug("Importing Notification");
|
debug("Importing Notification");
|
||||||
const { Notification } = require("./notification");
|
const { Notification } = require("./notification");
|
||||||
|
Notification.init();
|
||||||
|
|
||||||
debug("Importing Database");
|
debug("Importing Database");
|
||||||
const Database = require("./database");
|
const Database = require("./database");
|
||||||
|
|
||||||
|
|
|
@ -137,7 +137,6 @@ export default {
|
||||||
|
|
||||||
if (! Number.isInteger(actualWidth)) {
|
if (! Number.isInteger(actualWidth)) {
|
||||||
this.beatWidth = Math.round(actualWidth) / window.devicePixelRatio;
|
this.beatWidth = Math.round(actualWidth) / window.devicePixelRatio;
|
||||||
console.log(this.beatWidth);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! Number.isInteger(actualMargin)) {
|
if (! Number.isInteger(actualMargin)) {
|
||||||
|
|
|
@ -1,11 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="input-group mb-3">
|
<div class="input-group mb-3">
|
||||||
<!--
|
|
||||||
Hack - Disable Chrome save password
|
|
||||||
readonly + onfocus
|
|
||||||
https://stackoverflow.com/questions/41217019/how-to-prevent-a-browser-from-storing-passwords
|
|
||||||
-->
|
|
||||||
<input
|
<input
|
||||||
|
ref="input"
|
||||||
v-model="model"
|
v-model="model"
|
||||||
:type="visibility"
|
:type="visibility"
|
||||||
class="form-control"
|
class="form-control"
|
||||||
|
@ -13,8 +9,7 @@
|
||||||
:maxlength="maxlength"
|
:maxlength="maxlength"
|
||||||
:autocomplete="autocomplete"
|
:autocomplete="autocomplete"
|
||||||
:required="required"
|
:required="required"
|
||||||
:readonly="isReadOnly"
|
:readonly="readonly"
|
||||||
@focus="removeReadOnly"
|
|
||||||
>
|
>
|
||||||
|
|
||||||
<a v-if="visibility == 'password'" class="btn btn-outline-primary" @click="showInput()">
|
<a v-if="visibility == 'password'" class="btn btn-outline-primary" @click="showInput()">
|
||||||
|
@ -42,20 +37,20 @@ export default {
|
||||||
default: 255
|
default: 255
|
||||||
},
|
},
|
||||||
autocomplete: {
|
autocomplete: {
|
||||||
type: Boolean,
|
type: String,
|
||||||
|
default: undefined,
|
||||||
},
|
},
|
||||||
required: {
|
required: {
|
||||||
type: Boolean
|
type: Boolean
|
||||||
},
|
},
|
||||||
readonly: {
|
readonly: {
|
||||||
type: Boolean,
|
type: String,
|
||||||
default: false,
|
default: undefined,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
visibility: "password",
|
visibility: "password",
|
||||||
readOnlyValue: false,
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -66,22 +61,10 @@ export default {
|
||||||
set(value) {
|
set(value) {
|
||||||
this.$emit("update:modelValue", value)
|
this.$emit("update:modelValue", value)
|
||||||
}
|
}
|
||||||
},
|
|
||||||
isReadOnly() {
|
|
||||||
// Actually readonly from prop
|
|
||||||
if (this.readonly) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hack - Disable Chrome save password
|
|
||||||
return this.readOnlyValue;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
// Hack - Disable Chrome save password
|
|
||||||
if (this.autocomplete) {
|
|
||||||
this.readOnlyValue = "readonly";
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
showInput() {
|
showInput() {
|
||||||
|
@ -90,13 +73,6 @@ export default {
|
||||||
hideInput() {
|
hideInput() {
|
||||||
this.visibility = "password";
|
this.visibility = "password";
|
||||||
},
|
},
|
||||||
|
|
||||||
// Hack - Disable Chrome save password
|
|
||||||
removeReadOnly() {
|
|
||||||
if (this.autocomplete) {
|
|
||||||
this.readOnlyValue = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -37,44 +37,9 @@
|
||||||
<input id="name" v-model="notification.name" type="text" class="form-control" required>
|
<input id="name" v-model="notification.name" type="text" class="form-control" required>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<template v-if="notification.type === 'telegram'">
|
<Telegram></Telegram>
|
||||||
<div class="mb-3">
|
|
||||||
<label for="telegram-bot-token" class="form-label">Bot Token</label>
|
|
||||||
<HiddenInput id="telegram-bot-token" v-model="notification.telegramBotToken" :required="true" :readonly="true"></HiddenInput>
|
|
||||||
<div class="form-text">
|
|
||||||
You can get a token from <a href="https://t.me/BotFather" target="_blank">https://t.me/BotFather</a>.
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mb-3">
|
<!-- TODO: Convert all into vue components, but not an easy task. -->
|
||||||
<label for="telegram-chat-id" class="form-label">Chat ID</label>
|
|
||||||
|
|
||||||
<div class="input-group mb-3">
|
|
||||||
<input id="telegram-chat-id" v-model="notification.telegramChatID" type="text" class="form-control" required>
|
|
||||||
<button v-if="notification.telegramBotToken" class="btn btn-outline-secondary" type="button" @click="autoGetTelegramChatID">
|
|
||||||
Auto Get
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-text">
|
|
||||||
Support Direct Chat / Group / Channel's Chat ID
|
|
||||||
|
|
||||||
<p style="margin-top: 8px;">
|
|
||||||
You can get your chat id by sending message to the bot and go to this url to view the chat_id:
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p style="margin-top: 8px;">
|
|
||||||
<template v-if="notification.telegramBotToken">
|
|
||||||
<a :href="telegramGetUpdatesURL" target="_blank" style="word-break: break-word;">{{ telegramGetUpdatesURL }}</a>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template v-else>
|
|
||||||
{{ telegramGetUpdatesURL }}
|
|
||||||
</template>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template v-if="notification.type === 'webhook'">
|
<template v-if="notification.type === 'webhook'">
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
|
@ -130,7 +95,7 @@
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="password" class="form-label">Password</label>
|
<label for="password" class="form-label">Password</label>
|
||||||
<HiddenInput id="password" v-model="notification.smtpPassword" :required="true" autocomplete="false"></HiddenInput>
|
<HiddenInput id="password" v-model="notification.smtpPassword" :required="true" autocomplete="one-time-code"></HiddenInput>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
|
@ -195,7 +160,7 @@
|
||||||
<template v-if="notification.type === 'gotify'">
|
<template v-if="notification.type === 'gotify'">
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="gotify-application-token" class="form-label">Application Token</label>
|
<label for="gotify-application-token" class="form-label">Application Token</label>
|
||||||
<HiddenInput id="gotify-application-token" v-model="notification.gotifyapplicationToken" :required="true"></HiddenInput>
|
<HiddenInput id="gotify-application-token" v-model="notification.gotifyapplicationToken" :required="true" autocomplete="one-time-code"></HiddenInput>
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="gotify-server-url" class="form-label">Server URL</label>
|
<label for="gotify-server-url" class="form-label">Server URL</label>
|
||||||
|
@ -306,13 +271,13 @@
|
||||||
<template v-if="notification.type === 'pushy'">
|
<template v-if="notification.type === 'pushy'">
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="pushy-app-token" class="form-label">API_KEY</label>
|
<label for="pushy-app-token" class="form-label">API_KEY</label>
|
||||||
<HiddenInput id="pushy-app-token" v-model="notification.pushyAPIKey" :required="true"></HiddenInput>
|
<HiddenInput id="pushy-app-token" v-model="notification.pushyAPIKey" :required="true" autocomplete="one-time-code"></HiddenInput>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="pushy-user-key" class="form-label">USER_TOKEN</label>
|
<label for="pushy-user-key" class="form-label">USER_TOKEN</label>
|
||||||
<div class="input-group mb-3">
|
<div class="input-group mb-3">
|
||||||
<HiddenInput id="pushy-user-key" v-model="notification.pushyToken" :required="true"></HiddenInput>
|
<HiddenInput id="pushy-user-key" v-model="notification.pushyToken" :required="true" autocomplete="one-time-code"></HiddenInput>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p style="margin-top: 8px;">
|
<p style="margin-top: 8px;">
|
||||||
|
@ -323,7 +288,7 @@
|
||||||
<template v-if="notification.type === 'octopush'">
|
<template v-if="notification.type === 'octopush'">
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="octopush-key" class="form-label">API KEY</label>
|
<label for="octopush-key" class="form-label">API KEY</label>
|
||||||
<HiddenInput id="octopush-key" v-model="notification.octopushAPIKey" :required="true"></HiddenInput>
|
<HiddenInput id="octopush-key" v-model="notification.octopushAPIKey" :required="true" autocomplete="one-time-code"></HiddenInput>
|
||||||
<label for="octopush-login" class="form-label">API LOGIN</label>
|
<label for="octopush-login" class="form-label">API LOGIN</label>
|
||||||
<input id="octopush-login" v-model="notification.octopushLogin" type="text" class="form-control" required>
|
<input id="octopush-login" v-model="notification.octopushLogin" type="text" class="form-control" required>
|
||||||
</div>
|
</div>
|
||||||
|
@ -354,9 +319,9 @@
|
||||||
<template v-if="notification.type === 'pushover'">
|
<template v-if="notification.type === 'pushover'">
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="pushover-user" class="form-label">User Key<span style="color: red;"><sup>*</sup></span></label>
|
<label for="pushover-user" class="form-label">User Key<span style="color: red;"><sup>*</sup></span></label>
|
||||||
<HiddenInput id="pushover-user" v-model="notification.pushoveruserkey" :required="true"></HiddenInput>
|
<HiddenInput id="pushover-user" v-model="notification.pushoveruserkey" :required="true" autocomplete="one-time-code"></HiddenInput>
|
||||||
<label for="pushover-app-token" class="form-label">Application Token<span style="color: red;"><sup>*</sup></span></label>
|
<label for="pushover-app-token" class="form-label">Application Token<span style="color: red;"><sup>*</sup></span></label>
|
||||||
<HiddenInput id="pushover-app-token" v-model="notification.pushoverapptoken" :required="true"></HiddenInput>
|
<HiddenInput id="pushover-app-token" v-model="notification.pushoverapptoken" :required="true" autocomplete="one-time-code"></HiddenInput>
|
||||||
<label for="pushover-device" class="form-label">Device</label>
|
<label for="pushover-device" class="form-label">Device</label>
|
||||||
<input id="pushover-device" v-model="notification.pushoverdevice" type="text" class="form-control">
|
<input id="pushover-device" v-model="notification.pushoverdevice" type="text" class="form-control">
|
||||||
<label for="pushover-device" class="form-label">Message Title</label>
|
<label for="pushover-device" class="form-label">Message Title</label>
|
||||||
|
@ -442,7 +407,7 @@
|
||||||
<template v-if="notification.type === 'pushbullet'">
|
<template v-if="notification.type === 'pushbullet'">
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="pushbullet-access-token" class="form-label">Access Token</label>
|
<label for="pushbullet-access-token" class="form-label">Access Token</label>
|
||||||
<HiddenInput id="pushbullet-access-token" v-model="notification.pushbulletAccessToken" :required="true"></HiddenInput>
|
<HiddenInput id="pushbullet-access-token" v-model="notification.pushbulletAccessToken" :required="true" autocomplete="one-time-code"></HiddenInput>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p style="margin-top: 8px;">
|
<p style="margin-top: 8px;">
|
||||||
|
@ -453,7 +418,7 @@
|
||||||
<template v-if="notification.type === 'line'">
|
<template v-if="notification.type === 'line'">
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="line-channel-access-token" class="form-label">Channel access token</label>
|
<label for="line-channel-access-token" class="form-label">Channel access token</label>
|
||||||
<HiddenInput id="line-channel-access-token" v-model="notification.lineChannelAccessToken" :required="true"></HiddenInput>
|
<HiddenInput id="line-channel-access-token" v-model="notification.lineChannelAccessToken" :required="true" autocomplete="one-time-code"></HiddenInput>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-text">
|
<div class="form-text">
|
||||||
Line Developers Console - <b>Basic Settings</b>
|
Line Developers Console - <b>Basic Settings</b>
|
||||||
|
@ -469,6 +434,8 @@
|
||||||
First access the <a href="https://developers.line.biz/console/" target="_blank">Line Developers Console</a>, create a provider and channel (Messaging API), then you can get the channel access token and user id from the above mentioned menu items.
|
First access the <a href="https://developers.line.biz/console/" target="_blank">Line Developers Console</a>, create a provider and channel (Messaging API), then you can get the channel access token and user id from the above mentioned menu items.
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<!-- DEPRECATED! Please create vue component in "./src/components/notifications/{notification name}.vue" -->
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button v-if="id" type="button" class="btn btn-danger" :disabled="processing" @click="deleteConfirm">
|
<button v-if="id" type="button" class="btn btn-danger" :disabled="processing" @click="deleteConfirm">
|
||||||
|
@ -495,15 +462,18 @@
|
||||||
import { Modal } from "bootstrap"
|
import { Modal } from "bootstrap"
|
||||||
import { ucfirst } from "../util.ts"
|
import { ucfirst } from "../util.ts"
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { useToast } from "vue-toastification"
|
|
||||||
import Confirm from "./Confirm.vue";
|
import Confirm from "./Confirm.vue";
|
||||||
import HiddenInput from "./HiddenInput.vue";
|
import HiddenInput from "./HiddenInput.vue";
|
||||||
const toast = useToast()
|
import Telegram from "./notifications/Telegram.vue";
|
||||||
|
import { useToast } from "vue-toastification"
|
||||||
|
const toast = useToast();
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
Confirm,
|
Confirm,
|
||||||
HiddenInput,
|
HiddenInput,
|
||||||
|
Telegram,
|
||||||
},
|
},
|
||||||
props: {},
|
props: {},
|
||||||
data() {
|
data() {
|
||||||
|
@ -519,17 +489,7 @@ export default {
|
||||||
appriseInstalled: false,
|
appriseInstalled: false,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
|
||||||
telegramGetUpdatesURL() {
|
|
||||||
let token = "<YOUR BOT TOKEN HERE>"
|
|
||||||
|
|
||||||
if (this.notification.telegramBotToken) {
|
|
||||||
token = this.notification.telegramBotToken;
|
|
||||||
}
|
|
||||||
|
|
||||||
return `https://api.telegram.org/bot${token}/getUpdates`;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
watch: {
|
watch: {
|
||||||
"notification.type"(to, from) {
|
"notification.type"(to, from) {
|
||||||
let oldName;
|
let oldName;
|
||||||
|
@ -615,32 +575,6 @@ export default {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
async autoGetTelegramChatID() {
|
|
||||||
try {
|
|
||||||
let res = await axios.get(this.telegramGetUpdatesURL)
|
|
||||||
|
|
||||||
if (res.data.result.length >= 1) {
|
|
||||||
let update = res.data.result[res.data.result.length - 1]
|
|
||||||
|
|
||||||
if (update.channel_post) {
|
|
||||||
this.notification.telegramChatID = update.channel_post.chat.id;
|
|
||||||
} else if (update.message) {
|
|
||||||
this.notification.telegramChatID = update.message.chat.id;
|
|
||||||
} else {
|
|
||||||
throw new Error("Chat ID is not found, please send a message to this bot first")
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
throw new Error("Chat ID is not found, please send a message to this bot first")
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
toast.error(error.message)
|
|
||||||
}
|
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
98
src/components/notifications/Telegram.vue
Normal file
98
src/components/notifications/Telegram.vue
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
<template>
|
||||||
|
<template v-if="$parent.notification.type === name">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="telegram-bot-token" class="form-label">Bot Token</label>
|
||||||
|
<HiddenInput id="telegram-bot-token" v-model="$parent.notification.telegramBotToken" :required="true" autocomplete="one-time-code"></HiddenInput>
|
||||||
|
<div class="form-text">
|
||||||
|
You can get a token from <a href="https://t.me/BotFather" target="_blank">https://t.me/BotFather</a>.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="telegram-chat-id" class="form-label">Chat ID</label>
|
||||||
|
|
||||||
|
<div class="input-group mb-3">
|
||||||
|
<input id="telegram-chat-id" v-model="$parent.notification.telegramChatID" type="text" class="form-control" required>
|
||||||
|
<button v-if="$parent.notification.telegramBotToken" class="btn btn-outline-secondary" type="button" @click="autoGetTelegramChatID">
|
||||||
|
{{ $t("Auto Get") }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-text">
|
||||||
|
Support Direct Chat / Group / Channel's Chat ID
|
||||||
|
|
||||||
|
<p style="margin-top: 8px;">
|
||||||
|
You can get your chat id by sending message to the bot and go to this url to view the chat_id:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p style="margin-top: 8px;">
|
||||||
|
<template v-if="$parent.notification.telegramBotToken">
|
||||||
|
<a :href="telegramGetUpdatesURL" target="_blank" style="word-break: break-word;">{{ telegramGetUpdatesURL }}</a>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template v-else>
|
||||||
|
{{ telegramGetUpdatesURL }}
|
||||||
|
</template>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import HiddenInput from "../HiddenInput.vue";
|
||||||
|
import axios from "axios";
|
||||||
|
import { useToast } from "vue-toastification"
|
||||||
|
const toast = useToast();
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
HiddenInput,
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
name: "telegram",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
telegramGetUpdatesURL() {
|
||||||
|
let token = "<YOUR BOT TOKEN HERE>"
|
||||||
|
|
||||||
|
if (this.$parent.notification.telegramBotToken) {
|
||||||
|
token = this.$parent.notification.telegramBotToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
return `https://api.telegram.org/bot${token}/getUpdates`;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async autoGetTelegramChatID() {
|
||||||
|
try {
|
||||||
|
let res = await axios.get(this.telegramGetUpdatesURL)
|
||||||
|
|
||||||
|
if (res.data.result.length >= 1) {
|
||||||
|
let update = res.data.result[res.data.result.length - 1]
|
||||||
|
|
||||||
|
if (update.channel_post) {
|
||||||
|
this.notification.telegramChatID = update.channel_post.chat.id;
|
||||||
|
} else if (update.message) {
|
||||||
|
this.notification.telegramChatID = update.message.chat.id;
|
||||||
|
} else {
|
||||||
|
throw new Error("Chat ID is not found, please send a message to this bot first")
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
throw new Error("Chat ID is not found, please send a message to this bot first")
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
toast.error(error.message)
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -115,5 +115,6 @@ export default {
|
||||||
confirmClearStatisticsMsg: "Are you sure want to delete ALL statistics?",
|
confirmClearStatisticsMsg: "Are you sure want to delete ALL statistics?",
|
||||||
"Clear Data": "Clear Data",
|
"Clear Data": "Clear Data",
|
||||||
Events: "Events",
|
Events: "Events",
|
||||||
Heartbeats: "Heartbeats"
|
Heartbeats: "Heartbeats",
|
||||||
|
"Auto Get": "Auto Get"
|
||||||
}
|
}
|
||||||
|
|
|
@ -119,4 +119,5 @@ export default {
|
||||||
respTime: "Antw. Zeit (ms)",
|
respTime: "Antw. Zeit (ms)",
|
||||||
notAvailableShort: "N/A",
|
notAvailableShort: "N/A",
|
||||||
Create: "Erstellen",
|
Create: "Erstellen",
|
||||||
|
"Auto Get": "Auto Get"
|
||||||
}
|
}
|
||||||
|
|
|
@ -118,5 +118,6 @@ export default {
|
||||||
Create: "Create",
|
Create: "Create",
|
||||||
"Clear Data": "Clear Data",
|
"Clear Data": "Clear Data",
|
||||||
Events: "Events",
|
Events: "Events",
|
||||||
Heartbeats: "Heartbeats"
|
Heartbeats: "Heartbeats",
|
||||||
|
"Auto Get": "Auto Get"
|
||||||
}
|
}
|
||||||
|
|
|
@ -115,5 +115,6 @@ export default {
|
||||||
confirmClearStatisticsMsg: "Are you sure want to delete ALL statistics?",
|
confirmClearStatisticsMsg: "Are you sure want to delete ALL statistics?",
|
||||||
"Clear Data": "Clear Data",
|
"Clear Data": "Clear Data",
|
||||||
Events: "Events",
|
Events: "Events",
|
||||||
Heartbeats: "Heartbeats"
|
Heartbeats: "Heartbeats",
|
||||||
|
"Auto Get": "Auto Get"
|
||||||
}
|
}
|
||||||
|
|
|
@ -115,5 +115,6 @@ export default {
|
||||||
confirmClearStatisticsMsg: "Are you sure want to delete ALL statistics?",
|
confirmClearStatisticsMsg: "Are you sure want to delete ALL statistics?",
|
||||||
"Clear Data": "Clear Data",
|
"Clear Data": "Clear Data",
|
||||||
Events: "Events",
|
Events: "Events",
|
||||||
Heartbeats: "Heartbeats"
|
Heartbeats: "Heartbeats",
|
||||||
|
"Auto Get": "Auto Get"
|
||||||
}
|
}
|
||||||
|
|
|
@ -115,5 +115,6 @@ export default {
|
||||||
confirmClearStatisticsMsg: "Are you sure want to delete ALL statistics?",
|
confirmClearStatisticsMsg: "Are you sure want to delete ALL statistics?",
|
||||||
"Clear Data": "Clear Data",
|
"Clear Data": "Clear Data",
|
||||||
Events: "Events",
|
Events: "Events",
|
||||||
Heartbeats: "Heartbeats"
|
Heartbeats: "Heartbeats",
|
||||||
|
"Auto Get": "Auto Get"
|
||||||
}
|
}
|
||||||
|
|
|
@ -115,5 +115,6 @@ export default {
|
||||||
confirmClearStatisticsMsg: "Are you sure want to delete ALL statistics?",
|
confirmClearStatisticsMsg: "Are you sure want to delete ALL statistics?",
|
||||||
"Clear Data": "Clear Data",
|
"Clear Data": "Clear Data",
|
||||||
Events: "Events",
|
Events: "Events",
|
||||||
Heartbeats: "Heartbeats"
|
Heartbeats: "Heartbeats",
|
||||||
|
"Auto Get": "Auto Get"
|
||||||
}
|
}
|
||||||
|
|
|
@ -115,5 +115,6 @@ export default {
|
||||||
confirmClearStatisticsMsg: "Are you sure want to delete ALL statistics?",
|
confirmClearStatisticsMsg: "Are you sure want to delete ALL statistics?",
|
||||||
"Clear Data": "Clear Data",
|
"Clear Data": "Clear Data",
|
||||||
Events: "Events",
|
Events: "Events",
|
||||||
Heartbeats: "Heartbeats"
|
Heartbeats: "Heartbeats",
|
||||||
|
"Auto Get": "Auto Get"
|
||||||
}
|
}
|
||||||
|
|
|
@ -109,5 +109,12 @@ export default {
|
||||||
"Repeat Password": "Powtórz hasło",
|
"Repeat Password": "Powtórz hasło",
|
||||||
respTime: "Czas odp. (ms)",
|
respTime: "Czas odp. (ms)",
|
||||||
notAvailableShort: "N/A",
|
notAvailableShort: "N/A",
|
||||||
Create: "Stwórz"
|
Create: "Stwórz",
|
||||||
|
clearEventsMsg: "Are you sure want to delete all events for this monitor?",
|
||||||
|
clearHeartbeatsMsg: "Are you sure want to delete all heartbeats for this monitor?",
|
||||||
|
confirmClearStatisticsMsg: "Are you sure want to delete ALL statistics?",
|
||||||
|
"Clear Data": "Clear Data",
|
||||||
|
Events: "Events",
|
||||||
|
Heartbeats: "Heartbeats",
|
||||||
|
"Auto Get": "Auto Get"
|
||||||
}
|
}
|
||||||
|
|
|
@ -115,5 +115,6 @@ export default {
|
||||||
confirmClearStatisticsMsg: "Are you sure want to delete ALL statistics?",
|
confirmClearStatisticsMsg: "Are you sure want to delete ALL statistics?",
|
||||||
"Clear Data": "Clear Data",
|
"Clear Data": "Clear Data",
|
||||||
Events: "Events",
|
Events: "Events",
|
||||||
Heartbeats: "Heartbeats"
|
Heartbeats: "Heartbeats",
|
||||||
|
"Auto Get": "Auto Get"
|
||||||
}
|
}
|
||||||
|
|
|
@ -115,5 +115,6 @@ export default {
|
||||||
confirmClearStatisticsMsg: "Are you sure want to delete ALL statistics?",
|
confirmClearStatisticsMsg: "Are you sure want to delete ALL statistics?",
|
||||||
"Clear Data": "Clear Data",
|
"Clear Data": "Clear Data",
|
||||||
Events: "Events",
|
Events: "Events",
|
||||||
Heartbeats: "Heartbeats"
|
Heartbeats: "Heartbeats",
|
||||||
|
"Auto Get": "Auto Get"
|
||||||
}
|
}
|
||||||
|
|
|
@ -115,5 +115,6 @@ export default {
|
||||||
confirmClearStatisticsMsg: "Are you sure want to delete ALL statistics?",
|
confirmClearStatisticsMsg: "Are you sure want to delete ALL statistics?",
|
||||||
"Clear Data": "Clear Data",
|
"Clear Data": "Clear Data",
|
||||||
Events: "Events",
|
Events: "Events",
|
||||||
Heartbeats: "Heartbeats"
|
Heartbeats: "Heartbeats",
|
||||||
|
"Auto Get": "Auto Get"
|
||||||
}
|
}
|
||||||
|
|
|
@ -115,5 +115,6 @@ export default {
|
||||||
confirmClearStatisticsMsg: "Are you sure want to delete ALL statistics?",
|
confirmClearStatisticsMsg: "Are you sure want to delete ALL statistics?",
|
||||||
"Clear Data": "Clear Data",
|
"Clear Data": "Clear Data",
|
||||||
Events: "Events",
|
Events: "Events",
|
||||||
Heartbeats: "Heartbeats"
|
Heartbeats: "Heartbeats",
|
||||||
|
"Auto Get": "Auto Get"
|
||||||
}
|
}
|
||||||
|
|
|
@ -115,5 +115,6 @@ export default {
|
||||||
confirmClearStatisticsMsg: "Are you sure want to delete ALL statistics?",
|
confirmClearStatisticsMsg: "Are you sure want to delete ALL statistics?",
|
||||||
"Clear Data": "Clear Data",
|
"Clear Data": "Clear Data",
|
||||||
Events: "Events",
|
Events: "Events",
|
||||||
Heartbeats: "Heartbeats"
|
Heartbeats: "Heartbeats",
|
||||||
|
"Auto Get": "Auto Get"
|
||||||
}
|
}
|
||||||
|
|
|
@ -115,5 +115,6 @@ export default {
|
||||||
confirmClearStatisticsMsg: "是否確定刪除所有監測器的脈搏資料?(您的監測器會繼續正常運作)",
|
confirmClearStatisticsMsg: "是否確定刪除所有監測器的脈搏資料?(您的監測器會繼續正常運作)",
|
||||||
"Clear Data": "清除資料",
|
"Clear Data": "清除資料",
|
||||||
Events: "事件",
|
Events: "事件",
|
||||||
Heartbeats: "脈搏"
|
Heartbeats: "脈搏",
|
||||||
|
"Auto Get": "自動獲取"
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,7 +85,12 @@ export default {
|
||||||
this.$root.toastRes(res)
|
this.$root.toastRes(res)
|
||||||
|
|
||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
|
this.processing = true;
|
||||||
|
|
||||||
|
this.$root.login(this.username, this.password, (res) => {
|
||||||
|
this.processing = false;
|
||||||
this.$router.push("/")
|
this.$router.push("/")
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in a new issue