Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add status page summary API #1927

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
9 changes: 5 additions & 4 deletions server/model/group.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,20 @@ const { R } = require("redbean-node");
class Group extends BeanModel {

/**
* Return an object that ready to parse to JSON for public Only show
* necessary data to public
* Return an object that ready to parse to JSON for public
* Only show necessary data to public
* @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>} Object ready to parse
*/
async toPublicJSON(showTags = false, certExpiry = false) {
async toPublicJSON(showTags = false, certExpiry = false, showStatus = false) {
let monitorBeanList = await this.getMonitorList();
let monitorList = [];

for (let bean of monitorBeanList) {
monitorList.push(await bean.toPublicJSON(showTags, certExpiry));
monitorList.push(await bean.toPublicJSON(showTags, certExpiry, showStatus));
}

return {
Expand Down
23 changes: 22 additions & 1 deletion server/model/monitor.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,31 @@ const rootCertificates = rootCertificatesFingerprints();
*/
class Monitor extends BeanModel {

/**
* 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) {
Empty2k12 marked this conversation as resolved.
Show resolved Hide resolved
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
* @param {boolean} showTags Include tags in JSON
* @param {boolean} certExpiry Include certificate expiry info in
* JSON
* @param {boolean} showStatus Should the JSON show the status
* @returns {Promise<object>} Object ready to parse
*/
async toPublicJSON(showTags = false, certExpiry = false) {
async toPublicJSON(showTags = false, certExpiry = false, showStatus = false) {
let obj = {
id: this.id,
name: this.name,
Expand All @@ -66,6 +82,11 @@ class Monitor extends BeanModel {
obj.validCert = validCert;
}

if (showStatus) {
const heartbeat = await Monitor.getPreviousHeartbeat(this.id);
obj.status = this.statusToKey(heartbeat.status);
}

return obj;
}

Expand Down
21 changes: 14 additions & 7 deletions server/model/status_page.js
Original file line number Diff line number Diff line change
Expand Up @@ -257,12 +257,12 @@ class StatusPage extends BeanModel {

/**
* Get all status page data in one call
* @param {StatusPage} statusPage Status page to get data for
* @returns {object} Status page data
* @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) {
const config = await statusPage.toPublicJSON();

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,
Expand All @@ -283,13 +283,20 @@ class StatusPage extends BeanModel {
]);

for (let groupBean of list) {
let monitorGroup = await groupBean.toPublicJSON(showTags, config?.showCertificateExpiry);
let monitorGroup = await groupBean.toPublicJSON(showTags, false, includeStatus);
publicGroupList.push(monitorGroup);
}

let config = {};
if (includeConfig) {
config = {
config: await statusPage.toPublicJSON()
};
}

// Response
return {
config,
...config,
incident,
publicGroupList,
maintenanceList,
Expand Down
35 changes: 34 additions & 1 deletion server/routers/status-page-router.js
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down Expand Up @@ -33,6 +33,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, false);

if (!statusPageData) {
response.statusCode = 404;
response.json({
msg: "Not Found"
});
return;
}

// Response
response.json(statusPageData);

} catch (error) {
sendHttpError(response, error.message);
}
});

// Status page config, incident, monitor list
router.get("/api/status-page/:slug", cache("5 minutes"), async (request, response) => {
allowDevAllOrigin(response);
Expand Down
Loading