Compare commits

...

3 commits

Author SHA1 Message Date
hadestructhor
6bade1fe81 feat: add support for plausible, cleanup and refactor code 2025-02-19 00:08:30 +01:00
hadestructhor
cda2ae5568
Merge branch 'master' into feature/umami-analytics-status-page 2025-02-18 23:26:45 +01:00
Zaid Hafeez
b45dc6787d
Use GitHub's new "GitHub Hosted" Ubuntu ARM runner (#5587)
Some checks failed
Auto Test / e2e-test (push) Has been cancelled
Auto Test / armv7-simple-test (18, ARMv7) (push) Has been cancelled
Auto Test / armv7-simple-test (20, ARMv7) (push) Has been cancelled
Auto Test / check-linters (push) Has been cancelled
CodeQL / Analyze (push) Has been cancelled
Merge Conflict Labeler / Labeling (push) Has been cancelled
validate / json-yaml-validate (push) Has been cancelled
validate / validate (push) Has been cancelled
Auto Test / auto-test (18, ARM64) (push) Has been cancelled
Auto Test / auto-test (18, macos-latest) (push) Has been cancelled
Auto Test / auto-test (18, ubuntu-latest) (push) Has been cancelled
Auto Test / auto-test (18, windows-latest) (push) Has been cancelled
Auto Test / auto-test (20, ARM64) (push) Has been cancelled
Auto Test / auto-test (20, macos-latest) (push) Has been cancelled
Auto Test / auto-test (20, ubuntu-latest) (push) Has been cancelled
Auto Test / auto-test (20, windows-latest) (push) Has been cancelled
Co-authored-by: Frank Elsinga <frank@elsinga.de>
2025-02-16 21:06:19 +01:00
7 changed files with 97 additions and 11 deletions

View file

@ -78,7 +78,7 @@ jobs:
e2e-test:
needs: [ ]
runs-on: ARM64
runs-on: ubuntu-24.04-arm
steps:
- run: git config --global core.autocrlf false # Mainly for Windows
- uses: actions/checkout@v4

View file

@ -0,0 +1,44 @@
const googleAnalytics = require("./google-analytics");
const umamiAnalytics = require("./umami-analytics");
const plausibleAnalytics = require("./plausible-analytics");
/**
* Returns a string that represents the javascript that is required to insert the selected Analytics' script
* into a webpage.
* @param {typeof import("../model/status_page").StatusPage} statusPage Status page populate HTML with
* @returns {string} HTML script tags to inject into page
*/
function getAnalyticsScript(statusPage) {
switch (statusPage.analyticsType) {
case "google":
return googleAnalytics.getGoogleAnalyticsScript(statusPage.analyticsId);
case "umami":
return umamiAnalytics.getUmamiAnalyticsScript(statusPage.analyticsDomainUrl, statusPage.analyticsId);
case "plausible":
return plausibleAnalytics.getPlausibleAnalyticsScript(statusPage.analyticsDomainUrl, statusPage.analyticsId);
default:
return null;
}
}
/**
* Function that checks wether the selected analytics has been configured properly
* @param {typeof import("../model/status_page").StatusPage} statusPage Status page populate HTML with
* @returns {boolean} Boolean defining if the analytics config is valid
*/
function isValidAnalyticsConfig(statusPage) {
switch (statusPage.analyticsType) {
case "google":
return statusPage.analyticsId != null;
case "umami":
case "plausible":
return statusPage.analyticsId != null && statusPage.analyticsDomainUrl != null;
default:
return false;
}
}
module.exports = {
getAnalyticsScript,
isValidAnalyticsConfig
};

View file

@ -0,0 +1,36 @@
const jsesc = require("jsesc");
const { escape } = require("html-escaper");
/**
* Returns a string that represents the javascript that is required to insert the Plausible Analytics script
* into a webpage.
* @param {string} plausibleDomainUrl Domain name with tld to use with the Plausible Analytics script.
* @param {string} domainsToMonitor Domains to track seperated by a ',' to add Plausible Analytics script.
* @returns {string} HTML script tags to inject into page
*/
function getPlausibleAnalyticsScript(plausibleDomainUrl, domainsToMonitor) {
let escapedDomainUrlJS = jsesc(plausibleDomainUrl, { isScriptContext: true });
let escapedWebsiteIdJS = jsesc(domainsToMonitor, { isScriptContext: true });
if (escapedDomainUrlJS) {
escapedDomainUrlJS = escapedDomainUrlJS.trim();
}
if (escapedWebsiteIdJS) {
escapedWebsiteIdJS = escapedWebsiteIdJS.trim();
}
// Escape the domain url for use in an HTML attribute.
let escapedDomainUrlHTMLAttribute = escape(escapedDomainUrlJS);
// Escape the website id for use in an HTML attribute.
let escapedWebsiteIdHTMLAttribute = escape(escapedWebsiteIdJS);
return `
<script defer src="https://${escapedDomainUrlHTMLAttribute}/js/script.js" data-domain="${escapedWebsiteIdHTMLAttribute}"></script>
`;
}
module.exports = {
getPlausibleAnalyticsScript
};

View file

@ -3,8 +3,7 @@ const { R } = require("redbean-node");
const cheerio = require("cheerio");
const { UptimeKumaServer } = require("../uptime-kuma-server");
const jsesc = require("jsesc");
const googleAnalytics = require("../google-analytics");
const umamiAnalytics = require("../umami-analytics");
const analytics = require("../analytics/analytics");
const { marked } = require("marked");
const { Feed } = require("feed");
const config = require("../config");
@ -121,14 +120,9 @@ class StatusPage extends BeanModel {
const head = $("head");
if (statusPage.analyticsType === "google" && statusPage.analyticsId) {
let escapedGoogleAnalyticsScript = googleAnalytics.getGoogleAnalyticsScript(statusPage.analyticsId);
head.append($(escapedGoogleAnalyticsScript));
}
if (statusPage.analyticsType === "umami" && statusPage.analyticsDomainUrl && statusPage.analyticsId) {
let escapedUmamiAnalyticsScript = umamiAnalytics.getUmamiAnalyticsScript(statusPage.analyticsDomainUrl, statusPage.analyticsId);
head.append($(escapedUmamiAnalyticsScript));
if (analytics.isValidAnalyticsConfig(statusPage)) {
let escapedAnalyticsScript = analytics.getAnalyticsScript(statusPage);
head.append($(escapedAnalyticsScript));
}
// OG Meta Tags

View file

@ -20,6 +20,8 @@ test.describe("Status Page", () => {
const googleAnalyticsId = "G-123";
const umamiAnalyticsDomainUrl = "example.com";
const umamiAnalyticsWebsiteId = "606487e2-bc25-45f9-9132-fa8b065aad46";
const plausibleAnalyticsDomainUrl = "example.com";
const plausibleAnalyticsDomainsUrls = "one.com,two.com";
const customCss = "body { background: rgb(0, 128, 128) !important; }";
const descriptionText = "This is an example status page.";
const incidentTitle = "Example Outage Incident";
@ -132,6 +134,16 @@ test.describe("Status Page", () => {
expect(await page.locator("head").innerHTML()).toContain(umamiAnalyticsDomainUrl);
expect(await page.locator("head").innerHTML()).toContain(umamiAnalyticsWebsiteId);
await page.getByTestId("edit-button").click();
// Fill in plausible analytics after editing
await page.getByTestId("analytics-type-select").selectOption("plausible");
await page.getByTestId("analytics-domain-url-input").fill(plausibleAnalyticsDomainUrl);
await page.getByTestId("analytics-id-input").fill(plausibleAnalyticsDomainsUrls);
await page.getByTestId("save-button").click();
await screenshot(testInfo, page);
expect(await page.locator("head").innerHTML()).toContain(plausibleAnalyticsDomainUrl);
expect(await page.locator("head").innerHTML()).toContain(plausibleAnalyticsDomainsUrls);
});
// @todo Test certificate expiry