mirror of
https://github.com/louislam/uptime-kuma.git
synced 2024-12-24 21:24:28 -08:00
[Status Page] wip, combine api, add status_page_id into group and incident tables
This commit is contained in:
parent
18ec42b060
commit
1033ca5cf4
|
@ -25,4 +25,7 @@ CREATE TABLE [status_page_cname](
|
||||||
[domain] VARCHAR NOT NULL UNIQUE
|
[domain] VARCHAR NOT NULL UNIQUE
|
||||||
);
|
);
|
||||||
|
|
||||||
|
ALTER TABLE incident ADD status_page_id INTEGER;
|
||||||
|
ALTER TABLE [group] ADD status_page_id INTEGER;
|
||||||
|
|
||||||
COMMIT;
|
COMMIT;
|
||||||
|
|
|
@ -240,8 +240,18 @@ class Database {
|
||||||
statusPage.search_engine_index = await setting("searchEngineIndex");
|
statusPage.search_engine_index = await setting("searchEngineIndex");
|
||||||
statusPage.show_tags = await setting("statusPageTags");
|
statusPage.show_tags = await setting("statusPageTags");
|
||||||
statusPage.password = null;
|
statusPage.password = null;
|
||||||
await R.store(statusPage);
|
let id = await R.store(statusPage);
|
||||||
|
|
||||||
|
await R.exec("UPDATE incident SET status_page_id = ? WHERE status_page_id IS NULL", [
|
||||||
|
id
|
||||||
|
]);
|
||||||
|
|
||||||
|
await R.exec("UPDATE [group] SET status_page_id = ? WHERE status_page_id IS NULL", [
|
||||||
|
id
|
||||||
|
]);
|
||||||
|
|
||||||
await R.exec("DELETE FROM setting WHERE type = 'statusPage'");
|
await R.exec("DELETE FROM setting WHERE type = 'statusPage'");
|
||||||
|
|
||||||
console.log("Migrating Status Page - Done");
|
console.log("Migrating Status Page - Done");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,12 @@ class StatusPage extends BeanModel {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static async slugToID(slug) {
|
||||||
|
return await R.getCell("SELECT id FROM status_page WHERE slug = ? ", [
|
||||||
|
slug
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = StatusPage;
|
module.exports = StatusPage;
|
||||||
|
|
|
@ -6,6 +6,7 @@ const apicache = require("../modules/apicache");
|
||||||
const Monitor = require("../model/monitor");
|
const Monitor = require("../model/monitor");
|
||||||
const dayjs = require("dayjs");
|
const dayjs = require("dayjs");
|
||||||
const { UP, flipStatus, debug } = require("../../src/util");
|
const { UP, flipStatus, debug } = require("../../src/util");
|
||||||
|
const StatusPage = require("../model/status_page");
|
||||||
let router = express.Router();
|
let router = express.Router();
|
||||||
|
|
||||||
let cache = apicache.middleware;
|
let cache = apicache.middleware;
|
||||||
|
@ -82,11 +83,12 @@ router.get("/api/push/:pushToken", async (request, response) => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Status Page Config
|
// Status page config, incident, monitor list
|
||||||
router.get("/api/status-page/config/:slug", async (request, response) => {
|
router.get("/api/status-page/:slug", cache("5 minutes"), async (request, response) => {
|
||||||
allowDevAllOrigin(response);
|
allowDevAllOrigin(response);
|
||||||
let slug = request.params.slug;
|
let slug = request.params.slug;
|
||||||
|
|
||||||
|
// Get Status Page
|
||||||
let statusPage = await R.findOne("status_page", " slug = ? ", [
|
let statusPage = await R.findOne("status_page", " slug = ? ", [
|
||||||
slug
|
slug
|
||||||
]);
|
]);
|
||||||
|
@ -99,50 +101,30 @@ router.get("/api/status-page/config/:slug", async (request, response) => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
response.json(await statusPage.toPublicJSON());
|
|
||||||
});
|
|
||||||
|
|
||||||
// Status Page - Get the current Incident
|
|
||||||
// Can fetch only if published
|
|
||||||
router.get("/api/status-page/incident/:slug", async (_, response) => {
|
|
||||||
allowDevAllOrigin(response);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await checkPublished();
|
// Incident
|
||||||
|
let incident = await R.findOne("incident", " pin = 1 AND active = 1 AND status_page_id = ? ", [
|
||||||
let incident = await R.findOne("incident", " pin = 1 AND active = 1");
|
statusPage.id,
|
||||||
|
]);
|
||||||
|
|
||||||
if (incident) {
|
if (incident) {
|
||||||
incident = incident.toPublicJSON();
|
incident = incident.toPublicJSON();
|
||||||
}
|
}
|
||||||
|
|
||||||
response.json({
|
// Public Group List
|
||||||
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/:slug", cache("5 minutes"), async (_request, response) => {
|
|
||||||
allowDevAllOrigin(response);
|
|
||||||
|
|
||||||
try {
|
|
||||||
await checkPublished();
|
|
||||||
const publicGroupList = [];
|
const publicGroupList = [];
|
||||||
const tagsVisible = (await getSettings("statusPage")).statusPageTags;
|
const tagsVisible = !!statusPage.show_tags;
|
||||||
const list = await R.find("group", " public = 1 ORDER BY weight ");
|
const list = await R.find("group", " public = 1 AND status_page_id = ? ORDER BY weight ", [
|
||||||
|
statusPage.id
|
||||||
|
]);
|
||||||
|
|
||||||
for (let groupBean of list) {
|
for (let groupBean of list) {
|
||||||
let monitorGroup = await groupBean.toPublicJSON();
|
let monitorGroup = await groupBean.toPublicJSON();
|
||||||
if (tagsVisible) {
|
if (tagsVisible) {
|
||||||
monitorGroup.monitorList = await Promise.all(monitorGroup.monitorList.map(async (monitor) => {
|
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
|
// Includes tags as an array in response, allows for tags to be displayed on public status page
|
||||||
const tags = await R.getAll(
|
const tags = await R.getAll(
|
||||||
`SELECT monitor_tag.monitor_id, monitor_tag.value, tag.name, tag.color
|
`SELECT monitor_tag.monitor_id, monitor_tag.value, tag.name, tag.color
|
||||||
FROM monitor_tag
|
FROM monitor_tag
|
||||||
JOIN tag
|
JOIN tag
|
||||||
ON monitor_tag.tag_id = tag.id
|
ON monitor_tag.tag_id = tag.id
|
||||||
|
@ -158,29 +140,39 @@ router.get("/api/status-page/monitor-list/:slug", cache("5 minutes"), async (_re
|
||||||
publicGroupList.push(monitorGroup);
|
publicGroupList.push(monitorGroup);
|
||||||
}
|
}
|
||||||
|
|
||||||
response.json(publicGroupList);
|
// Response
|
||||||
|
response.json({
|
||||||
|
config: await statusPage.toPublicJSON(),
|
||||||
|
incident,
|
||||||
|
publicGroupList
|
||||||
|
});
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
send403(response, error.message);
|
send403(response, error.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Status Page Polling Data
|
// Status Page Polling Data
|
||||||
// Can fetch only if published
|
// Can fetch only if published
|
||||||
router.get("/api/status-page/heartbeat/:slug", cache("5 minutes"), async (_request, response) => {
|
router.get("/api/status-page/heartbeat/:slug", cache("1 minutes"), async (request, response) => {
|
||||||
allowDevAllOrigin(response);
|
allowDevAllOrigin(response);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await checkPublished();
|
|
||||||
|
|
||||||
let heartbeatList = {};
|
let heartbeatList = {};
|
||||||
let uptimeList = {};
|
let uptimeList = {};
|
||||||
|
|
||||||
|
let slug = request.params.slug;
|
||||||
|
let statusPageID = await StatusPage.slugToID(slug);
|
||||||
|
|
||||||
let monitorIDList = await R.getCol(`
|
let monitorIDList = await R.getCol(`
|
||||||
SELECT monitor_group.monitor_id FROM monitor_group, \`group\`
|
SELECT monitor_group.monitor_id FROM monitor_group, \`group\`
|
||||||
WHERE monitor_group.group_id = \`group\`.id
|
WHERE monitor_group.group_id = \`group\`.id
|
||||||
AND public = 1
|
AND public = 1
|
||||||
`);
|
AND \`group\`.status_page_id = ?
|
||||||
|
`, [
|
||||||
|
statusPageID
|
||||||
|
]);
|
||||||
|
|
||||||
for (let monitorID of monitorIDList) {
|
for (let monitorID of monitorIDList) {
|
||||||
let list = await R.getAll(`
|
let list = await R.getAll(`
|
||||||
|
@ -209,12 +201,6 @@ router.get("/api/status-page/heartbeat/:slug", cache("5 minutes"), async (_reque
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
async function checkPublished() {
|
|
||||||
if (! await isPublished()) {
|
|
||||||
throw new Error("The status page is not published");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default is published
|
* Default is published
|
||||||
* @returns {Promise<boolean>}
|
* @returns {Promise<boolean>}
|
||||||
|
|
|
@ -5,21 +5,31 @@ const { debug } = require("../../src/util");
|
||||||
const ImageDataURI = require("../image-data-uri");
|
const ImageDataURI = require("../image-data-uri");
|
||||||
const Database = require("../database");
|
const Database = require("../database");
|
||||||
const apicache = require("../modules/apicache");
|
const apicache = require("../modules/apicache");
|
||||||
|
const StatusPage = require("../model/status_page");
|
||||||
|
|
||||||
module.exports.statusPageSocketHandler = (socket) => {
|
module.exports.statusPageSocketHandler = (socket) => {
|
||||||
|
|
||||||
// Post or edit incident
|
// Post or edit incident
|
||||||
socket.on("postIncident", async (incident, callback) => {
|
socket.on("postIncident", async (slug, incident, callback) => {
|
||||||
try {
|
try {
|
||||||
checkLogin(socket);
|
checkLogin(socket);
|
||||||
|
|
||||||
await R.exec("UPDATE incident SET pin = 0 ");
|
let statusPageID = await StatusPage.slugToID(slug);
|
||||||
|
|
||||||
|
if (!statusPageID) {
|
||||||
|
throw new Error("slug is not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
await R.exec("UPDATE incident SET pin = 0 WHERE status_page_id = ? ", [
|
||||||
|
statusPageID
|
||||||
|
]);
|
||||||
|
|
||||||
let incidentBean;
|
let incidentBean;
|
||||||
|
|
||||||
if (incident.id) {
|
if (incident.id) {
|
||||||
incidentBean = await R.findOne("incident", " id = ?", [
|
incidentBean = await R.findOne("incident", " id = ? AND status_page_id = ? ", [
|
||||||
incident.id
|
incident.id,
|
||||||
|
statusPageID
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,6 +41,7 @@ module.exports.statusPageSocketHandler = (socket) => {
|
||||||
incidentBean.content = incident.content;
|
incidentBean.content = incident.content;
|
||||||
incidentBean.style = incident.style;
|
incidentBean.style = incident.style;
|
||||||
incidentBean.pin = true;
|
incidentBean.pin = true;
|
||||||
|
incidentBean.status_page_id = statusPageID;
|
||||||
|
|
||||||
if (incident.id) {
|
if (incident.id) {
|
||||||
incidentBean.lastUpdatedDate = R.isoDateTime(dayjs.utc());
|
incidentBean.lastUpdatedDate = R.isoDateTime(dayjs.utc());
|
||||||
|
@ -52,11 +63,15 @@ module.exports.statusPageSocketHandler = (socket) => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on("unpinIncident", async (callback) => {
|
socket.on("unpinIncident", async (slug, callback) => {
|
||||||
try {
|
try {
|
||||||
checkLogin(socket);
|
checkLogin(socket);
|
||||||
|
|
||||||
await R.exec("UPDATE incident SET pin = 0 WHERE pin = 1");
|
let statusPageID = await StatusPage.slugToID(slug);
|
||||||
|
|
||||||
|
await R.exec("UPDATE incident SET pin = 0 WHERE pin = 1 AND status_page_id = ? ", [
|
||||||
|
statusPageID
|
||||||
|
]);
|
||||||
|
|
||||||
callback({
|
callback({
|
||||||
ok: true,
|
ok: true,
|
||||||
|
@ -125,13 +140,15 @@ module.exports.statusPageSocketHandler = (socket) => {
|
||||||
for (let group of publicGroupList) {
|
for (let group of publicGroupList) {
|
||||||
let groupBean;
|
let groupBean;
|
||||||
if (group.id) {
|
if (group.id) {
|
||||||
groupBean = await R.findOne("group", " id = ? AND public = 1 ", [
|
groupBean = await R.findOne("group", " id = ? AND public = 1 AND status_page_id = ? ", [
|
||||||
group.id
|
group.id,
|
||||||
|
statusPage.id
|
||||||
]);
|
]);
|
||||||
} else {
|
} else {
|
||||||
groupBean = R.dispense("group");
|
groupBean = R.dispense("group");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
groupBean.status_page_id = statusPage.id;
|
||||||
groupBean.name = group.name;
|
groupBean.name = group.name;
|
||||||
groupBean.public = true;
|
groupBean.public = true;
|
||||||
groupBean.weight = groupOrder++;
|
groupBean.weight = groupOrder++;
|
||||||
|
@ -143,7 +160,6 @@ module.exports.statusPageSocketHandler = (socket) => {
|
||||||
]);
|
]);
|
||||||
|
|
||||||
let monitorOrder = 1;
|
let monitorOrder = 1;
|
||||||
console.log(group.monitorList);
|
|
||||||
|
|
||||||
for (let monitor of group.monitorList) {
|
for (let monitor of group.monitorList) {
|
||||||
let relationBean = R.dispense("monitor_group");
|
let relationBean = R.dispense("monitor_group");
|
||||||
|
|
|
@ -404,9 +404,12 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
"config.showTags"(value) {
|
"config.showTags"(value) {
|
||||||
console.log("here???");
|
|
||||||
this.changeTagsVisibility(value);
|
this.changeTagsVisibility(value);
|
||||||
}
|
},
|
||||||
|
|
||||||
|
"$root.monitorList"() {
|
||||||
|
this.changeTagsVisibility(this.config.showTags);
|
||||||
|
},
|
||||||
|
|
||||||
},
|
},
|
||||||
async created() {
|
async created() {
|
||||||
|
@ -437,29 +440,14 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
axios.get("/api/status-page/" + this.slug).then((res) => {
|
axios.get("/api/status-page/" + this.slug).then((res) => {
|
||||||
this.config = res.data;
|
this.config = res.data.config;
|
||||||
|
|
||||||
if (this.config.logo) {
|
if (this.config.logo) {
|
||||||
this.imgDataUrl = this.config.logo;
|
this.imgDataUrl = this.config.logo;
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
axios.get("/api/status-page/config/" + this.slug).then((res) => {
|
this.incident = res.data.incident;
|
||||||
this.config = res.data;
|
this.$root.publicGroupList = res.data.publicGroupList;
|
||||||
|
|
||||||
if (this.config.logo) {
|
|
||||||
this.imgDataUrl = this.config.logo;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
axios.get("/api/status-page/incident/" + this.slug).then((res) => {
|
|
||||||
if (res.data.ok) {
|
|
||||||
this.incident = res.data.incident;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
axios.get("/api/status-page/monitor-list/" + this.slug).then((res) => {
|
|
||||||
this.$root.publicGroupList = res.data;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// 5mins a loop
|
// 5mins a loop
|
||||||
|
@ -560,21 +548,27 @@ export default {
|
||||||
|
|
||||||
changeTagsVisibility(show) {
|
changeTagsVisibility(show) {
|
||||||
|
|
||||||
// On load, the status page will not include tags if it's not enabled for security reasons
|
// If Edit Mode
|
||||||
// Which means if we enable tags, it won't show in the UI until saved
|
if (Object.keys(this.$root.monitorList).length > 0) {
|
||||||
// So we have this to enhance UX and load in the tags from the authenticated source instantly
|
// On load, the status page will not include tags if it's not enabled for security reasons
|
||||||
this.$root.publicGroupList = this.$root.publicGroupList.map((group) => {
|
// Which means if we enable tags, it won't show in the UI until saved
|
||||||
return {
|
// So we have this to enhance UX and load in the tags from the authenticated source instantly
|
||||||
...group,
|
this.$root.publicGroupList = this.$root.publicGroupList.map((group) => {
|
||||||
monitorList: group.monitorList.map((monitor) => {
|
return {
|
||||||
// We only include the tags if visible so we can reuse the logic to hide the tags on disable
|
...group,
|
||||||
return {
|
monitorList: group.monitorList.map((monitor) => {
|
||||||
...monitor,
|
// We only include the tags if visible so we can reuse the logic to hide the tags on disable
|
||||||
tags: show ? this.$root.monitorList[monitor.id].tags : []
|
return {
|
||||||
};
|
...monitor,
|
||||||
})
|
tags: show ? this.$root.monitorList[monitor.id].tags : []
|
||||||
};
|
};
|
||||||
});
|
})
|
||||||
|
};
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -610,7 +604,7 @@ export default {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.$root.getSocket().emit("postIncident", this.incident, (res) => {
|
this.$root.getSocket().emit("postIncident", this.slug, this.incident, (res) => {
|
||||||
|
|
||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
this.enableEditIncidentMode = false;
|
this.enableEditIncidentMode = false;
|
||||||
|
|
Loading…
Reference in a new issue