add apprise support

This commit is contained in:
LouisLam 2021-07-18 18:51:58 +08:00
parent 13c9244e3f
commit 66037e236c
6 changed files with 133 additions and 74 deletions

View file

@ -20,11 +20,10 @@ RUN apk add --no-cache --virtual .build-deps make g++ python3 python3-dev && \
# Runtime Error => ModuleNotFoundError: No module named 'six' => pip3 install six # Runtime Error => ModuleNotFoundError: No module named 'six' => pip3 install six
# Runtime Error 2 => ModuleNotFoundError: No module named 'six' => apk add py3-six # Runtime Error 2 => ModuleNotFoundError: No module named 'six' => apk add py3-six
ENV CRYPTOGRAPHY_DONT_BUILD_RUST=1 ENV CRYPTOGRAPHY_DONT_BUILD_RUST=1
RUN apk add --no-cache python3 RUN apk add --no-cache python3 py3-pip py3-six cargo
RUN apk add --no-cache --virtual .build-deps libffi-dev musl-dev openssl-dev cargo py3-pip python3-dev && \ RUN apk add --no-cache --virtual .build-deps libffi-dev musl-dev openssl-dev python3-dev && \
pip3 install apprise && \ pip3 install apprise && \
apk del .build-deps apk del .build-deps
RUN apk add --no-cache py3-six
RUN apprise --version RUN apprise --version
# New things add here # New things add here

7
package-lock.json generated
View file

@ -1,6 +1,6 @@
{ {
"name": "uptime-kuma", "name": "uptime-kuma",
"version": "1.0.4", "version": "1.0.5",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {
@ -655,6 +655,11 @@
"delayed-stream": "~1.0.0" "delayed-stream": "~1.0.0"
} }
}, },
"command-exists": {
"version": "1.2.9",
"resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.9.tgz",
"integrity": "sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w=="
},
"commander": { "commander": {
"version": "6.2.1", "version": "6.2.1",
"resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz",

View file

@ -19,6 +19,7 @@
"axios": "^0.21.1", "axios": "^0.21.1",
"bcrypt": "^5.0.1", "bcrypt": "^5.0.1",
"bootstrap": "^5.0.0", "bootstrap": "^5.0.0",
"command-exists": "^1.2.9",
"dayjs": "^1.10.4", "dayjs": "^1.10.4",
"express": "^4.17.1", "express": "^4.17.1",
"form-data": "^4.0.0", "form-data": "^4.0.0",

View file

@ -2,9 +2,16 @@ const axios = require("axios");
const {R} = require("redbean-node"); const {R} = require("redbean-node");
const FormData = require('form-data'); const FormData = require('form-data');
const nodemailer = require("nodemailer"); const nodemailer = require("nodemailer");
const child_process = require("child_process");
class Notification { class Notification {
static async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { static async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let res = {
ok: true,
msg: "Sent Successfully"
}
if (notification.type === "telegram") { if (notification.type === "telegram") {
try { try {
await axios.get(`https://api.telegram.org/bot${notification.telegramBotToken}/sendMessage`, { await axios.get(`https://api.telegram.org/bot${notification.telegramBotToken}/sendMessage`, {
@ -210,6 +217,10 @@ class Notification {
return false; return false;
} }
} else if (notification.type === "apprise") {
return Notification.apprise(notification, msg)
} else { } else {
throw new Error("Notification type is not supported") throw new Error("Notification type is not supported")
} }
@ -274,16 +285,26 @@ class Notification {
return true; return true;
} }
static async discord(notification, msg) { static async apprise(notification, msg) {
const client = new Discord.Client(); let s = child_process.spawnSync("apprise", [ "-vv", "-b", msg, notification.appriseURL])
await client.login(notification.discordToken) let output = s.stdout.toString();
const channel = await client.channels.fetch(notification.discordChannelID); console.log(output)
await channel.send(msg);
client.destroy() if (output) {
return {
ok: ! output.includes("ERROR"),
msg: output
}
} else {
return { }
}
}
return true; static checkApprise() {
let commandExistsSync = require('command-exists').sync;
let exists = commandExistsSync('apprise');
return exists;
} }
} }

View file

@ -35,12 +35,15 @@ let needSetup = false;
(async () => { (async () => {
await initDatabase(); await initDatabase();
console.log("Adding route")
app.use('/', express.static("dist")); app.use('/', express.static("dist"));
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');
}); });
console.log("Adding socket handler")
io.on('connection', async (socket) => { io.on('connection', async (socket) => {
socket.emit("info", { socket.emit("info", {
@ -437,12 +440,9 @@ let needSetup = false;
try { try {
checkLogin(socket) checkLogin(socket)
await Notification.send(notification, notification.name + " Testing") let res = await Notification.send(notification, notification.name + " Testing")
callback({ callback(res);
ok: true,
msg: "Sent Successfully"
});
} catch (e) { } catch (e) {
callback({ callback({
@ -451,11 +451,20 @@ let needSetup = false;
}); });
} }
}); });
socket.on("checkApprise", async (callback) => {
try {
checkLogin(socket)
callback(Notification.checkApprise());
} catch (e) {
callback(false);
}
});
}); });
console.log("Init")
server.listen(port, hostname, () => { server.listen(port, hostname, () => {
console.log(`Listening on ${hostname}:${port}`); console.log(`Listening on ${hostname}:${port}`);
startMonitors(); startMonitors();
}); });
@ -551,10 +560,11 @@ async function initDatabase() {
} }
console.log("Connecting to Database") console.log("Connecting to Database")
R.setup('sqlite', { R.setup('sqlite', {
filename: path filename: path
}); });
console.log("Connected")
R.freeze(true) R.freeze(true)
await R.autoloadModels("./server/model"); await R.autoloadModels("./server/model");
@ -569,6 +579,7 @@ async function initDatabase() {
jwtSecretBean.value = passwordHash.generate(dayjs() + "") jwtSecretBean.value = passwordHash.generate(dayjs() + "")
await R.store(jwtSecretBean) await R.store(jwtSecretBean)
console.log("Stored JWT secret into database")
} else { } else {
console.log("Load JWT secret from database.") console.log("Load JWT secret from database.")
} }

View file

@ -21,6 +21,7 @@
<option value="gotify">Gotify</option> <option value="gotify">Gotify</option>
<option value="slack">Slack</option> <option value="slack">Slack</option>
<option value="pushover">Pushover</option> <option value="pushover">Pushover</option>
<option value="apprise">Apprise (Support 50+ Notification services)</option>
</select> </select>
</div> </div>
@ -269,6 +270,29 @@
</div> </div>
</template> </template>
<template v-if="notification.type === 'apprise'">
<div class="mb-3">
<label for="gotify-application-token" class="form-label">Apprise URL</label>
<input type="text" class="form-control" id="gotify-application-token" required v-model="notification.appriseURL">
<div class="form-text">
<p>Example: twilio://AccountSid:AuthToken@FromPhoneNo</p>
<p>
Read more: <a href="https://github.com/caronc/apprise/wiki#notification-services" target="_blank">https://github.com/caronc/apprise/wiki#notification-services</a>
</p>
</div>
</div>
<div class="mb-3">
<p>
Status:
<span class="text-primary" v-if="appriseInstalled">Apprise is installed</span>
<span class="text-danger" v-else>Apprise is not installed. <a href="https://github.com/caronc/apprise">Read more</a></span>
</p>
</div>
</template>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button type="button" class="btn btn-danger" @click="deleteConfirm" :disabled="processing" v-if="id">Delete</button> <button type="button" class="btn btn-danger" @click="deleteConfirm" :disabled="processing" v-if="id">Delete</button>
@ -307,17 +331,15 @@ export default {
type: null, type: null,
gotifyPriority: 8 gotifyPriority: 8
}, },
appriseInstalled: false,
} }
}, },
mounted() { mounted() {
this.modal = new Modal(this.$refs.modal) this.modal = new Modal(this.$refs.modal)
// TODO: for edit this.$root.getSocket().emit("checkApprise", (installed) => {
this.$root.getSocket().emit("getSettings", "notification", (data) => { this.appriseInstalled = installed;
// this.notification = data
}) })
}, },
methods: { methods: {