From 35360e2069b04466dbaee87d522b97736d9d53aa Mon Sep 17 00:00:00 2001 From: Jens Neuber Date: Mon, 3 Jan 2022 15:48:52 +0100 Subject: [PATCH 001/163] add badges --- package-lock.json | 182 ++++++++++++++++++++++++++++++++--- package.json | 2 + server/routers/api-router.js | 62 +++++++++++- server/util-server.js | 10 ++ 4 files changed, 239 insertions(+), 17 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6b6c75cc7..219b940ff 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,6 +17,7 @@ "@popperjs/core": "~2.10.2", "args-parser": "~1.3.0", "axios": "~0.21.4", + "badge-maker": "^3.3.1", "bcryptjs": "~2.4.3", "bootstrap": "5.1.3", "bree": "~7.1.0", @@ -24,6 +25,7 @@ "chart.js": "~3.6.0", "chartjs-adapter-dayjs": "~1.0.0", "check-password-strength": "^2.0.3", + "chroma-js": "^2.1.2", "command-exists": "~1.2.9", "compare-versions": "~3.6.0", "dayjs": "~1.10.7", @@ -3552,6 +3554,14 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/anafanafo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anafanafo/-/anafanafo-2.0.0.tgz", + "integrity": "sha512-Nlfq7NC4AOkTJerWRIZcOAiMNtIDVIGWGvQ98O7Jl6Kr2Dk0dX5u4MqN778kSRTy5KRqchpLdF2RtLFEz9FVkQ==", + "dependencies": { + "char-width-table-consumer": "^1.0.0" + } + }, "node_modules/ansi-colors": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", @@ -4016,6 +4026,22 @@ "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=" }, + "node_modules/badge-maker": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/badge-maker/-/badge-maker-3.3.1.tgz", + "integrity": "sha512-OO/PS7Zg2E6qaUWzHEHt21Q5VjcFBAJVA8ztgT/fIdSZFBUwoyeo0ZhA6V5tUM8Vcjq8DJl6jfGhpjESssyqMQ==", + "dependencies": { + "anafanafo": "2.0.0", + "css-color-converter": "^2.0.0" + }, + "bin": { + "badge": "lib/badge-cli.js" + }, + "engines": { + "node": ">= 10", + "npm": ">= 5" + } + }, "node_modules/bail": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/bail/-/bail-1.0.5.tgz", @@ -4098,6 +4124,11 @@ "node": ">=8" } }, + "node_modules/binary-search": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/binary-search/-/binary-search-1.3.6.tgz", + "integrity": "sha512-nbE1WxOTTrUWIfsfZ4aHGYu5DOuNkbxGokjV6Z2kxfJK3uaAb8zNK1muzOeipoLHZjInT4Br88BHpzevc681xA==" + }, "node_modules/bintrees": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/bintrees/-/bintrees-1.0.1.tgz", @@ -4422,6 +4453,14 @@ "node": ">=10" } }, + "node_modules/char-width-table-consumer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/char-width-table-consumer/-/char-width-table-consumer-1.0.0.tgz", + "integrity": "sha512-Fz4UD0LBpxPgL9i29CJ5O4KANwaMnX/OhhbxzvNa332h+9+nRKyeuLw4wA51lt/ex67+/AdsoBQJF3kgX2feYQ==", + "dependencies": { + "binary-search": "^1.3.5" + } + }, "node_modules/character-entities": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz", @@ -4505,6 +4544,29 @@ "node": ">=10" } }, + "node_modules/chroma-js": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/chroma-js/-/chroma-js-2.1.2.tgz", + "integrity": "sha512-ri/ouYDWuxfus3UcaMxC1Tfp3IE9K5iQzxc2hSxbBRVNQFut1UuGAsZmiAf2mOUubzGJwgMSv9lHg+XqLaz1QQ==", + "dependencies": { + "cross-env": "^6.0.3" + } + }, + "node_modules/chroma-js/node_modules/cross-env": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-6.0.3.tgz", + "integrity": "sha512-+KqxF6LCvfhWvADcDPqo64yVIB31gv/jQulX2NGzKS/g3GEVz6/pt4wjHFtFWsHMddebWD/sDthJemzM4MaAag==", + "dependencies": { + "cross-spawn": "^7.0.0" + }, + "bin": { + "cross-env": "src/bin/cross-env.js", + "cross-env-shell": "src/bin/cross-env-shell.js" + }, + "engines": { + "node": ">=8.0" + } + }, "node_modules/ci-info": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.2.0.tgz", @@ -4796,7 +4858,6 @@ "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -4806,6 +4867,31 @@ "node": ">= 8" } }, + "node_modules/css-color-converter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/css-color-converter/-/css-color-converter-2.0.0.tgz", + "integrity": "sha512-oLIG2soZz3wcC3aAl/7Us5RS8Hvvc6I8G8LniF/qfMmrm7fIKQ8RIDDRZeKyGL2SrWfNqYspuLShbnjBMVWm8g==", + "dependencies": { + "color-convert": "^0.5.2", + "color-name": "^1.1.4", + "css-unit-converter": "^1.1.2" + } + }, + "node_modules/css-color-converter/node_modules/color-convert": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-0.5.3.tgz", + "integrity": "sha1-vbbGnOZg+t/+CwAHzER+G59ygr0=" + }, + "node_modules/css-color-converter/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/css-unit-converter": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/css-unit-converter/-/css-unit-converter-1.1.2.tgz", + "integrity": "sha512-IiJwMC8rdZE0+xiEZHeru6YoONC4rfPMqGm2W85jMIbkFvv5nFTwJVFHam2eFrN6txmoUYFAFXiv8ICVeTO0MA==" + }, "node_modules/cssesc": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", @@ -7516,8 +7602,7 @@ "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "devOptional": true + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" }, "node_modules/isobject": { "version": "3.0.1", @@ -11074,7 +11159,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, "engines": { "node": ">=8" } @@ -12505,7 +12589,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, "dependencies": { "shebang-regex": "^3.0.0" }, @@ -12517,7 +12600,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, "engines": { "node": ">=8" } @@ -14401,7 +14483,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "devOptional": true, "dependencies": { "isexe": "^2.0.0" }, @@ -17293,6 +17374,14 @@ "uri-js": "^4.2.2" } }, + "anafanafo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anafanafo/-/anafanafo-2.0.0.tgz", + "integrity": "sha512-Nlfq7NC4AOkTJerWRIZcOAiMNtIDVIGWGvQ98O7Jl6Kr2Dk0dX5u4MqN778kSRTy5KRqchpLdF2RtLFEz9FVkQ==", + "requires": { + "char-width-table-consumer": "^1.0.0" + } + }, "ansi-colors": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", @@ -17659,6 +17748,15 @@ "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=" }, + "badge-maker": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/badge-maker/-/badge-maker-3.3.1.tgz", + "integrity": "sha512-OO/PS7Zg2E6qaUWzHEHt21Q5VjcFBAJVA8ztgT/fIdSZFBUwoyeo0ZhA6V5tUM8Vcjq8DJl6jfGhpjESssyqMQ==", + "requires": { + "anafanafo": "2.0.0", + "css-color-converter": "^2.0.0" + } + }, "bail": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/bail/-/bail-1.0.5.tgz", @@ -17711,6 +17809,11 @@ "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", "dev": true }, + "binary-search": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/binary-search/-/binary-search-1.3.6.tgz", + "integrity": "sha512-nbE1WxOTTrUWIfsfZ4aHGYu5DOuNkbxGokjV6Z2kxfJK3uaAb8zNK1muzOeipoLHZjInT4Br88BHpzevc681xA==" + }, "bintrees": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/bintrees/-/bintrees-1.0.1.tgz", @@ -17963,6 +18066,14 @@ "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", "dev": true }, + "char-width-table-consumer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/char-width-table-consumer/-/char-width-table-consumer-1.0.0.tgz", + "integrity": "sha512-Fz4UD0LBpxPgL9i29CJ5O4KANwaMnX/OhhbxzvNa332h+9+nRKyeuLw4wA51lt/ex67+/AdsoBQJF3kgX2feYQ==", + "requires": { + "binary-search": "^1.3.5" + } + }, "character-entities": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz", @@ -18023,6 +18134,24 @@ "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==" }, + "chroma-js": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/chroma-js/-/chroma-js-2.1.2.tgz", + "integrity": "sha512-ri/ouYDWuxfus3UcaMxC1Tfp3IE9K5iQzxc2hSxbBRVNQFut1UuGAsZmiAf2mOUubzGJwgMSv9lHg+XqLaz1QQ==", + "requires": { + "cross-env": "^6.0.3" + }, + "dependencies": { + "cross-env": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-6.0.3.tgz", + "integrity": "sha512-+KqxF6LCvfhWvADcDPqo64yVIB31gv/jQulX2NGzKS/g3GEVz6/pt4wjHFtFWsHMddebWD/sDthJemzM4MaAag==", + "requires": { + "cross-spawn": "^7.0.0" + } + } + } + }, "ci-info": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.2.0.tgz", @@ -18258,13 +18387,39 @@ "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, "requires": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, + "css-color-converter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/css-color-converter/-/css-color-converter-2.0.0.tgz", + "integrity": "sha512-oLIG2soZz3wcC3aAl/7Us5RS8Hvvc6I8G8LniF/qfMmrm7fIKQ8RIDDRZeKyGL2SrWfNqYspuLShbnjBMVWm8g==", + "requires": { + "color-convert": "^0.5.2", + "color-name": "^1.1.4", + "css-unit-converter": "^1.1.2" + }, + "dependencies": { + "color-convert": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-0.5.3.tgz", + "integrity": "sha1-vbbGnOZg+t/+CwAHzER+G59ygr0=" + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + } + } + }, + "css-unit-converter": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/css-unit-converter/-/css-unit-converter-1.1.2.tgz", + "integrity": "sha512-IiJwMC8rdZE0+xiEZHeru6YoONC4rfPMqGm2W85jMIbkFvv5nFTwJVFHam2eFrN6txmoUYFAFXiv8ICVeTO0MA==" + }, "cssesc": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", @@ -20275,8 +20430,7 @@ "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "devOptional": true + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" }, "isobject": { "version": "3.0.1", @@ -22957,8 +23111,7 @@ "path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" }, "path-parse": { "version": "1.0.7", @@ -24042,7 +24195,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, "requires": { "shebang-regex": "^3.0.0" } @@ -24050,8 +24202,7 @@ "shebang-regex": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" }, "signal-exit": { "version": "3.0.6", @@ -25468,7 +25619,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "devOptional": true, "requires": { "isexe": "^2.0.0" } diff --git a/package.json b/package.json index 32c51176d..cc9d005fc 100644 --- a/package.json +++ b/package.json @@ -62,6 +62,7 @@ "@popperjs/core": "~2.10.2", "args-parser": "~1.3.0", "axios": "~0.21.4", + "badge-maker": "^3.3.1", "bcryptjs": "~2.4.3", "bootstrap": "5.1.3", "bree": "~7.1.0", @@ -69,6 +70,7 @@ "chart.js": "~3.6.0", "chartjs-adapter-dayjs": "~1.0.0", "check-password-strength": "^2.0.3", + "chroma-js": "^2.1.2", "command-exists": "~1.2.9", "compare-versions": "~3.6.0", "dayjs": "~1.10.7", diff --git a/server/routers/api-router.js b/server/routers/api-router.js index 1920cef71..8573226f8 100644 --- a/server/routers/api-router.js +++ b/server/routers/api-router.js @@ -1,11 +1,12 @@ let express = require("express"); -const { allowDevAllOrigin, getSettings, setting } = require("../util-server"); +const { allowDevAllOrigin, getSettings, setting, percentageToColor } = require("../util-server"); const { R } = require("redbean-node"); const server = require("../server"); const apicache = require("../modules/apicache"); const Monitor = require("../model/monitor"); const dayjs = require("dayjs"); const { UP, flipStatus, debug } = require("../../src/util"); +const { makeBadge } = require("badge-maker"); let router = express.Router(); let cache = apicache.middleware; @@ -214,6 +215,65 @@ router.get("/api/status-page/heartbeat", cache("5 minutes"), async (_request, re } }); +router.get("/api/badge/:id/:type", cache("5 minutes"), async (request, response) => { + allowDevAllOrigin(response); + + const { + label, + labelPrefix, + labelSuffix = "h", + prefix, + suffix, + } = request.query; + + try { + await checkPublished(); + + const requestedMonitorId = parseInt(request.params.id, 10); + const requestedType = parseInt(request.params.type, 10) ?? 24; + + let publicMonitor = await R.getRow(` + SELECT monitor_group.monitor_id FROM monitor_group, \`group\` + WHERE monitor_group.group_id = \`group\`.id + AND monitor_group.monitor_id = ? + AND public = 1 + `, + [requestedMonitorId] + ); + + const badgeValues = {}; + + if (!publicMonitor) { + badgeValues.message = "N/A"; + badgeValues.color = "#CCCCCC"; + } else { + const uptime = await Monitor.calcUptime( + requestedType, + requestedMonitorId + ); + + badgeValues.color = percentageToColor(uptime); + + badgeValues.label = [labelPrefix, label ?? requestedType, labelSuffix] + .filter((part) => part ?? part !== "") + .join(""); + + badgeValues.message = [prefix, `${uptime * 100} %`, suffix] + .filter((part) => part ?? part !== "") + .join(""); + + } + + const svg = makeBadge(badgeValues); + + response.type("image/svg+xml"); + response.send(svg); + } catch (error) { + send403(response, error.message); + } +} +); + async function checkPublished() { if (! await isPublished()) { throw new Error("The status page is not published"); diff --git a/server/util-server.js b/server/util-server.js index 68f59f67f..3f2918937 100644 --- a/server/util-server.js +++ b/server/util-server.js @@ -10,6 +10,7 @@ const iconv = require("iconv-lite"); const chardet = require("chardet"); const fs = require("fs"); const nodeJsUtil = require("util"); +const chroma = require("chroma-js"); // From ping-lite exports.WIN = /^win/.test(process.platform); @@ -370,3 +371,12 @@ exports.errorLog = (error, outputToConsole = true) => { } } catch (_) { } }; + +exports.percentageToColor = (percentage, maxHue = 90, minHue = 10) => { + const hue = percentage * (maxHue - minHue) + minHue; + try { + return chroma(`hsl(${hue}, 90%, 40%)`).hex(); + } catch (err) { + return "grey"; + } +}; From 1c5bce8afa4f37f88a1495ae57b60209c2fe9180 Mon Sep 17 00:00:00 2001 From: Jens Neuber Date: Mon, 3 Jan 2022 16:04:37 +0100 Subject: [PATCH 002/163] a little documentation --- server/routers/api-router.js | 4 +++- server/util-server.js | 10 ++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/server/routers/api-router.js b/server/routers/api-router.js index 8573226f8..d5f8aaa7f 100644 --- a/server/routers/api-router.js +++ b/server/routers/api-router.js @@ -244,6 +244,8 @@ router.get("/api/badge/:id/:type", cache("5 minutes"), async (request, response) const badgeValues = {}; if (!publicMonitor) { + // return a "n/a" badge in grey, if monitor is not public / not available / non exsitant + badgeValues.message = "N/A"; badgeValues.color = "#CCCCCC"; } else { @@ -261,9 +263,9 @@ router.get("/api/badge/:id/:type", cache("5 minutes"), async (request, response) badgeValues.message = [prefix, `${uptime * 100} %`, suffix] .filter((part) => part ?? part !== "") .join(""); - } + // build the svg based on given values const svg = makeBadge(badgeValues); response.type("image/svg+xml"); diff --git a/server/util-server.js b/server/util-server.js index 3f2918937..838e597d7 100644 --- a/server/util-server.js +++ b/server/util-server.js @@ -372,6 +372,16 @@ exports.errorLog = (error, outputToConsole = true) => { } catch (_) { } }; +/** + * Returns a color code in hex format based on a given percentage: + * 0% => hue = 10 => red + * 100% => hue = 90 => green + * + * @param {number} percentage, float, 0 to 1 + * @param {number} maxHue, int + * @param {number} minHue, int + * @returns {string}, hex value + */ exports.percentageToColor = (percentage, maxHue = 90, minHue = 10) => { const hue = percentage * (maxHue - minHue) + minHue; try { From d74404e106773fd3fe6cd82b9cfe167664503eab Mon Sep 17 00:00:00 2001 From: Jens Neuber Date: Mon, 3 Jan 2022 16:23:23 +0100 Subject: [PATCH 003/163] minor fixes --- server/routers/api-router.js | 2 +- server/util-server.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/server/routers/api-router.js b/server/routers/api-router.js index d5f8aaa7f..e36f1f269 100644 --- a/server/routers/api-router.js +++ b/server/routers/api-router.js @@ -247,7 +247,7 @@ router.get("/api/badge/:id/:type", cache("5 minutes"), async (request, response) // return a "n/a" badge in grey, if monitor is not public / not available / non exsitant badgeValues.message = "N/A"; - badgeValues.color = "#CCCCCC"; + badgeValues.color = "#999"; } else { const uptime = await Monitor.calcUptime( requestedType, diff --git a/server/util-server.js b/server/util-server.js index 838e597d7..55b368a19 100644 --- a/server/util-server.js +++ b/server/util-server.js @@ -387,6 +387,6 @@ exports.percentageToColor = (percentage, maxHue = 90, minHue = 10) => { try { return chroma(`hsl(${hue}, 90%, 40%)`).hex(); } catch (err) { - return "grey"; + return "#999"; } }; From 3625915a8504deac161f805d5ed0b9ae46c84c58 Mon Sep 17 00:00:00 2001 From: Jens Neuber Date: Tue, 4 Jan 2022 12:21:53 +0100 Subject: [PATCH 004/163] add ping, status badge --- server/config.js | 10 ++- server/routers/api-router.js | 158 +++++++++++++++++++++++++++++++---- server/util-server.js | 3 +- 3 files changed, 152 insertions(+), 19 deletions(-) diff --git a/server/config.js b/server/config.js index 24ccfaa14..8a9a67f83 100644 --- a/server/config.js +++ b/server/config.js @@ -1,7 +1,15 @@ const args = require("args-parser")(process.argv); const demoMode = args["demo"] || false; +const badgeConstants = { + naColor: "#999", + defaultUpColor: "#66c20a", + defaultDownColor: "#c2290a", + defaultPingColor: "blue", // as defined by badge-maker / shields.io +}; + module.exports = { args, - demoMode + demoMode, + badgeConstants }; diff --git a/server/routers/api-router.js b/server/routers/api-router.js index e36f1f269..a68ea050f 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 } = require("../util-server"); +const { allowDevAllOrigin, getSettings, setting, percentageToColor, allowAllOrigin } = require("../util-server"); const { R } = require("redbean-node"); const server = require("../server"); const apicache = require("../modules/apicache"); @@ -7,6 +7,7 @@ const Monitor = require("../model/monitor"); const dayjs = require("dayjs"); const { UP, flipStatus, debug } = require("../../src/util"); const { makeBadge } = require("badge-maker"); +const { badgeConstants } = require("../config"); let router = express.Router(); let cache = apicache.middleware; @@ -215,22 +216,23 @@ router.get("/api/status-page/heartbeat", cache("5 minutes"), async (_request, re } }); -router.get("/api/badge/:id/:type", cache("5 minutes"), async (request, response) => { - allowDevAllOrigin(response); +router.get("/api/badge/:id/status", cache("5 minutes"), async (request, response) => { + allowAllOrigin(response); const { label, - labelPrefix, - labelSuffix = "h", - prefix, - suffix, + upLabel = "Up", + downLabel = "Down", + upColor = badgeConstants.defaultUpColor, + downColor = badgeConstants.defaultDownColor, + value // for demo purpose only } = request.query; try { await checkPublished(); const requestedMonitorId = parseInt(request.params.id, 10); - const requestedType = parseInt(request.params.type, 10) ?? 24; + const overrideValue = value !== undefined ? parseInt(value) : undefined; let publicMonitor = await R.getRow(` SELECT monitor_group.monitor_id FROM monitor_group, \`group\` @@ -244,23 +246,146 @@ router.get("/api/badge/:id/:type", cache("5 minutes"), async (request, response) const badgeValues = {}; if (!publicMonitor) { - // return a "n/a" badge in 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 badgeValues.message = "N/A"; - badgeValues.color = "#999"; + badgeValues.color = badgeConstants.naColor; } else { - const uptime = await Monitor.calcUptime( - requestedType, + const heartbeat = await Monitor.getPreviousHeartbeat(requestedMonitorId); + const state = overrideValue !== undefined ? overrideValue : heartbeat.status === 1; + + badgeValues.color = state ? upColor : downColor; + badgeValues.message = label ?? state ? upLabel : downLabel; + } + + // build the svg based on given values + const svg = makeBadge(badgeValues); + + response.type("image/svg+xml"); + response.send(svg); + } catch (error) { + send403(response, error.message); + } +}); + +router.get("/api/badge/:id/uptime/:duration?", cache("5 minutes"), async (request, response) => { + allowAllOrigin(response); + + const { + label, + labelPrefix, + labelSuffix = "h", + prefix, + suffix = "%", + color, + labelColor, + value // for demo purpose only + } = request.query; + + try { + await checkPublished(); + + const requestedMonitorId = parseInt(request.params.id, 10); + // if no duration is given, set value to 24 (h) + const requestedDuration = request.params.duration !== undefined ? parseInt(request.params.duration, 10) : 24; + const overrideValue = value && parseFloat(value); + + let publicMonitor = await R.getRow(` + SELECT monitor_group.monitor_id FROM monitor_group, \`group\` + WHERE monitor_group.group_id = \`group\`.id + AND monitor_group.monitor_id = ? + AND public = 1 + `, + [requestedMonitorId] + ); + + const badgeValues = {}; + + 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 { + const uptime = overrideValue ?? await Monitor.calcUptime( + requestedDuration, requestedMonitorId ); - badgeValues.color = percentageToColor(uptime); + badgeValues.color = color ?? percentageToColor(uptime); + badgeValues.labelColor = labelColor ?? ""; - badgeValues.label = [labelPrefix, label ?? requestedType, labelSuffix] + badgeValues.label = [labelPrefix, label ?? requestedDuration, labelSuffix] .filter((part) => part ?? part !== "") .join(""); - badgeValues.message = [prefix, `${uptime * 100} %`, suffix] + badgeValues.message = [prefix, `${uptime * 100}`, suffix] + .filter((part) => part ?? part !== "") + .join(""); + } + + // build the SVG based on given values + const svg = makeBadge(badgeValues); + + response.type("image/svg+xml"); + response.send(svg); + } catch (error) { + send403(response, error.message); + } +}); + +router.get("/api/badge/:id/ping/:duration?", cache("5 minutes"), async (request, response) => { + allowAllOrigin(response); + + const { + label, + labelPrefix, + labelSuffix = "h", + prefix, + suffix = "ms", + color = badgeConstants.defaultPingColor, + labelColor, + value + } = request.query; + + try { + await checkPublished(); + + const requestedMonitorId = parseInt(request.params.id, 10); + + // Default duration is 24 (h) if not defined in queryParam, limited to 720h (30d) + const requestedDuration = Math.min(request.params.duration ? parseInt(request.params.duration, 10) : 24, 720); + const overrideValue = value && parseFloat(value); + + const publicAvgPing = parseInt(await R.getCell(` + SELECT AVG(ping) FROM monitor_group, \`group\`, heartbeat + WHERE monitor_group.group_id = \`group\`.id + AND heartbeat.time > DATETIME('now', ? || ' hours') + AND heartbeat.ping IS NOT NULL + AND public = 1 + AND heartbeat.monitor_id = ? + `, + [-requestedDuration, requestedMonitorId] + )); + + const badgeValues = {}; + + if (!publicAvgPing) { + // 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 { + const avgPing = parseInt(overrideValue ?? publicAvgPing); + + badgeValues.color = color; + badgeValues.labelColor = labelColor ?? ""; + + badgeValues.label = [labelPrefix, label ?? requestedDuration, labelSuffix] + .filter((part) => part ?? part !== "") + .join(""); + + badgeValues.message = [prefix, avgPing, suffix] .filter((part) => part ?? part !== "") .join(""); } @@ -273,8 +398,7 @@ router.get("/api/badge/:id/:type", cache("5 minutes"), async (request, response) } catch (error) { send403(response, error.message); } -} -); +}); async function checkPublished() { if (! await isPublished()) { diff --git a/server/util-server.js b/server/util-server.js index 55b368a19..0bcc4dd5a 100644 --- a/server/util-server.js +++ b/server/util-server.js @@ -11,6 +11,7 @@ const chardet = require("chardet"); const fs = require("fs"); const nodeJsUtil = require("util"); const chroma = require("chroma-js"); +const { badgeConstants } = require("./config"); // From ping-lite exports.WIN = /^win/.test(process.platform); @@ -387,6 +388,6 @@ exports.percentageToColor = (percentage, maxHue = 90, minHue = 10) => { try { return chroma(`hsl(${hue}, 90%, 40%)`).hex(); } catch (err) { - return "#999"; + return badgeConstants.naColor; } }; From 7abbf421d02cdb076e7dda1a4e03d8f055c739ac Mon Sep 17 00:00:00 2001 From: Jens Neuber Date: Tue, 4 Jan 2022 12:23:16 +0100 Subject: [PATCH 005/163] PR feedback --- server/routers/api-router.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/routers/api-router.js b/server/routers/api-router.js index a68ea050f..1bd1c13b7 100644 --- a/server/routers/api-router.js +++ b/server/routers/api-router.js @@ -390,7 +390,7 @@ router.get("/api/badge/:id/ping/:duration?", cache("5 minutes"), async (request, .join(""); } - // build the svg based on given values + // build the SVG based on given values const svg = makeBadge(badgeValues); response.type("image/svg+xml"); From f455e3a45439c516e0bf5295bdc8bd50ce450dcd Mon Sep 17 00:00:00 2001 From: Jens Neuber Date: Tue, 4 Jan 2022 13:40:53 +0100 Subject: [PATCH 006/163] add shields.io 'style' parameter --- server/routers/api-router.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/server/routers/api-router.js b/server/routers/api-router.js index 1bd1c13b7..8264800bf 100644 --- a/server/routers/api-router.js +++ b/server/routers/api-router.js @@ -225,6 +225,7 @@ 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 } = request.query; @@ -243,7 +244,7 @@ router.get("/api/badge/:id/status", cache("5 minutes"), async (request, response [requestedMonitorId] ); - const badgeValues = {}; + const badgeValues = { style }; if (!publicMonitor) { // return a "N/A" badge in naColor (grey), if monitor is not public / not available / non exsitant @@ -279,6 +280,7 @@ router.get("/api/badge/:id/uptime/:duration?", cache("5 minutes"), async (reques suffix = "%", color, labelColor, + style = "flat", value // for demo purpose only } = request.query; @@ -299,7 +301,7 @@ router.get("/api/badge/:id/uptime/:duration?", cache("5 minutes"), async (reques [requestedMonitorId] ); - const badgeValues = {}; + const badgeValues = { style }; if (!publicMonitor) { // return a "N/A" badge in naColor (grey), if monitor is not public / not available / non exsitant @@ -345,7 +347,8 @@ router.get("/api/badge/:id/ping/:duration?", cache("5 minutes"), async (request, suffix = "ms", color = badgeConstants.defaultPingColor, labelColor, - value + style = "flat", + value // for demo purpose only } = request.query; try { @@ -368,7 +371,7 @@ router.get("/api/badge/:id/ping/:duration?", cache("5 minutes"), async (request, [-requestedDuration, requestedMonitorId] )); - const badgeValues = {}; + const badgeValues = { style }; if (!publicAvgPing) { // return a "N/A" badge in naColor (grey), if monitor is not public / not available / non exsitant From 6acc9546a00bb14d2a5bb3f721238072cae327b3 Mon Sep 17 00:00:00 2001 From: Jens Neuber Date: Tue, 4 Jan 2022 16:00:21 +0100 Subject: [PATCH 007/163] PR feedback + remove redundant code + add a test --- server/config.js | 5 ++++ server/routers/api-router.js | 48 +++++++++++++++--------------------- server/util-server.js | 11 +++++++++ test/backend.spec.js | 22 +++++++++++++++++ 4 files changed, 58 insertions(+), 28 deletions(-) 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(""); + }); +}); + From 28c0e16a0ca569770036c635bdb15a6958e9a017 Mon Sep 17 00:00:00 2001 From: Jens Neuber Date: Tue, 4 Jan 2022 16:01:40 +0100 Subject: [PATCH 008/163] PR feedback --- server/config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/config.js b/server/config.js index f47765077..d46f24b75 100644 --- a/server/config.js +++ b/server/config.js @@ -16,5 +16,5 @@ const badgeConstants = { module.exports = { args, demoMode, - badgeConstants + badgeConstants, }; From df8f93f0c206b2e34b1c6c29f420e1283cb2fb6b Mon Sep 17 00:00:00 2001 From: Jens Neuber Date: Wed, 5 Jan 2022 11:48:25 +0100 Subject: [PATCH 009/163] clean uptime percentage display --- server/routers/api-router.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/server/routers/api-router.js b/server/routers/api-router.js index 6e0a2dec5..3b8ebe822 100644 --- a/server/routers/api-router.js +++ b/server/routers/api-router.js @@ -313,13 +313,16 @@ router.get("/api/badge/:id/uptime/:duration?", cache("5 minutes"), async (reques requestedMonitorId ); + // limit the displayed uptime percentage to four ( two, when displayed as percent ) decimal digits + const cleanUptime = parseFloat(uptime.toPrecision(4)); + // 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 ?? ""; // 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]); + badgeValues.message = filterAndJoin([prefix, `${cleanUptime * 100}`, suffix]); } // build the SVG based on given values From a9d264ccfc1c8c1c350d0b301650b689af0c74a9 Mon Sep 17 00:00:00 2001 From: Jens Neuber Date: Wed, 5 Jan 2022 15:25:42 +0100 Subject: [PATCH 010/163] PR feedback: remove spaces in comments Co-authored-by: Adam Stachowicz --- server/routers/api-router.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/routers/api-router.js b/server/routers/api-router.js index 3b8ebe822..45d416a88 100644 --- a/server/routers/api-router.js +++ b/server/routers/api-router.js @@ -313,7 +313,7 @@ router.get("/api/badge/:id/uptime/:duration?", cache("5 minutes"), async (reques requestedMonitorId ); - // 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 = parseFloat(uptime.toPrecision(4)); // use a given, custom color or calculate one based on the uptime value From faf6719e7c3ea3dc3981878db1dd983b4d1b4dd3 Mon Sep 17 00:00:00 2001 From: Jens Neuber Date: Wed, 5 Jan 2022 15:25:56 +0100 Subject: [PATCH 011/163] PR feedback: remove spaces in parenthesis Co-authored-by: Adam Stachowicz --- server/routers/api-router.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/routers/api-router.js b/server/routers/api-router.js index 45d416a88..4ba51dbfd 100644 --- a/server/routers/api-router.js +++ b/server/routers/api-router.js @@ -318,7 +318,7 @@ router.get("/api/badge/:id/uptime/:duration?", cache("5 minutes"), async (reques // 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) + // 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 ?? requestedDuration, labelSuffix]); From 499042504fae637ae745eaf53f00c676b3db1160 Mon Sep 17 00:00:00 2001 From: Jens Neuber Date: Wed, 5 Jan 2022 15:26:07 +0100 Subject: [PATCH 012/163] PR feedback: remove spaces in parenthesis Co-authored-by: Adam Stachowicz --- server/routers/api-router.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/routers/api-router.js b/server/routers/api-router.js index 4ba51dbfd..18da6b47f 100644 --- a/server/routers/api-router.js +++ b/server/routers/api-router.js @@ -320,7 +320,7 @@ router.get("/api/badge/:id/uptime/:duration?", cache("5 minutes"), async (reques badgeValues.color = color ?? percentageToColor(uptime); // 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 ) + // 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, `${cleanUptime * 100}`, suffix]); } From 43f8fc701c2ea779652107a4b801bd6ed6946b84 Mon Sep 17 00:00:00 2001 From: Jens Neuber Date: Wed, 5 Jan 2022 15:26:23 +0100 Subject: [PATCH 013/163] PR feedback: remove spaces in parenthesis Co-authored-by: Adam Stachowicz --- server/routers/api-router.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/routers/api-router.js b/server/routers/api-router.js index 18da6b47f..81423407d 100644 --- a/server/routers/api-router.js +++ b/server/routers/api-router.js @@ -381,7 +381,7 @@ 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) + // 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 ?? requestedDuration, labelSuffix]); From f00ec4dfef0f9be5174c170c17ac0d6d13a6c6e4 Mon Sep 17 00:00:00 2001 From: Jens Neuber Date: Wed, 5 Jan 2022 15:26:29 +0100 Subject: [PATCH 014/163] PR feedback: remove spaces in parenthesis Co-authored-by: Adam Stachowicz --- server/routers/api-router.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/routers/api-router.js b/server/routers/api-router.js index 81423407d..42bf5fed7 100644 --- a/server/routers/api-router.js +++ b/server/routers/api-router.js @@ -383,7 +383,7 @@ router.get("/api/badge/:id/ping/:duration?", cache("5 minutes"), async (request, badgeValues.color = color; // 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 ) + // 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]); } From 3dda5938f2180c4af2b9edd6f165c196c707da1c Mon Sep 17 00:00:00 2001 From: Raphael Bernhart Date: Fri, 21 Jan 2022 15:39:49 +0100 Subject: [PATCH 015/163] =?UTF-8?q?=F0=9F=92=84=20Add=20condition=20to=20d?= =?UTF-8?q?iv=20tag=20for=20styling=20reasons?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/PublicGroupList.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/PublicGroupList.vue b/src/components/PublicGroupList.vue index f30edcef5..bd68e94e0 100644 --- a/src/components/PublicGroupList.vue +++ b/src/components/PublicGroupList.vue @@ -41,7 +41,7 @@ {{ monitor.element.name }} -
+
From c57b2c4d287ac1ac9242ca3bc99a72236bc0606c Mon Sep 17 00:00:00 2001 From: Raphael Bernhart Date: Fri, 21 Jan 2022 17:13:24 +0100 Subject: [PATCH 016/163] =?UTF-8?q?=F0=9F=92=84=20Fix=20spacing=20to=20get?= =?UTF-8?q?=20pixel=20perfectness?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/assets/app.scss | 2 +- src/components/PublicGroupList.vue | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/assets/app.scss b/src/assets/app.scss index cec644676..f4d994629 100644 --- a/src/assets/app.scss +++ b/src/assets/app.scss @@ -339,7 +339,7 @@ textarea.form-control { .item { display: block; text-decoration: none; - padding: 13px 15px 10px 15px; + padding: 15px; border-radius: 10px; transition: all ease-in-out 0.15s; diff --git a/src/components/PublicGroupList.vue b/src/components/PublicGroupList.vue index bd68e94e0..334282d82 100644 --- a/src/components/PublicGroupList.vue +++ b/src/components/PublicGroupList.vue @@ -33,8 +33,8 @@ + + From f23baf9c2241284fed55b2b47a88c5efe7970574 Mon Sep 17 00:00:00 2001 From: DasCanard Date: Tue, 24 May 2022 23:14:27 +0200 Subject: [PATCH 099/163] Added Push Monitor to Discord Notifications --- server/notification-providers/discord.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/server/notification-providers/discord.js b/server/notification-providers/discord.js index 77b04d9d3..28ead7b7a 100644 --- a/server/notification-providers/discord.js +++ b/server/notification-providers/discord.js @@ -55,8 +55,8 @@ class Discord extends NotificationProvider { value: monitorJSON["name"], }, { - name: "Service URL / Address", - value: address, + name: monitorJSON["type"] === "push" ? "Service Type" : "Service URL", + value: monitorJSON["type"] === "push" ? "Heartbeat" : address, }, { name: "Time (UTC)", @@ -90,8 +90,8 @@ class Discord extends NotificationProvider { value: monitorJSON["name"], }, { - name: "Service URL", - value: address.startsWith("http") ? "[Visit Service](" + address + ")" : address, + name: monitorJSON["type"] === "push" ? "Service Type" : "Service URL", + value: monitorJSON["type"] === "push" ? "Heartbeat" : address.startsWith("http") ? "[Visit Service](" + address + ")" : address, }, { name: "Time (UTC)", @@ -99,7 +99,7 @@ class Discord extends NotificationProvider { }, { name: "Ping", - value: heartbeatJSON["ping"] + "ms", + value: heartbeatJSON["ping"] == null ? "N/A" : heartbeatJSON["ping"] + " ms", }, ], }], From 5830f1e0b5c0bced9904e2db67af875d0d224422 Mon Sep 17 00:00:00 2001 From: Marc Hagen Date: Wed, 16 Feb 2022 23:09:22 +0100 Subject: [PATCH 100/163] [feat] Adding PagerDuty notification --- server/notification-providers/pagerduty.js | 113 +++++++++++++++++++++ server/notification.js | 2 + src/components/notifications/PagerDuty.vue | 40 ++++++++ src/components/notifications/index.js | 2 + src/languages/en.js | 9 ++ 5 files changed, 166 insertions(+) create mode 100644 server/notification-providers/pagerduty.js create mode 100644 src/components/notifications/PagerDuty.vue diff --git a/server/notification-providers/pagerduty.js b/server/notification-providers/pagerduty.js new file mode 100644 index 000000000..86e9a0992 --- /dev/null +++ b/server/notification-providers/pagerduty.js @@ -0,0 +1,113 @@ +const NotificationProvider = require("./notification-provider"); +const axios = require("axios"); +const { UP, DOWN, getMonitorRelativeURL } = require("../../src/util"); +const { setting } = require("../util-server"); +let successMessage = "Sent Successfully."; + +class PagerDuty extends NotificationProvider { + name = "PagerDuty"; + + /** + * @inheritdoc + */ + async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { + try { + if (heartbeatJSON == null) { + const title = "Uptime Kuma Alert"; + const monitor = { + type: "ping", + url: "Uptime Kuma Test Button", + }; + return this.postNotification(notification, title, msg, monitor); + } + + if (heartbeatJSON.status === UP) { + const title = "Uptime Kuma Monitor ✅ Up"; + const eventAction = notification.pagerdutyAutoResolve || null; + + return this.postNotification(notification, title, heartbeatJSON.msg, monitorJSON, eventAction); + } + + if (heartbeatJSON.status === DOWN) { + const title = "Uptime Kuma Monitor 🔴 Down"; + return this.postNotification(notification, title, heartbeatJSON.msg, monitorJSON, "trigger"); + } + } catch (error) { + this.throwGeneralAxiosError(error); + } + } + + /** + * Check if result is successful, result code should be in range 2xx + * @param {Object} result Axios response object + * @throws {Error} The status code is not in range 2xx + */ + checkResult(result) { + if (result.status == null) { + throw new Error("PagerDuty notification failed with invalid response!"); + } + if (result.status < 200 || result.status >= 300) { + throw new Error("PagerDuty notification failed with status code " + result.status); + } + } + + /** + * Send the message + * @param {BeanModel} notification Message title + * @param {string} title Message title + * @param {string} body Message + * @param {Object} monitorInfo Monitor details (For Up/Down only) + * @param {?string} eventAction Action event for PagerDuty (trigger, acknowledge, resolve) + * @returns {string} + */ + async postNotification(notification, title, body, monitorInfo, eventAction = "trigger") { + + if (eventAction == null) { + return "No action required"; + } + + let monitorUrl; + if (monitorInfo.type === "port") { + monitorUrl = monitorInfo.hostname; + if (monitorInfo.port) { + monitorUrl += ":" + monitorInfo.port; + } + } else if (monitorInfo.hostname != null) { + monitorUrl = monitorInfo.hostname; + } else { + monitorUrl = monitorInfo.url; + } + + const options = { + method: "POST", + url: notification.pagerdutyIntegrationUrl, + headers: { "Content-Type": "application/json" }, + data: { + payload: { + summary: `[${title}] [${monitorInfo.name}] ${body}`, + severity: notification.pagerdutyPriority || "warning", + source: monitorUrl, + }, + routing_key: notification.pagerdutyIntegrationKey, + event_action: eventAction, + dedup_key: "Uptime Kuma/" + monitorInfo.id, + } + }; + + const baseURL = await setting("primaryBaseURL"); + if (baseURL && monitorInfo) { + options.client = "Uptime Kuma"; + options.client_url = baseURL + getMonitorRelativeURL(monitorInfo.id); + } + + let result = await axios.request(options); + this.checkResult(result); + if (result.statusText != null) { + return "PagerDuty notification succeed: " + result.statusText; + } + + return successMessage; + } +} + +module.exports = PagerDuty; diff --git a/server/notification.js b/server/notification.js index 269e94440..d0b6f40d9 100644 --- a/server/notification.js +++ b/server/notification.js @@ -29,6 +29,7 @@ const SerwerSMS = require("./notification-providers/serwersms"); const Stackfield = require("./notification-providers/stackfield"); const WeCom = require("./notification-providers/wecom"); const GoogleChat = require("./notification-providers/google-chat"); +const PagerDuty = require("./notification-providers/pagerduty"); const Gorush = require("./notification-providers/gorush"); const Alerta = require("./notification-providers/alerta"); const OneBot = require("./notification-providers/onebot"); @@ -74,6 +75,7 @@ class Notification { new Stackfield(), new WeCom(), new GoogleChat(), + new PagerDuty(), new Gorush(), new Alerta(), new OneBot(), diff --git a/src/components/notifications/PagerDuty.vue b/src/components/notifications/PagerDuty.vue new file mode 100644 index 000000000..73f604437 --- /dev/null +++ b/src/components/notifications/PagerDuty.vue @@ -0,0 +1,40 @@ + + + diff --git a/src/components/notifications/index.js b/src/components/notifications/index.js index 496d35fa0..37beb24d3 100644 --- a/src/components/notifications/index.js +++ b/src/components/notifications/index.js @@ -27,6 +27,7 @@ import SerwerSMS from "./SerwerSMS.vue"; import Stackfield from "./Stackfield.vue"; import WeCom from "./WeCom.vue"; import GoogleChat from "./GoogleChat.vue"; +import PagerDuty from "./PagerDuty.vue"; import Gorush from "./Gorush.vue"; import Alerta from "./Alerta.vue"; import OneBot from "./OneBot.vue"; @@ -67,6 +68,7 @@ const NotificationFormList = { "stackfield": Stackfield, "WeCom": WeCom, "GoogleChat": GoogleChat, + "PagerDuty": PagerDuty, "gorush": Gorush, "alerta": Alerta, "OneBot": OneBot, diff --git a/src/languages/en.js b/src/languages/en.js index d634e5456..aa6737dd8 100644 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -331,6 +331,8 @@ export default { info: "info", warning: "warning", danger: "danger", + error: "error", + critical: "critical", primary: "primary", light: "light", dark: "dark", @@ -371,6 +373,13 @@ export default { smtpDkimHashAlgo: "Hash Algorithm (Optional)", smtpDkimheaderFieldNames: "Header Keys to sign (Optional)", smtpDkimskipFields: "Header Keys not to sign (Optional)", + wayToGetPagerDutyKey: "You can get this by going to Service -> Service Directory -> (Select a service) -> Integrations -> Add integration. Here you can search for \"Events API V2\". More info {0}", + "Integration Key": "Integration Key", + "Integration URL": "Integration URL", + "Auto resolve or acknowledged": "Auto resolve or acknowledged", + "do nothing": "do nothing", + "auto acknowledged": "auto acknowledged", + "auto resolve": "auto resolve", gorush: "Gorush", alerta: "Alerta", alertaApiEndpoint: "API Endpoint", From 5566b038c84792a7f59502e050d5eafa89641fd3 Mon Sep 17 00:00:00 2001 From: burakurer <58211081+burakurer@users.noreply.github.com> Date: Wed, 25 May 2022 17:35:05 +0300 Subject: [PATCH 101/163] Update tr-TR.js --- src/languages/tr-TR.js | 399 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 383 insertions(+), 16 deletions(-) diff --git a/src/languages/tr-TR.js b/src/languages/tr-TR.js index 0edd60206..08cafa2c3 100644 --- a/src/languages/tr-TR.js +++ b/src/languages/tr-TR.js @@ -1,6 +1,7 @@ export default { languageName: "Türkçe", checkEverySecond: "{0} Saniyede bir kontrol et.", + retryCheckEverySecond: "{0} Saniyede bir dene.", retriesDescription: "Servisin kapalı olarak işaretlenmeden ve bir bildirim gönderilmeden önce maksimum yeniden deneme sayısı", ignoreTLSError: "HTTPS web siteleri için TLS/SSL hatasını yoksay", upsideDownModeDescription: "Servisin durumunu tersine çevirir. Servis çalışıyorsa kapalı olarak işaretler.", @@ -12,12 +13,20 @@ export default { pauseDashboardHome: "Durdur", deleteMonitorMsg: "Servisi silmek istediğinden emin misin?", deleteNotificationMsg: "Bu bildirimi tüm servisler için silmek istediğinden emin misin?", + dnsPortDescription: "DNS sunucusu bağlantı noktası. Varsayılan değer 53'tür. Bağlantı noktasını istediğiniz zaman değiştirebilirsiniz.", resolverserverDescription: "Cloudflare varsayılan sunucudur, çözümleyici sunucusunu istediğiniz zaman değiştirebilirsiniz.", rrtypeDescription: "İzlemek istediğiniz servisin RR-Tipini seçin", pauseMonitorMsg: "Durdurmak istediğinden emin misin?", + enableDefaultNotificationDescription: "Bu bildirim her yeni serviste aktif olacaktır. Bildirimi servisler için ayrı ayrı deaktive edebilirsiniz. ", clearEventsMsg: "Bu servisin bütün kayıtlarını silmek istediğinden emin misin?", clearHeartbeatsMsg: "Bu servis için tüm sağlık durumunu silmek istediğinden emin misin?", confirmClearStatisticsMsg: "Tüm istatistikleri silmek istediğinden emin misin?", + importHandleDescription: "Aynı isimdeki bütün servisleri ve bildirimleri atlamak için 'Var olanı atla' seçiniz. 'Üzerine yaz' var olan bütün servisleri ve bildirimleri silecektir. ", + confirmImportMsg: "Yedeği içeri aktarmak istediğinize emin misiniz? Lütfen doğru içeri aktarma seçeneğini seçtiğinizden emin olunuz. ", + twoFAVerifyLabel: "Lütfen tokeni yazarak 2FA doğrulamanın çalıştığından emin olunuz.", + tokenValidSettingsMsg: "Token geçerli! Şimdi 2FA ayarlarını kaydedebilirsiniz. ", + confirmEnableTwoFAMsg: "2FA'ı etkinleştirmek istediğinizden emin misiniz?", + confirmDisableTwoFAMsg: "2FA'ı devre dışı bırakmak istediğinize emin misiniz?", Settings: "Ayarlar", Dashboard: "Panel", "New Update": "Yeni Güncelleme", @@ -25,6 +34,7 @@ export default { Appearance: "Görünüm", Theme: "Tema", General: "Genel", + "Primary Base URL": "Birincil Temel URL", Version: "Versiyon", "Check Update On GitHub": "GitHub'da Güncellemeyi Kontrol Edin", List: "Liste", @@ -62,10 +72,14 @@ export default { Port: "Port", "Heartbeat Interval": "Servis Test Aralığı", Retries: "Yeniden deneme", + "Heartbeat Retry Interval": "Sağlık Durumları Tekrar Deneme Sıklığı", Advanced: "Gelişmiş", "Upside Down Mode": "Ters/Düz Modu", "Max. Redirects": "Maksimum Yönlendirme", "Accepted Status Codes": "Kabul Edilen Durum Kodları", + "Push URL": "Push URL", + needPushEvery: "Bu URL'yi her {0} saniyede bir aramalısınız.", + pushOptionalParams: "İsteğe bağlı parametreler: {0}", Save: "Kaydet", Notifications: "Bildirimler", "Not available, please setup.": "Atanmış bildirim yöntemi yok. Ayarlardan belirleyebilirsiniz.", @@ -109,28 +123,19 @@ export default { "Last Result": "En son sonuçlar", "Create your admin account": "Yönetici hesabınızı oluşturun", "Repeat Password": "Şifrenizi tekrar girin", - respTime: "Cevap Süresi (ms)", - notAvailableShort: "N/A", - Create: "Yarat", - "Clear Data": "Verileri Temizle", - Events: "Olaylar", - Heartbeats: "Sağlık Durumları", - "Auto Get": "Otomatik Al", - retryCheckEverySecond: "{0} Saniyede bir dene.", - enableDefaultNotificationDescription: "Bu bildirim her yeni serviste aktif olacaktır. Bildirimi servisler için ayrı ayrı deaktive edebilirsiniz. ", - importHandleDescription: "Aynı isimdeki bütün servisleri ve bildirimleri atlamak için 'Var olanı atla' seçiniz. 'Üzerine yaz' var olan bütün servisleri ve bildirimleri silecektir. ", - confirmImportMsg: "Yedeği içeri aktarmak istediğinize emin misiniz? Lütfen doğru içeri aktarma seçeneğini seçtiğinizden emin olunuz. ", - twoFAVerifyLabel: "Lütfen tokeni yazarak 2FA doğrulamanın çalıştığından emin olunuz.", - tokenValidSettingsMsg: "Token geçerli! Şimdi 2FA ayarlarını kaydedebilirsiniz. ", - confirmEnableTwoFAMsg: "2FA'ı etkinleştirmek istediğinizden emin misiniz?", - confirmDisableTwoFAMsg: "2FA'ı devre dışı bırakmak istediğinize emin misiniz?", - "Heartbeat Retry Interval": "Sağlık Durumları Tekrar Deneme Sıklığı", "Import Backup": "Yedeği içe aktar", "Export Backup": "Yedeği dışa aktar", Export: "Dışa aktar", Import: "İçe aktar", + respTime: "Cevap Süresi (ms)", + notAvailableShort: "N/A", "Default enabled": "Varsayılan etkinleştirilmiş", "Apply on all existing monitors": "Var olan bütün servislere uygula", + Create: "Oluştur", + "Clear Data": "Verileri Temizle", + Events: "Olaylar", + Heartbeats: "Sağlık Durumları", + "Auto Get": "Otomatik Al", backupDescription: "Bütün servisleri ve bildirimleri JSON dosyasına yedekleyebilirsiniz.", backupDescription2: "Not: Geçmiş ve etkinlik verileri içinde değildir.", backupDescription3: "Dışa aktarma dosyasında bildirim tokeni gibi hassas veriler bulunur, dikkatli bir şekilde saklayınız.", @@ -149,4 +154,366 @@ export default { "Two Factor Authentication": "İki Faktörlü Kimlik Doğrulama (2FA)", Active: "Aktif", Inactive: "İnaktif", + Token: "Token", + "Show URI": "URI'yi göster", + Tags: "Etiketler", + "Add New below or Select...": "Aşağıya Yeni Ekle veya Seç...", + "Tag with this name already exist.": "Bu ada sahip etiket zaten var.", + "Tag with this value already exist.": "Bu değere sahip etiket zaten var.", + color: "renk", + "value (optional)": "değer (isteğe bağlı)", + Gray: "Gri", + Red: "Kırmızı", + Orange: "Turuncu", + Green: "Yeşil", + Blue: "Mavi", + Indigo: "Çivit mavisi", + Purple: "Mor", + Pink: "Pembe", + "Search...": "Ara...", + "Avg. Ping": "Ortalama Ping", + "Avg. Response": "Ortalama Cevap Süresi", + "Entry Page": "Giriş Sayfası", + statusPageNothing: "Burada hiçbir şey yok, lütfen bir grup veya servis ekleyin.", + "No Services": "Hizmet Yok", + "All Systems Operational": "Tüm Sistemler Operasyonel", + "Partially Degraded Service": "Kısmen Bozulmuş Hizmet", + "Degraded Service": "Bozulmuş Hizmet", + "Add Group": "Grup Ekle", + "Add a monitor": "Servis Ekle", + "Edit Status Page": "Durum Sayfasını Düzenle", + "Go to Dashboard": "Panele Git", + "Status Page": "Durum Sayfası", + "Status Pages": "Durum Sayfaları", + defaultNotificationName: "My {notification} Alert ({number})", + here: "burada", + Required: "Gerekli", + telegram: "Telegram", + "Bot Token": "Bot Token", + wayToGetTelegramToken: "{0} adresinden bir token alabilirsiniz.", + "Chat ID": "Chat ID", + supportTelegramChatID: "Doğrudan Sohbet / Grup / Kanalın Sohbet Kimliğini Destekleyin", + wayToGetTelegramChatID: "Bot'a bir mesaj göndererek ve chat_id'yi görüntülemek için bu URL'ye giderek sohbet kimliğinizi alabilirsiniz:", + "YOUR BOT TOKEN HERE": "BOT TOKENİNİZ BURADA", + chatIDNotFound: "Chat ID bulunamadı; lütfen önce bu bota bir mesaj gönderin", + webhook: "Webhook", + "Post URL": "Post URL", + "Content Type": "Content Type", + webhookJsonDesc: "{0}, Express.js gibi tüm modern HTTP sunucuları için iyidir", + webhookFormDataDesc: "{multipart} PHP için iyidir. JSON'un {decodeFunction} ile ayrıştırılması gerekecek", + smtp: "E-mail (SMTP)", + secureOptionNone: "Hiçbiri / STARTTLS (25, 587)", + secureOptionTLS: "TLS (465)", + "Ignore TLS Error": "TLS Hatasını Yoksay", + "From Email": "E-postadan", + emailCustomSubject: "Özel Konu", + "To Email": "E-postaya", + smtpCC: "CC", + smtpBCC: "BCC", + discord: "Discord", + "Discord Webhook URL": "Discord Webhook URL", + wayToGetDiscordURL: "Bunu Sunucu Ayarları -> Entegrasyonlar -> Webhook Oluştur'a giderek alabilirsiniz.", + "Bot Display Name": "Botun Görünecek Adı", + "Prefix Custom Message": "Önek Özel Mesaj", + "Hello @everyone is...": "Merhaba {'@'}everyone ...", + teams: "Microsoft Teams", + "Webhook URL": "Webhook URL", + wayToGetTeamsURL: "Bir webhook URL'sinin nasıl oluşturulacağını öğrenebilirsiniz {0}.", + signal: "Signal", + Number: "Numara", + Recipients: "Alıcılar", + needSignalAPI: "REST API ile bir signal istemciniz olması gerekiyor.", + wayToCheckSignalURL: "Nasıl kurulacağını görmek için bu URL'yi kontrol edebilirsiniz:", + signalImportant: "ÖNEMLİ: Alıcılarda grupları ve sayıları karıştıramazsınız!", + gotify: "Gotify", + "Application Token": "Uygulama Tokeni", + "Server URL": "Sunucu URL", + Priority: "Öncelik", + slack: "Slack", + "Icon Emoji": "İkon Emoji", + "Channel Name": "Kanal Adı", + "Uptime Kuma URL": "Uptime Kuma URL", + aboutWebhooks: "Webhook hakkında daha fazla bilgi: {0}", + aboutChannelName: "Webhook kanalını atlamak istiyorsanız, {0} Kanal Adı alanına kanal adını girin. Ör: #diğer-kanal", + aboutKumaURL: "Uptime Kuma URL alanını boş bırakırsanız, varsayılan olarak Project GitHub sayfası olur.", + emojiCheatSheet: "Emoji cheat sheet: {0}", + "rocket.chat": "Rocket.Chat", + pushover: "Pushover", + pushy: "Pushy", + PushByTechulus: "Push by Techulus", + octopush: "Octopush", + promosms: "PromoSMS", + clicksendsms: "ClickSend SMS", + lunasea: "LunaSea", + apprise: "Apprise (50'den fazla Bildirim hizmetini destekler)", + GoogleChat: "Google Chat (sadece Google Workspace)", + pushbullet: "Pushbullet", + line: "Line Messenger", + mattermost: "Mattermost", + "User Key": "Kullancı Anahtarı", + Device: "Cihaz", + "Message Title": "Mesaj Başlığı", + "Notification Sound": "Bilgilendirme sesi", + "More info on:": "Daha fazla bilgi: {0}", + pushoverDesc1: "Acil durum önceliği (2), yeniden denemeler arasında varsayılan olarak 30 saniyelik bir zaman aşımına sahiptir ve 1 saat sonra sona erecektir.", + pushoverDesc2: "Farklı cihazlara bildirim göndermek istiyorsanız Cihaz alanını doldurunuz.", + "SMS Type": "SMS Tipi", + octopushTypePremium: "Premium (Hızlı - uyarı için önerilir)", + octopushTypeLowCost: "Düşük Maliyet (Yavaş - bazen operatör tarafından engellenir)", + checkPrice: "{0} fiyatlarını kontrol edin:", + apiCredentials: "API kimlik bilgileri", + octopushLegacyHint: "Octopush'un (2011-2020) eski sürümünü mü yoksa yeni sürümünü mü kullanıyorsunuz?", + "Check octopush prices": "Octopush fiyatlarını kontrol edin {0}.", + octopushPhoneNumber: "Telefon numarası (uluslararası biçim, örneğin: +33612345678) ", + octopushSMSSender: "SMS Gönderici Adı : 3-11 alfanümerik karakter ve boşluk (a-zA-Z0-9)", + "LunaSea Device ID": "LunaSea Cihaz ID", + "Apprise URL": "Apprise URL", + "Example:": "Örnek: {0}", + "Read more:": "Daha fazla oku: {0}", + "Status:": "Durum: {0}", + "Read more": "Daha fazla oku", + appriseInstalled: "Apprise yüklendi.", + appriseNotInstalled: "Appris yüklü değil. {0}", + "Access Token": "Erişim Tokeni", + "Channel access token": "Kanal erişim tokeni", + "Line Developers Console": "Line Geliştirici Konsolu", + lineDevConsoleTo: "Line Geliştirici Konsolu - {0}", + "Basic Settings": "Temel Ayarlar", + "User ID": "Kullanıcı ID", + "Messaging API": "Messaging API", + wayToGetLineChannelToken: "Önce {0}'e erişin, bir sağlayıcı ve kanal (Messaging API) oluşturun, ardından yukarıda belirtilen menü öğelerinden kanal erişim tokenini ve kullanıcı id alabilirsiniz.", + "Icon URL": "Simge URL", + aboutIconURL: "Varsayılan profil resmini geçersiz kılmak için \"Simge URL\" bölümünde bir resme bağlantı sağlayabilirsiniz. Simge Emojisi ayarlanmışsa kullanılmayacaktır.", + aboutMattermostChannelName: "Kanal adını \"Kanal Adı\" alanına girerek Webhook'un gönderi yaptığı varsayılan kanalı geçersiz kılabilirsiniz. Bunun Mattermost Webhook ayarlarında etkinleştirilmesi gerekir. Ör: #diğer-kanal", + matrix: "Matrix", + promosmsTypeEco: "SMS ECO - ucuz ama yavaş ve genellikle aşırı yüklü. Yalnızca Polonyalı alıcılarla sınırlıdır.", + promosmsTypeFlash: "SMS FLASH - Mesaj, alıcı cihazda otomatik olarak gösterilecektir. Yalnızca Polonyalı alıcılarla sınırlıdır.", + promosmsTypeFull: "SMS FULL - Premium SMS katmanı, Gönderici Adınızı kullanabilirsiniz (Önce adınızı kaydetmeniz gerekir). Uyarılar için güvenilir.", + promosmsTypeSpeed: "SMS HIZI - Sistemde en yüksek öncelik. Çok hızlı ve güvenilir ancak maliyetli (SMS FULL fiyatının yaklaşık iki katı).", + promosmsPhoneNumber: "Telefon numarası (Polonyalı alıcı için Alan kodlarını atlayabilirsiniz)", + promosmsSMSSender: "SMS Gönderici Adı : Ön kayıtlı ad veya varsayılanlardan biri: InfoSMS, SMS Info, MaxSMS, INFO, SMS", + "Feishu WebHookUrl": "Feishu WebHookURL", + matrixHomeserverURL: "Homeserver URL (http(s):// ve isteğe bağlı olarak bağlantı noktası ile)", + "Internal Room Id": "Internal Room ID", + matrixDesc1: "Internal Room ID'sini, Matrix istemcinizdeki oda ayarlarının gelişmiş bölümüne bakarak bulabilirsiniz. !QMdRCpUIfLwsfjxye6:home.server gibi görünmelidir.", + matrixDesc2: "Hesabınıza ve katıldığınız tüm odalara tam erişime izin vereceğinden, yeni bir kullanıcı oluşturmanız ve kendi Matrix kullanıcınızın erişim belirtecini kullanmamanız şiddetle tavsiye edilir. Bunun yerine, yeni bir kullanıcı oluşturun ve onu yalnızca bildirimi almak istediğiniz odaya davet edin. {0} komutunu çalıştırarak erişim tokenini alabilirsiniz.", + Method: "Yöntem", + Body: "Gövde", + Headers: "Başlıklar", + PushUrl: "Push URL", + HeadersInvalidFormat: "İstek başlıkları geçerli JSON değil:", + BodyInvalidFormat: "İstek gövdesi geçerli JSON değil:", + "Monitor History": "Servis Geçmişi", + clearDataOlderThan: "{0} gün boyunca izleme geçmişi verilerini saklayın.", + PasswordsDoNotMatch: "Parolalar uyuşmuyor.", + records: "kayıtlar", + "One record": "Bir Kayıt", + steamApiKeyDescription: "Bir Steam Oyun Sunucusunu izlemek için bir Steam Web-API anahtarına ihtiyacınız vardır. API anahtarınızı buradan kaydedebilirsiniz: ", + "Current User": "Şu anki kullanıcı", + topic: "Başlık", + topicExplanation: "İzlenecek MQTT servisi", + successMessage: "Başarılı Mesaj", + successMessageExplanation: "Başarılı olarak kabul edilecek MQTT mesajı", + recent: "Son", + Done: "Tamamlandı", + Info: "Bilgi", + Security: "Güvenlik", + "Steam API Key": "Steam API Anahtarı", + "Shrink Database": "Veritabanını Küçült", + "Pick a RR-Type...": "Bir RR-Tipi seçin...", + "Pick Accepted Status Codes...": "Kabul Edilen Durum Kodlarını Seçin...", + Default: "Varsayılan", + "HTTP Options": "HTTP Ayarları", + "Create Incident": "Olay Oluştur", + Title: "Başlık", + Content: "İçerik", + Style: "Stil", + info: "info", + warning: "warning", + danger: "danger", + primary: "primary", + light: "light", + dark: "dark", + Post: "Post", + "Please input title and content": "Lütfen başlık ve içerik girin", + Created: "Oluşturuldu", + "Last Updated": "Son Güncelleme", + Unpin: "Unpin", + "Switch to Light Theme": "Açık Temaya Geç", + "Switch to Dark Theme": "Karanlık Temaya Geç", + "Show Tags": "Etiketleri Göster", + "Hide Tags": "Etiketleri Gizle", + Description: "Açıklama", + "No monitors available.": "Kullanılabilir servis yok.", + "Add one": "Bir tane ekle", + "No Monitors": "Servis Yok", + "Untitled Group": "Adsız Grup", + Services: "Hizmetler", + Discard: "İptal Et", + Cancel: "İptal Et", + "Powered by": "Powered by", + shrinkDatabaseDescription: "SQLite için veritabanı VACUUM'unu tetikleyin. Veritabanınız 1.10.0'dan sonra oluşturulduysa, AUTO_VACUUM zaten etkinleştirilmiştir ve bu eyleme gerek yoktur.", + serwersms: "SerwerSMS.pl", + serwersmsAPIUser: "API Kullanıcı Adı (webapi_ öneki dahil)", + serwersmsAPIPassword: "API Şifre", + serwersmsPhoneNumber: "Telefon numarası", + serwersmsSenderName: "SMS Gönderici Adı (müşteri portalı üzerinden kayıtlı)", + stackfield: "Stackfield", + Customize: "Özelleştirme", + "Custom Footer": "Özel Altbilgi", + "Custom CSS": "Özel CSS", + smtpDkimSettings: "DKIM Ayarları", + smtpDkimDesc: "Kullanım için lütfen Nodemailer DKIM'e {0} bakın.", + documentation: "belgeler", + smtpDkimDomain: "Alan adı", + smtpDkimKeySelector: "Anahtar Seçici", + smtpDkimPrivateKey: "Özel anahtar", + smtpDkimHashAlgo: "Hash Algoritması (Opsiyonel)", + smtpDkimheaderFieldNames: "İmzalanacak Başlık Anahtarları (Opsiyonel)", + smtpDkimskipFields: "İmzalamayacak Başlık Anahtarları (Opsiyonel)", + gorush: "Gorush", + alerta: "Alerta", + alertaApiEndpoint: "API Endpoint", + alertaEnvironment: "Environment", + alertaApiKey: "API Key", + alertaAlertState: "Uyarı Durumu", + alertaRecoverState: "Kurtarma Durumu", + deleteStatusPageMsg: "Bu durum sayfasını silmek istediğinizden emin misiniz?", + Proxies: "Proxy'ler", + default: "Varsayılan", + enabled: "Etkinleştirilmiş", + setAsDefault: "Varsayılan Olarak Ayarla", + deleteProxyMsg: "Bu proxy'yi tüm servisler için silmek istediğinizden emin misiniz?", + proxyDescription: "Proxy'lerin çalışması için bir servise atanması gerekir.", + enableProxyDescription: "Bu proxy, etkinleştirilene kadar izleme isteklerini etkilemeyecektir. Aktivasyon durumuna göre proxy'yi tüm servislerden geçici olarak devre dışı bırakabilirsiniz.", + setAsDefaultProxyDescription: "Bu proxy, yeni servisler için varsayılan olarak etkinleştirilecektir. Yine de proxy'yi her servis için ayrı ayrı devre dışı bırakabilirsiniz.", + "Certificate Chain": "Sertifika Zinciri", + Valid: "Geçerli", + Invalid: "Geçersiz", + AccessKeyId: "AccessKey ID", + SecretAccessKey: "AccessKey Secret", + PhoneNumbers: "PhoneNumbers", + TemplateCode: "TemplateCode", + SignName: "SignName", + "Sms template must contain parameters: ": "Sms şablonu parametreleri içermelidir:", + "Bark Endpoint": "Bark Endpoint", + WebHookUrl: "WebHookUrl", + SecretKey: "SecretKey", + "For safety, must use secret key": "Güvenlik için gizli anahtar kullanılmalıdır", + "Device Token": "Cihaz Tokeni", + Platform: "Platform", + iOS: "iOS", + Android: "Android", + Huawei: "Huawei", + High: "High", + Retry: "Retry", + Topic: "Topic", + "WeCom Bot Key": "WeCom Bot Key", + "Setup Proxy": "Proxy kur", + "Proxy Protocol": "Proxy Protokolü", + "Proxy Server": "Proxy Sunucusu", + "Proxy server has authentication": "Proxy sunucusunun kimlik doğrulaması var", + User: "Kullanıcı", + Installed: "Yüklenmiş", + "Not installed": "Yüklü değil", + Running: "Çalışıyor", + "Not running": "Çalışmıyor", + "Remove Token": "Tokeni Kaldır", + Start: "Başlat", + Stop: "Durdur", + "Uptime Kuma": "Uptime Kuma", + "Add New Status Page": "Yeni Durum Sayfası Ekle", + Slug: "Slug", + "Accept characters:": "Kabul edilen karakterler:", + startOrEndWithOnly: "Yalnızca {0} ile başlayın veya bitirin", + "No consecutive dashes": "Ardışık tire yok", + Next: "Sonraki", + "The slug is already taken. Please choose another slug.": "Slug zaten alındı. Lütfen başka bir slug seçin.", + "No Proxy": "Proxy Yok", + "HTTP Basic Auth": "HTTP Temel Yetkilendirme", + "New Status Page": "Yeni Durum Sayfası", + "Page Not Found": "Sayfa bulunamadı", + "Reverse Proxy": "Ters Proxy", + Backup: "Yedek", + About: "Hakkında", + wayToGetCloudflaredURL: "(Cloudflared'i {0} adresinden indirin)", + cloudflareWebsite: "Cloudflare Website", + "Message:": "Mesaj:", + "Don't know how to get the token? Please read the guide:": "Tokeni nasıl alacağınızı bilmiyor musunuz? Lütfen kılavuzu okuyun:", + "The current connection may be lost if you are currently connecting via Cloudflare Tunnel. Are you sure want to stop it? Type your current password to confirm it.": "Halihazırda Cloudflare Tüneli üzerinden bağlanıyorsanız mevcut bağlantı kesilebilir. Durdurmak istediğinden emin misin? Onaylamak için mevcut şifrenizi yazın.", + "Other Software": "Diğer Yazılımlar", + "For example: nginx, Apache and Traefik.": "Örneğin: nginx, Apache ve Traefik.", + "Please read": "Lütfen oku", + "Subject:": "Başlık:", + "Valid To:": "Geçerlilik:", + "Days Remaining:": "Kalan günler:", + "Issuer:": "Veren:", + "Fingerprint:": "Parmak izi:", + "No status pages": "Durum sayfası yok", + "Domain Name Expiry Notification": "Alan Adı Sona Erme Bildirimi", + Proxy: "Proxy", + "Date Created": "Tarih Oluşturuldu", + onebotHttpAddress: "OneBot HTTP Adresi", + onebotMessageType: "OneBot Mesaj Türü", + onebotGroupMessage: "Grup", + onebotPrivateMessage: "Özel", + onebotUserOrGroupId: "Grup/Kullanıcı Kimliği", + onebotSafetyTips: "Güvenlik için erişim tokeni ayarlamalısınız", + "PushDeer Key": "PushDeer Anahtarı", + "Footer Text": "Altbilgi metni", + "Show Powered By": "\"Powered by\" kısmını göster", + "Domain Names": "Alan isimleri", + signedInDisp: "{0} olarak oturum açıldı", + signedInDispDisabled: "Yetkilendirme Devre Dışı.", + "Certificate Expiry Notification": "Sertifika Sona Erme Bildirimi", + "API Username": "API Kullanıc Adı", + "API Key": "API Anahtarı", + "Recipient Number": "Alıcı Numarası", + "From Name/Number": "İsimden/Numaradan", + "Leave blank to use a shared sender number.": "Paylaşılan bir gönderen numarası kullanmak için boş bırakın.", + "Octopush API Version": "Octopush API Sürümü", + "Legacy Octopush-DM": "Eski Octopush-DM", + "endpoint": "endpoint", + octopushAPIKey: "Kontrol panelindeki HTTP API kimlik bilgilerinden \"API Key\"", + octopushLogin: "Kontrol panelindeki HTTP API kimlik bilgilerinden \"Login\"", + promosmsLogin: "API Oturum Açma Adı", + promosmsPassword: "API Şifresi", + "pushoversounds pushover": "Pushover (varsayılan)", + "pushoversounds bike": "Bisiklet", + "pushoversounds bugle": "Boru", + "pushoversounds cashregister": "Yazar kasa", + "pushoversounds classical": "Klasik", + "pushoversounds cosmic": "Kozmik", + "pushoversounds falling": "Düşme", + "pushoversounds gamelan": "Oyun Alanı", + "pushoversounds incoming": "Gelen", + "pushoversounds intermission": "Ara", + "pushoversounds magic": "Büyü", + "pushoversounds mechanical": "Mekanik", + "pushoversounds pianobar": "Piano", + "pushoversounds siren": "Siren", + "pushoversounds spacealarm": "Uzay Alarmı", + "pushoversounds tugboat": "Römorkör", + "pushoversounds alien": "Uzaylı Alarmı (uzun)", + "pushoversounds climb": "Tırmanış (uzun)", + "pushoversounds persistent": "Sürekli (uzun)", + "pushoversounds echo": "Pushover Yankı (uzun)", + "pushoversounds updown": "Yukarı Aşağı (uzun)", + "pushoversounds vibrate": "Sadece titreşim", + "pushoversounds none": "Yok (sessiz)", + pushyAPIKey: "Gizli API Anahtarı", + pushyToken: "Cihaz tokeni", + "Show update if available": "Varsa güncellemeyi göster", + "Also check beta release": "Ayrıca beta sürümünü kontrol edin", + "Using a Reverse Proxy?": "Ters Proxy mi Kullanıyorsunuz?", + "Check how to config it for WebSocket": "WebSocket için nasıl yapılandırılacağını kontrol edin", + "Steam Game Server": "Steam Oyun Sunucusu", + "Most likely causes:": "En olası nedenler:", + "The resource is no longer available.": "Kaynak artık mevcut değil.", + "There might be a typing error in the address.": "Adreste bir yazım hatası olabilir.", + "What you can try:": "Ne deneyebilirsin:", + "Retype the address.": "Adresi tekrar yazın.", + "Go back to the previous page.": "Bir önceki sayfaya geri git.", + "Coming Soon": "Yakında gelecek", + wayToGetClickSendSMSToken: "API Kullanıcı Adı ve API Anahtarını {0} adresinden alabilirsiniz.", }; From 0a8c922abf0b5919d4b6df83b08de133f164eb4d Mon Sep 17 00:00:00 2001 From: Louis Lam Date: Wed, 25 May 2022 23:34:47 +0800 Subject: [PATCH 102/163] Fix default value of pagerduty-integration-url --- src/components/notifications/PagerDuty.vue | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/components/notifications/PagerDuty.vue b/src/components/notifications/PagerDuty.vue index 73f604437..059a9aef2 100644 --- a/src/components/notifications/PagerDuty.vue +++ b/src/components/notifications/PagerDuty.vue @@ -8,7 +8,7 @@
- +
@@ -36,5 +36,10 @@ export default { components: { HiddenInput, }, + mounted() { + if (typeof this.$parent.notification.pagerdutyIntegrationUrl === "undefined") { + this.$parent.notification.pagerdutyIntegrationUrl = "https://events.pagerduty.com/v2/enqueue"; + } + } }; From 46ee149b700e26c517eaabb1ccf6db111e1f5482 Mon Sep 17 00:00:00 2001 From: Nelson Chan Date: Thu, 26 May 2022 12:12:29 +0800 Subject: [PATCH 103/163] Chore: Slightly improve design --- src/components/settings/Notifications.vue | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/components/settings/Notifications.vue b/src/components/settings/Notifications.vue index 187f4b7d5..9e9553c3a 100644 --- a/src/components/settings/Notifications.vue +++ b/src/components/settings/Notifications.vue @@ -26,7 +26,7 @@
{{ day }} {{ $t("day(s)") }} -
@@ -95,6 +95,11 @@ export default { From cf2ca71deecc218c1977de12bfa7d88cffc6f208 Mon Sep 17 00:00:00 2001 From: "sur.la.route" Date: Tue, 14 Jun 2022 07:42:53 -0500 Subject: [PATCH 155/163] prevent null workstation #'s from passing.. to axios-ntlm --- server/model/monitor.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/server/model/monitor.js b/server/model/monitor.js index 7c269fe26..63fd37114 100644 --- a/server/model/monitor.js +++ b/server/model/monitor.js @@ -279,12 +279,18 @@ class Monitor extends BeanModel { if (this.auth_method === "ntlm") { options.httpsAgent.keepAlive = true; - res = await httpNtlm(options, { + let ntlmOptions = + { username: this.basic_auth_user, password: this.basic_auth_pass, domain: this.authDomain, - workstation: this.authWorkstation, - }); + } + + if (this.authWorkstation) { + ntlmOptions.workstation= this.authWorkstation; + } + + res = await httpNtlm(options, ntlmOptions); } else { res = await axiosClient.request(options); From 6995a2998015c86046434ced4b835a60c9d4ae16 Mon Sep 17 00:00:00 2001 From: "sur.la.route" Date: Tue, 14 Jun 2022 07:45:04 -0500 Subject: [PATCH 156/163] workstation field should be text, not password --- src/pages/EditMonitor.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/EditMonitor.vue b/src/pages/EditMonitor.vue index bf0b5655c..1d902b1e3 100644 --- a/src/pages/EditMonitor.vue +++ b/src/pages/EditMonitor.vue @@ -404,7 +404,7 @@
- +
From 98f3c126e5febd7777cf361d8e771a8aa594177c Mon Sep 17 00:00:00 2001 From: Christopher Pickering Date: Tue, 14 Jun 2022 07:58:35 -0500 Subject: [PATCH 157/163] passed lint --- server/model/monitor.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/server/model/monitor.js b/server/model/monitor.js index 63fd37114..774875303 100644 --- a/server/model/monitor.js +++ b/server/model/monitor.js @@ -279,15 +279,14 @@ class Monitor extends BeanModel { if (this.auth_method === "ntlm") { options.httpsAgent.keepAlive = true; - let ntlmOptions = - { + let ntlmOptions = { username: this.basic_auth_user, password: this.basic_auth_pass, domain: this.authDomain, - } + }; if (this.authWorkstation) { - ntlmOptions.workstation= this.authWorkstation; + ntlmOptions.workstation = this.authWorkstation; } res = await httpNtlm(options, ntlmOptions); From 660005b143b6a79ee15624b090474049980595d8 Mon Sep 17 00:00:00 2001 From: Christopher Pickering Date: Tue, 14 Jun 2022 08:49:36 -0500 Subject: [PATCH 158/163] cleaned up code --- package-lock.json | 4 ++-- server/model/monitor.js | 11 +++-------- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/package-lock.json b/package-lock.json index 24f4cca4f..87342813a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "uptime-kuma", - "version": "1.16.1", + "version": "1.17.0-beta.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "uptime-kuma", - "version": "1.16.1", + "version": "1.17.0-beta.0", "license": "MIT", "dependencies": { "@fortawesome/fontawesome-svg-core": "~1.2.36", diff --git a/server/model/monitor.js b/server/model/monitor.js index 774875303..3e026fb62 100644 --- a/server/model/monitor.js +++ b/server/model/monitor.js @@ -279,17 +279,12 @@ class Monitor extends BeanModel { if (this.auth_method === "ntlm") { options.httpsAgent.keepAlive = true; - let ntlmOptions = { + res = await httpNtlm(options, { username: this.basic_auth_user, password: this.basic_auth_pass, domain: this.authDomain, - }; - - if (this.authWorkstation) { - ntlmOptions.workstation = this.authWorkstation; - } - - res = await httpNtlm(options, ntlmOptions); + workstation: this.authWorkstation ? this.authWorkstation : undefined + }); } else { res = await axiosClient.request(options); From 483cbfb6364b742a8ba0de28b56b235c0fd4a140 Mon Sep 17 00:00:00 2001 From: Christopher Pickering Date: Tue, 14 Jun 2022 09:00:23 -0500 Subject: [PATCH 159/163] added default value for sql server connection string --- src/pages/EditMonitor.vue | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pages/EditMonitor.vue b/src/pages/EditMonitor.vue index bf0b5655c..fb063da70 100644 --- a/src/pages/EditMonitor.vue +++ b/src/pages/EditMonitor.vue @@ -583,6 +583,7 @@ export default { method: "GET", interval: 60, retryInterval: this.interval, + databaseConnectionString: "Server=,;Database=;User Id=;Password=;Encrypt=;TrustServerCertificate=;Connection Timeout=", maxretries: 0, notificationIDList: {}, ignoreTls: false, From 62acd2edb1507f6979d8e9df1c2f86d6ad1d3e8b Mon Sep 17 00:00:00 2001 From: Nelson Chan Date: Tue, 14 Jun 2022 22:43:44 +0800 Subject: [PATCH 160/163] Fix: misc. layout fix on mobile --- src/assets/app.scss | 6 ++++++ src/components/MonitorList.vue | 18 +++++++++++++++--- src/pages/List.vue | 10 +++++++++- src/router.js | 8 ++++---- 4 files changed, 34 insertions(+), 8 deletions(-) diff --git a/src/assets/app.scss b/src/assets/app.scss index 93ff3ff3a..5adc76fa1 100644 --- a/src/assets/app.scss +++ b/src/assets/app.scss @@ -363,6 +363,12 @@ textarea.form-control { overflow-y: auto; height: calc(100% - 65px); } + + @media (max-width: 770px) { + &.scrollbar { + height: calc(100% - 40px); + } + } .item { display: block; diff --git a/src/components/MonitorList.vue b/src/components/MonitorList.vue index 7aeadd1e1..c4e621f96 100644 --- a/src/components/MonitorList.vue +++ b/src/components/MonitorList.vue @@ -69,10 +69,22 @@ export default { }; }, computed: { + /** + * Improve the sticky appearance of the list by increasing its + * height as user scrolls down. + * Not used on mobile. + */ boxStyle() { - return { - height: `calc(100vh - 160px + ${this.windowTop}px)`, - }; + if (window.innerWidth > 550) { + return { + height: `calc(100vh - 160px + ${this.windowTop}px)`, + }; + } else { + return { + height: "calc(100vh - 160px)", + }; + } + }, sortedMonitorList() { diff --git a/src/pages/List.vue b/src/pages/List.vue index 9cbf3f2ff..dd2d46059 100644 --- a/src/pages/List.vue +++ b/src/pages/List.vue @@ -1,6 +1,6 @@ @@ -14,3 +14,11 @@ export default { }; + diff --git a/src/router.js b/src/router.js index 179dbe185..726194776 100644 --- a/src/router.js +++ b/src/router.js @@ -65,12 +65,12 @@ const routes = [ path: "/add", component: EditMonitor, }, - { - path: "/list", - component: List, - }, ], }, + { + path: "/list", + component: List, + }, { path: "/settings", component: Settings, From c170b1edd0d3715a62ae45250f8c6a756dbad412 Mon Sep 17 00:00:00 2001 From: Louis Lam Date: Wed, 15 Jun 2022 15:18:14 +0800 Subject: [PATCH 161/163] Better optgroup text color --- docker/debian-base.dockerfile | 6 ++++-- src/assets/app.scss | 19 +++++++++++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/docker/debian-base.dockerfile b/docker/debian-base.dockerfile index f2016b802..6d0a0648d 100644 --- a/docker/debian-base.dockerfile +++ b/docker/debian-base.dockerfile @@ -12,7 +12,8 @@ RUN apt update && \ apt --yes --no-install-recommends install python3 python3-pip python3-cryptography python3-six python3-yaml python3-click python3-markdown python3-requests python3-requests-oauthlib \ sqlite3 iputils-ping util-linux dumb-init && \ pip3 --no-cache-dir install apprise==0.9.8.3 && \ - rm -rf /var/lib/apt/lists/* + rm -rf /var/lib/apt/lists/* && \ + apt --yes autoremove # Install cloudflared # dpkg --add-architecture arm: cloudflared do not provide armhf, this is workaround. Read more: https://github.com/cloudflare/cloudflared/issues/583 @@ -22,5 +23,6 @@ RUN node ./extra/download-cloudflared.js $TARGETPLATFORM && \ apt update && \ apt --yes --no-install-recommends install ./cloudflared.deb && \ rm -rf /var/lib/apt/lists/* && \ - rm -f cloudflared.deb + rm -f cloudflared.deb && \ + apt --yes autoremove diff --git a/src/assets/app.scss b/src/assets/app.scss index 93ff3ff3a..5073302da 100644 --- a/src/assets/app.scss +++ b/src/assets/app.scss @@ -34,6 +34,25 @@ textarea.form-control { } } + +// optgroup +optgroup { + color: #b1b1b1; + option { + color: #212529; + } +} + +.dark { + optgroup { + color: #535864; + option { + color: $dark-font-color; + } + } +} + +// Scrollbar ::-webkit-scrollbar-thumb { background: #ccc; border-radius: 20px; From 8f1e193de3294921578f334d6355801789a3d32e Mon Sep 17 00:00:00 2001 From: Louis Lam Date: Wed, 15 Jun 2022 19:02:55 +0800 Subject: [PATCH 162/163] [vite] Change legacy browse target to `since 2015` --- config/vite.config.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/config/vite.config.js b/config/vite.config.js index 59cbe446e..c8bba8532 100644 --- a/config/vite.config.js +++ b/config/vite.config.js @@ -14,8 +14,7 @@ export default defineConfig({ plugins: [ vue(), legacy({ - targets: [ "ie > 11" ], - additionalLegacyPolyfills: [ "regenerator-runtime/runtime" ] + targets: [ "since 2015" ], }), visualizer({ filename: "tmp/dist-stats.html" From fdbdf83a0d8f37080b378837ffa634eb757dffa1 Mon Sep 17 00:00:00 2001 From: Louis Lam Date: Wed, 15 Jun 2022 19:11:52 +0800 Subject: [PATCH 163/163] Fix data type of `notification.isDefault` and `notification.active` (#1765) --- server/client.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/server/client.js b/server/client.js index f6f133d19..279acd3a6 100644 --- a/server/client.js +++ b/server/client.js @@ -22,7 +22,10 @@ async function sendNotificationList(socket) { ]); for (let bean of list) { - result.push(bean.export()); + let notificationObject = bean.export(); + notificationObject.isDefault = (notificationObject.isDefault === 1); + notificationObject.active = (notificationObject.active === 1); + result.push(notificationObject); } io.to(socket.userID).emit("notificationList", result);