mirror of
https://github.com/louislam/uptime-kuma.git
synced 2024-11-23 23:04:04 +00:00
fix: 🐛 badge requestedDuration
This commit is contained in:
parent
e5ff86e6ac
commit
53c4bba387
4 changed files with 97 additions and 29 deletions
|
@ -11,7 +11,17 @@ const { R } = require("redbean-node");
|
||||||
const apicache = require("../modules/apicache");
|
const apicache = require("../modules/apicache");
|
||||||
const Monitor = require("../model/monitor");
|
const Monitor = require("../model/monitor");
|
||||||
const dayjs = require("dayjs");
|
const dayjs = require("dayjs");
|
||||||
const { UP, MAINTENANCE, DOWN, PENDING, flipStatus, log, badgeConstants } = require("../../src/util");
|
const {
|
||||||
|
UP,
|
||||||
|
MAINTENANCE,
|
||||||
|
DOWN,
|
||||||
|
PENDING,
|
||||||
|
flipStatus,
|
||||||
|
log,
|
||||||
|
badgeConstants,
|
||||||
|
durationUnits,
|
||||||
|
isNumeric,
|
||||||
|
} = require("../../src/util");
|
||||||
const StatusPage = require("../model/status_page");
|
const StatusPage = require("../model/status_page");
|
||||||
const { UptimeKumaServer } = require("../uptime-kuma-server");
|
const { UptimeKumaServer } = require("../uptime-kuma-server");
|
||||||
const { makeBadge } = require("badge-maker");
|
const { makeBadge } = require("badge-maker");
|
||||||
|
@ -232,6 +242,11 @@ router.get("/api/badge/:id/uptime/:duration?", cache("5 minutes"), async (reques
|
||||||
let requestedDuration = request.params.duration !== undefined ? request.params.duration : "24";
|
let requestedDuration = request.params.duration !== undefined ? request.params.duration : "24";
|
||||||
const overrideValue = value && parseFloat(value);
|
const overrideValue = value && parseFloat(value);
|
||||||
|
|
||||||
|
if (isNumeric(requestedDuration)) { // all numeric only
|
||||||
|
requestedDuration = `${requestedDuration}${durationUnits.HOUR}`;
|
||||||
|
}
|
||||||
|
const duration = requestedDuration.slice(0, -1);
|
||||||
|
|
||||||
let publicMonitor = await R.getRow(`
|
let publicMonitor = await R.getRow(`
|
||||||
SELECT monitor_group.monitor_id FROM monitor_group, \`group\`
|
SELECT monitor_group.monitor_id FROM monitor_group, \`group\`
|
||||||
WHERE monitor_group.group_id = \`group\`.id
|
WHERE monitor_group.group_id = \`group\`.id
|
||||||
|
@ -249,7 +264,7 @@ router.get("/api/badge/:id/uptime/:duration?", cache("5 minutes"), async (reques
|
||||||
badgeValues.color = badgeConstants.naColor;
|
badgeValues.color = badgeConstants.naColor;
|
||||||
} else {
|
} else {
|
||||||
const uptimeCalculator = await UptimeCalculator.getUptimeCalculator(requestedMonitorId);
|
const uptimeCalculator = await UptimeCalculator.getUptimeCalculator(requestedMonitorId);
|
||||||
const uptime = overrideValue ?? uptimeCalculator.getDataByDuration(`${requestedDuration}h`).uptime;
|
const uptime = overrideValue ?? uptimeCalculator.getDataByDuration(requestedDuration).uptime;
|
||||||
|
|
||||||
// limit the displayed uptime percentage to four (two, when displayed as percent) decimal digits
|
// limit the displayed uptime percentage to four (two, when displayed as percent) decimal digits
|
||||||
const cleanUptime = (uptime * 100).toPrecision(4);
|
const cleanUptime = (uptime * 100).toPrecision(4);
|
||||||
|
@ -261,7 +276,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)
|
// build a label string. If a custom label is given, override the default one (requestedDuration)
|
||||||
badgeValues.label = filterAndJoin([
|
badgeValues.label = filterAndJoin([
|
||||||
labelPrefix,
|
labelPrefix,
|
||||||
label ?? `Uptime (${requestedDuration}${labelSuffix})`,
|
label ?? `Uptime (${duration}${labelSuffix})`,
|
||||||
]);
|
]);
|
||||||
badgeValues.message = filterAndJoin([ prefix, cleanUptime, suffix ]);
|
badgeValues.message = filterAndJoin([ prefix, cleanUptime, suffix ]);
|
||||||
}
|
}
|
||||||
|
@ -298,13 +313,17 @@ router.get("/api/badge/:id/ping/:duration?", cache("5 minutes"), async (request,
|
||||||
let requestedDuration = request.params.duration !== undefined ? request.params.duration : "24";
|
let requestedDuration = request.params.duration !== undefined ? request.params.duration : "24";
|
||||||
const overrideValue = value && parseFloat(value);
|
const overrideValue = value && parseFloat(value);
|
||||||
|
|
||||||
|
if (isNumeric(requestedDuration)) { // all numeric only
|
||||||
|
requestedDuration = `${requestedDuration}${durationUnits.HOUR}`;
|
||||||
|
}
|
||||||
|
const duration = requestedDuration.slice(0, -1);
|
||||||
|
|
||||||
// Check if monitor is public
|
// Check if monitor is public
|
||||||
|
|
||||||
const uptimeCalculator = await UptimeCalculator.getUptimeCalculator(requestedMonitorId);
|
const uptimeCalculator = await UptimeCalculator.getUptimeCalculator(requestedMonitorId);
|
||||||
const publicAvgPing = uptimeCalculator.getDataByDuration(`${requestedDuration}h`).avgPing;
|
const publicAvgPing = uptimeCalculator.getDataByDuration(requestedDuration).avgPing;
|
||||||
|
|
||||||
const badgeValues = { style };
|
const badgeValues = { style };
|
||||||
|
|
||||||
if (!publicAvgPing) {
|
if (!publicAvgPing) {
|
||||||
// return a "N/A" badge in naColor (grey), if monitor is not public / not available / non exsitant
|
// return a "N/A" badge in naColor (grey), if monitor is not public / not available / non exsitant
|
||||||
|
|
||||||
|
@ -317,7 +336,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)
|
// use a given, custom labelColor or use the default badge label color (defined by badge-maker)
|
||||||
badgeValues.labelColor = labelColor ?? "";
|
badgeValues.labelColor = labelColor ?? "";
|
||||||
// build a lable string. If a custom label is given, override the default one (requestedDuration)
|
// 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 (${duration}${labelSuffix})` ]);
|
||||||
badgeValues.message = filterAndJoin([ prefix, avgPing, suffix ]);
|
badgeValues.message = filterAndJoin([ prefix, avgPing, suffix ]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,12 @@
|
||||||
const dayjs = require("dayjs");
|
const dayjs = require("dayjs");
|
||||||
const { UP, MAINTENANCE, DOWN, PENDING } = require("../src/util");
|
const {
|
||||||
|
UP,
|
||||||
|
MAINTENANCE,
|
||||||
|
DOWN,
|
||||||
|
PENDING,
|
||||||
|
durationUnits,
|
||||||
|
isNumeric
|
||||||
|
} = require("../src/util");
|
||||||
const { LimitQueue } = require("./utils/limit-queue");
|
const { LimitQueue } = require("./utils/limit-queue");
|
||||||
const { log } = require("../src/util");
|
const { log } = require("../src/util");
|
||||||
const { R } = require("redbean-node");
|
const { R } = require("redbean-node");
|
||||||
|
@ -543,7 +550,9 @@ class UptimeCalculator {
|
||||||
if (type === "minute" && num > 24 * 60) {
|
if (type === "minute" && num > 24 * 60) {
|
||||||
throw new Error("The maximum number of minutes is 1440");
|
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
|
// Get the current time period key based on the type
|
||||||
let key = this.getKey(this.getCurrentDate(), type);
|
let key = this.getKey(this.getCurrentDate(), type);
|
||||||
|
|
||||||
|
@ -742,24 +751,36 @@ class UptimeCalculator {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the uptime data for given duration.
|
* Get the uptime data for given duration.
|
||||||
* @param {string} duration A string with a number and a unit (h, d, or y), such as 24h, 30d, 1y.
|
* @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
|
* @returns {UptimeDataResult} UptimeDataResult
|
||||||
* @throws {Error} Invalid duration
|
* @throws {Error} Invalid duration / Unsupported unit
|
||||||
*/
|
*/
|
||||||
getDataByDuration(duration) {
|
getDataByDuration(duration) {
|
||||||
const unit = duration.substring(duration.length - 1);
|
const durationNumStr = duration.slice(0, -1);
|
||||||
const num = parseInt(duration.substring(0, duration.length - 1));
|
|
||||||
|
|
||||||
const typeMap = {
|
if (!isNumeric(durationNumStr)) {
|
||||||
h: "hour",
|
throw new Error(`Invalid duration: ${duration}`);
|
||||||
d: "day",
|
}
|
||||||
y: "year"
|
const num = Number(durationNumStr);
|
||||||
};
|
const unit = duration.slice(-1);
|
||||||
|
|
||||||
if (!Object.keys(typeMap).includes(unit)) {
|
switch (unit) {
|
||||||
throw new Error("Invalid duration");
|
case durationUnits.MINUTE:
|
||||||
|
return this.getData(num, "minute");
|
||||||
|
case durationUnits.HOUR:
|
||||||
|
return this.getData(num, "hour");
|
||||||
|
case durationUnits.DAY:
|
||||||
|
return this.getData(num, "day");
|
||||||
|
case durationUnits.WEEK:
|
||||||
|
return this.getData(7 * num, "day");
|
||||||
|
case durationUnits.MONTH:
|
||||||
|
return this.getData(30 * num, "day");
|
||||||
|
case durationUnits.YEAR:
|
||||||
|
return this.getData(365 * num, "day");
|
||||||
|
default:
|
||||||
|
throw new Error(`Unsupported unit (${unit}) for badge duration ${duration}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return this.getData(num, typeMap[unit]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
16
src/util.js
16
src/util.js
|
@ -10,8 +10,8 @@
|
||||||
*/
|
*/
|
||||||
var _a;
|
var _a;
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
exports.sleep = exports.flipStatus = exports.badgeConstants = exports.CONSOLE_STYLE_BgGray = exports.CONSOLE_STYLE_BgWhite = exports.CONSOLE_STYLE_BgCyan = exports.CONSOLE_STYLE_BgMagenta = exports.CONSOLE_STYLE_BgBlue = exports.CONSOLE_STYLE_BgYellow = exports.CONSOLE_STYLE_BgGreen = exports.CONSOLE_STYLE_BgRed = exports.CONSOLE_STYLE_BgBlack = exports.CONSOLE_STYLE_FgPink = exports.CONSOLE_STYLE_FgBrown = exports.CONSOLE_STYLE_FgViolet = exports.CONSOLE_STYLE_FgLightBlue = exports.CONSOLE_STYLE_FgLightGreen = exports.CONSOLE_STYLE_FgOrange = exports.CONSOLE_STYLE_FgGray = exports.CONSOLE_STYLE_FgWhite = exports.CONSOLE_STYLE_FgCyan = exports.CONSOLE_STYLE_FgMagenta = exports.CONSOLE_STYLE_FgBlue = exports.CONSOLE_STYLE_FgYellow = exports.CONSOLE_STYLE_FgGreen = exports.CONSOLE_STYLE_FgRed = exports.CONSOLE_STYLE_FgBlack = exports.CONSOLE_STYLE_Hidden = exports.CONSOLE_STYLE_Reverse = exports.CONSOLE_STYLE_Blink = exports.CONSOLE_STYLE_Underscore = exports.CONSOLE_STYLE_Dim = exports.CONSOLE_STYLE_Bright = exports.CONSOLE_STYLE_Reset = exports.MIN_INTERVAL_SECOND = exports.MAX_INTERVAL_SECOND = exports.SQL_DATETIME_FORMAT_WITHOUT_SECOND = exports.SQL_DATETIME_FORMAT = exports.SQL_DATE_FORMAT = exports.STATUS_PAGE_MAINTENANCE = exports.STATUS_PAGE_PARTIAL_DOWN = exports.STATUS_PAGE_ALL_UP = exports.STATUS_PAGE_ALL_DOWN = exports.MAINTENANCE = exports.PENDING = exports.UP = exports.DOWN = exports.appName = exports.isNode = exports.isDev = void 0;
|
exports.flipStatus = exports.durationUnits = exports.badgeConstants = exports.CONSOLE_STYLE_BgGray = exports.CONSOLE_STYLE_BgWhite = exports.CONSOLE_STYLE_BgCyan = exports.CONSOLE_STYLE_BgMagenta = exports.CONSOLE_STYLE_BgBlue = exports.CONSOLE_STYLE_BgYellow = exports.CONSOLE_STYLE_BgGreen = exports.CONSOLE_STYLE_BgRed = exports.CONSOLE_STYLE_BgBlack = exports.CONSOLE_STYLE_FgPink = exports.CONSOLE_STYLE_FgBrown = exports.CONSOLE_STYLE_FgViolet = exports.CONSOLE_STYLE_FgLightBlue = exports.CONSOLE_STYLE_FgLightGreen = exports.CONSOLE_STYLE_FgOrange = exports.CONSOLE_STYLE_FgGray = exports.CONSOLE_STYLE_FgWhite = exports.CONSOLE_STYLE_FgCyan = exports.CONSOLE_STYLE_FgMagenta = exports.CONSOLE_STYLE_FgBlue = exports.CONSOLE_STYLE_FgYellow = exports.CONSOLE_STYLE_FgGreen = exports.CONSOLE_STYLE_FgRed = exports.CONSOLE_STYLE_FgBlack = exports.CONSOLE_STYLE_Hidden = exports.CONSOLE_STYLE_Reverse = exports.CONSOLE_STYLE_Blink = exports.CONSOLE_STYLE_Underscore = exports.CONSOLE_STYLE_Dim = exports.CONSOLE_STYLE_Bright = exports.CONSOLE_STYLE_Reset = exports.MIN_INTERVAL_SECOND = exports.MAX_INTERVAL_SECOND = exports.SQL_DATETIME_FORMAT_WITHOUT_SECOND = exports.SQL_DATETIME_FORMAT = exports.SQL_DATE_FORMAT = exports.STATUS_PAGE_MAINTENANCE = exports.STATUS_PAGE_PARTIAL_DOWN = exports.STATUS_PAGE_ALL_UP = exports.STATUS_PAGE_ALL_DOWN = exports.MAINTENANCE = exports.PENDING = exports.UP = exports.DOWN = exports.appName = exports.isNode = exports.isDev = void 0;
|
||||||
exports.intHash = exports.localToUTC = exports.utcToLocal = exports.utcToISODateTime = exports.isoToUTCDateTime = exports.parseTimeFromTimeObject = exports.parseTimeObject = exports.getMaintenanceRelativeURL = exports.getMonitorRelativeURL = exports.genSecret = exports.getCryptoRandomInt = exports.getRandomInt = exports.getRandomArbitrary = exports.TimeLogger = exports.polyfill = exports.log = exports.debug = exports.ucfirst = void 0;
|
exports.isNumeric = exports.intHash = exports.localToUTC = exports.utcToLocal = exports.utcToISODateTime = exports.isoToUTCDateTime = exports.parseTimeFromTimeObject = exports.parseTimeObject = exports.getMaintenanceRelativeURL = exports.getMonitorRelativeURL = exports.genSecret = exports.getCryptoRandomInt = exports.getRandomInt = exports.getRandomArbitrary = exports.TimeLogger = exports.polyfill = exports.log = exports.debug = exports.ucfirst = exports.sleep = void 0;
|
||||||
const dayjs = require("dayjs");
|
const dayjs = require("dayjs");
|
||||||
exports.isDev = process.env.NODE_ENV === "development";
|
exports.isDev = process.env.NODE_ENV === "development";
|
||||||
exports.isNode = typeof process !== "undefined" && ((_a = process === null || process === void 0 ? void 0 : process.versions) === null || _a === void 0 ? void 0 : _a.node);
|
exports.isNode = typeof process !== "undefined" && ((_a = process === null || process === void 0 ? void 0 : process.versions) === null || _a === void 0 ? void 0 : _a.node);
|
||||||
|
@ -96,6 +96,14 @@ exports.badgeConstants = {
|
||||||
defaultCertExpireWarnDays: "14",
|
defaultCertExpireWarnDays: "14",
|
||||||
defaultCertExpireDownDays: "7"
|
defaultCertExpireDownDays: "7"
|
||||||
};
|
};
|
||||||
|
exports.durationUnits = {
|
||||||
|
MINUTE: "m",
|
||||||
|
HOUR: "h",
|
||||||
|
DAY: "d",
|
||||||
|
WEEK: "w",
|
||||||
|
MONTH: "M",
|
||||||
|
YEAR: "y"
|
||||||
|
};
|
||||||
function flipStatus(s) {
|
function flipStatus(s) {
|
||||||
if (s === exports.UP) {
|
if (s === exports.UP) {
|
||||||
return exports.DOWN;
|
return exports.DOWN;
|
||||||
|
@ -396,3 +404,7 @@ function intHash(str, length = 10) {
|
||||||
return (hash % length + length) % length;
|
return (hash % length + length) % length;
|
||||||
}
|
}
|
||||||
exports.intHash = intHash;
|
exports.intHash = intHash;
|
||||||
|
function isNumeric(str) {
|
||||||
|
return /^([0-9]+)$/.test(str);
|
||||||
|
}
|
||||||
|
exports.isNumeric = isNumeric;
|
||||||
|
|
28
src/util.ts
28
src/util.ts
|
@ -93,11 +93,6 @@ const consoleLevelColors : Record<string, string> = {
|
||||||
"DEBUG": CONSOLE_STYLE_FgGray,
|
"DEBUG": CONSOLE_STYLE_FgGray,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Flip the status of s
|
|
||||||
* @param s input status: UP or DOWN
|
|
||||||
* @returns {number} UP or DOWN
|
|
||||||
*/
|
|
||||||
export const badgeConstants = {
|
export const badgeConstants = {
|
||||||
naColor: "#999",
|
naColor: "#999",
|
||||||
defaultUpColor: "#66c20a",
|
defaultUpColor: "#66c20a",
|
||||||
|
@ -118,7 +113,20 @@ export const badgeConstants = {
|
||||||
defaultCertExpireDownDays: "7"
|
defaultCertExpireDownDays: "7"
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Flip the status of s */
|
export const durationUnits = {
|
||||||
|
MINUTE: "m",
|
||||||
|
HOUR: "h",
|
||||||
|
DAY: "d",
|
||||||
|
WEEK: "w",
|
||||||
|
MONTH: "M",
|
||||||
|
YEAR: "y"
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flip the status of s
|
||||||
|
* @param s input status: UP or DOWN
|
||||||
|
* @returns {number} UP or DOWN
|
||||||
|
*/
|
||||||
export function flipStatus(s: number) {
|
export function flipStatus(s: number) {
|
||||||
if (s === UP) {
|
if (s === UP) {
|
||||||
return DOWN;
|
return DOWN;
|
||||||
|
@ -643,3 +651,11 @@ export function intHash(str : string, length = 10) : number {
|
||||||
return (hash % length + length) % length; // Ensure the result is non-negative
|
return (hash % length + length) % length; // Ensure the result is non-negative
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a string is numeric.
|
||||||
|
* @param {string} str - The input string to check
|
||||||
|
* @returns {boolean} Returns true if the input string is numeric, false otherwise
|
||||||
|
*/
|
||||||
|
export function isNumeric(str: string): boolean {
|
||||||
|
return /^([0-9]+)$/.test(str);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue