mirror of
https://github.com/louislam/uptime-kuma.git
synced 2024-12-24 06:49:41 -05:00
implement webhook
This commit is contained in:
parent
d24a15410e
commit
0ad04d1468
27
package-lock.json
generated
27
package-lock.json
generated
@ -278,8 +278,7 @@
|
|||||||
"asynckit": {
|
"asynckit": {
|
||||||
"version": "0.4.0",
|
"version": "0.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||||
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=",
|
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"atob": {
|
"atob": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
@ -575,7 +574,6 @@
|
|||||||
"version": "1.0.8",
|
"version": "1.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||||
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"delayed-stream": "~1.0.0"
|
"delayed-stream": "~1.0.0"
|
||||||
}
|
}
|
||||||
@ -740,8 +738,7 @@
|
|||||||
"delayed-stream": {
|
"delayed-stream": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||||
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
|
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"delegates": {
|
"delegates": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
@ -1170,13 +1167,12 @@
|
|||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"form-data": {
|
"form-data": {
|
||||||
"version": "2.3.3",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
|
||||||
"integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
|
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"asynckit": "^0.4.0",
|
"asynckit": "^0.4.0",
|
||||||
"combined-stream": "^1.0.6",
|
"combined-stream": "^1.0.8",
|
||||||
"mime-types": "^2.1.12"
|
"mime-types": "^2.1.12"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -2760,6 +2756,17 @@
|
|||||||
"uuid": "^3.3.2"
|
"uuid": "^3.3.2"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"form-data": {
|
||||||
|
"version": "2.3.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
|
||||||
|
"integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
|
||||||
|
"optional": true,
|
||||||
|
"requires": {
|
||||||
|
"asynckit": "^0.4.0",
|
||||||
|
"combined-stream": "^1.0.6",
|
||||||
|
"mime-types": "^2.1.12"
|
||||||
|
}
|
||||||
|
},
|
||||||
"qs": {
|
"qs": {
|
||||||
"version": "6.5.2",
|
"version": "6.5.2",
|
||||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
|
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
"bootstrap": "^5.0.0",
|
"bootstrap": "^5.0.0",
|
||||||
"dayjs": "^1.10.4",
|
"dayjs": "^1.10.4",
|
||||||
"express": "^4.17.1",
|
"express": "^4.17.1",
|
||||||
|
"form-data": "^4.0.0",
|
||||||
"jsonwebtoken": "^8.5.1",
|
"jsonwebtoken": "^8.5.1",
|
||||||
"password-hash": "^1.2.2",
|
"password-hash": "^1.2.2",
|
||||||
"redbean-node": "0.0.20",
|
"redbean-node": "0.0.20",
|
||||||
|
@ -109,7 +109,7 @@ class Monitor extends BeanModel {
|
|||||||
if (! previousBeat || previousBeat.status !== bean.status) {
|
if (! previousBeat || previousBeat.status !== bean.status) {
|
||||||
bean.important = true;
|
bean.important = true;
|
||||||
|
|
||||||
let notificationList = await R.getAll(`SELECT notification.* FROM notification, monitor_notification WHERE monitor_id = ? `, [
|
let notificationList = await R.getAll(`SELECT notification.* FROM notification, monitor_notification WHERE monitor_id = ? AND monitor_notification.notification_id = notification.id `, [
|
||||||
this.id
|
this.id
|
||||||
])
|
])
|
||||||
|
|
||||||
@ -125,7 +125,7 @@ class Monitor extends BeanModel {
|
|||||||
let msg = `[${this.name}] [${text}] ${bean.msg}`;
|
let msg = `[${this.name}] [${text}] ${bean.msg}`;
|
||||||
|
|
||||||
for(let notification of notificationList) {
|
for(let notification of notificationList) {
|
||||||
promiseList.push(Notification.send(JSON.parse(notification.config), msg));
|
promiseList.push(Notification.send(JSON.parse(notification.config), msg, await this.toJSON(), bean.toJSON()));
|
||||||
}
|
}
|
||||||
|
|
||||||
await Promise.all(promiseList);
|
await Promise.all(promiseList);
|
||||||
|
@ -1,16 +1,56 @@
|
|||||||
const axios = require("axios");
|
const axios = require("axios");
|
||||||
const {R} = require("redbean-node");
|
const {R} = require("redbean-node");
|
||||||
|
const FormData = require('form-data');
|
||||||
|
|
||||||
class Notification {
|
class Notification {
|
||||||
static async send(notification, msg) {
|
static async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
||||||
if (notification.type === "telegram") {
|
if (notification.type === "telegram") {
|
||||||
let res = await axios.get(`https://api.telegram.org/bot${notification.telegramBotToken}/sendMessage`, {
|
try {
|
||||||
params: {
|
await axios.get(`https://api.telegram.org/bot${notification.telegramBotToken}/sendMessage`, {
|
||||||
chat_id: notification.telegramChatID,
|
params: {
|
||||||
text: msg,
|
chat_id: notification.telegramChatID,
|
||||||
|
text: msg,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} 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 {
|
||||||
|
finalData = data;
|
||||||
}
|
}
|
||||||
})
|
|
||||||
return true;
|
let res = await axios.post(notification.webhookURL, finalData, config)
|
||||||
|
|
||||||
|
console.log(res.data)
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
throw new Error("Notification type is not supported")
|
throw new Error("Notification type is not supported")
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,8 @@ const Monitor = require("./model/monitor");
|
|||||||
const {getSettings} = require("./util-server");
|
const {getSettings} = require("./util-server");
|
||||||
const {Notification} = require("./notification")
|
const {Notification} = require("./notification")
|
||||||
|
|
||||||
|
app.use(express.json())
|
||||||
|
|
||||||
let totalClient = 0;
|
let totalClient = 0;
|
||||||
let jwtSecret = null;
|
let jwtSecret = null;
|
||||||
let monitorList = {};
|
let monitorList = {};
|
||||||
@ -27,6 +29,13 @@ let monitorList = {};
|
|||||||
|
|
||||||
app.use('/', express.static("dist"));
|
app.use('/', express.static("dist"));
|
||||||
|
|
||||||
|
app.post('/test-webhook', function(request, response, next) {
|
||||||
|
console.log("Test Webhook (application/json only)")
|
||||||
|
console.log("Content-Type: " + request.header("Content-Type"))
|
||||||
|
console.log(request.body)
|
||||||
|
response.end();
|
||||||
|
});
|
||||||
|
|
||||||
app.get('*', function(request, response, next) {
|
app.get('*', function(request, response, next) {
|
||||||
response.sendFile(process.cwd() + '/dist/index.html');
|
response.sendFile(process.cwd() + '/dist/index.html');
|
||||||
});
|
});
|
||||||
|
@ -10,7 +10,6 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
|
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="type" class="form-label">Notification Type</label>
|
<label for="type" class="form-label">Notification Type</label>
|
||||||
<select class="form-select" id="type" v-model="notification.type">
|
<select class="form-select" id="type" v-model="notification.type">
|
||||||
@ -26,39 +25,62 @@
|
|||||||
<input type="text" class="form-control" id="name" required v-model="notification.name">
|
<input type="text" class="form-control" id="name" required v-model="notification.name">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-3" v-if="notification.type === 'telegram'">
|
<template v-if="notification.type === 'telegram'">
|
||||||
<label for="telegram-bot-token" class="form-label">Bot Token</label>
|
<div class="mb-3">
|
||||||
<input type="text" class="form-control" id="telegram-bot-token" required v-model="notification.telegramBotToken">
|
<label for="telegram-bot-token" class="form-label">Bot Token</label>
|
||||||
<div class="form-text">You can get a token from <a href="https://t.me/BotFather" target="_blank">https://t.me/BotFather</a>.</div>
|
<input type="text" class="form-control" id="telegram-bot-token" required v-model="notification.telegramBotToken">
|
||||||
|
<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 type="text" class="form-control" id="telegram-chat-id" required v-model="notification.telegramChatID">
|
||||||
|
<button class="btn btn-outline-secondary" type="button" @click="autoGetTelegramChatID" v-if="notification.telegramBotToken">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">{{ telegramGetUpdatesURL }}</a>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template v-else>
|
||||||
|
{{ telegramGetUpdatesURL }}
|
||||||
|
</template>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template v-if="notification.type === 'webhook'">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="webhook-url" class="form-label">Post URL</label>
|
||||||
|
<input type="url" pattern="https?://.+" class="form-control" id="webhook-url" required v-model="notification.webhookURL">
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-3" v-if="notification.type === 'telegram'">
|
<div class="mb-3">
|
||||||
<label for="telegram-chat-id" class="form-label">Chat ID</label>
|
<label for="webhook-content-type" class="form-label">Content Type</label>
|
||||||
|
<select class="form-select" id="webhook-content-type" v-model="notification.webhookContentType" required>
|
||||||
<div class="input-group mb-3">
|
<option value="json">application/json</option>
|
||||||
<input type="text" class="form-control" id="telegram-chat-id" required v-model="notification.telegramChatID">
|
<option value="form-data">multipart/form-data</option>
|
||||||
<button class="btn btn-outline-secondary" type="button" @click="autoGetTelegramChatID" v-if="notification.telegramBotToken">Auto Get</button>
|
</select>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-text">
|
<div class="form-text">
|
||||||
Support Direct Chat / Group / Channel's Chat ID
|
<p>"application/json" is good for any modern http servers such as express.js</p>
|
||||||
|
<p>"multipart/form-data" is good for PHP, you just need to parse the json by <strong>json_decode($_POST['data'])</strong></p>
|
||||||
<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">{{ telegramGetUpdatesURL }}</a>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template v-else>
|
|
||||||
{{ telegramGetUpdatesURL }}
|
|
||||||
</template>
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
Reference in New Issue
Block a user