diff --git a/server/model/status_page.js b/server/model/status_page.js
index ebab3016..4413e665 100644
--- a/server/model/status_page.js
+++ b/server/model/status_page.js
@@ -23,7 +23,7 @@ class StatusPage extends BeanModel {
]);
if (statusPage) {
- response.send(StatusPage.renderHTML(indexHTML, statusPage));
+ response.send(await StatusPage.renderHTML(indexHTML, statusPage));
} else {
response.status(404).send(UptimeKumaServer.getInstance().indexHTML);
}
@@ -34,7 +34,7 @@ class StatusPage extends BeanModel {
* @param {string} indexHTML
* @param {StatusPage} statusPage
*/
- static renderHTML(indexHTML, statusPage) {
+ static async renderHTML(indexHTML, statusPage) {
const $ = cheerio.load(indexHTML);
const description155 = statusPage.description.substring(0, 155);
@@ -53,9 +53,52 @@ class StatusPage extends BeanModel {
head.append(``);
head.append(``);
+ // Preload data
+ const json = JSON.stringify(await StatusPage.getStatusPageData(statusPage));
+ head.append(`
+
+ `);
+
return $.root().html();
}
+ /**
+ * Get all status page data in one call
+ * @param {StatusPage} statusPage
+ */
+ static async getStatusPageData(statusPage) {
+ // Incident
+ let incident = await R.findOne("incident", " pin = 1 AND active = 1 AND status_page_id = ? ", [
+ statusPage.id,
+ ]);
+
+ if (incident) {
+ incident = incident.toPublicJSON();
+ }
+
+ // Public Group List
+ const publicGroupList = [];
+ const showTags = !!statusPage.show_tags;
+
+ const list = await R.find("group", " public = 1 AND status_page_id = ? ORDER BY weight ", [
+ statusPage.id
+ ]);
+
+ for (let groupBean of list) {
+ let monitorGroup = await groupBean.toPublicJSON(showTags);
+ publicGroupList.push(monitorGroup);
+ }
+
+ // Response
+ return {
+ config: await statusPage.toPublicJSON(),
+ incident,
+ publicGroupList
+ };
+ }
+
/**
* Loads domain mapping from DB
* Return object like this: { "test-uptime.kuma.pet": "default" }
diff --git a/server/routers/api-router.js b/server/routers/api-router.js
index 24a42069..f4628bc6 100644
--- a/server/routers/api-router.js
+++ b/server/routers/api-router.js
@@ -1,5 +1,5 @@
let express = require("express");
-const { allowDevAllOrigin, allowAllOrigin, percentageToColor, filterAndJoin } = require("../util-server");
+const { allowDevAllOrigin, allowAllOrigin, percentageToColor, filterAndJoin, send403 } = require("../util-server");
const { R } = require("redbean-node");
const apicache = require("../modules/apicache");
const Monitor = require("../model/monitor");
@@ -99,108 +99,6 @@ router.get("/api/push/:pushToken", async (request, response) => {
}
});
-// Status page config, incident, monitor list
-router.get("/api/status-page/:slug", cache("5 minutes"), async (request, response) => {
- allowDevAllOrigin(response);
- let slug = request.params.slug;
-
- // Get Status Page
- let statusPage = await R.findOne("status_page", " slug = ? ", [
- slug
- ]);
-
- if (!statusPage) {
- response.statusCode = 404;
- response.json({
- msg: "Not Found"
- });
- return;
- }
-
- try {
- // Incident
- let incident = await R.findOne("incident", " pin = 1 AND active = 1 AND status_page_id = ? ", [
- statusPage.id,
- ]);
-
- if (incident) {
- incident = incident.toPublicJSON();
- }
-
- // Public Group List
- const publicGroupList = [];
- const showTags = !!statusPage.show_tags;
-
- const list = await R.find("group", " public = 1 AND status_page_id = ? ORDER BY weight ", [
- statusPage.id
- ]);
-
- for (let groupBean of list) {
- let monitorGroup = await groupBean.toPublicJSON(showTags);
- publicGroupList.push(monitorGroup);
- }
-
- // Response
- response.json({
- config: await statusPage.toPublicJSON(),
- incident,
- publicGroupList
- });
-
- } catch (error) {
- send403(response, error.message);
- }
-
-});
-
-// Status Page Polling Data
-// Can fetch only if published
-router.get("/api/status-page/heartbeat/:slug", cache("1 minutes"), async (request, response) => {
- allowDevAllOrigin(response);
-
- try {
- let heartbeatList = {};
- let uptimeList = {};
-
- let slug = request.params.slug;
- let statusPageID = await StatusPage.slugToID(slug);
-
- let monitorIDList = await R.getCol(`
- SELECT monitor_group.monitor_id FROM monitor_group, \`group\`
- WHERE monitor_group.group_id = \`group\`.id
- AND public = 1
- AND \`group\`.status_page_id = ?
- `, [
- statusPageID
- ]);
-
- for (let monitorID of monitorIDList) {
- let list = await R.getAll(`
- SELECT * FROM heartbeat
- WHERE monitor_id = ?
- ORDER BY time DESC
- LIMIT 50
- `, [
- monitorID,
- ]);
-
- list = R.convertToBeans("heartbeat", list);
- heartbeatList[monitorID] = list.reverse().map(row => row.toPublicJSON());
-
- const type = 24;
- uptimeList[`${monitorID}_${type}`] = await Monitor.calcUptime(type, monitorID);
- }
-
- response.json({
- heartbeatList,
- uptimeList
- });
-
- } catch (error) {
- send403(response, error.message);
- }
-});
-
router.get("/api/badge/:id/status", cache("5 minutes"), async (request, response) => {
allowAllOrigin(response);
@@ -377,16 +275,4 @@ router.get("/api/badge/:id/ping/:duration?", cache("5 minutes"), async (request,
}
});
-/**
- * Send a 403 response
- * @param {Object} res Express response object
- * @param {string} [msg=""] Message to send
- */
-function send403(res, msg = "") {
- res.status(403).json({
- "status": "fail",
- "msg": msg,
- });
-}
-
module.exports = router;
diff --git a/server/routers/status-page-router.js b/server/routers/status-page-router.js
index 77b79113..465afdf8 100644
--- a/server/routers/status-page-router.js
+++ b/server/routers/status-page-router.js
@@ -2,6 +2,9 @@ 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 { R } = require("redbean-node");
+const Monitor = require("../model/monitor");
let router = express.Router();
@@ -23,4 +26,85 @@ router.get("/status-page", cache("5 minutes"), async (request, response) => {
await StatusPage.handleStatusPageResponse(response, server.indexHTML, slug);
});
+// Status page config, incident, monitor list
+router.get("/api/status-page/:slug", cache("5 minutes"), async (request, response) => {
+ allowDevAllOrigin(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);
+
+ if (!statusPageData) {
+ response.statusCode = 404;
+ response.json({
+ msg: "Not Found"
+ });
+ return;
+ }
+
+ // Response
+ response.json(statusPageData);
+
+ } catch (error) {
+ send403(response, error.message);
+ }
+});
+
+// Status Page Polling Data
+// Can fetch only if published
+router.get("/api/status-page/heartbeat/:slug", cache("1 minutes"), async (request, response) => {
+ allowDevAllOrigin(response);
+
+ try {
+ let heartbeatList = {};
+ let uptimeList = {};
+
+ let slug = request.params.slug;
+ let statusPageID = await StatusPage.slugToID(slug);
+
+ let monitorIDList = await R.getCol(`
+ SELECT monitor_group.monitor_id FROM monitor_group, \`group\`
+ WHERE monitor_group.group_id = \`group\`.id
+ AND public = 1
+ AND \`group\`.status_page_id = ?
+ `, [
+ statusPageID
+ ]);
+
+ for (let monitorID of monitorIDList) {
+ let list = await R.getAll(`
+ SELECT * FROM heartbeat
+ WHERE monitor_id = ?
+ ORDER BY time DESC
+ LIMIT 50
+ `, [
+ monitorID,
+ ]);
+
+ list = R.convertToBeans("heartbeat", list);
+ heartbeatList[monitorID] = list.reverse().map(row => row.toPublicJSON());
+
+ const type = 24;
+ uptimeList[`${monitorID}_${type}`] = await Monitor.calcUptime(type, monitorID);
+ }
+
+ response.json({
+ heartbeatList,
+ uptimeList
+ });
+
+ } catch (error) {
+ send403(response, error.message);
+ }
+});
+
module.exports = router;
diff --git a/server/util-server.js b/server/util-server.js
index db7f525c..71b2c505 100644
--- a/server/util-server.js
+++ b/server/util-server.js
@@ -185,7 +185,7 @@ exports.dnsResolve = function (hostname, resolverServer, resolverPort, rrtype) {
// Remove brackets from IPv6 addresses so we can re-add them to
// prevent issues with ::1:5300 (::1 port 5300)
resolverServer = resolverServer.replace("[", "").replace("]", "");
- resolver.setServers([`[${resolverServer}]:${resolverPort}`]);
+ resolver.setServers([ `[${resolverServer}]:${resolverPort}` ]);
return new Promise((resolve, reject) => {
if (rrtype === "PTR") {
resolver.reverse(hostname, (err, records) => {
@@ -558,3 +558,15 @@ exports.percentageToColor = (percentage, maxHue = 90, minHue = 10) => {
exports.filterAndJoin = (parts, connector = "") => {
return parts.filter((part) => !!part && part !== "").join(connector);
};
+
+/**
+ * Send a 403 response
+ * @param {Object} res Express response object
+ * @param {string} [msg=""] Message to send
+ */
+module.exports.send403 = (res, msg = "") => {
+ res.status(403).json({
+ "status": "fail",
+ "msg": msg,
+ });
+};
diff --git a/src/pages/StatusPage.vue b/src/pages/StatusPage.vue
index c7502253..fbcbf9e8 100644
--- a/src/pages/StatusPage.vue
+++ b/src/pages/StatusPage.vue
@@ -538,7 +538,7 @@ export default {
this.slug = "default";
}
- axios.get("/api/status-page/" + this.slug).then((res) => {
+ this.getData().then((res) => {
this.config = res.data.config;
if (!this.config.domainNameList) {
@@ -567,6 +567,21 @@ export default {
},
methods: {
+ /**
+ * Get status page data
+ * It should be preloaded in window.preloadData
+ * @returns {Promise}
+ */
+ getData: function () {
+ if (window.preloadData) {
+ return new Promise(resolve => resolve({
+ data: window.preloadData
+ }));
+ } else {
+ return axios.get("/api/status-page/" + this.slug);
+ }
+ },
+
highlighter(code) {
return highlight(code, languages.css);
},