diff --git a/db/patch-incident-table.sql b/db/patch-incident-table.sql new file mode 100644 index 000000000..a0598e4aa --- /dev/null +++ b/db/patch-incident-table.sql @@ -0,0 +1,17 @@ +-- You should not modify if this have pushed to Github, unless it does serious wrong with the db. +BEGIN TRANSACTION; + +create table incident +( + id INTEGER not null + constraint incident_pk + primary key autoincrement, + title VARCHAR(255) not null, + content TEXT not null, + style VARCHAR(30) default 'warning' not null, + created_date DATETIME default (DATETIME('now')) not null, + pin BOOLEAN default 1 not null, + active BOOLEAN default 1 not null +); + +COMMIT; diff --git a/server/database.js b/server/database.js index 39b723ced..847203cad 100644 --- a/server/database.js +++ b/server/database.js @@ -34,6 +34,7 @@ class Database { "patch-2fa.sql": true, "patch-add-retry-interval-monitor.sql": true, "patch-monitor-public-weight.sql": true, + "patch-incident-table.sql": true, } /** diff --git a/server/model/incident.js b/server/model/incident.js new file mode 100644 index 000000000..5f232751a --- /dev/null +++ b/server/model/incident.js @@ -0,0 +1,17 @@ +const { BeanModel } = require("redbean-node/dist/bean-model"); + +class Incident extends BeanModel { + + toPublicJSON() { + return { + id: this.id, + style: this.style, + title: this.title, + content: this.content, + pin: this.pin, + createdDate: this.createdDate, + }; + } +} + +module.exports = Incident; diff --git a/server/routers/api-router.js b/server/routers/api-router.js index 9c4240cac..1d02e7106 100644 --- a/server/routers/api-router.js +++ b/server/routers/api-router.js @@ -38,7 +38,10 @@ router.get("/api/status-page/incident", async (_, response) => { try { await checkPublished(); - // TODO: + response.json({ + ok: true, + incident: (await R.findOne("incident", " pin = 1 AND active = 1")).toPublicJSON(), + }) } catch (error) { send403(response, error.message); diff --git a/server/server.js b/server/server.js index 70db99a70..f6eec4bdc 100644 --- a/server/server.js +++ b/server/server.js @@ -35,7 +35,7 @@ console.log("Importing this project modules"); debug("Importing Monitor"); const Monitor = require("./model/monitor"); debug("Importing Settings"); -const { getSettings, setSettings, setting, initJWTSecret, genSecret, allowDevAllOrigin } = require("./util-server"); +const { getSettings, setSettings, setting, initJWTSecret, genSecret, allowDevAllOrigin, checkLogin } = require("./util-server"); debug("Importing Notification"); const { Notification } = require("./notification"); @@ -91,6 +91,7 @@ module.exports.io = io; // Must be after io instantiation const { sendNotificationList, sendHeartbeatList, sendImportantHeartbeatList } = require("./client"); +const { statusPageSocketHandler } = require("./socket-handlers/status-page-socket-handler"); app.use(express.json()); @@ -1104,7 +1105,10 @@ exports.entryPage = "dashboard"; } }); - debug("added all socket handlers") + // Status Page Socket Handler for admin only + statusPageSocketHandler(socket); + + debug("added all socket handlers"); // *************************** // Better do anything after added all socket handlers here @@ -1208,12 +1212,6 @@ async function getMonitorJSONList(userID) { return result; } -function checkLogin(socket) { - if (! socket.userID) { - throw new Error("You are not logged in."); - } -} - async function initDatabase() { if (! fs.existsSync(Database.path)) { console.log("Copying Database") diff --git a/server/socket-handlers/status-page-socket-handler.js b/server/socket-handlers/status-page-socket-handler.js new file mode 100644 index 000000000..8da814d7c --- /dev/null +++ b/server/socket-handlers/status-page-socket-handler.js @@ -0,0 +1,61 @@ +const { R } = require("redbean-node"); +const { checkLogin } = require("../util-server"); +const dayjs = require("dayjs"); + +module.exports.statusPageSocketHandler = (socket) => { + + // Post or edit incident + socket.on("postIncident", async (incident, callback) => { + try { + checkLogin(socket); + + await R.exec("UPDATE incident SET pin = 0 "); + + let incidentBean; + + if (incident.id) { + incidentBean = await R.findOne("incident", " id = ?", [ + incident.id + ]); + } + + if (incidentBean == null) { + incidentBean = R.dispense("incident"); + } + + incidentBean.title = incident.title; + incidentBean.content = incident.content; + incidentBean.style = incident.style; + incidentBean.pin = true; + incidentBean.createdDate = R.isoDateTime(dayjs.utc()); + await R.store(incidentBean); + + callback({ + ok: true, + incident: incidentBean.toPublicJSON(), + }) + } catch (error) { + callback({ + ok: false, + msg: error.message, + }) + } + }); + + socket.on("unpinIncident", async (callback) => { + try { + checkLogin(socket); + + await R.exec("UPDATE incident SET pin = 0 WHERE pin = 1"); + + callback({ + ok: true, + }) + } catch (error) { + callback({ + ok: false, + msg: error.message, + }) + } + }); +} diff --git a/server/util-server.js b/server/util-server.js index ea2b0157a..7dbbb6dfa 100644 --- a/server/util-server.js +++ b/server/util-server.js @@ -293,3 +293,9 @@ exports.allowAllOrigin = (res) => { res.header("Access-Control-Allow-Origin", "*"); res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); } + +exports.checkLogin = (socket) => { + if (! socket.userID) { + throw new Error("You are not logged in."); + } +} diff --git a/src/components/GroupList.vue b/src/components/PublicGroupList.vue similarity index 96% rename from src/components/GroupList.vue rename to src/components/PublicGroupList.vue index 753a6492a..0187e2035 100644 --- a/src/components/GroupList.vue +++ b/src/components/PublicGroupList.vue @@ -9,7 +9,7 @@