Render <StatusPage> if domain matched

This commit is contained in:
Louis Lam 2022-04-06 22:43:22 +08:00
parent fee88b32e3
commit c4e74c9943
6 changed files with 91 additions and 16 deletions

View file

@ -3,6 +3,20 @@ const { R } = require("redbean-node");
class StatusPage extends BeanModel { class StatusPage extends BeanModel {
static domainMappingList = { };
/**
* Return object like this: { "test-uptime.kuma.pet": "default" }
* @returns {Promise<void>}
*/
static async loadDomainMappingList() {
this.domainMappingList = await R.getAssoc(`
SELECT domain, slug
FROM status_page, status_page_cname
WHERE status_page.id = status_page_cname.status_page_id
`);
}
static async sendStatusPageList(io, socket) { static async sendStatusPageList(io, socket) {
let result = {}; let result = {};
@ -16,6 +30,18 @@ class StatusPage extends BeanModel {
return list; return list;
} }
getDomainList() {
let domainList = [];
for (let domain in StatusPage.domainMappingList) {
let s = StatusPage.domainMappingList[domain];
if (this.slug === s) {
domainList.push(domain);
}
}
return domainList;
}
async toJSON() { async toJSON() {
return { return {
id: this.id, id: this.id,
@ -26,6 +52,7 @@ class StatusPage extends BeanModel {
theme: this.theme, theme: this.theme,
published: !!this.published, published: !!this.published,
showTags: !!this.show_tags, showTags: !!this.show_tags,
domainList: this.getDomainList(),
}; };
} }

View file

@ -12,9 +12,19 @@ let router = express.Router();
let cache = apicache.middleware; let cache = apicache.middleware;
let io = server.io; let io = server.io;
router.get("/api/entry-page", async (_, response) => { router.get("/api/entry-page", async (request, response) => {
allowDevAllOrigin(response); allowDevAllOrigin(response);
response.json(server.entryPage);
let result = { };
if (request.hostname in StatusPage.domainMappingList) {
result.type = "statusPageMatchedDomain";
result.statusPageSlug = StatusPage.domainMappingList[request.hostname];
} else {
result.type = "entryPage";
result.entryPage = server.entryPage;
}
response.json(result);
}); });
router.get("/api/push/:pushToken", async (request, response) => { router.get("/api/push/:pushToken", async (request, response) => {

View file

@ -197,6 +197,7 @@ exports.entryPage = "dashboard";
await initDatabase(testMode); await initDatabase(testMode);
exports.entryPage = await setting("entryPage"); exports.entryPage = await setting("entryPage");
await StatusPage.loadDomainMappingList();
console.log("Adding route"); console.log("Adding route");
@ -205,8 +206,13 @@ exports.entryPage = "dashboard";
// *************************** // ***************************
// Entry Page // Entry Page
app.get("/", async (_request, response) => { app.get("/", async (request, response) => {
if (exports.entryPage && exports.entryPage.startsWith("statusPage-")) { debug(`Request Domain: ${request.hostname}`);
if (request.hostname in StatusPage.domainMappingList) {
debug("This is a status page domain");
response.send(indexHTML);
} else if (exports.entryPage && exports.entryPage.startsWith("statusPage-")) {
response.redirect("/status/" + exports.entryPage.replace("statusPage-", "")); response.redirect("/status/" + exports.entryPage.replace("statusPage-", ""));
} else { } else {
response.redirect("/dashboard"); response.redirect("/dashboard");

View file

@ -37,6 +37,7 @@ import {
faPen, faPen,
faExternalLinkSquareAlt, faExternalLinkSquareAlt,
faSpinner, faSpinner,
faUndo,
} from "@fortawesome/free-solid-svg-icons"; } from "@fortawesome/free-solid-svg-icons";
library.add( library.add(
@ -73,6 +74,7 @@ library.add(
faPen, faPen,
faExternalLinkSquareAlt, faExternalLinkSquareAlt,
faSpinner, faSpinner,
faUndo,
); );
export { FontAwesomeIcon }; export { FontAwesomeIcon };

View file

@ -1,23 +1,44 @@
<template> <template>
<div> <div>
<!-- <StatusPage v-if="statusPageSlug" override-slug="statusPageSlug" />
TODO: If the domain name matched, directly render the <StatusPage> component.
-->
</div> </div>
</template> </template>
<script> <script>
import axios from "axios"; import axios from "axios";
import StatusPage from "./StatusPage.vue";
export default { export default {
components: {
StatusPage,
},
data() {
return {
statusPageSlug: null,
};
},
async mounted() { async mounted() {
let entryPage = (await axios.get("/api/entry-page")).data;
// There are only 2 cases that could come in here.
// 1. Matched status Page domain name
// 2. Vue Frontend Dev
let res = (await axios.get("/api/entry-page")).data;
if (res.type === "statusPageMatchedDomain") {
this.statusPageSlug = res.statusPageSlug;
} else if (res.type === "entryPage") { // Dev only
const entryPage = res.entryPage;
if (entryPage === "statusPage") { if (entryPage === "statusPage") {
this.$router.push("/status"); this.$router.push("/status");
} else { } else {
this.$router.push("/dashboard"); this.$router.push("/dashboard");
} }
} else {
this.$router.push("/dashboard");
}
}, },
}; };

View file

@ -35,9 +35,9 @@
<input id="password" v-model="config.password" disabled type="password" autocomplete="new-password" class="form-control"> <input id="password" v-model="config.password" disabled type="password" autocomplete="new-password" class="form-control">
</div> </div>
<div v-if="false" class="my-3"> <div class="my-3">
<label for="cname" class="form-label">Domain Names <sup>Coming Soon</sup></label> <label for="cname" class="form-label">Domain Names</label>
<textarea id="cname" v-model="config.domanNames" rows="3" disabled class="form-control" :placeholder="domainNamesPlaceholder"></textarea> <textarea id="cname" v-model="config.domanNames" rows="3" class="form-control" :placeholder="domainNamesPlaceholder"></textarea>
</div> </div>
<div class="danger-zone"> <div class="danger-zone">
@ -55,7 +55,7 @@
</button> </button>
<button class="btn btn-danger me-2" @click="discard"> <button class="btn btn-danger me-2" @click="discard">
<font-awesome-icon icon="save" /> <font-awesome-icon icon="undo" />
{{ $t("Discard") }} {{ $t("Discard") }}
</button> </button>
</div> </div>
@ -259,6 +259,7 @@ const favicon = new Favico({
}); });
export default { export default {
components: { components: {
PublicGroupList, PublicGroupList,
ImageCropUpload, ImageCropUpload,
@ -278,6 +279,14 @@ export default {
next(); next();
}, },
props: {
overrideSlug: {
type: String,
required: false,
default: null,
},
},
data() { data() {
return { return {
slug: null, slug: null,
@ -294,7 +303,7 @@ export default {
loadedData: false, loadedData: false,
baseURL: "", baseURL: "",
clickedEditButton: false, clickedEditButton: false,
domainNamesPlaceholder: "domain1.com\ndomain2.com\n..." domainNamesPlaceholder: "example1.com\nexample2.com\n..."
}; };
}, },
computed: { computed: {
@ -449,7 +458,7 @@ export default {
this.baseURL = getResBaseURL(); this.baseURL = getResBaseURL();
}, },
async mounted() { async mounted() {
this.slug = this.$route.params.slug; this.slug = this.overrideSlug || this.$route.params.slug;
if (!this.slug) { if (!this.slug) {
this.slug = "default"; this.slug = "default";