diff --git a/server/server.js b/server/server.js index b9363109a..8d375b62c 100644 --- a/server/server.js +++ b/server/server.js @@ -127,7 +127,7 @@ const StatusPage = require("./model/status_page"); const { cloudflaredSocketHandler, autoStart: cloudflaredAutoStart, stop: cloudflaredStop } = require("./socket-handlers/cloudflared-socket-handler"); const { proxySocketHandler } = require("./socket-handlers/proxy-socket-handler"); const { dockerSocketHandler } = require("./socket-handlers/docker-socket-handler"); -const apicache = require("./modules/apicache"); +const { maintenanceSocketHandler } = require("./socket-handlers/maintenance-socket-handler"); app.use(express.json()); @@ -146,12 +146,6 @@ app.use(function (req, res, next) { */ let jwtSecret = null; -/** -* Main maintenance list -* @type {{}} -*/ -let maintenanceList = {}; - /** * Show Setup Page * @type {boolean} @@ -733,135 +727,6 @@ let needSetup = false; } }); - // Add a new maintenance - socket.on("addMaintenance", async (maintenance, callback) => { - try { - checkLogin(socket); - let bean = R.dispense("maintenance"); - - bean.import(maintenance); - bean.user_id = socket.userID; - let maintenanceID = await R.store(bean); - - await sendMaintenanceList(socket); - - callback({ - ok: true, - msg: "Added Successfully.", - maintenanceID, - }); - - } catch (e) { - callback({ - ok: false, - msg: e.message, - }); - } - }); - - // Edit a maintenance - socket.on("editMaintenance", async (maintenance, callback) => { - try { - checkLogin(socket); - - let bean = await R.findOne("maintenance", " id = ? ", [ maintenance.id ]); - - if (bean.user_id !== socket.userID) { - throw new Error("Permission denied."); - } - - bean.title = maintenance.title; - bean.description = maintenance.description; - bean.start_date = maintenance.start_date; - bean.end_date = maintenance.end_date; - - await R.store(bean); - - await sendMaintenanceList(socket); - - callback({ - ok: true, - msg: "Saved.", - maintenanceID: bean.id, - }); - - } catch (e) { - console.error(e); - callback({ - ok: false, - msg: e.message, - }); - } - }); - - // Add a new monitor_maintenance - socket.on("addMonitorMaintenance", async (maintenanceID, monitors, callback) => { - try { - checkLogin(socket); - - await R.exec("DELETE FROM monitor_maintenance WHERE maintenance_id = ?", [ - maintenanceID - ]); - - for await (const monitor of monitors) { - let bean = R.dispense("monitor_maintenance"); - - bean.import({ - monitor_id: monitor.id, - maintenance_id: maintenanceID - }); - await R.store(bean); - } - - apicache.clear(); - - callback({ - ok: true, - msg: "Added Successfully.", - }); - - } catch (e) { - callback({ - ok: false, - msg: e.message, - }); - } - }); - - // Add a new monitor_maintenance - socket.on("addMaintenanceStatusPage", async (maintenanceID, statusPages, callback) => { - try { - checkLogin(socket); - - await R.exec("DELETE FROM maintenance_status_page WHERE maintenance_id = ?", [ - maintenanceID - ]); - - for await (const statusPage of statusPages) { - let bean = R.dispense("maintenance_status_page"); - - bean.import({ - status_page_id: statusPage.id, - maintenance_id: maintenanceID - }); - await R.store(bean); - } - - apicache.clear(); - - callback({ - ok: true, - msg: "Added Successfully.", - }); - - } catch (e) { - callback({ - ok: false, - msg: e.message, - }); - } - }); - socket.on("getMonitorList", async (callback) => { try { checkLogin(socket); @@ -878,22 +743,6 @@ let needSetup = false; } }); - socket.on("getMaintenanceList", async (callback) => { - try { - checkLogin(socket); - await sendMaintenanceList(socket); - callback({ - ok: true, - }); - } catch (e) { - console.error(e); - callback({ - ok: false, - msg: e.message, - }); - } - }); - socket.on("getMonitor", async (monitorID, callback) => { try { checkLogin(socket); @@ -942,54 +791,6 @@ let needSetup = false; } }); - socket.on("getMonitorMaintenance", async (maintenanceID, callback) => { - try { - checkLogin(socket); - - console.log(`Get Monitors for Maintenance: ${maintenanceID} User ID: ${socket.userID}`); - - let monitors = await R.getAll("SELECT monitor.id, monitor.name FROM monitor_maintenance mm JOIN monitor ON mm.monitor_id = monitor.id WHERE mm.maintenance_id = ? ", [ - maintenanceID, - ]); - - callback({ - ok: true, - monitors, - }); - - } catch (e) { - console.error(e); - callback({ - ok: false, - msg: e.message, - }); - } - }); - - socket.on("getMaintenanceStatusPage", async (maintenanceID, callback) => { - try { - checkLogin(socket); - - console.log(`Get Status Pages for Maintenance: ${maintenanceID} User ID: ${socket.userID}`); - - let statusPages = await R.getAll("SELECT status_page.id, status_page.title FROM maintenance_status_page msp JOIN status_page ON msp.status_page_id = status_page.id WHERE msp.maintenance_id = ? ", [ - maintenanceID, - ]); - - callback({ - ok: true, - statusPages, - }); - - } catch (e) { - console.error(e); - callback({ - ok: false, - msg: e.message, - }); - } - }); - socket.on("getMonitorBeats", async (monitorID, period, callback) => { try { checkLogin(socket); @@ -1094,36 +895,6 @@ let needSetup = false; } }); - socket.on("deleteMaintenance", async (maintenanceID, callback) => { - try { - checkLogin(socket); - - console.log(`Delete Maintenance: ${maintenanceID} User ID: ${socket.userID}`); - - if (maintenanceID in maintenanceList) { - delete maintenanceList[maintenanceID]; - } - - await R.exec("DELETE FROM maintenance WHERE id = ? AND user_id = ? ", [ - maintenanceID, - socket.userID, - ]); - - callback({ - ok: true, - msg: "Deleted Successfully.", - }); - - await sendMaintenanceList(socket); - - } catch (e) { - callback({ - ok: false, - msg: e.message, - }); - } - }); - socket.on("getTags", async (callback) => { try { checkLogin(socket); @@ -1704,6 +1475,7 @@ let needSetup = false; databaseSocketHandler(socket); proxySocketHandler(socket); dockerSocketHandler(socket); + maintenanceSocketHandler(socket); log.debug("server", "added all socket handlers"); @@ -1794,17 +1566,6 @@ async function checkOwner(userID, monitorID) { } } -/** - * Send maintenance list to client - * @param {Socket} socket Socket.io instance to send to - * @returns {Object} - */ -async function sendMaintenanceList(socket) { - let list = await getMaintenanceJSONList(socket.userID); - io.to(socket.userID).emit("maintenanceList", list); - return list; -} - /** * Function called after user login * This function is used to send the heartbeat list of a monitor. @@ -1817,7 +1578,7 @@ async function afterLogin(socket, user) { socket.join(user.id); let monitorList = await server.sendMonitorList(socket); - sendMaintenanceList(socket); + server.sendMaintenanceList(socket); sendNotificationList(socket); sendProxyList(socket); sendDockerHostList(socket); @@ -1839,25 +1600,6 @@ async function afterLogin(socket, user) { } } -/** - * Get a list of maintenances for the given user. - * @param {string} userID - The ID of the user to get maintenances for. - * @returns {Promise} A promise that resolves to an object with maintenance IDs as keys and maintenances objects as values. - */ -async function getMaintenanceJSONList(userID) { - let result = {}; - - let maintenanceList = await R.find("maintenance", " user_id = ? ORDER BY end_date DESC, title", [ - userID, - ]); - - for (let maintenance of maintenanceList) { - result[maintenance.id] = await maintenance.toJSON(); - } - - return result; -} - /** * Initialize the database * @param {boolean} [testMode=false] Should the connection be diff --git a/server/socket-handlers/maintenance-socket-handler.js b/server/socket-handlers/maintenance-socket-handler.js new file mode 100644 index 000000000..e93d8d60d --- /dev/null +++ b/server/socket-handlers/maintenance-socket-handler.js @@ -0,0 +1,235 @@ +const { checkLogin } = require("../util-server"); +const { log } = require("../../src/util"); +const { R } = require("redbean-node"); +const apicache = require("../modules/apicache"); +const { UptimeKumaServer } = require("../uptime-kuma-server"); +const server = UptimeKumaServer.getInstance(); + +/** + * Handlers for Maintenance + * @param {Socket} socket Socket.io instance + */ +module.exports.maintenanceSocketHandler = (socket) => { + // Add a new maintenance + socket.on("addMaintenance", async (maintenance, callback) => { + try { + checkLogin(socket); + let bean = R.dispense("maintenance"); + + bean.import(maintenance); + bean.user_id = socket.userID; + let maintenanceID = await R.store(bean); + + await server.sendMaintenanceList(socket); + + callback({ + ok: true, + msg: "Added Successfully.", + maintenanceID, + }); + + } catch (e) { + callback({ + ok: false, + msg: e.message, + }); + } + }); + + // Edit a maintenance + socket.on("editMaintenance", async (maintenance, callback) => { + try { + checkLogin(socket); + + let bean = await R.findOne("maintenance", " id = ? ", [ maintenance.id ]); + + if (bean.user_id !== socket.userID) { + throw new Error("Permission denied."); + } + + bean.title = maintenance.title; + bean.description = maintenance.description; + bean.start_date = maintenance.start_date; + bean.end_date = maintenance.end_date; + + await R.store(bean); + + await server.sendMaintenanceList(socket); + + callback({ + ok: true, + msg: "Saved.", + maintenanceID: bean.id, + }); + + } catch (e) { + console.error(e); + callback({ + ok: false, + msg: e.message, + }); + } + }); + + // Add a new monitor_maintenance + socket.on("addMonitorMaintenance", async (maintenanceID, monitors, callback) => { + try { + checkLogin(socket); + + await R.exec("DELETE FROM monitor_maintenance WHERE maintenance_id = ?", [ + maintenanceID + ]); + + for await (const monitor of monitors) { + let bean = R.dispense("monitor_maintenance"); + + bean.import({ + monitor_id: monitor.id, + maintenance_id: maintenanceID + }); + await R.store(bean); + } + + apicache.clear(); + + callback({ + ok: true, + msg: "Added Successfully.", + }); + + } catch (e) { + callback({ + ok: false, + msg: e.message, + }); + } + }); + + // Add a new monitor_maintenance + socket.on("addMaintenanceStatusPage", async (maintenanceID, statusPages, callback) => { + try { + checkLogin(socket); + + await R.exec("DELETE FROM maintenance_status_page WHERE maintenance_id = ?", [ + maintenanceID + ]); + + for await (const statusPage of statusPages) { + let bean = R.dispense("maintenance_status_page"); + + bean.import({ + status_page_id: statusPage.id, + maintenance_id: maintenanceID + }); + await R.store(bean); + } + + apicache.clear(); + + callback({ + ok: true, + msg: "Added Successfully.", + }); + + } catch (e) { + callback({ + ok: false, + msg: e.message, + }); + } + }); + + socket.on("getMaintenanceList", async (callback) => { + try { + checkLogin(socket); + await server.sendMaintenanceList(socket); + callback({ + ok: true, + }); + } catch (e) { + console.error(e); + callback({ + ok: false, + msg: e.message, + }); + } + }); + + socket.on("getMonitorMaintenance", async (maintenanceID, callback) => { + try { + checkLogin(socket); + + console.log(`Get Monitors for Maintenance: ${maintenanceID} User ID: ${socket.userID}`); + + let monitors = await R.getAll("SELECT monitor.id, monitor.name FROM monitor_maintenance mm JOIN monitor ON mm.monitor_id = monitor.id WHERE mm.maintenance_id = ? ", [ + maintenanceID, + ]); + + callback({ + ok: true, + monitors, + }); + + } catch (e) { + console.error(e); + callback({ + ok: false, + msg: e.message, + }); + } + }); + + socket.on("getMaintenanceStatusPage", async (maintenanceID, callback) => { + try { + checkLogin(socket); + + console.log(`Get Status Pages for Maintenance: ${maintenanceID} User ID: ${socket.userID}`); + + let statusPages = await R.getAll("SELECT status_page.id, status_page.title FROM maintenance_status_page msp JOIN status_page ON msp.status_page_id = status_page.id WHERE msp.maintenance_id = ? ", [ + maintenanceID, + ]); + + callback({ + ok: true, + statusPages, + }); + + } catch (e) { + console.error(e); + callback({ + ok: false, + msg: e.message, + }); + } + }); + + socket.on("deleteMaintenance", async (maintenanceID, callback) => { + try { + checkLogin(socket); + + console.log(`Delete Maintenance: ${maintenanceID} User ID: ${socket.userID}`); + + if (maintenanceID in server.maintenanceList) { + delete server.maintenanceList[maintenanceID]; + } + + await R.exec("DELETE FROM maintenance WHERE id = ? AND user_id = ? ", [ + maintenanceID, + socket.userID, + ]); + + callback({ + ok: true, + msg: "Deleted Successfully.", + }); + + await server.sendMaintenanceList(socket); + + } catch (e) { + callback({ + ok: false, + msg: e.message, + }); + } + }); +}; diff --git a/server/uptime-kuma-server.js b/server/uptime-kuma-server.js index 98de65a43..a8a365936 100644 --- a/server/uptime-kuma-server.js +++ b/server/uptime-kuma-server.js @@ -26,6 +26,13 @@ class UptimeKumaServer { * @type {{}} */ monitorList = {}; + + /** + * Main maintenance list + * @type {{}} + */ + maintenanceList = {}; + entryPage = "dashboard"; app = undefined; httpServer = undefined; @@ -104,6 +111,36 @@ class UptimeKumaServer { return result; } + /** + * Send maintenance list to client + * @param {Socket} socket Socket.io instance to send to + * @returns {Object} + */ + async sendMaintenanceList(socket) { + let list = await this.getMaintenanceJSONList(socket.userID); + this.io.to(socket.userID).emit("maintenanceList", list); + return list; + } + + /** + * Get a list of maintenances for the given user. + * @param {string} userID - The ID of the user to get maintenances for. + * @returns {Promise} A promise that resolves to an object with maintenance IDs as keys and maintenances objects as values. + */ + async getMaintenanceJSONList(userID) { + let result = {}; + + let maintenanceList = await R.find("maintenance", " user_id = ? ORDER BY end_date DESC, title", [ + userID, + ]); + + for (let maintenance of maintenanceList) { + result[maintenance.id] = await maintenance.toJSON(); + } + + return result; + } + /** * Write error to log file * @param {any} error The error to write