mirror of
https://github.com/louislam/uptime-kuma.git
synced 2024-11-10 15:44:15 -08:00
12ef9f39c5
Also to note: due to the transition of tagsVisible this breaks compatibility with the previous commits, delete the tagsVisible setting in the database to fix.
245 lines
6.7 KiB
JavaScript
245 lines
6.7 KiB
JavaScript
let express = require("express");
|
|
const { allowDevAllOrigin, getSettings, setting } = require("../util-server");
|
|
const { R } = require("redbean-node");
|
|
const server = require("../server");
|
|
const apicache = require("../modules/apicache");
|
|
const Monitor = require("../model/monitor");
|
|
const dayjs = require("dayjs");
|
|
const { UP, flipStatus, debug } = require("../../src/util");
|
|
let router = express.Router();
|
|
|
|
let cache = apicache.middleware;
|
|
let io = server.io;
|
|
|
|
router.get("/api/entry-page", async (_, response) => {
|
|
allowDevAllOrigin(response);
|
|
response.json(server.entryPage);
|
|
});
|
|
|
|
router.get("/api/push/:pushToken", async (request, response) => {
|
|
try {
|
|
|
|
let pushToken = request.params.pushToken;
|
|
let msg = request.query.msg || "OK";
|
|
let ping = request.query.ping || null;
|
|
|
|
let monitor = await R.findOne("monitor", " push_token = ? AND active = 1 ", [
|
|
pushToken
|
|
]);
|
|
|
|
if (! monitor) {
|
|
throw new Error("Monitor not found or not active.");
|
|
}
|
|
|
|
const previousHeartbeat = await R.getRow(`
|
|
SELECT status, time FROM heartbeat
|
|
WHERE id = (select MAX(id) from heartbeat where monitor_id = ?)
|
|
`, [
|
|
monitor.id
|
|
]);
|
|
|
|
let status = UP;
|
|
if (monitor.isUpsideDown()) {
|
|
status = flipStatus(status);
|
|
}
|
|
|
|
let isFirstBeat = true;
|
|
let previousStatus = status;
|
|
let duration = 0;
|
|
|
|
let bean = R.dispense("heartbeat");
|
|
bean.time = R.isoDateTime(dayjs.utc());
|
|
|
|
if (previousHeartbeat) {
|
|
isFirstBeat = false;
|
|
previousStatus = previousHeartbeat.status;
|
|
duration = dayjs(bean.time).diff(dayjs(previousHeartbeat.time), "second");
|
|
}
|
|
|
|
debug("PreviousStatus: " + previousStatus);
|
|
debug("Current Status: " + status);
|
|
|
|
bean.important = Monitor.isImportantBeat(isFirstBeat, previousStatus, status);
|
|
bean.monitor_id = monitor.id;
|
|
bean.status = status;
|
|
bean.msg = msg;
|
|
bean.ping = ping;
|
|
bean.duration = duration;
|
|
|
|
await R.store(bean);
|
|
|
|
io.to(monitor.user_id).emit("heartbeat", bean.toJSON());
|
|
Monitor.sendStats(io, monitor.id, monitor.user_id);
|
|
|
|
response.json({
|
|
ok: true,
|
|
});
|
|
|
|
if (bean.important) {
|
|
await Monitor.sendNotification(isFirstBeat, monitor, bean);
|
|
}
|
|
|
|
} catch (e) {
|
|
response.json({
|
|
ok: false,
|
|
msg: e.message
|
|
});
|
|
}
|
|
});
|
|
|
|
// Status Page Config
|
|
router.get("/api/status-page/config", async (_request, response) => {
|
|
allowDevAllOrigin(response);
|
|
|
|
let config = await getSettings("statusPage");
|
|
|
|
if (! config.statusPageTheme) {
|
|
config.statusPageTheme = "light";
|
|
}
|
|
|
|
if (! config.statusPagePublished) {
|
|
config.statusPagePublished = true;
|
|
}
|
|
|
|
if (! config.statusPageTags) {
|
|
config.statusPageTags = false;
|
|
}
|
|
|
|
if (! config.title) {
|
|
config.title = "Uptime Kuma";
|
|
}
|
|
|
|
response.json(config);
|
|
});
|
|
|
|
// Status Page - Get the current Incident
|
|
// Can fetch only if published
|
|
router.get("/api/status-page/incident", async (_, response) => {
|
|
allowDevAllOrigin(response);
|
|
|
|
try {
|
|
await checkPublished();
|
|
|
|
let incident = await R.findOne("incident", " pin = 1 AND active = 1");
|
|
|
|
if (incident) {
|
|
incident = incident.toPublicJSON();
|
|
}
|
|
|
|
response.json({
|
|
ok: true,
|
|
incident,
|
|
});
|
|
|
|
} catch (error) {
|
|
send403(response, error.message);
|
|
}
|
|
});
|
|
|
|
// Status Page - Monitor List
|
|
// Can fetch only if published
|
|
router.get("/api/status-page/monitor-list", cache("5 minutes"), async (_request, response) => {
|
|
allowDevAllOrigin(response);
|
|
|
|
try {
|
|
await checkPublished();
|
|
const publicGroupList = [];
|
|
const tagsVisible = (await getSettings("statusPage")).statusPageTags;
|
|
const list = await R.find("group", " public = 1 ORDER BY weight ");
|
|
for (let groupBean of list) {
|
|
let monitorGroup = await groupBean.toPublicJSON();
|
|
if (tagsVisible) {
|
|
monitorGroup.monitorList = await Promise.all(monitorGroup.monitorList.map( async (monitor)=>{
|
|
// Includes tags as an array in response, allows for tags to be displayed on public status page
|
|
const tags = await R.getAll(
|
|
`SELECT monitor_tag.monitor_id, monitor_tag.value, tag.name, tag.color
|
|
FROM monitor_tag
|
|
JOIN tag
|
|
ON monitor_tag.tag_id = tag.id
|
|
WHERE monitor_tag.monitor_id = ?`, [monitor.id]
|
|
);
|
|
return {...monitor,tags: tags}
|
|
}));
|
|
}
|
|
|
|
publicGroupList.push(monitorGroup);
|
|
}
|
|
|
|
response.json(publicGroupList);
|
|
|
|
} catch (error) {
|
|
send403(response, error.message);
|
|
}
|
|
});
|
|
|
|
// Status Page Polling Data
|
|
// Can fetch only if published
|
|
router.get("/api/status-page/heartbeat", cache("5 minutes"), async (_request, response) => {
|
|
allowDevAllOrigin(response);
|
|
|
|
try {
|
|
await checkPublished();
|
|
|
|
let heartbeatList = {};
|
|
let uptimeList = {};
|
|
|
|
let monitorIDList = await R.getCol(`
|
|
SELECT monitor_group.monitor_id FROM monitor_group, \`group\`
|
|
WHERE monitor_group.group_id = \`group\`.id
|
|
AND public = 1
|
|
`);
|
|
|
|
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);
|
|
}
|
|
});
|
|
|
|
async function checkPublished() {
|
|
if (! await isPublished()) {
|
|
throw new Error("The status page is not published");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Default is published
|
|
* @returns {Promise<boolean>}
|
|
*/
|
|
async function isPublished() {
|
|
const value = await setting("statusPagePublished");
|
|
if (value === null) {
|
|
return true;
|
|
}
|
|
return value;
|
|
}
|
|
|
|
function send403(res, msg = "") {
|
|
res.status(403).json({
|
|
"status": "fail",
|
|
"msg": msg,
|
|
});
|
|
}
|
|
|
|
module.exports = router;
|