mirror of
https://github.com/louislam/uptime-kuma.git
synced 2024-12-22 05:55:16 -05:00
Merge branch 'master' into simple_pagination
This commit is contained in:
commit
16f363ac38
@ -3,3 +3,11 @@
|
||||
/node_modules
|
||||
/data/kuma.db
|
||||
/.do
|
||||
**/.dockerignore
|
||||
**/.git
|
||||
**/.gitignore
|
||||
**/docker-compose*
|
||||
**/Dockerfile*
|
||||
LICENSE
|
||||
README.md
|
||||
.editorconfig
|
||||
|
@ -17,11 +17,14 @@ RUN apk add --no-cache --virtual .build-deps make g++ python3 python3-dev && \
|
||||
# Compilation Fail 3 => Google Search "alpine opensslv.h" => Add openssl-dev
|
||||
# Compilation Fail 4 => Google Search "alpine opensslv.h" again => Change to libressl-dev musl-dev
|
||||
# Compilation Fail 5 => Google Search "ERROR: libressl3.3-libtls-3.3.3-r0: trying to overwrite usr/lib/libtls.so.20 owned by libretls-3.3.3-r0." again => Change back to openssl-dev with musl-dev
|
||||
# Runtime Error => ModuleNotFoundError: No module named 'six' => pip3 install six
|
||||
# Runtime Error 2 => ModuleNotFoundError: No module named 'six' => apk add py3-six
|
||||
ENV CRYPTOGRAPHY_DONT_BUILD_RUST=1
|
||||
RUN apk add --no-cache python3
|
||||
RUN apk add --no-cache --virtual .build-deps libffi-dev musl-dev openssl-dev cargo py3-pip python3-dev && \
|
||||
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 python3-dev && \
|
||||
pip3 install apprise && \
|
||||
apk del .build-deps
|
||||
RUN apprise --version
|
||||
|
||||
# New things add here
|
||||
|
||||
@ -31,7 +34,7 @@ RUN npm run build
|
||||
|
||||
EXPOSE 3001
|
||||
VOLUME ["/app/data"]
|
||||
HEALTHCHECK --interval=5s --timeout=3s --start-period=30s CMD node extra/healthcheck.js
|
||||
HEALTHCHECK --interval=60s --timeout=30s --start-period=300s CMD node extra/healthcheck.js
|
||||
CMD ["npm", "run", "start-server"]
|
||||
|
||||
FROM release AS nightly
|
||||
|
7
package-lock.json
generated
7
package-lock.json
generated
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "uptime-kuma",
|
||||
"version": "1.0.4",
|
||||
"version": "1.0.5",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
@ -655,6 +655,11 @@
|
||||
"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": {
|
||||
"version": "6.2.1",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz",
|
||||
|
@ -1,6 +1,11 @@
|
||||
{
|
||||
"name": "uptime-kuma",
|
||||
"version": "1.0.5",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/louislam/uptime-kuma.git"
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "vite --host",
|
||||
"start-server": "node server/server.js",
|
||||
@ -19,6 +24,7 @@
|
||||
"axios": "^0.21.1",
|
||||
"bcrypt": "^5.0.1",
|
||||
"bootstrap": "^5.0.0",
|
||||
"command-exists": "^1.2.9",
|
||||
"dayjs": "^1.10.4",
|
||||
"express": "^4.17.1",
|
||||
"form-data": "^4.0.0",
|
||||
|
@ -2,9 +2,16 @@ const axios = require("axios");
|
||||
const {R} = require("redbean-node");
|
||||
const FormData = require('form-data');
|
||||
const nodemailer = require("nodemailer");
|
||||
const child_process = require("child_process");
|
||||
|
||||
class Notification {
|
||||
static async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
||||
|
||||
let res = {
|
||||
ok: true,
|
||||
msg: "Sent Successfully"
|
||||
}
|
||||
|
||||
if (notification.type === "telegram") {
|
||||
try {
|
||||
await axios.get(`https://api.telegram.org/bot${notification.telegramBotToken}/sendMessage`, {
|
||||
@ -210,6 +217,10 @@ class Notification {
|
||||
return false;
|
||||
}
|
||||
|
||||
} else if (notification.type === "apprise") {
|
||||
|
||||
return Notification.apprise(notification, msg)
|
||||
|
||||
} else {
|
||||
throw new Error("Notification type is not supported")
|
||||
}
|
||||
@ -274,16 +285,26 @@ class Notification {
|
||||
return true;
|
||||
}
|
||||
|
||||
static async discord(notification, msg) {
|
||||
const client = new Discord.Client();
|
||||
await client.login(notification.discordToken)
|
||||
static async apprise(notification, msg) {
|
||||
let s = child_process.spawnSync("apprise", [ "-vv", "-b", msg, notification.appriseURL])
|
||||
let output = s.stdout.toString();
|
||||
|
||||
const channel = await client.channels.fetch(notification.discordChannelID);
|
||||
await channel.send(msg);
|
||||
console.log(output)
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -35,12 +35,15 @@ let needSetup = false;
|
||||
(async () => {
|
||||
await initDatabase();
|
||||
|
||||
console.log("Adding route")
|
||||
app.use('/', express.static("dist"));
|
||||
|
||||
app.get('*', function(request, response, next) {
|
||||
response.sendFile(process.cwd() + '/dist/index.html');
|
||||
});
|
||||
|
||||
|
||||
console.log("Adding socket handler")
|
||||
io.on('connection', async (socket) => {
|
||||
|
||||
socket.emit("info", {
|
||||
@ -437,12 +440,9 @@ let needSetup = false;
|
||||
try {
|
||||
checkLogin(socket)
|
||||
|
||||
await Notification.send(notification, notification.name + " Testing")
|
||||
let res = await Notification.send(notification, notification.name + " Testing")
|
||||
|
||||
callback({
|
||||
ok: true,
|
||||
msg: "Sent Successfully"
|
||||
});
|
||||
callback(res);
|
||||
|
||||
} catch (e) {
|
||||
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, () => {
|
||||
console.log(`Listening on ${hostname}:${port}`);
|
||||
|
||||
startMonitors();
|
||||
});
|
||||
|
||||
@ -551,10 +560,11 @@ async function initDatabase() {
|
||||
}
|
||||
|
||||
console.log("Connecting to Database")
|
||||
|
||||
R.setup('sqlite', {
|
||||
filename: path
|
||||
});
|
||||
console.log("Connected")
|
||||
|
||||
R.freeze(true)
|
||||
await R.autoloadModels("./server/model");
|
||||
|
||||
@ -569,6 +579,7 @@ async function initDatabase() {
|
||||
|
||||
jwtSecretBean.value = passwordHash.generate(dayjs() + "")
|
||||
await R.store(jwtSecretBean)
|
||||
console.log("Stored JWT secret into database")
|
||||
} else {
|
||||
console.log("Load JWT secret from database.")
|
||||
}
|
||||
|
@ -15,14 +15,14 @@
|
||||
<label for="floatingPassword">Password</label>
|
||||
</div>
|
||||
|
||||
<div class="form-check mb-3 mt-3" >
|
||||
<label>
|
||||
<div class="form-check mb-3 mt-3 d-flex justify-content-center pe-4">
|
||||
<div class="form-check">
|
||||
<input type="checkbox" value="remember-me" class="form-check-input" id="remember" v-model="$root.remember">
|
||||
|
||||
<label class="form-check-label" for="remember">
|
||||
Remember me
|
||||
</label>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<button class="w-100 btn btn-primary" type="submit" :disabled="processing">Login</button>
|
||||
|
||||
|
@ -10,60 +10,61 @@
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="type" class="form-label">Notification Type</label>
|
||||
<select class="form-select" id="type" v-model="notification.type">
|
||||
<option value="telegram">Telegram</option>
|
||||
<option value="webhook">Webhook</option>
|
||||
<option value="smtp">Email (SMTP)</option>
|
||||
<option value="discord">Discord</option>
|
||||
<option value="signal">Signal</option>
|
||||
<option value="gotify">Gotify</option>
|
||||
<option value="slack">Slack</option>
|
||||
<option value="pushover">Pushover</option>
|
||||
<option value="apprise">Apprise (Support 50+ Notification services)</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="name" class="form-label">Friendly Name</label>
|
||||
<input type="text" class="form-control" id="name" required v-model="notification.name">
|
||||
</div>
|
||||
|
||||
<template v-if="notification.type === 'telegram'">
|
||||
<div class="mb-3">
|
||||
<label for="type" class="form-label">Notification Type</label>
|
||||
<select class="form-select" id="type" v-model="notification.type">
|
||||
<option value="telegram">Telegram</option>
|
||||
<option value="webhook">Webhook</option>
|
||||
<option value="smtp">Email (SMTP)</option>
|
||||
<option value="discord">Discord</option>
|
||||
<option value="signal">Signal</option>
|
||||
<option value="gotify">Gotify</option>
|
||||
<option value="slack">Slack</option>
|
||||
<option value="pushover">Pushover</option>
|
||||
</select>
|
||||
<label for="telegram-bot-token" class="form-label">Bot Token</label>
|
||||
<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="name" class="form-label">Friendly Name</label>
|
||||
<input type="text" class="form-control" id="name" required v-model="notification.name">
|
||||
<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 v-if="notification.type === 'telegram'">
|
||||
<div class="mb-3">
|
||||
<label for="telegram-bot-token" class="form-label">Bot Token</label>
|
||||
<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>
|
||||
|
||||
<template v-if="notification.type === 'webhook'">
|
||||
<div class="mb-3">
|
||||
@ -269,6 +270,29 @@
|
||||
</div>
|
||||
</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 class="modal-footer">
|
||||
<button type="button" class="btn btn-danger" @click="deleteConfirm" :disabled="processing" v-if="id">Delete</button>
|
||||
@ -307,17 +331,15 @@ export default {
|
||||
type: null,
|
||||
gotifyPriority: 8
|
||||
},
|
||||
appriseInstalled: false,
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.modal = new Modal(this.$refs.modal)
|
||||
|
||||
// TODO: for edit
|
||||
this.$root.getSocket().emit("getSettings", "notification", (data) => {
|
||||
// this.notification = data
|
||||
this.$root.getSocket().emit("checkApprise", (installed) => {
|
||||
this.appriseInstalled = installed;
|
||||
})
|
||||
|
||||
|
||||
},
|
||||
methods: {
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user