diff --git a/server/routers/api-router.js b/server/routers/api-router.js index 9c572f686..ed6db2cd1 100644 --- a/server/routers/api-router.js +++ b/server/routers/api-router.js @@ -232,8 +232,8 @@ router.get("/api/badge/:id/uptime/:duration?", cache("5 minutes"), async (reques let requestedDuration = request.params.duration !== undefined ? request.params.duration : "24h"; const overrideValue = value && parseFloat(value); - if (requestedDuration === "24") { - requestedDuration = "24h"; + if (/^[0-9]+$/.test(requestedDuration)) { + requestedDuration = `${requestedDuration}h`; } let publicMonitor = await R.getRow(` @@ -265,7 +265,7 @@ router.get("/api/badge/:id/uptime/:duration?", cache("5 minutes"), async (reques // build a label string. If a custom label is given, override the default one (requestedDuration) badgeValues.label = filterAndJoin([ labelPrefix, - label ?? `Uptime (${requestedDuration}${labelSuffix})`, + label ?? `Uptime (${requestedDuration.slice(0, -1)}${labelSuffix})`, ]); badgeValues.message = filterAndJoin([ prefix, cleanUptime, suffix ]); } @@ -302,8 +302,8 @@ router.get("/api/badge/:id/ping/:duration?", cache("5 minutes"), async (request, let requestedDuration = request.params.duration !== undefined ? request.params.duration : "24h"; const overrideValue = value && parseFloat(value); - if (requestedDuration === "24") { - requestedDuration = "24h"; + if (/^[0-9]+$/.test(requestedDuration)) { + requestedDuration = `${requestedDuration}h`; } // Check if monitor is public @@ -325,7 +325,7 @@ router.get("/api/badge/:id/ping/:duration?", cache("5 minutes"), async (request, // use a given, custom labelColor or use the default badge label color (defined by badge-maker) badgeValues.labelColor = labelColor ?? ""; // build a lable string. If a custom label is given, override the default one (requestedDuration) - badgeValues.label = filterAndJoin([ labelPrefix, label ?? `Avg. Ping (${requestedDuration}${labelSuffix})` ]); + badgeValues.label = filterAndJoin([ labelPrefix, label ?? `Avg. Ping (${requestedDuration.slice(0, -1)}${labelSuffix})` ]); badgeValues.message = filterAndJoin([ prefix, avgPing, suffix ]); } diff --git a/server/uptime-calculator.js b/server/uptime-calculator.js index 55059e960..f2738b96a 100644 --- a/server/uptime-calculator.js +++ b/server/uptime-calculator.js @@ -543,7 +543,9 @@ class UptimeCalculator { if (type === "minute" && num > 24 * 60) { throw new Error("The maximum number of minutes is 1440"); } - + if (type === "day" && num > 365) { + throw new Error("The maximum number of days is 365"); + } // Get the current time period key based on the type let key = this.getKey(this.getCurrentDate(), type); @@ -741,20 +743,36 @@ class UptimeCalculator { } /** - * Get the uptime data by duration - * @param {'24h'|'30d'|'1y'} duration Only accept 24h, 30d, 1y + * Get the uptime data for given duration. + * @param {string} duration A string with a number and a unit (m,h,d,w,M,y), such as 24h, 30d, 1y. * @returns {UptimeDataResult} UptimeDataResult - * @throws {Error} Invalid duration + * @throws {Error} Invalid duration / Unsupported unit */ getDataByDuration(duration) { - if (duration === "24h") { - return this.get24Hour(); - } else if (duration === "30d") { - return this.get30Day(); - } else if (duration === "1y") { - return this.get1Year(); - } else { - throw new Error("Invalid duration"); + const durationNumStr = duration.slice(0, -1); + + if (!/^[0-9]+$/.test(durationNumStr)) { + throw new Error(`Invalid duration: ${duration}`); + } + const num = Number(durationNumStr); + const unit = duration.slice(-1); + + switch (unit) { + case "m": + return this.getData(num, "minute"); + case "h": + return this.getData(num, "hour"); + case "d": + return this.getData(num, "day"); + case "w": + return this.getData(7 * num, "day"); + case "M": + return this.getData(30 * num, "day"); + case "y": + return this.getData(365 * num, "day"); + default: + throw new Error(`Unsupported unit (${unit}) for badge duration ${duration}` + ); } }