diff --git a/server/config.js b/server/config.js index 8a9a67f83..f47765077 100644 --- a/server/config.js +++ b/server/config.js @@ -6,6 +6,11 @@ const badgeConstants = { defaultUpColor: "#66c20a", defaultDownColor: "#c2290a", defaultPingColor: "blue", // as defined by badge-maker / shields.io + defaultStyle: "flat", + defaultPingValueSuffix: "ms", + defaultPingLabelSuffix: "h", + defaultUptimeValueSuffix: "%", + defaultUptimeLabelSuffix: "h", }; module.exports = { diff --git a/server/routers/api-router.js b/server/routers/api-router.js index 8264800bf..6e0a2dec5 100644 --- a/server/routers/api-router.js +++ b/server/routers/api-router.js @@ -1,5 +1,5 @@ let express = require("express"); -const { allowDevAllOrigin, getSettings, setting, percentageToColor, allowAllOrigin } = require("../util-server"); +const { allowDevAllOrigin, getSettings, setting, percentageToColor, allowAllOrigin, filterAndJoin } = require("../util-server"); const { R } = require("redbean-node"); const server = require("../server"); const apicache = require("../modules/apicache"); @@ -225,8 +225,8 @@ router.get("/api/badge/:id/status", cache("5 minutes"), async (request, response downLabel = "Down", upColor = badgeConstants.defaultUpColor, downColor = badgeConstants.defaultDownColor, - style = "flat", - value // for demo purpose only + style = badgeConstants.defaultStyle, + value, // for demo purpose only } = request.query; try { @@ -275,13 +275,13 @@ router.get("/api/badge/:id/uptime/:duration?", cache("5 minutes"), async (reques const { label, labelPrefix, - labelSuffix = "h", + labelSuffix = badgeConstants.defaultUptimeLabelSuffix, prefix, - suffix = "%", + suffix = badgeConstants.defaultUptimeValueSuffix, color, labelColor, - style = "flat", - value // for demo purpose only + style = badgeConstants.defaultStyle, + value, // for demo purpose only } = request.query; try { @@ -305,7 +305,6 @@ router.get("/api/badge/:id/uptime/:duration?", cache("5 minutes"), async (reques if (!publicMonitor) { // return a "N/A" badge in naColor (grey), if monitor is not public / not available / non exsitant - badgeValues.message = "N/A"; badgeValues.color = badgeConstants.naColor; } else { @@ -314,16 +313,13 @@ router.get("/api/badge/:id/uptime/:duration?", cache("5 minutes"), async (reques requestedMonitorId ); + // use a given, custom color or calculate one based on the uptime value badgeValues.color = color ?? percentageToColor(uptime); + // use a given, custom labelColor or use the default badge label color ( defined by badge-maker) badgeValues.labelColor = labelColor ?? ""; - - badgeValues.label = [labelPrefix, label ?? requestedDuration, labelSuffix] - .filter((part) => part ?? part !== "") - .join(""); - - badgeValues.message = [prefix, `${uptime * 100}`, suffix] - .filter((part) => part ?? part !== "") - .join(""); + // build a lable string. If a custom label is given, override the default one ( requestedDuration ) + badgeValues.label = filterAndJoin([labelPrefix, label ?? requestedDuration, labelSuffix]); + badgeValues.message = filterAndJoin([prefix, `${uptime * 100}`, suffix]); } // build the SVG based on given values @@ -342,13 +338,13 @@ router.get("/api/badge/:id/ping/:duration?", cache("5 minutes"), async (request, const { label, labelPrefix, - labelSuffix = "h", + labelSuffix = badgeConstants.defaultPingLabelSuffix, prefix, - suffix = "ms", + suffix = badgeConstants.defaultPingValueSuffix, color = badgeConstants.defaultPingColor, labelColor, - style = "flat", - value // for demo purpose only + style = badgeConstants.defaultStyle, + value, // for demo purpose only } = request.query; try { @@ -382,15 +378,11 @@ router.get("/api/badge/:id/ping/:duration?", cache("5 minutes"), async (request, const avgPing = parseInt(overrideValue ?? publicAvgPing); badgeValues.color = color; + // use a given, custom labelColor or use the default badge label color ( defined by badge-maker) badgeValues.labelColor = labelColor ?? ""; - - badgeValues.label = [labelPrefix, label ?? requestedDuration, labelSuffix] - .filter((part) => part ?? part !== "") - .join(""); - - badgeValues.message = [prefix, avgPing, suffix] - .filter((part) => part ?? part !== "") - .join(""); + // build a lable string. If a custom label is given, override the default one ( requestedDuration ) + badgeValues.label = filterAndJoin([labelPrefix, label ?? requestedDuration, labelSuffix]); + badgeValues.message = filterAndJoin([prefix, avgPing, suffix]); } // build the SVG based on given values diff --git a/server/util-server.js b/server/util-server.js index 0bcc4dd5a..8cc92facd 100644 --- a/server/util-server.js +++ b/server/util-server.js @@ -391,3 +391,14 @@ exports.percentageToColor = (percentage, maxHue = 90, minHue = 10) => { return badgeConstants.naColor; } }; + +/** + * Joins and array of string to one string after filtering out empty values + * + * @param {string[]} parts + * @param {string} connector + * @returns {string} + */ +exports.filterAndJoin = (parts, connector = "") => { + return parts.filter((part) => !!part && part !== "").join(connector); +}; diff --git a/test/backend.spec.js b/test/backend.spec.js index bbfc6897b..220b5f355 100644 --- a/test/backend.spec.js +++ b/test/backend.spec.js @@ -164,3 +164,25 @@ describe("Test reset-password", () => { }, 120000); }); +describe("The function filterAndJoin", () => { + it("should join and array of strings to one string", () => { + const result = utilServerRewire.filterAndJoin(["one", "two", "three"]); + expect(result).toBe("onetwothree"); + }); + + it("should join strings using a given connector", () => { + const result = utilServerRewire.filterAndJoin(["one", "two", "three"], "-"); + expect(result).toBe("one-two-three"); + }); + + it("should filter null, undefined and empty strings before joining", () => { + const result = utilServerRewire.filterAndJoin([undefined, "", "three"], "--"); + expect(result).toBe("three"); + }); + + it("should return an empty string if all parts are filtered out", () => { + const result = utilServerRewire.filterAndJoin([undefined, "", ""], "--"); + expect(result).toBe(""); + }); +}); +