diff --git a/.editorconfig b/.editorconfig index af09f8cd0..a882f5c2d 100644 --- a/.editorconfig +++ b/.editorconfig @@ -13,3 +13,6 @@ trim_trailing_whitespace = false [*.yaml] indent_size = 2 + +[*.yml] +indent_size = 2 diff --git a/db/kuma.db b/db/kuma.db index 9eeb517ea..07c93cf89 100644 Binary files a/db/kuma.db and b/db/kuma.db differ diff --git a/public/icon.png b/public/icon.png new file mode 100644 index 000000000..4ff5fdc6a Binary files /dev/null and b/public/icon.png differ diff --git a/server/notification.js b/server/notification.js index b6b7b7acd..c60160a8a 100644 --- a/server/notification.js +++ b/server/notification.js @@ -1,5 +1,5 @@ const axios = require("axios"); -const { R } = require("redbean-node"); +const {R} = require("redbean-node"); const FormData = require('form-data'); const nodemailer = require("nodemailer"); @@ -52,62 +52,64 @@ class Notification { } else if (notification.type === "smtp") { return await Notification.smtp(notification, msg) - } else if (notification.type === "signal") { - try { - let data = { - "message": msg, - "number": notification.signalNumber, - "recipients": notification.signalRecipients.replace(/\s/g, '').split(",") - }; - let config = {}; - - let res = await axios.post(notification.signalURL, data, config) - return true; - } catch (error) { - console.log(error) - return false; - } - } else if (notification.type === "discord") { try { - // If heartbeatJSON is null, assume we're testing. - if (heartbeatJSON == null) { - let data = { - username: 'Uptime-Kuma', - content: msg - } - let res = await axios.post(notification.discordWebhookUrl, data) - return true; - } - // If heartbeatJSON is not null, we go into the normal alerting loop. - if (heartbeatJSON['status'] == 0) { - var alertColor = "16711680"; - } else if (heartbeatJSON['status'] == 1) { - var alertColor = "65280"; - } + // If heartbeatJSON is null, assume we're testing. + if(heartbeatJSON == null) { let data = { - username: 'Uptime-Kuma', - embeds: [{ - title: "Uptime-Kuma Alert", - color: alertColor, - fields: [ - { - name: "Time (UTC)", - value: heartbeatJSON["time"] - }, - { - name: "Message", - value: msg - } - ] - }] + username: 'Uptime-Kuma', + content: msg } let res = await axios.post(notification.discordWebhookUrl, data) return true; - } catch (error) { - console.log(error) - return false; + } + // If heartbeatJSON is not null, we go into the normal alerting loop. + if(heartbeatJSON['status'] == 0) { + var alertColor = "16711680"; + } else if(heartbeatJSON['status'] == 1) { + var alertColor = "65280"; + } + let data = { + username: 'Uptime-Kuma', + embeds: [{ + title: "Uptime-Kuma Alert", + color: alertColor, + fields: [ + { + name: "Time (UTC)", + value: heartbeatJSON["time"] + }, + { + name: "Message", + value: msg + } + ] + }] + } + let res = await axios.post(notification.discordWebhookUrl, data) + return true; + } catch(error) { + console.log(error) + return false; } + return await Notification.discord(notification, msg) + + } else if (notification.type === "signal") { + try { + let data = { + "message": msg, + "number": notification.signalNumber, + "recipients": notification.signalRecipients.replace(/\s/g, '').split(",") + }; + let config = {}; + + let res = await axios.post(notification.signalURL, data, config) + return true; + } catch (error) { + console.log(error) + return false; + } + } else { throw new Error("Notification type is not supported") } @@ -122,7 +124,7 @@ class Notification { userID, ]) - if (!bean) { + if (! bean) { throw new Error("notification not found") } @@ -142,7 +144,7 @@ class Notification { userID, ]) - if (!bean) { + if (! bean) { throw new Error("notification not found") } @@ -171,6 +173,18 @@ class Notification { return true; } + + static async discord(notification, msg) { + const client = new Discord.Client(); + await client.login(notification.discordToken) + + const channel = await client.channels.fetch(notification.discordChannelID); + await channel.send(msg); + + client.destroy() + + return true; + } } module.exports = { diff --git a/server/server.js b/server/server.js index 66f6b4a8e..c335b25f2 100644 --- a/server/server.js +++ b/server/server.js @@ -5,20 +5,18 @@ const server = http.createServer(app); const { Server } = require("socket.io"); const io = new Server(server); const dayjs = require("dayjs"); -const { R } = require("redbean-node"); +const {R} = require("redbean-node"); const passwordHash = require('password-hash'); const jwt = require('jsonwebtoken'); const Monitor = require("./model/monitor"); const fs = require("fs"); -const { getSettings } = require("./util-server"); -const { Notification } = require("./notification") +const {getSettings} = require("./util-server"); +const {Notification} = require("./notification") const args = require('args-parser')(process.argv); -console.log("args:") -console.log(args) - +const version = require('../package.json').version; const hostname = args.host || "0.0.0.0" -const port = args.port || 50013 +const port = args.port || 3001 app.use(express.json()) @@ -32,18 +30,16 @@ let needSetup = false; 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'); }); io.on('connection', async (socket) => { + + socket.emit("info", { + version, + }) + console.log('a user connected'); totalClient++; @@ -194,7 +190,7 @@ let needSetup = false; try { checkLogin(socket) - let bean = await R.findOne("monitor", " id = ? ", [monitor.id]) + let bean = await R.findOne("monitor", " id = ? ", [ monitor.id ]) if (bean.user_id !== socket.userID) { throw new Error("Permission denied.") @@ -332,7 +328,7 @@ let needSetup = false; try { checkLogin(socket) - if (!password.currentPassword) { + if (! password.currentPassword) { throw new Error("Invalid new password") } @@ -471,7 +467,7 @@ async function checkOwner(userID, monitorID) { userID, ]) - if (!row) { + if (! row) { throw new Error("You do not own this monitor."); } } @@ -526,7 +522,7 @@ async function getMonitorJSONList(userID) { } function checkLogin(socket) { - if (!socket.userID) { + if (! socket.userID) { throw new Error("You are not logged in."); } } @@ -534,7 +530,7 @@ function checkLogin(socket) { async function initDatabase() { const path = './data/kuma.db'; - if (!fs.existsSync(path)) { + if (! fs.existsSync(path)) { console.log("Copy Database") fs.copyFileSync("./db/kuma.db", path); } @@ -551,7 +547,7 @@ async function initDatabase() { "jwtSecret" ]); - if (!jwtSecretBean) { + if (! jwtSecretBean) { console.log("JWT secret is not found, generate one.") jwtSecretBean = R.dispense("setting") jwtSecretBean.key = "jwtSecret" @@ -638,7 +634,7 @@ async function sendHeartbeatList(socket, monitorID) { let result = []; for (let bean of list) { - result.unshift(bean.toJSON()) + result.unshift(bean.toJSON()) } socket.emit("heartbeatList", monitorID, result) diff --git a/src/assets/app.scss b/src/assets/app.scss index 96e1eb2ab..cb72fb9dd 100644 --- a/src/assets/app.scss +++ b/src/assets/app.scss @@ -1,46 +1,16 @@ @import "vars.scss"; @import "node_modules/bootstrap/scss/bootstrap"; -html, -body, -input, -.modal-content { - background: var(--page-background); - color: var(--main-font-color); -} -a, -.table, -.nav-link { - color: var(--main-font-color); -} -.nav-pills .nav-link.active, -.nav-pills .show > .nav-link { - color: #0a0a0a; -} - -.nav-link:hover, -.nav-link:focus { - color: #5cdd8b; -} - -.form-control, -.form-control:focus, -.form-select, -.form-select:focus { - color: var(--main-font-color); - background-color: var(--background-4); -} - #app { - font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, - segoe ui, Roboto, helvetica neue, Arial, noto sans, sans-serif, - apple color emoji, segoe ui emoji, segoe ui symbol, noto color emoji; + font-family: ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,segoe ui,Roboto,helvetica neue,Arial,noto sans,sans-serif,apple color emoji,segoe ui emoji,segoe ui symbol,noto color emoji; } .shadow-box { overflow: hidden; - box-shadow: 0 15px 70px rgba(0, 0, 0, 0.1); + box-shadow: 0 15px 70px rgba(0, 0, 0, .1); padding: 10px; + border-radius: 10px; + &.big-padding { padding: 20px; } @@ -52,14 +22,10 @@ a, } .btn-primary { - // color: white; - color: #0a0a0a; + color: white; - &:hover, - &:active, - &:focus, - &.active { - color: #0a0a0a; + &:hover, &:active, &:focus, &.active { + color: white; background-color: $highlight; border-color: $highlight; } @@ -70,8 +36,3 @@ a, backdrop-filter: blur(3px); } -@media (prefers-color-scheme: dark) { - a:hover { - color: #7ce8a4; - } -} diff --git a/src/components/HeartbeatBar.vue b/src/components/HeartbeatBar.vue index 9e063fb29..48ffd2926 100644 --- a/src/components/HeartbeatBar.vue +++ b/src/components/HeartbeatBar.vue @@ -159,7 +159,7 @@ export default { border-radius: 50rem; &.empty { - background-color: var(--background-ternary); + background-color: aliceblue; } &.down { diff --git a/src/components/Status.vue b/src/components/Status.vue index 274c0a154..c5fec2241 100644 --- a/src/components/Status.vue +++ b/src/components/Status.vue @@ -1,5 +1,5 @@ diff --git a/src/components/Uptime.vue b/src/components/Uptime.vue index 0c3e90e7e..ad8114fcb 100644 --- a/src/components/Uptime.vue +++ b/src/components/Uptime.vue @@ -57,7 +57,5 @@ export default { diff --git a/src/layouts/Layout.vue b/src/layouts/Layout.vue index 8731eb07c..b9aca97f6 100644 --- a/src/layouts/Layout.vue +++ b/src/layouts/Layout.vue @@ -8,7 +8,7 @@
- + Uptime Kuma @@ -21,7 +21,7 @@
- + Uptime Kuma @@ -33,6 +33,14 @@ + +