From 3ac752246d6d097ff980631d524d706676862282 Mon Sep 17 00:00:00 2001 From: Gero Gerke Date: Wed, 20 Jul 2022 00:11:15 +0200 Subject: [PATCH 01/10] Add status page summary API --- server/model/monitor.js | 8 ++++++- server/model/status_page.js | 5 ++-- server/routers/status-page-router.js | 35 +++++++++++++++++++++++++++- 3 files changed, 44 insertions(+), 4 deletions(-) diff --git a/server/model/monitor.js b/server/model/monitor.js index cb044f0f15..5b098356be 100644 --- a/server/model/monitor.js +++ b/server/model/monitor.js @@ -31,7 +31,7 @@ class Monitor extends BeanModel { * Only show necessary data to public * @returns {Object} */ - async toPublicJSON(showTags = false) { + async toPublicJSON(showTags = false, includeStatus = false) { let obj = { id: this.id, name: this.name, @@ -45,6 +45,12 @@ class Monitor extends BeanModel { if (showTags) { obj.tags = await this.getTags(); } + + if (includeStatus) { + const heartbeat = await Monitor.getPreviousHeartbeat(this.id); + obj.status = heartbeat.status === 1 ? "up" : "down"; + } + return obj; } diff --git a/server/model/status_page.js b/server/model/status_page.js index 82d184bfda..5ac398c391 100644 --- a/server/model/status_page.js +++ b/server/model/status_page.js @@ -72,8 +72,9 @@ class StatusPage extends BeanModel { /** * Get all status page data in one call * @param {StatusPage} statusPage + * @param {boolean} includeStatus whether each monitor should include the status of the monitor ("up" or "down") */ - static async getStatusPageData(statusPage) { + static async getStatusPageData(statusPage, includeStatus = false) { // Incident let incident = await R.findOne("incident", " pin = 1 AND active = 1 AND status_page_id = ? ", [ statusPage.id, @@ -92,7 +93,7 @@ class StatusPage extends BeanModel { ]); for (let groupBean of list) { - let monitorGroup = await groupBean.toPublicJSON(showTags); + let monitorGroup = await groupBean.toPublicJSON(showTags, includeStatus); publicGroupList.push(monitorGroup); } diff --git a/server/routers/status-page-router.js b/server/routers/status-page-router.js index de075db8dd..95bd9eace1 100644 --- a/server/routers/status-page-router.js +++ b/server/routers/status-page-router.js @@ -2,7 +2,7 @@ let express = require("express"); const apicache = require("../modules/apicache"); const { UptimeKumaServer } = require("../uptime-kuma-server"); const StatusPage = require("../model/status_page"); -const { allowDevAllOrigin, send403 } = require("../util-server"); +const { allowAllOrigin, allowDevAllOrigin, send403 } = require("../util-server"); const { R } = require("redbean-node"); const Monitor = require("../model/monitor"); @@ -26,6 +26,39 @@ router.get("/status-page", cache("5 minutes"), async (request, response) => { await StatusPage.handleStatusPageResponse(response, server.indexHTML, slug); }); +// Status page config, incident, monitor list with status ("up" or "down") +router.get("/api/status-page/:slug/summary", cache("5 minutes"), async (request, response) => { + allowAllOrigin(response); + let slug = request.params.slug; + + try { + // Get Status Page + let statusPage = await R.findOne("status_page", " slug = ? ", [ + slug + ]); + + if (!statusPage) { + return null; + } + + let statusPageData = await StatusPage.getStatusPageData(statusPage, true); + + if (!statusPageData) { + response.statusCode = 404; + response.json({ + msg: "Not Found" + }); + return; + } + + // Response + response.json(statusPageData); + + } catch (error) { + send403(response, error.message); + } +}); + // Status page config, incident, monitor list router.get("/api/status-page/:slug", cache("5 minutes"), async (request, response) => { allowDevAllOrigin(response); From 80e7400185e88101e198533dde132a23fb9b8cae Mon Sep 17 00:00:00 2001 From: Gero Gerke Date: Tue, 26 Jul 2022 13:47:23 +0200 Subject: [PATCH 02/10] Updates --- server/model/group.js | 4 ++-- server/model/status_page.js | 12 ++++++++++-- server/routers/status-page-router.js | 2 +- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/server/model/group.js b/server/model/group.js index 3f3b3b1294..32e3cc397d 100644 --- a/server/model/group.js +++ b/server/model/group.js @@ -9,12 +9,12 @@ class Group extends BeanModel { * @param {boolean} [showTags=false] Should the JSON include monitor tags * @returns {Object} */ - async toPublicJSON(showTags = false) { + async toPublicJSON(showTags = false, showStatus = false) { let monitorBeanList = await this.getMonitorList(); let monitorList = []; for (let bean of monitorBeanList) { - monitorList.push(await bean.toPublicJSON(showTags)); + monitorList.push(await bean.toPublicJSON(showTags, showStatus)); } return { diff --git a/server/model/status_page.js b/server/model/status_page.js index 5ac398c391..b9e661d3d6 100644 --- a/server/model/status_page.js +++ b/server/model/status_page.js @@ -73,8 +73,9 @@ class StatusPage extends BeanModel { * Get all status page data in one call * @param {StatusPage} statusPage * @param {boolean} includeStatus whether each monitor should include the status of the monitor ("up" or "down") + * @param {boolean} includeConfig whether the config for the status paghe should be included in the returned JSON */ - static async getStatusPageData(statusPage, includeStatus = false) { + static async getStatusPageData(statusPage, includeStatus = false, includeConfig = true) { // Incident let incident = await R.findOne("incident", " pin = 1 AND active = 1 AND status_page_id = ? ", [ statusPage.id, @@ -97,9 +98,16 @@ class StatusPage extends BeanModel { publicGroupList.push(monitorGroup); } + let config = {}; + if (includeConfig) { + config = { + config: await statusPage.toPublicJSON() + } + } + // Response return { - config: await statusPage.toPublicJSON(), + ...config, incident, publicGroupList }; diff --git a/server/routers/status-page-router.js b/server/routers/status-page-router.js index 95bd9eace1..5a24962fe3 100644 --- a/server/routers/status-page-router.js +++ b/server/routers/status-page-router.js @@ -41,7 +41,7 @@ router.get("/api/status-page/:slug/summary", cache("5 minutes"), async (request, return null; } - let statusPageData = await StatusPage.getStatusPageData(statusPage, true); + let statusPageData = await StatusPage.getStatusPageData(statusPage, true, false); if (!statusPageData) { response.statusCode = 404; From 2781ff566b1160946febc360178ed7b673597ef4 Mon Sep 17 00:00:00 2001 From: Gero Gerke Date: Thu, 28 Jul 2022 12:44:06 +0200 Subject: [PATCH 03/10] Make linter happy --- server/model/status_page.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/model/status_page.js b/server/model/status_page.js index b9e661d3d6..870eb9b4f9 100644 --- a/server/model/status_page.js +++ b/server/model/status_page.js @@ -102,7 +102,7 @@ class StatusPage extends BeanModel { if (includeConfig) { config = { config: await statusPage.toPublicJSON() - } + }; } // Response From 1630c01fd9038a5970dcb358958494ea170e2d38 Mon Sep 17 00:00:00 2001 From: Gero Gerke Date: Thu, 5 Jan 2023 15:56:08 +0100 Subject: [PATCH 04/10] chore: add support for new monitor states --- server/model/monitor.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/server/model/monitor.js b/server/model/monitor.js index 473c39d506..763763fedf 100644 --- a/server/model/monitor.js +++ b/server/model/monitor.js @@ -26,6 +26,16 @@ const { UptimeCacheList } = require("../uptime-cache-list"); */ class Monitor extends BeanModel { + statusToKey(status) { + switch (status) { + case 0: return "down"; + case 1: return "up"; + case 2: return "pending"; + case 4: return "maintenance"; + default: return "unknown"; + } + } + /** * Return an object that ready to parse to JSON for public * Only show necessary data to public @@ -49,7 +59,7 @@ class Monitor extends BeanModel { if (includeStatus) { const heartbeat = await Monitor.getPreviousHeartbeat(this.id); - obj.status = heartbeat.status === 1 ? "up" : "down"; + obj.status = this.statusToKey(heartbeat.status); } return obj; From f33d09918d9c4f0888b12c54b277c7e7a70a1463 Mon Sep 17 00:00:00 2001 From: Gero Gerke Date: Tue, 10 Jan 2023 10:41:04 +0100 Subject: [PATCH 05/10] Update server/model/group.js Co-authored-by: Matthew Nickson --- server/model/group.js | 1 + 1 file changed, 1 insertion(+) diff --git a/server/model/group.js b/server/model/group.js index 32e3cc397d..596d2b0e9e 100644 --- a/server/model/group.js +++ b/server/model/group.js @@ -7,6 +7,7 @@ class Group extends BeanModel { * Return an object that ready to parse to JSON for public * Only show necessary data to public * @param {boolean} [showTags=false] Should the JSON include monitor tags + * @param {boolean} [showStatus = false] Should the JSON include the status * @returns {Object} */ async toPublicJSON(showTags = false, showStatus = false) { From 3dbc32b225aaf64f843680bbf83486e952a85bc8 Mon Sep 17 00:00:00 2001 From: Gero Gerke Date: Tue, 10 Jan 2023 10:41:18 +0100 Subject: [PATCH 06/10] Update server/model/monitor.js Co-authored-by: Matthew Nickson --- server/model/monitor.js | 1 + 1 file changed, 1 insertion(+) diff --git a/server/model/monitor.js b/server/model/monitor.js index 763763fedf..c130dce96f 100644 --- a/server/model/monitor.js +++ b/server/model/monitor.js @@ -39,6 +39,7 @@ class Monitor extends BeanModel { /** * Return an object that ready to parse to JSON for public * Only show necessary data to public + * @param {boolean} [includeStatus = false] Should the JSON include the status * @returns {Object} */ async toPublicJSON(showTags = false, includeStatus = false) { From 1b5ea7d44ed02197036c6410d638de88164cb86a Mon Sep 17 00:00:00 2001 From: Gero Gerke Date: Tue, 10 Jan 2023 10:41:25 +0100 Subject: [PATCH 07/10] Update server/model/status_page.js Co-authored-by: Matthew Nickson --- server/model/status_page.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/model/status_page.js b/server/model/status_page.js index 09838629c9..6fce5415f5 100644 --- a/server/model/status_page.js +++ b/server/model/status_page.js @@ -80,8 +80,8 @@ class StatusPage extends BeanModel { /** * Get all status page data in one call * @param {StatusPage} statusPage - * @param {boolean} includeStatus whether each monitor should include the status of the monitor ("up" or "down") - * @param {boolean} includeConfig whether the config for the status paghe should be included in the returned JSON + * @param {boolean} [includeStatus = false] whether each monitor should include the status of the monitor ("up" or "down") + * @param {boolean} [includeConfig = true] whether the config for the status paghe should be included in the returned JSON */ static async getStatusPageData(statusPage, includeStatus = false, includeConfig = true) { // Incident From 98d8598052813d2430dda472d8a5f1cd49890ece Mon Sep 17 00:00:00 2001 From: Gero Gerke Date: Tue, 10 Jan 2023 10:47:24 +0100 Subject: [PATCH 08/10] chore: add jsdocs for missing functions --- server/model/monitor.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/server/model/monitor.js b/server/model/monitor.js index c130dce96f..f773bba82d 100644 --- a/server/model/monitor.js +++ b/server/model/monitor.js @@ -26,6 +26,10 @@ const { UptimeCacheList } = require("../uptime-cache-list"); */ class Monitor extends BeanModel { + /** + * Formats the status code to a human readable form + * @returns {string} a human readable string that corresponds to the status code + */ statusToKey(status) { switch (status) { case 0: return "down"; @@ -39,10 +43,10 @@ class Monitor extends BeanModel { /** * Return an object that ready to parse to JSON for public * Only show necessary data to public - * @param {boolean} [includeStatus = false] Should the JSON include the status + * @param {boolean} [showStatus = false] Should the JSON show the status * @returns {Object} */ - async toPublicJSON(showTags = false, includeStatus = false) { + async toPublicJSON(showTags = false, showStatus = false) { let obj = { id: this.id, name: this.name, @@ -58,7 +62,7 @@ class Monitor extends BeanModel { obj.tags = await this.getTags(); } - if (includeStatus) { + if (showStatus) { const heartbeat = await Monitor.getPreviousHeartbeat(this.id); obj.status = this.statusToKey(heartbeat.status); } From f171e101fdd7b45ac435d5840c2bf5294bf05aab Mon Sep 17 00:00:00 2001 From: Gero Gerke Date: Sat, 23 Nov 2024 16:17:57 +0100 Subject: [PATCH 09/10] post-merge adaptations --- server/model/status_page.js | 4 ++-- server/routers/status-page-router.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/server/model/status_page.js b/server/model/status_page.js index 82354be223..03591bd014 100644 --- a/server/model/status_page.js +++ b/server/model/status_page.js @@ -259,7 +259,7 @@ class StatusPage extends BeanModel { * Get all status page data in one call * @param {StatusPage} statusPage * @param {boolean} [includeStatus = false] whether each monitor should include the status of the monitor ("up" or "down") - * @param {boolean} [includeConfig = true] whether the config for the status paghe should be included in the returned JSON + * @param {boolean} [includeConfig = true] whether the config for the status page should be included in the returned JSON */ static async getStatusPageData(statusPage, includeStatus = false, includeConfig = true) { // Incident @@ -282,7 +282,7 @@ class StatusPage extends BeanModel { ]); for (let groupBean of list) { - let monitorGroup = await groupBean.toPublicJSON(showTags, includeStatus); + let monitorGroup = await groupBean.toPublicJSON(showTags, false, includeStatus); publicGroupList.push(monitorGroup); } diff --git a/server/routers/status-page-router.js b/server/routers/status-page-router.js index 6a14186bca..60c5af6334 100644 --- a/server/routers/status-page-router.js +++ b/server/routers/status-page-router.js @@ -2,7 +2,7 @@ let express = require("express"); const apicache = require("../modules/apicache"); const { UptimeKumaServer } = require("../uptime-kuma-server"); const StatusPage = require("../model/status_page"); -const { allowDevAllOrigin, sendHttpError } = require("../util-server"); +const { allowAllOrigin, allowDevAllOrigin, sendHttpError } = require("../util-server"); const { R } = require("redbean-node"); const { badgeConstants } = require("../../src/util"); const { makeBadge } = require("badge-maker"); From a8c30f5ab8928d687355568fcf0c2ee775c1c042 Mon Sep 17 00:00:00 2001 From: Gero Gerke Date: Sat, 23 Nov 2024 16:28:01 +0100 Subject: [PATCH 10/10] fix lint errors --- server/model/group.js | 8 +++++--- server/model/monitor.js | 4 ++-- server/model/status_page.js | 7 ++++--- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/server/model/group.js b/server/model/group.js index 9dd896e2cf..87c3a59b8e 100644 --- a/server/model/group.js +++ b/server/model/group.js @@ -6,9 +6,11 @@ class Group extends BeanModel { /** * Return an object that ready to parse to JSON for public * Only show necessary data to public - * @param {boolean} [showTags=false] Should the JSON include monitor tags - * @param {boolean} [showStatus = false] Should the JSON include the status - * @returns {Object} + * @param {boolean} showTags Should the JSON include monitor tags + * @param {boolean} certExpiry Should JSON include info about + * certificate expiry? + * @param {boolean} showStatus Should the JSON include the status + * @returns {Promise} Object ready to parse */ async toPublicJSON(showTags = false, certExpiry = false, showStatus = false) { let monitorBeanList = await this.getMonitorList(); diff --git a/server/model/monitor.js b/server/model/monitor.js index 0abb6e0a94..dd936478c6 100644 --- a/server/model/monitor.js +++ b/server/model/monitor.js @@ -37,8 +37,8 @@ const rootCertificates = rootCertificatesFingerprints(); class Monitor extends BeanModel { /** -<<<<<<< HEAD * Formats the status code to a human readable form + * @param {number} status the internal status code of the monitor * @returns {string} a human readable string that corresponds to the status code */ statusToKey(status) { @@ -57,7 +57,7 @@ class Monitor extends BeanModel { * @param {boolean} showTags Include tags in JSON * @param {boolean} certExpiry Include certificate expiry info in * JSON - * @param {boolean} [showStatus = false] Should the JSON show the status + * @param {boolean} showStatus Should the JSON show the status * @returns {Promise} Object ready to parse */ async toPublicJSON(showTags = false, certExpiry = false, showStatus = false) { diff --git a/server/model/status_page.js b/server/model/status_page.js index 03591bd014..c987741768 100644 --- a/server/model/status_page.js +++ b/server/model/status_page.js @@ -257,9 +257,10 @@ class StatusPage extends BeanModel { /** * Get all status page data in one call - * @param {StatusPage} statusPage - * @param {boolean} [includeStatus = false] whether each monitor should include the status of the monitor ("up" or "down") - * @param {boolean} [includeConfig = true] whether the config for the status page should be included in the returned JSON + * @param {StatusPage} statusPage the status page to return the data for + * @param {boolean} includeStatus whether each monitor should include the status of the monitor ("up" or "down") + * @param {boolean} includeConfig whether the config for the status page should be included in the returned JSON + * @returns {object} the status page data object */ static async getStatusPageData(statusPage, includeStatus = false, includeConfig = true) { // Incident