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 {
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) {
let result = {};
@ -16,6 +30,18 @@ class StatusPage extends BeanModel {
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() {
return {
id: this.id,
@ -26,6 +52,7 @@ class StatusPage extends BeanModel {
theme: this.theme,
published: !!this.published,
showTags: !!this.show_tags,
domainList: this.getDomainList(),
};
}

View file

@ -12,9 +12,19 @@ let router = express.Router();
let cache = apicache.middleware;
let io = server.io;
router.get("/api/entry-page", async (_, response) => {
router.get("/api/entry-page", async (request, 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) => {

View file

@ -197,6 +197,7 @@ exports.entryPage = "dashboard";
await initDatabase(testMode);
exports.entryPage = await setting("entryPage");
await StatusPage.loadDomainMappingList();
console.log("Adding route");
@ -205,8 +206,13 @@ exports.entryPage = "dashboard";
// ***************************
// Entry Page
app.get("/", async (_request, response) => {
if (exports.entryPage && exports.entryPage.startsWith("statusPage-")) {
app.get("/", async (request, response) => {
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-", ""));
} else {
response.redirect("/dashboard");

View file

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

View file

@ -1,23 +1,44 @@
<template>
<div>
<!--
TODO: If the domain name matched, directly render the <StatusPage> component.
-->
<StatusPage v-if="statusPageSlug" override-slug="statusPageSlug" />
</div>
</template>
<script>
import axios from "axios";
import StatusPage from "./StatusPage.vue";
export default {
components: {
StatusPage,
},
data() {
return {
statusPageSlug: null,
};
},
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") {
this.$router.push("/status");
} else {
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">
</div>
<div v-if="false" class="my-3">
<label for="cname" class="form-label">Domain Names <sup>Coming Soon</sup></label>
<textarea id="cname" v-model="config.domanNames" rows="3" disabled class="form-control" :placeholder="domainNamesPlaceholder"></textarea>
<div class="my-3">
<label for="cname" class="form-label">Domain Names</label>
<textarea id="cname" v-model="config.domanNames" rows="3" class="form-control" :placeholder="domainNamesPlaceholder"></textarea>
</div>
<div class="danger-zone">
@ -55,7 +55,7 @@
</button>
<button class="btn btn-danger me-2" @click="discard">
<font-awesome-icon icon="save" />
<font-awesome-icon icon="undo" />
{{ $t("Discard") }}
</button>
</div>
@ -259,6 +259,7 @@ const favicon = new Favico({
});
export default {
components: {
PublicGroupList,
ImageCropUpload,
@ -278,6 +279,14 @@ export default {
next();
},
props: {
overrideSlug: {
type: String,
required: false,
default: null,
},
},
data() {
return {
slug: null,
@ -294,7 +303,7 @@ export default {
loadedData: false,
baseURL: "",
clickedEditButton: false,
domainNamesPlaceholder: "domain1.com\ndomain2.com\n..."
domainNamesPlaceholder: "example1.com\nexample2.com\n..."
};
},
computed: {
@ -449,7 +458,7 @@ export default {
this.baseURL = getResBaseURL();
},
async mounted() {
this.slug = this.$route.params.slug;
this.slug = this.overrideSlug || this.$route.params.slug;
if (!this.slug) {
this.slug = "default";