mirror of
https://github.com/louislam/uptime-kuma.git
synced 2025-01-26 03:52:28 +02:00
Merge branch 'master' into mqtt2
# Conflicts: # server/database.js # server/util-server.js
This commit is contained in:
commit
5fa62a888c
50
.eslintrc.js
50
.eslintrc.js
@ -22,39 +22,47 @@ module.exports = {
|
|||||||
requireConfigFile: false,
|
requireConfigFile: false,
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
"linebreak-style": ["error", "unix"],
|
"yoda": "error",
|
||||||
"camelcase": ["warn", {
|
eqeqeq: [ "warn", "smart" ],
|
||||||
|
"linebreak-style": [ "error", "unix" ],
|
||||||
|
"camelcase": [ "warn", {
|
||||||
"properties": "never",
|
"properties": "never",
|
||||||
"ignoreImports": true
|
"ignoreImports": true
|
||||||
}],
|
}],
|
||||||
// override/add rules settings here, such as:
|
"no-unused-vars": [ "warn", {
|
||||||
// 'vue/no-unused-vars': 'error'
|
"args": "none"
|
||||||
"no-unused-vars": "warn",
|
}],
|
||||||
indent: [
|
indent: [
|
||||||
"error",
|
"error",
|
||||||
4,
|
4,
|
||||||
{
|
{
|
||||||
ignoredNodes: ["TemplateLiteral"],
|
ignoredNodes: [ "TemplateLiteral" ],
|
||||||
SwitchCase: 1,
|
SwitchCase: 1,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
quotes: ["warn", "double"],
|
quotes: [ "warn", "double" ],
|
||||||
semi: "error",
|
semi: "error",
|
||||||
"vue/html-indent": ["warn", 4], // default: 2
|
"vue/html-indent": [ "warn", 4 ], // default: 2
|
||||||
"vue/max-attributes-per-line": "off",
|
"vue/max-attributes-per-line": "off",
|
||||||
"vue/singleline-html-element-content-newline": "off",
|
"vue/singleline-html-element-content-newline": "off",
|
||||||
"vue/html-self-closing": "off",
|
"vue/html-self-closing": "off",
|
||||||
|
"vue/require-component-is": "off", // not allow is="style" https://github.com/vuejs/eslint-plugin-vue/issues/462#issuecomment-430234675
|
||||||
"vue/attribute-hyphenation": "off", // This change noNL to "no-n-l" unexpectedly
|
"vue/attribute-hyphenation": "off", // This change noNL to "no-n-l" unexpectedly
|
||||||
"no-multi-spaces": ["error", {
|
"no-multi-spaces": [ "error", {
|
||||||
ignoreEOLComments: true,
|
ignoreEOLComments: true,
|
||||||
}],
|
}],
|
||||||
"space-before-function-paren": ["error", {
|
"array-bracket-spacing": [ "warn", "always", {
|
||||||
|
"singleValue": true,
|
||||||
|
"objectsInArrays": false,
|
||||||
|
"arraysInArrays": false
|
||||||
|
}],
|
||||||
|
"space-before-function-paren": [ "error", {
|
||||||
"anonymous": "always",
|
"anonymous": "always",
|
||||||
"named": "never",
|
"named": "never",
|
||||||
"asyncArrow": "always"
|
"asyncArrow": "always"
|
||||||
}],
|
}],
|
||||||
"curly": "error",
|
"curly": "error",
|
||||||
"object-curly-spacing": ["error", "always"],
|
"object-curly-spacing": [ "error", "always" ],
|
||||||
"object-curly-newline": "off",
|
"object-curly-newline": "off",
|
||||||
"object-property-newline": "error",
|
"object-property-newline": "error",
|
||||||
"comma-spacing": "error",
|
"comma-spacing": "error",
|
||||||
@ -65,36 +73,36 @@ module.exports = {
|
|||||||
"space-infix-ops": "warn",
|
"space-infix-ops": "warn",
|
||||||
"arrow-spacing": "warn",
|
"arrow-spacing": "warn",
|
||||||
"no-trailing-spaces": "warn",
|
"no-trailing-spaces": "warn",
|
||||||
"no-constant-condition": ["error", {
|
"no-constant-condition": [ "error", {
|
||||||
"checkLoops": false,
|
"checkLoops": false,
|
||||||
}],
|
}],
|
||||||
"space-before-blocks": "warn",
|
"space-before-blocks": "warn",
|
||||||
//'no-console': 'warn',
|
//'no-console': 'warn',
|
||||||
"no-extra-boolean-cast": "off",
|
"no-extra-boolean-cast": "off",
|
||||||
"no-multiple-empty-lines": ["warn", {
|
"no-multiple-empty-lines": [ "warn", {
|
||||||
"max": 1,
|
"max": 1,
|
||||||
"maxBOF": 0,
|
"maxBOF": 0,
|
||||||
}],
|
}],
|
||||||
"lines-between-class-members": ["warn", "always", {
|
"lines-between-class-members": [ "warn", "always", {
|
||||||
exceptAfterSingleLine: true,
|
exceptAfterSingleLine: true,
|
||||||
}],
|
}],
|
||||||
"no-unneeded-ternary": "error",
|
"no-unneeded-ternary": "error",
|
||||||
"array-bracket-newline": ["error", "consistent"],
|
"array-bracket-newline": [ "error", "consistent" ],
|
||||||
"eol-last": ["error", "always"],
|
"eol-last": [ "error", "always" ],
|
||||||
//'prefer-template': 'error',
|
//'prefer-template': 'error',
|
||||||
"comma-dangle": ["warn", "only-multiline"],
|
"comma-dangle": [ "warn", "only-multiline" ],
|
||||||
"no-empty": ["error", {
|
"no-empty": [ "error", {
|
||||||
"allowEmptyCatch": true
|
"allowEmptyCatch": true
|
||||||
}],
|
}],
|
||||||
"no-control-regex": "off",
|
"no-control-regex": "off",
|
||||||
"one-var": ["error", "never"],
|
"one-var": [ "error", "never" ],
|
||||||
"max-statements-per-line": ["error", { "max": 1 }]
|
"max-statements-per-line": [ "error", { "max": 1 }]
|
||||||
},
|
},
|
||||||
"overrides": [
|
"overrides": [
|
||||||
{
|
{
|
||||||
"files": [ "src/languages/*.js", "src/icon.js" ],
|
"files": [ "src/languages/*.js", "src/icon.js" ],
|
||||||
"rules": {
|
"rules": {
|
||||||
"comma-dangle": ["error", "always-multiline"],
|
"comma-dangle": [ "error", "always-multiline" ],
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
const config = {};
|
const config = {};
|
||||||
|
|
||||||
if (process.env.TEST_FRONTEND) {
|
if (process.env.TEST_FRONTEND) {
|
||||||
config.presets = ["@babel/preset-env"];
|
config.presets = [ "@babel/preset-env" ];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (process.env.TEST_BACKEND) {
|
if (process.env.TEST_BACKEND) {
|
||||||
config.plugins = ["babel-plugin-rewire"];
|
config.plugins = [ "babel-plugin-rewire" ];
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = config;
|
module.exports = config;
|
||||||
|
@ -10,15 +10,15 @@ export default defineConfig({
|
|||||||
plugins: [
|
plugins: [
|
||||||
vue(),
|
vue(),
|
||||||
legacy({
|
legacy({
|
||||||
targets: ["ie > 11"],
|
targets: [ "ie > 11" ],
|
||||||
additionalLegacyPolyfills: ["regenerator-runtime/runtime"]
|
additionalLegacyPolyfills: [ "regenerator-runtime/runtime" ]
|
||||||
})
|
})
|
||||||
],
|
],
|
||||||
css: {
|
css: {
|
||||||
postcss: {
|
postcss: {
|
||||||
"parser": postCssScss,
|
"parser": postCssScss,
|
||||||
"map": false,
|
"map": false,
|
||||||
"plugins": [postcssRTLCSS]
|
"plugins": [ postcssRTLCSS ]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
6
db/patch-status-page-footer-css.sql
Normal file
6
db/patch-status-page-footer-css.sql
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
-- You should not modify if this have pushed to Github, unless it does serious wrong with the db.
|
||||||
|
BEGIN TRANSACTION;
|
||||||
|
ALTER TABLE status_page ADD footer_text TEXT;
|
||||||
|
ALTER TABLE status_page ADD custom_css TEXT;
|
||||||
|
ALTER TABLE status_page ADD show_powered_by BOOLEAN NOT NULL DEFAULT 1;
|
||||||
|
COMMIT;
|
@ -5,7 +5,6 @@ const util = require("../../src/util");
|
|||||||
|
|
||||||
util.polyfill();
|
util.polyfill();
|
||||||
|
|
||||||
const oldVersion = pkg.version;
|
|
||||||
const version = process.env.VERSION;
|
const version = process.env.VERSION;
|
||||||
|
|
||||||
console.log("Beta Version: " + version);
|
console.log("Beta Version: " + version);
|
||||||
@ -32,7 +31,7 @@ if (! exists) {
|
|||||||
function commit(version) {
|
function commit(version) {
|
||||||
let msg = "Update to " + version;
|
let msg = "Update to " + version;
|
||||||
|
|
||||||
let res = childProcess.spawnSync("git", ["commit", "-m", msg, "-a"]);
|
let res = childProcess.spawnSync("git", [ "commit", "-m", msg, "-a" ]);
|
||||||
let stdout = res.stdout.toString().trim();
|
let stdout = res.stdout.toString().trim();
|
||||||
console.log(stdout);
|
console.log(stdout);
|
||||||
|
|
||||||
@ -40,15 +39,15 @@ function commit(version) {
|
|||||||
throw new Error("commit error");
|
throw new Error("commit error");
|
||||||
}
|
}
|
||||||
|
|
||||||
res = childProcess.spawnSync("git", ["push", "origin", "master"]);
|
res = childProcess.spawnSync("git", [ "push", "origin", "master" ]);
|
||||||
console.log(res.stdout.toString().trim());
|
console.log(res.stdout.toString().trim());
|
||||||
}
|
}
|
||||||
|
|
||||||
function tag(version) {
|
function tag(version) {
|
||||||
let res = childProcess.spawnSync("git", ["tag", version]);
|
let res = childProcess.spawnSync("git", [ "tag", version ]);
|
||||||
console.log(res.stdout.toString().trim());
|
console.log(res.stdout.toString().trim());
|
||||||
|
|
||||||
res = childProcess.spawnSync("git", ["push", "origin", version]);
|
res = childProcess.spawnSync("git", [ "push", "origin", version ]);
|
||||||
console.log(res.stdout.toString().trim());
|
console.log(res.stdout.toString().trim());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,15 +56,7 @@ function tagExists(version) {
|
|||||||
throw new Error("invalid version");
|
throw new Error("invalid version");
|
||||||
}
|
}
|
||||||
|
|
||||||
let res = childProcess.spawnSync("git", ["tag", "-l", version]);
|
let res = childProcess.spawnSync("git", [ "tag", "-l", version ]);
|
||||||
|
|
||||||
return res.stdout.toString().trim() === version;
|
return res.stdout.toString().trim() === version;
|
||||||
}
|
}
|
||||||
|
|
||||||
function safeDelete(dir) {
|
|
||||||
if (fs.existsSync(dir)) {
|
|
||||||
fs.rmdirSync(dir, {
|
|
||||||
recursive: true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -29,7 +29,7 @@ const github = require("@actions/github");
|
|||||||
owner: issue.owner,
|
owner: issue.owner,
|
||||||
repo: issue.repo,
|
repo: issue.repo,
|
||||||
issue_number: issue.number,
|
issue_number: issue.number,
|
||||||
labels: ["invalid-format"]
|
labels: [ "invalid-format" ]
|
||||||
});
|
});
|
||||||
|
|
||||||
// Add the issue closing comment
|
// Add the issue closing comment
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
const pkg = require("../package.json");
|
const pkg = require("../package.json");
|
||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
const rmSync = require("./fs-rmSync.js");
|
const childProcess = require("child_process");
|
||||||
const child_process = require("child_process");
|
|
||||||
const util = require("../src/util");
|
const util = require("../src/util");
|
||||||
|
|
||||||
util.polyfill();
|
util.polyfill();
|
||||||
@ -42,7 +41,7 @@ if (! exists) {
|
|||||||
function commit(version) {
|
function commit(version) {
|
||||||
let msg = "Update to " + version;
|
let msg = "Update to " + version;
|
||||||
|
|
||||||
let res = child_process.spawnSync("git", ["commit", "-m", msg, "-a"]);
|
let res = childProcess.spawnSync("git", [ "commit", "-m", msg, "-a" ]);
|
||||||
let stdout = res.stdout.toString().trim();
|
let stdout = res.stdout.toString().trim();
|
||||||
console.log(stdout);
|
console.log(stdout);
|
||||||
|
|
||||||
@ -52,7 +51,7 @@ function commit(version) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function tag(version) {
|
function tag(version) {
|
||||||
let res = child_process.spawnSync("git", ["tag", version]);
|
let res = childProcess.spawnSync("git", [ "tag", version ]);
|
||||||
console.log(res.stdout.toString().trim());
|
console.log(res.stdout.toString().trim());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,7 +66,7 @@ function tagExists(version) {
|
|||||||
throw new Error("invalid version");
|
throw new Error("invalid version");
|
||||||
}
|
}
|
||||||
|
|
||||||
let res = child_process.spawnSync("git", ["tag", "-l", version]);
|
let res = childProcess.spawnSync("git", [ "tag", "-l", version ]);
|
||||||
|
|
||||||
return res.stdout.toString().trim() === version;
|
return res.stdout.toString().trim() === version;
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
const child_process = require("child_process");
|
const childProcess = require("child_process");
|
||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
|
|
||||||
const newVersion = process.env.VERSION;
|
const newVersion = process.env.VERSION;
|
||||||
@ -16,23 +16,23 @@ function updateWiki(newVersion) {
|
|||||||
|
|
||||||
safeDelete(wikiDir);
|
safeDelete(wikiDir);
|
||||||
|
|
||||||
child_process.spawnSync("git", ["clone", "https://github.com/louislam/uptime-kuma.wiki.git", wikiDir]);
|
childProcess.spawnSync("git", [ "clone", "https://github.com/louislam/uptime-kuma.wiki.git", wikiDir ]);
|
||||||
let content = fs.readFileSync(howToUpdateFilename).toString();
|
let content = fs.readFileSync(howToUpdateFilename).toString();
|
||||||
|
|
||||||
// Replace the version: https://regex101.com/r/hmj2Bc/1
|
// Replace the version: https://regex101.com/r/hmj2Bc/1
|
||||||
content = content.replace(/(git checkout )([^\s]+)/, `$1${newVersion}`);
|
content = content.replace(/(git checkout )([^\s]+)/, `$1${newVersion}`);
|
||||||
fs.writeFileSync(howToUpdateFilename, content);
|
fs.writeFileSync(howToUpdateFilename, content);
|
||||||
|
|
||||||
child_process.spawnSync("git", ["add", "-A"], {
|
childProcess.spawnSync("git", [ "add", "-A" ], {
|
||||||
cwd: wikiDir,
|
cwd: wikiDir,
|
||||||
});
|
});
|
||||||
|
|
||||||
child_process.spawnSync("git", ["commit", "-m", `Update to ${newVersion}`], {
|
childProcess.spawnSync("git", [ "commit", "-m", `Update to ${newVersion}` ], {
|
||||||
cwd: wikiDir,
|
cwd: wikiDir,
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log("Pushing to Github");
|
console.log("Pushing to Github");
|
||||||
child_process.spawnSync("git", ["push"], {
|
childProcess.spawnSync("git", [ "push" ], {
|
||||||
cwd: wikiDir,
|
cwd: wikiDir,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
31
package-lock.json
generated
31
package-lock.json
generated
@ -45,6 +45,7 @@
|
|||||||
"password-hash": "~1.2.2",
|
"password-hash": "~1.2.2",
|
||||||
"postcss-rtlcss": "~3.4.1",
|
"postcss-rtlcss": "~3.4.1",
|
||||||
"postcss-scss": "~4.0.3",
|
"postcss-scss": "~4.0.3",
|
||||||
|
"prismjs": "^1.27.0",
|
||||||
"prom-client": "~13.2.0",
|
"prom-client": "~13.2.0",
|
||||||
"prometheus-api-metrics": "~3.2.1",
|
"prometheus-api-metrics": "~3.2.1",
|
||||||
"qrcode": "~1.5.0",
|
"qrcode": "~1.5.0",
|
||||||
@ -64,6 +65,7 @@
|
|||||||
"vue-i18n": "~9.1.9",
|
"vue-i18n": "~9.1.9",
|
||||||
"vue-image-crop-upload": "~3.0.3",
|
"vue-image-crop-upload": "~3.0.3",
|
||||||
"vue-multiselect": "~3.0.0-alpha.2",
|
"vue-multiselect": "~3.0.0-alpha.2",
|
||||||
|
"vue-prism-editor": "^2.0.0-alpha.2",
|
||||||
"vue-qrcode": "~1.0.0",
|
"vue-qrcode": "~1.0.0",
|
||||||
"vue-router": "~4.0.14",
|
"vue-router": "~4.0.14",
|
||||||
"vue-toastification": "~2.0.0-rc.5",
|
"vue-toastification": "~2.0.0-rc.5",
|
||||||
@ -13012,6 +13014,14 @@
|
|||||||
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/prismjs": {
|
||||||
|
"version": "1.27.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.27.0.tgz",
|
||||||
|
"integrity": "sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/proc-log": {
|
"node_modules/proc-log": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/proc-log/-/proc-log-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/proc-log/-/proc-log-2.0.1.tgz",
|
||||||
@ -15790,6 +15800,17 @@
|
|||||||
"npm": ">= 3.0.0"
|
"npm": ">= 3.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/vue-prism-editor": {
|
||||||
|
"version": "2.0.0-alpha.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/vue-prism-editor/-/vue-prism-editor-2.0.0-alpha.2.tgz",
|
||||||
|
"integrity": "sha512-Gu42ba9nosrE+gJpnAEuEkDMqG9zSUysIR8SdXUw8MQKDjBnnNR9lHC18uOr/ICz7yrA/5c7jHJr9lpElODC7w==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"vue": "^3.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/vue-qrcode": {
|
"node_modules/vue-qrcode": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/vue-qrcode/-/vue-qrcode-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/vue-qrcode/-/vue-qrcode-1.0.0.tgz",
|
||||||
@ -26033,6 +26054,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"prismjs": {
|
||||||
|
"version": "1.27.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.27.0.tgz",
|
||||||
|
"integrity": "sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA=="
|
||||||
|
},
|
||||||
"proc-log": {
|
"proc-log": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/proc-log/-/proc-log-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/proc-log/-/proc-log-2.0.1.tgz",
|
||||||
@ -28156,6 +28182,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/vue-multiselect/-/vue-multiselect-3.0.0-alpha.2.tgz",
|
"resolved": "https://registry.npmjs.org/vue-multiselect/-/vue-multiselect-3.0.0-alpha.2.tgz",
|
||||||
"integrity": "sha512-Xp9fGJECns45v+v8jXbCIsAkCybYkEg0lNwr7Z6HDUSMyx2TEIK2giipPE+qXiShEc1Ipn+ZtttH2iq9hwXP4Q=="
|
"integrity": "sha512-Xp9fGJECns45v+v8jXbCIsAkCybYkEg0lNwr7Z6HDUSMyx2TEIK2giipPE+qXiShEc1Ipn+ZtttH2iq9hwXP4Q=="
|
||||||
},
|
},
|
||||||
|
"vue-prism-editor": {
|
||||||
|
"version": "2.0.0-alpha.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/vue-prism-editor/-/vue-prism-editor-2.0.0-alpha.2.tgz",
|
||||||
|
"integrity": "sha512-Gu42ba9nosrE+gJpnAEuEkDMqG9zSUysIR8SdXUw8MQKDjBnnNR9lHC18uOr/ICz7yrA/5c7jHJr9lpElODC7w=="
|
||||||
|
},
|
||||||
"vue-qrcode": {
|
"vue-qrcode": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/vue-qrcode/-/vue-qrcode-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/vue-qrcode/-/vue-qrcode-1.0.0.tgz",
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
"install-legacy": "npm install --legacy-peer-deps",
|
"install-legacy": "npm install --legacy-peer-deps",
|
||||||
"update-legacy": "npm update --legacy-peer-deps",
|
"update-legacy": "npm update --legacy-peer-deps",
|
||||||
"lint:js": "eslint --ext \".js,.vue\" --ignore-path .gitignore .",
|
"lint:js": "eslint --ext \".js,.vue\" --ignore-path .gitignore .",
|
||||||
|
"lint-fix:js": "eslint --ext \".js,.vue\" --fix --ignore-path .gitignore .",
|
||||||
"lint:style": "stylelint \"**/*.{vue,css,scss}\" --ignore-path .gitignore",
|
"lint:style": "stylelint \"**/*.{vue,css,scss}\" --ignore-path .gitignore",
|
||||||
"lint": "npm run lint:js && npm run lint:style",
|
"lint": "npm run lint:js && npm run lint:style",
|
||||||
"dev": "vite --host --config ./config/vite.config.js",
|
"dev": "vite --host --config ./config/vite.config.js",
|
||||||
@ -93,6 +94,7 @@
|
|||||||
"password-hash": "~1.2.2",
|
"password-hash": "~1.2.2",
|
||||||
"postcss-rtlcss": "~3.4.1",
|
"postcss-rtlcss": "~3.4.1",
|
||||||
"postcss-scss": "~4.0.3",
|
"postcss-scss": "~4.0.3",
|
||||||
|
"prismjs": "^1.27.0",
|
||||||
"prom-client": "~13.2.0",
|
"prom-client": "~13.2.0",
|
||||||
"prometheus-api-metrics": "~3.2.1",
|
"prometheus-api-metrics": "~3.2.1",
|
||||||
"qrcode": "~1.5.0",
|
"qrcode": "~1.5.0",
|
||||||
@ -112,6 +114,7 @@
|
|||||||
"vue-i18n": "~9.1.9",
|
"vue-i18n": "~9.1.9",
|
||||||
"vue-image-crop-upload": "~3.0.3",
|
"vue-image-crop-upload": "~3.0.3",
|
||||||
"vue-multiselect": "~3.0.0-alpha.2",
|
"vue-multiselect": "~3.0.0-alpha.2",
|
||||||
|
"vue-prism-editor": "^2.0.0-alpha.2",
|
||||||
"vue-qrcode": "~1.0.0",
|
"vue-qrcode": "~1.0.0",
|
||||||
"vue-router": "~4.0.14",
|
"vue-router": "~4.0.14",
|
||||||
"vue-toastification": "~2.0.0-rc.5",
|
"vue-toastification": "~2.0.0-rc.5",
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
const { checkLogin } = require("./util-server");
|
|
||||||
const { R } = require("redbean-node");
|
const { R } = require("redbean-node");
|
||||||
|
|
||||||
class TwoFA {
|
class TwoFA {
|
||||||
|
@ -98,7 +98,7 @@ async function sendImportantHeartbeatList(socket, monitorID, toUser = false, ove
|
|||||||
async function sendProxyList(socket) {
|
async function sendProxyList(socket) {
|
||||||
const timeLogger = new TimeLogger();
|
const timeLogger = new TimeLogger();
|
||||||
|
|
||||||
const list = await R.find("proxy", " user_id = ? ", [socket.userID]);
|
const list = await R.find("proxy", " user_id = ? ", [ socket.userID ]);
|
||||||
io.to(socket.userID).emit("proxyList", list.map(bean => bean.export()));
|
io.to(socket.userID).emit("proxyList", list.map(bean => bean.export()));
|
||||||
|
|
||||||
timeLogger.print("Send Proxy List");
|
timeLogger.print("Send Proxy List");
|
||||||
|
@ -56,6 +56,7 @@ class Database {
|
|||||||
"patch-status-page.sql": true,
|
"patch-status-page.sql": true,
|
||||||
"patch-proxy.sql": true,
|
"patch-proxy.sql": true,
|
||||||
"patch-monitor-expiry-notification.sql": true,
|
"patch-monitor-expiry-notification.sql": true,
|
||||||
|
"patch-status-page-footer-css.sql": true,
|
||||||
"patch-added-mqtt-monitor.sql": true,
|
"patch-added-mqtt-monitor.sql": true,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ const DEFAULT_KEEP_PERIOD = 180;
|
|||||||
try {
|
try {
|
||||||
await R.exec(
|
await R.exec(
|
||||||
"DELETE FROM heartbeat WHERE time < DATETIME('now', '-' || ? || ' days') ",
|
"DELETE FROM heartbeat WHERE time < DATETIME('now', '-' || ? || ' days') ",
|
||||||
[parsedPeriod]
|
[ parsedPeriod ]
|
||||||
);
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log(`Failed to clear old data: ${e.message}`);
|
log(`Failed to clear old data: ${e.message}`);
|
||||||
|
@ -9,7 +9,7 @@ const log = function (any) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const exit = function (error) {
|
const exit = function (error) {
|
||||||
if (error && error != 0) {
|
if (error && error !== 0) {
|
||||||
process.exit(error);
|
process.exit(error);
|
||||||
} else {
|
} else {
|
||||||
if (parentPort) {
|
if (parentPort) {
|
||||||
|
@ -42,7 +42,7 @@ class Monitor extends BeanModel {
|
|||||||
/**
|
/**
|
||||||
* Return an object that ready to parse to JSON
|
* Return an object that ready to parse to JSON
|
||||||
*/
|
*/
|
||||||
async toJSON() {
|
async toJSON(includeSensitiveData = true) {
|
||||||
|
|
||||||
let notificationIDList = {};
|
let notificationIDList = {};
|
||||||
|
|
||||||
@ -56,15 +56,11 @@ class Monitor extends BeanModel {
|
|||||||
|
|
||||||
const tags = await this.getTags();
|
const tags = await this.getTags();
|
||||||
|
|
||||||
return {
|
let data = {
|
||||||
id: this.id,
|
id: this.id,
|
||||||
name: this.name,
|
name: this.name,
|
||||||
url: this.url,
|
url: this.url,
|
||||||
method: this.method,
|
method: this.method,
|
||||||
body: this.body,
|
|
||||||
headers: this.headers,
|
|
||||||
basic_auth_user: this.basic_auth_user,
|
|
||||||
basic_auth_pass: this.basic_auth_pass,
|
|
||||||
hostname: this.hostname,
|
hostname: this.hostname,
|
||||||
port: this.port,
|
port: this.port,
|
||||||
maxretries: this.maxretries,
|
maxretries: this.maxretries,
|
||||||
@ -82,7 +78,6 @@ class Monitor extends BeanModel {
|
|||||||
dns_resolve_type: this.dns_resolve_type,
|
dns_resolve_type: this.dns_resolve_type,
|
||||||
dns_resolve_server: this.dns_resolve_server,
|
dns_resolve_server: this.dns_resolve_server,
|
||||||
dns_last_result: this.dns_last_result,
|
dns_last_result: this.dns_last_result,
|
||||||
pushToken: this.pushToken,
|
|
||||||
proxyId: this.proxy_id,
|
proxyId: this.proxy_id,
|
||||||
notificationIDList,
|
notificationIDList,
|
||||||
tags: tags,
|
tags: tags,
|
||||||
@ -91,10 +86,23 @@ class Monitor extends BeanModel {
|
|||||||
mqttTopic: this.mqttTopic,
|
mqttTopic: this.mqttTopic,
|
||||||
mqttSuccessMessage: this.mqttSuccessMessage
|
mqttSuccessMessage: this.mqttSuccessMessage
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (includeSensitiveData) {
|
||||||
|
data = {
|
||||||
|
...data,
|
||||||
|
headers: this.headers,
|
||||||
|
body: this.body,
|
||||||
|
basic_auth_user: this.basic_auth_user,
|
||||||
|
basic_auth_pass: this.basic_auth_pass,
|
||||||
|
pushToken: this.pushToken,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getTags() {
|
async getTags() {
|
||||||
return await R.getAll("SELECT mt.*, tag.name, tag.color FROM monitor_tag mt JOIN tag ON mt.tag_id = tag.id WHERE mt.monitor_id = ?", [this.id]);
|
return await R.getAll("SELECT mt.*, tag.name, tag.color FROM monitor_tag mt JOIN tag ON mt.tag_id = tag.id WHERE mt.monitor_id = ?", [ this.id ]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -266,7 +274,7 @@ class Monitor extends BeanModel {
|
|||||||
log.debug("monitor", "Cert Info Query Time: " + (dayjs().valueOf() - certInfoStartTime) + "ms");
|
log.debug("monitor", "Cert Info Query Time: " + (dayjs().valueOf() - certInfoStartTime) + "ms");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (process.env.UPTIME_KUMA_LOG_RESPONSE_BODY_MONITOR_ID == this.id) {
|
if (process.env.UPTIME_KUMA_LOG_RESPONSE_BODY_MONITOR_ID === this.id) {
|
||||||
log.info("monitor", res.data);
|
log.info("monitor", res.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -306,24 +314,24 @@ class Monitor extends BeanModel {
|
|||||||
let dnsRes = await dnsResolve(this.hostname, this.dns_resolve_server, this.dns_resolve_type);
|
let dnsRes = await dnsResolve(this.hostname, this.dns_resolve_server, this.dns_resolve_type);
|
||||||
bean.ping = dayjs().valueOf() - startTime;
|
bean.ping = dayjs().valueOf() - startTime;
|
||||||
|
|
||||||
if (this.dns_resolve_type == "A" || this.dns_resolve_type == "AAAA" || this.dns_resolve_type == "TXT") {
|
if (this.dns_resolve_type === "A" || this.dns_resolve_type === "AAAA" || this.dns_resolve_type === "TXT") {
|
||||||
dnsMessage += "Records: ";
|
dnsMessage += "Records: ";
|
||||||
dnsMessage += dnsRes.join(" | ");
|
dnsMessage += dnsRes.join(" | ");
|
||||||
} else if (this.dns_resolve_type == "CNAME" || this.dns_resolve_type == "PTR") {
|
} else if (this.dns_resolve_type === "CNAME" || this.dns_resolve_type === "PTR") {
|
||||||
dnsMessage = dnsRes[0];
|
dnsMessage = dnsRes[0];
|
||||||
} else if (this.dns_resolve_type == "CAA") {
|
} else if (this.dns_resolve_type === "CAA") {
|
||||||
dnsMessage = dnsRes[0].issue;
|
dnsMessage = dnsRes[0].issue;
|
||||||
} else if (this.dns_resolve_type == "MX") {
|
} else if (this.dns_resolve_type === "MX") {
|
||||||
dnsRes.forEach(record => {
|
dnsRes.forEach(record => {
|
||||||
dnsMessage += `Hostname: ${record.exchange} - Priority: ${record.priority} | `;
|
dnsMessage += `Hostname: ${record.exchange} - Priority: ${record.priority} | `;
|
||||||
});
|
});
|
||||||
dnsMessage = dnsMessage.slice(0, -2);
|
dnsMessage = dnsMessage.slice(0, -2);
|
||||||
} else if (this.dns_resolve_type == "NS") {
|
} else if (this.dns_resolve_type === "NS") {
|
||||||
dnsMessage += "Servers: ";
|
dnsMessage += "Servers: ";
|
||||||
dnsMessage += dnsRes.join(" | ");
|
dnsMessage += dnsRes.join(" | ");
|
||||||
} else if (this.dns_resolve_type == "SOA") {
|
} else if (this.dns_resolve_type === "SOA") {
|
||||||
dnsMessage += `NS-Name: ${dnsRes.nsname} | Hostmaster: ${dnsRes.hostmaster} | Serial: ${dnsRes.serial} | Refresh: ${dnsRes.refresh} | Retry: ${dnsRes.retry} | Expire: ${dnsRes.expire} | MinTTL: ${dnsRes.minttl}`;
|
dnsMessage += `NS-Name: ${dnsRes.nsname} | Hostmaster: ${dnsRes.hostmaster} | Serial: ${dnsRes.serial} | Refresh: ${dnsRes.refresh} | Retry: ${dnsRes.retry} | Expire: ${dnsRes.expire} | MinTTL: ${dnsRes.minttl}`;
|
||||||
} else if (this.dns_resolve_type == "SRV") {
|
} else if (this.dns_resolve_type === "SRV") {
|
||||||
dnsRes.forEach(record => {
|
dnsRes.forEach(record => {
|
||||||
dnsMessage += `Name: ${record.name} | Port: ${record.port} | Priority: ${record.priority} | Weight: ${record.weight} | `;
|
dnsMessage += `Name: ${record.name} | Port: ${record.port} | Priority: ${record.priority} | Weight: ${record.weight} | `;
|
||||||
});
|
});
|
||||||
@ -620,11 +628,11 @@ class Monitor extends BeanModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static async sendCertInfo(io, monitorID, userID) {
|
static async sendCertInfo(io, monitorID, userID) {
|
||||||
let tls_info = await R.findOne("monitor_tls_info", "monitor_id = ?", [
|
let tlsInfo = await R.findOne("monitor_tls_info", "monitor_id = ?", [
|
||||||
monitorID,
|
monitorID,
|
||||||
]);
|
]);
|
||||||
if (tls_info != null) {
|
if (tlsInfo != null) {
|
||||||
io.to(userID).emit("certInfo", monitorID, tls_info.info_json);
|
io.to(userID).emit("certInfo", monitorID, tlsInfo.info_json);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -738,7 +746,7 @@ class Monitor extends BeanModel {
|
|||||||
|
|
||||||
for (let notification of notificationList) {
|
for (let notification of notificationList) {
|
||||||
try {
|
try {
|
||||||
await Notification.send(JSON.parse(notification.config), msg, await monitor.toJSON(), bean.toJSON());
|
await Notification.send(JSON.parse(notification.config), msg, await monitor.toJSON(false), bean.toJSON());
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log.error("monitor", "Cannot send notification to " + notification.name);
|
log.error("monitor", "Cannot send notification to " + notification.name);
|
||||||
log.error("monitor", e);
|
log.error("monitor", e);
|
||||||
|
@ -92,6 +92,9 @@ class StatusPage extends BeanModel {
|
|||||||
published: !!this.published,
|
published: !!this.published,
|
||||||
showTags: !!this.show_tags,
|
showTags: !!this.show_tags,
|
||||||
domainNameList: this.getDomainNameList(),
|
domainNameList: this.getDomainNameList(),
|
||||||
|
customCSS: this.custom_css,
|
||||||
|
footerText: this.footer_text,
|
||||||
|
showPoweredBy: !!this.show_powered_by,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,6 +107,9 @@ class StatusPage extends BeanModel {
|
|||||||
theme: this.theme,
|
theme: this.theme,
|
||||||
published: !!this.published,
|
published: !!this.published,
|
||||||
showTags: !!this.show_tags,
|
showTags: !!this.show_tags,
|
||||||
|
customCSS: this.custom_css,
|
||||||
|
footerText: this.footer_text,
|
||||||
|
showPoweredBy: !!this.show_powered_by,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,17 +40,17 @@ class Alerta extends NotificationProvider {
|
|||||||
await axios.post(alertaUrl, postData, config);
|
await axios.post(alertaUrl, postData, config);
|
||||||
} else {
|
} else {
|
||||||
let datadup = Object.assign( {
|
let datadup = Object.assign( {
|
||||||
correlate: ["service_up", "service_down"],
|
correlate: [ "service_up", "service_down" ],
|
||||||
event: monitorJSON["type"],
|
event: monitorJSON["type"],
|
||||||
group: "uptimekuma-" + monitorJSON["type"],
|
group: "uptimekuma-" + monitorJSON["type"],
|
||||||
resource: monitorJSON["name"],
|
resource: monitorJSON["name"],
|
||||||
}, data );
|
}, data );
|
||||||
|
|
||||||
if (heartbeatJSON["status"] == DOWN) {
|
if (heartbeatJSON["status"] === DOWN) {
|
||||||
datadup.severity = notification.alertaAlertState; // critical
|
datadup.severity = notification.alertaAlertState; // critical
|
||||||
datadup.text = "Service " + monitorJSON["type"] + " is down.";
|
datadup.text = "Service " + monitorJSON["type"] + " is down.";
|
||||||
await axios.post(alertaUrl, datadup, config);
|
await axios.post(alertaUrl, datadup, config);
|
||||||
} else if (heartbeatJSON["status"] == UP) {
|
} else if (heartbeatJSON["status"] === UP) {
|
||||||
datadup.severity = notification.alertaRecoverState; // cleaned
|
datadup.severity = notification.alertaRecoverState; // cleaned
|
||||||
datadup.text = "Service " + monitorJSON["type"] + " is up.";
|
datadup.text = "Service " + monitorJSON["type"] + " is up.";
|
||||||
await axios.post(alertaUrl, datadup, config);
|
await axios.post(alertaUrl, datadup, config);
|
||||||
|
@ -64,7 +64,7 @@ class AliyunSMS extends NotificationProvider {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let result = await axios(config);
|
let result = await axios(config);
|
||||||
if (result.data.Message == "OK") {
|
if (result.data.Message === "OK") {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
const NotificationProvider = require("./notification-provider");
|
const NotificationProvider = require("./notification-provider");
|
||||||
const child_process = require("child_process");
|
const childProcess = require("child_process");
|
||||||
|
|
||||||
class Apprise extends NotificationProvider {
|
class Apprise extends NotificationProvider {
|
||||||
|
|
||||||
name = "apprise";
|
name = "apprise";
|
||||||
|
|
||||||
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
||||||
let s = child_process.spawnSync("apprise", [ "-vv", "-b", msg, notification.appriseURL]);
|
let s = childProcess.spawnSync("apprise", [ "-vv", "-b", msg, notification.appriseURL ]);
|
||||||
|
|
||||||
let output = (s.stdout) ? s.stdout.toString() : "ERROR: maybe apprise not found";
|
let output = (s.stdout) ? s.stdout.toString() : "ERROR: maybe apprise not found";
|
||||||
|
|
||||||
|
@ -28,12 +28,12 @@ class Bark extends NotificationProvider {
|
|||||||
barkEndpoint = barkEndpoint.substring(0, barkEndpoint.length - 1);
|
barkEndpoint = barkEndpoint.substring(0, barkEndpoint.length - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (msg != null && heartbeatJSON != null && heartbeatJSON["status"] == UP) {
|
if (msg != null && heartbeatJSON != null && heartbeatJSON["status"] === UP) {
|
||||||
let title = "UptimeKuma Monitor Up";
|
let title = "UptimeKuma Monitor Up";
|
||||||
return await this.postNotification(title, msg, barkEndpoint);
|
return await this.postNotification(title, msg, barkEndpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (msg != null && heartbeatJSON != null && heartbeatJSON["status"] == DOWN) {
|
if (msg != null && heartbeatJSON != null && heartbeatJSON["status"] === DOWN) {
|
||||||
let title = "UptimeKuma Monitor Down";
|
let title = "UptimeKuma Monitor Down";
|
||||||
return await this.postNotification(title, msg, barkEndpoint);
|
return await this.postNotification(title, msg, barkEndpoint);
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,7 @@ class DingDing extends NotificationProvider {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let result = await axios(config);
|
let result = await axios(config);
|
||||||
if (result.data.errmsg == "ok") {
|
if (result.data.errmsg === "ok") {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -35,7 +35,7 @@ class Discord extends NotificationProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If heartbeatJSON is not null, we go into the normal alerting loop.
|
// If heartbeatJSON is not null, we go into the normal alerting loop.
|
||||||
if (heartbeatJSON["status"] == DOWN) {
|
if (heartbeatJSON["status"] === DOWN) {
|
||||||
let discorddowndata = {
|
let discorddowndata = {
|
||||||
username: discordDisplayName,
|
username: discordDisplayName,
|
||||||
embeds: [{
|
embeds: [{
|
||||||
@ -70,7 +70,7 @@ class Discord extends NotificationProvider {
|
|||||||
await axios.post(notification.discordWebhookUrl, discorddowndata);
|
await axios.post(notification.discordWebhookUrl, discorddowndata);
|
||||||
return okMsg;
|
return okMsg;
|
||||||
|
|
||||||
} else if (heartbeatJSON["status"] == UP) {
|
} else if (heartbeatJSON["status"] === UP) {
|
||||||
let discordupdata = {
|
let discordupdata = {
|
||||||
username: discordDisplayName,
|
username: discordDisplayName,
|
||||||
embeds: [{
|
embeds: [{
|
||||||
|
@ -21,7 +21,7 @@ class Feishu extends NotificationProvider {
|
|||||||
return okMsg;
|
return okMsg;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (heartbeatJSON["status"] == DOWN) {
|
if (heartbeatJSON["status"] === DOWN) {
|
||||||
let downdata = {
|
let downdata = {
|
||||||
msg_type: "post",
|
msg_type: "post",
|
||||||
content: {
|
content: {
|
||||||
@ -48,7 +48,7 @@ class Feishu extends NotificationProvider {
|
|||||||
return okMsg;
|
return okMsg;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (heartbeatJSON["status"] == UP) {
|
if (heartbeatJSON["status"] === UP) {
|
||||||
let updata = {
|
let updata = {
|
||||||
msg_type: "post",
|
msg_type: "post",
|
||||||
content: {
|
content: {
|
||||||
|
@ -18,7 +18,7 @@ class Gorush extends NotificationProvider {
|
|||||||
let data = {
|
let data = {
|
||||||
"notifications": [
|
"notifications": [
|
||||||
{
|
{
|
||||||
"tokens": [notification.gorushDeviceToken],
|
"tokens": [ notification.gorushDeviceToken ],
|
||||||
"platform": platformMapping[notification.gorushPlatform],
|
"platform": platformMapping[notification.gorushPlatform],
|
||||||
"message": msg,
|
"message": msg,
|
||||||
// Optional
|
// Optional
|
||||||
|
@ -27,7 +27,7 @@ class Line extends NotificationProvider {
|
|||||||
]
|
]
|
||||||
};
|
};
|
||||||
await axios.post(lineAPIUrl, testMessage, config);
|
await axios.post(lineAPIUrl, testMessage, config);
|
||||||
} else if (heartbeatJSON["status"] == DOWN) {
|
} else if (heartbeatJSON["status"] === DOWN) {
|
||||||
let downMessage = {
|
let downMessage = {
|
||||||
"to": notification.lineUserID,
|
"to": notification.lineUserID,
|
||||||
"messages": [
|
"messages": [
|
||||||
@ -38,7 +38,7 @@ class Line extends NotificationProvider {
|
|||||||
]
|
]
|
||||||
};
|
};
|
||||||
await axios.post(lineAPIUrl, downMessage, config);
|
await axios.post(lineAPIUrl, downMessage, config);
|
||||||
} else if (heartbeatJSON["status"] == UP) {
|
} else if (heartbeatJSON["status"] === UP) {
|
||||||
let upMessage = {
|
let upMessage = {
|
||||||
"to": notification.lineUserID,
|
"to": notification.lineUserID,
|
||||||
"messages": [
|
"messages": [
|
||||||
|
@ -20,7 +20,7 @@ class LunaSea extends NotificationProvider {
|
|||||||
return okMsg;
|
return okMsg;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (heartbeatJSON["status"] == DOWN) {
|
if (heartbeatJSON["status"] === DOWN) {
|
||||||
let downdata = {
|
let downdata = {
|
||||||
"title": "UptimeKuma Alert: " + monitorJSON["name"],
|
"title": "UptimeKuma Alert: " + monitorJSON["name"],
|
||||||
"body": "[🔴 Down] " + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"],
|
"body": "[🔴 Down] " + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"],
|
||||||
@ -29,7 +29,7 @@ class LunaSea extends NotificationProvider {
|
|||||||
return okMsg;
|
return okMsg;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (heartbeatJSON["status"] == UP) {
|
if (heartbeatJSON["status"] === UP) {
|
||||||
let updata = {
|
let updata = {
|
||||||
"title": "UptimeKuma Alert: " + monitorJSON["name"],
|
"title": "UptimeKuma Alert: " + monitorJSON["name"],
|
||||||
"body": "[✅ Up] " + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"],
|
"body": "[✅ Up] " + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"],
|
||||||
|
@ -29,7 +29,7 @@ class Mattermost extends NotificationProvider {
|
|||||||
const mattermostIconEmoji = notification.mattermosticonemo;
|
const mattermostIconEmoji = notification.mattermosticonemo;
|
||||||
const mattermostIconUrl = notification.mattermosticonurl;
|
const mattermostIconUrl = notification.mattermosticonurl;
|
||||||
|
|
||||||
if (heartbeatJSON["status"] == DOWN) {
|
if (heartbeatJSON["status"] === DOWN) {
|
||||||
let mattermostdowndata = {
|
let mattermostdowndata = {
|
||||||
username: mattermostUserName,
|
username: mattermostUserName,
|
||||||
text: "Uptime Kuma Alert",
|
text: "Uptime Kuma Alert",
|
||||||
@ -73,7 +73,7 @@ class Mattermost extends NotificationProvider {
|
|||||||
mattermostdowndata
|
mattermostdowndata
|
||||||
);
|
);
|
||||||
return okMsg;
|
return okMsg;
|
||||||
} else if (heartbeatJSON["status"] == UP) {
|
} else if (heartbeatJSON["status"] === UP) {
|
||||||
let mattermostupdata = {
|
let mattermostupdata = {
|
||||||
username: mattermostUserName,
|
username: mattermostUserName,
|
||||||
text: "Uptime Kuma Alert",
|
text: "Uptime Kuma Alert",
|
||||||
|
@ -10,7 +10,7 @@ class Octopush extends NotificationProvider {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// Default - V2
|
// Default - V2
|
||||||
if (notification.octopushVersion == 2 || !notification.octopushVersion) {
|
if (notification.octopushVersion === 2 || !notification.octopushVersion) {
|
||||||
let config = {
|
let config = {
|
||||||
headers: {
|
headers: {
|
||||||
"api-key": notification.octopushAPIKey,
|
"api-key": notification.octopushAPIKey,
|
||||||
@ -31,13 +31,13 @@ class Octopush extends NotificationProvider {
|
|||||||
"sender": notification.octopushSenderName
|
"sender": notification.octopushSenderName
|
||||||
};
|
};
|
||||||
await axios.post("https://api.octopush.com/v1/public/sms-campaign/send", data, config);
|
await axios.post("https://api.octopush.com/v1/public/sms-campaign/send", data, config);
|
||||||
} else if (notification.octopushVersion == 1) {
|
} else if (notification.octopushVersion === 1) {
|
||||||
let data = {
|
let data = {
|
||||||
"user_login": notification.octopushDMLogin,
|
"user_login": notification.octopushDMLogin,
|
||||||
"api_key": notification.octopushDMAPIKey,
|
"api_key": notification.octopushDMAPIKey,
|
||||||
"sms_recipients": notification.octopushDMPhoneNumber,
|
"sms_recipients": notification.octopushDMPhoneNumber,
|
||||||
"sms_sender": notification.octopushDMSenderName,
|
"sms_sender": notification.octopushDMSenderName,
|
||||||
"sms_type": (notification.octopushDMSMSType == "sms_premium") ? "FR" : "XXX",
|
"sms_type": (notification.octopushDMSMSType === "sms_premium") ? "FR" : "XXX",
|
||||||
"transactional": "1",
|
"transactional": "1",
|
||||||
//octopush not supporting non ascii char
|
//octopush not supporting non ascii char
|
||||||
"sms_text": msg.replace(/[^\x00-\x7F]/g, ""),
|
"sms_text": msg.replace(/[^\x00-\x7F]/g, ""),
|
||||||
|
@ -27,7 +27,7 @@ class OneBot extends NotificationProvider {
|
|||||||
"auto_escape": true,
|
"auto_escape": true,
|
||||||
"message": pushText,
|
"message": pushText,
|
||||||
};
|
};
|
||||||
if (notification.msgType == "group") {
|
if (notification.msgType === "group") {
|
||||||
data["message_type"] = "group";
|
data["message_type"] = "group";
|
||||||
data["group_id"] = notification.recieverId;
|
data["group_id"] = notification.recieverId;
|
||||||
} else {
|
} else {
|
||||||
|
@ -25,14 +25,14 @@ class Pushbullet extends NotificationProvider {
|
|||||||
"body": "Testing Successful.",
|
"body": "Testing Successful.",
|
||||||
};
|
};
|
||||||
await axios.post(pushbulletUrl, testdata, config);
|
await axios.post(pushbulletUrl, testdata, config);
|
||||||
} else if (heartbeatJSON["status"] == DOWN) {
|
} else if (heartbeatJSON["status"] === DOWN) {
|
||||||
let downdata = {
|
let downdata = {
|
||||||
"type": "note",
|
"type": "note",
|
||||||
"title": "UptimeKuma Alert: " + monitorJSON["name"],
|
"title": "UptimeKuma Alert: " + monitorJSON["name"],
|
||||||
"body": "[🔴 Down] " + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"],
|
"body": "[🔴 Down] " + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"],
|
||||||
};
|
};
|
||||||
await axios.post(pushbulletUrl, downdata, config);
|
await axios.post(pushbulletUrl, downdata, config);
|
||||||
} else if (heartbeatJSON["status"] == UP) {
|
} else if (heartbeatJSON["status"] === UP) {
|
||||||
let updata = {
|
let updata = {
|
||||||
"type": "note",
|
"type": "note",
|
||||||
"title": "UptimeKuma Alert: " + monitorJSON["name"],
|
"title": "UptimeKuma Alert: " + monitorJSON["name"],
|
||||||
|
52
server/notification-providers/pushdeer.js
Normal file
52
server/notification-providers/pushdeer.js
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
const NotificationProvider = require("./notification-provider");
|
||||||
|
const axios = require("axios");
|
||||||
|
const { DOWN, UP } = require("../../src/util");
|
||||||
|
|
||||||
|
class PushDeer extends NotificationProvider {
|
||||||
|
|
||||||
|
name = "PushDeer";
|
||||||
|
|
||||||
|
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
|
||||||
|
let okMsg = "Sent Successfully.";
|
||||||
|
let pushdeerlink = "https://api2.pushdeer.com/message/push";
|
||||||
|
|
||||||
|
let valid = msg != null && monitorJSON != null && heartbeatJSON != null;
|
||||||
|
|
||||||
|
let title;
|
||||||
|
if (valid && heartbeatJSON.status === UP) {
|
||||||
|
title = "## Uptime Kuma: " + monitorJSON.name + " up";
|
||||||
|
} else if (valid && heartbeatJSON.status === DOWN) {
|
||||||
|
title = "## Uptime Kuma: " + monitorJSON.name + " down";
|
||||||
|
} else {
|
||||||
|
title = "## Uptime Kuma Message";
|
||||||
|
}
|
||||||
|
|
||||||
|
let data = {
|
||||||
|
"pushkey": notification.pushdeerKey,
|
||||||
|
"text": title,
|
||||||
|
"desp": msg.replace(/\n/g, "\n\n"),
|
||||||
|
"type": "markdown",
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
let res = await axios.post(pushdeerlink, data);
|
||||||
|
|
||||||
|
if ("error" in res.data) {
|
||||||
|
let error = res.data.error;
|
||||||
|
this.throwGeneralAxiosError(error);
|
||||||
|
}
|
||||||
|
if (res.data.content.result.length === 0) {
|
||||||
|
let error = "Invalid PushDeer key";
|
||||||
|
this.throwGeneralAxiosError(error);
|
||||||
|
} else if (JSON.parse(res.data.content.result[0]).success !== "ok") {
|
||||||
|
let error = "Unknown error";
|
||||||
|
this.throwGeneralAxiosError(error);
|
||||||
|
}
|
||||||
|
return okMsg;
|
||||||
|
} catch (error) {
|
||||||
|
this.throwGeneralAxiosError(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = PushDeer;
|
@ -1,6 +1,6 @@
|
|||||||
const nodemailer = require("nodemailer");
|
const nodemailer = require("nodemailer");
|
||||||
const NotificationProvider = require("./notification-provider");
|
const NotificationProvider = require("./notification-provider");
|
||||||
const { DOWN, UP } = require("../../src/util");
|
const { DOWN } = require("../../src/util");
|
||||||
|
|
||||||
class SMTP extends NotificationProvider {
|
class SMTP extends NotificationProvider {
|
||||||
|
|
||||||
|
@ -26,10 +26,10 @@ class WeCom extends NotificationProvider {
|
|||||||
|
|
||||||
composeMessage(heartbeatJSON, msg) {
|
composeMessage(heartbeatJSON, msg) {
|
||||||
let title;
|
let title;
|
||||||
if (msg != null && heartbeatJSON != null && heartbeatJSON["status"] == UP) {
|
if (msg != null && heartbeatJSON != null && heartbeatJSON["status"] === UP) {
|
||||||
title = "UptimeKuma Monitor Up";
|
title = "UptimeKuma Monitor Up";
|
||||||
}
|
}
|
||||||
if (msg != null && heartbeatJSON != null && heartbeatJSON["status"] == DOWN) {
|
if (msg != null && heartbeatJSON != null && heartbeatJSON["status"] === DOWN) {
|
||||||
title = "UptimeKuma Monitor Down";
|
title = "UptimeKuma Monitor Down";
|
||||||
}
|
}
|
||||||
if (msg != null) {
|
if (msg != null) {
|
||||||
|
@ -32,6 +32,7 @@ const GoogleChat = require("./notification-providers/google-chat");
|
|||||||
const Gorush = require("./notification-providers/gorush");
|
const Gorush = require("./notification-providers/gorush");
|
||||||
const Alerta = require("./notification-providers/alerta");
|
const Alerta = require("./notification-providers/alerta");
|
||||||
const OneBot = require("./notification-providers/onebot");
|
const OneBot = require("./notification-providers/onebot");
|
||||||
|
const PushDeer = require("./notification-providers/pushdeer");
|
||||||
|
|
||||||
class Notification {
|
class Notification {
|
||||||
|
|
||||||
@ -75,6 +76,7 @@ class Notification {
|
|||||||
new Gorush(),
|
new Gorush(),
|
||||||
new Alerta(),
|
new Alerta(),
|
||||||
new OneBot(),
|
new OneBot(),
|
||||||
|
new PushDeer(),
|
||||||
];
|
];
|
||||||
|
|
||||||
for (let item of list) {
|
for (let item of list) {
|
||||||
|
@ -9,24 +9,24 @@ const commonLabels = [
|
|||||||
"monitor_port",
|
"monitor_port",
|
||||||
];
|
];
|
||||||
|
|
||||||
const monitor_cert_days_remaining = new PrometheusClient.Gauge({
|
const monitorCertDaysRemaining = new PrometheusClient.Gauge({
|
||||||
name: "monitor_cert_days_remaining",
|
name: "monitor_cert_days_remaining",
|
||||||
help: "The number of days remaining until the certificate expires",
|
help: "The number of days remaining until the certificate expires",
|
||||||
labelNames: commonLabels
|
labelNames: commonLabels
|
||||||
});
|
});
|
||||||
|
|
||||||
const monitor_cert_is_valid = new PrometheusClient.Gauge({
|
const monitorCertIsValid = new PrometheusClient.Gauge({
|
||||||
name: "monitor_cert_is_valid",
|
name: "monitor_cert_is_valid",
|
||||||
help: "Is the certificate still valid? (1 = Yes, 0= No)",
|
help: "Is the certificate still valid? (1 = Yes, 0= No)",
|
||||||
labelNames: commonLabels
|
labelNames: commonLabels
|
||||||
});
|
});
|
||||||
const monitor_response_time = new PrometheusClient.Gauge({
|
const monitorResponseTime = new PrometheusClient.Gauge({
|
||||||
name: "monitor_response_time",
|
name: "monitor_response_time",
|
||||||
help: "Monitor Response Time (ms)",
|
help: "Monitor Response Time (ms)",
|
||||||
labelNames: commonLabels
|
labelNames: commonLabels
|
||||||
});
|
});
|
||||||
|
|
||||||
const monitor_status = new PrometheusClient.Gauge({
|
const monitorStatus = new PrometheusClient.Gauge({
|
||||||
name: "monitor_status",
|
name: "monitor_status",
|
||||||
help: "Monitor Status (1 = UP, 0= DOWN)",
|
help: "Monitor Status (1 = UP, 0= DOWN)",
|
||||||
labelNames: commonLabels
|
labelNames: commonLabels
|
||||||
@ -49,13 +49,13 @@ class Prometheus {
|
|||||||
|
|
||||||
if (typeof tlsInfo !== "undefined") {
|
if (typeof tlsInfo !== "undefined") {
|
||||||
try {
|
try {
|
||||||
let isValid = 0;
|
let isValid;
|
||||||
if (tlsInfo.valid == true) {
|
if (tlsInfo.valid === true) {
|
||||||
isValid = 1;
|
isValid = 1;
|
||||||
} else {
|
} else {
|
||||||
isValid = 0;
|
isValid = 0;
|
||||||
}
|
}
|
||||||
monitor_cert_is_valid.set(this.monitorLabelValues, isValid);
|
monitorCertIsValid.set(this.monitorLabelValues, isValid);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log.error("prometheus", "Caught error");
|
log.error("prometheus", "Caught error");
|
||||||
log.error("prometheus", e);
|
log.error("prometheus", e);
|
||||||
@ -63,7 +63,7 @@ class Prometheus {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
if (tlsInfo.certInfo != null) {
|
if (tlsInfo.certInfo != null) {
|
||||||
monitor_cert_days_remaining.set(this.monitorLabelValues, tlsInfo.certInfo.daysRemaining);
|
monitorCertDaysRemaining.set(this.monitorLabelValues, tlsInfo.certInfo.daysRemaining);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log.error("prometheus", "Caught error");
|
log.error("prometheus", "Caught error");
|
||||||
@ -72,7 +72,7 @@ class Prometheus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
monitor_status.set(this.monitorLabelValues, heartbeat.status);
|
monitorStatus.set(this.monitorLabelValues, heartbeat.status);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log.error("prometheus", "Caught error");
|
log.error("prometheus", "Caught error");
|
||||||
log.error("prometheus", e);
|
log.error("prometheus", e);
|
||||||
@ -80,10 +80,10 @@ class Prometheus {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
if (typeof heartbeat.ping === "number") {
|
if (typeof heartbeat.ping === "number") {
|
||||||
monitor_response_time.set(this.monitorLabelValues, heartbeat.ping);
|
monitorResponseTime.set(this.monitorLabelValues, heartbeat.ping);
|
||||||
} else {
|
} else {
|
||||||
// Is it good?
|
// Is it good?
|
||||||
monitor_response_time.set(this.monitorLabelValues, -1);
|
monitorResponseTime.set(this.monitorLabelValues, -1);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log.error("prometheus", "Caught error");
|
log.error("prometheus", "Caught error");
|
||||||
@ -93,10 +93,10 @@ class Prometheus {
|
|||||||
|
|
||||||
remove() {
|
remove() {
|
||||||
try {
|
try {
|
||||||
monitor_cert_days_remaining.remove(this.monitorLabelValues);
|
monitorCertDaysRemaining.remove(this.monitorLabelValues);
|
||||||
monitor_cert_is_valid.remove(this.monitorLabelValues);
|
monitorCertIsValid.remove(this.monitorLabelValues);
|
||||||
monitor_response_time.remove(this.monitorLabelValues);
|
monitorResponseTime.remove(this.monitorLabelValues);
|
||||||
monitor_status.remove(this.monitorLabelValues);
|
monitorStatus.remove(this.monitorLabelValues);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ const server = require("./server");
|
|||||||
|
|
||||||
class Proxy {
|
class Proxy {
|
||||||
|
|
||||||
static SUPPORTED_PROXY_PROTOCOLS = ["http", "https", "socks", "socks5", "socks4"]
|
static SUPPORTED_PROXY_PROTOCOLS = [ "http", "https", "socks", "socks5", "socks4" ]
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Saves and updates given proxy entity
|
* Saves and updates given proxy entity
|
||||||
@ -21,7 +21,7 @@ class Proxy {
|
|||||||
let bean;
|
let bean;
|
||||||
|
|
||||||
if (proxyID) {
|
if (proxyID) {
|
||||||
bean = await R.findOne("proxy", " id = ? AND user_id = ? ", [proxyID, userID]);
|
bean = await R.findOne("proxy", " id = ? AND user_id = ? ", [ proxyID, userID ]);
|
||||||
|
|
||||||
if (!bean) {
|
if (!bean) {
|
||||||
throw new Error("proxy not found");
|
throw new Error("proxy not found");
|
||||||
@ -71,14 +71,14 @@ class Proxy {
|
|||||||
* @return {Promise<void>}
|
* @return {Promise<void>}
|
||||||
*/
|
*/
|
||||||
static async delete(proxyID, userID) {
|
static async delete(proxyID, userID) {
|
||||||
const bean = await R.findOne("proxy", " id = ? AND user_id = ? ", [proxyID, userID]);
|
const bean = await R.findOne("proxy", " id = ? AND user_id = ? ", [ proxyID, userID ]);
|
||||||
|
|
||||||
if (!bean) {
|
if (!bean) {
|
||||||
throw new Error("proxy not found");
|
throw new Error("proxy not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete removed proxy from monitors if exists
|
// Delete removed proxy from monitors if exists
|
||||||
await R.exec("UPDATE monitor SET proxy_id = null WHERE proxy_id = ?", [proxyID]);
|
await R.exec("UPDATE monitor SET proxy_id = null WHERE proxy_id = ?", [ proxyID ]);
|
||||||
|
|
||||||
// Delete proxy from list
|
// Delete proxy from list
|
||||||
await R.trash(bean);
|
await R.trash(bean);
|
||||||
@ -172,12 +172,12 @@ class Proxy {
|
|||||||
*/
|
*/
|
||||||
async function applyProxyEveryMonitor(proxyID, userID) {
|
async function applyProxyEveryMonitor(proxyID, userID) {
|
||||||
// Find all monitors with id and proxy id
|
// Find all monitors with id and proxy id
|
||||||
const monitors = await R.getAll("SELECT id, proxy_id FROM monitor WHERE user_id = ?", [userID]);
|
const monitors = await R.getAll("SELECT id, proxy_id FROM monitor WHERE user_id = ?", [ userID ]);
|
||||||
|
|
||||||
// Update proxy id not match with given proxy id
|
// Update proxy id not match with given proxy id
|
||||||
for (const monitor of monitors) {
|
for (const monitor of monitors) {
|
||||||
if (monitor.proxy_id !== proxyID) {
|
if (monitor.proxy_id !== proxyID) {
|
||||||
await R.exec("UPDATE monitor SET proxy_id = ? WHERE id = ?", [proxyID, monitor.id]);
|
await R.exec("UPDATE monitor SET proxy_id = ? WHERE id = ?", [ proxyID, monitor.id ]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
let express = require("express");
|
let express = require("express");
|
||||||
const { allowDevAllOrigin, getSettings, setting } = require("../util-server");
|
const { allowDevAllOrigin } = require("../util-server");
|
||||||
const { R } = require("redbean-node");
|
const { R } = require("redbean-node");
|
||||||
const server = require("../server");
|
const server = require("../server");
|
||||||
const apicache = require("../modules/apicache");
|
const apicache = require("../modules/apicache");
|
||||||
@ -195,14 +195,6 @@ router.get("/api/status-page/heartbeat/:slug", cache("1 minutes"), async (reques
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
|
||||||
* Default is published
|
|
||||||
* @returns {Promise<boolean>}
|
|
||||||
*/
|
|
||||||
async function isPublished() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function send403(res, msg = "") {
|
function send403(res, msg = "") {
|
||||||
res.status(403).json({
|
res.status(403).json({
|
||||||
"status": "fail",
|
"status": "fail",
|
||||||
|
@ -11,7 +11,7 @@ if (nodeVersion < requiredVersion) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const args = require("args-parser")(process.argv);
|
const args = require("args-parser")(process.argv);
|
||||||
const { sleep, log, getRandomInt, genSecret, debug } = require("../src/util");
|
const { sleep, log, getRandomInt, genSecret, debug, isDev } = require("../src/util");
|
||||||
const config = require("./config");
|
const config = require("./config");
|
||||||
|
|
||||||
log.info("server", "Welcome to Uptime Kuma");
|
log.info("server", "Welcome to Uptime Kuma");
|
||||||
@ -108,7 +108,7 @@ if (hostname) {
|
|||||||
log.info("server", "Custom hostname: " + hostname);
|
log.info("server", "Custom hostname: " + hostname);
|
||||||
}
|
}
|
||||||
|
|
||||||
const port = [args.port, process.env.UPTIME_KUMA_PORT, process.env.PORT, 3001]
|
const port = [ args.port, process.env.UPTIME_KUMA_PORT, process.env.PORT, 3001 ]
|
||||||
.map(portValue => parseInt(portValue))
|
.map(portValue => parseInt(portValue))
|
||||||
.find(portValue => !isNaN(portValue));
|
.find(portValue => !isNaN(portValue));
|
||||||
|
|
||||||
@ -119,7 +119,7 @@ const disableFrameSameOrigin = args["disable-frame-sameorigin"] || !!process.env
|
|||||||
const cloudflaredToken = args["cloudflared-token"] || process.env.UPTIME_KUMA_CLOUDFLARED_TOKEN || undefined;
|
const cloudflaredToken = args["cloudflared-token"] || process.env.UPTIME_KUMA_CLOUDFLARED_TOKEN || undefined;
|
||||||
|
|
||||||
// 2FA / notp verification defaults
|
// 2FA / notp verification defaults
|
||||||
const twofa_verification_opts = {
|
const twoFAVerifyOptions = {
|
||||||
"window": 1,
|
"window": 1,
|
||||||
"time": 30
|
"time": 30
|
||||||
};
|
};
|
||||||
@ -175,6 +175,7 @@ app.use(function (req, res, next) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Total WebSocket client connected to server currently, no actual use
|
* Total WebSocket client connected to server currently, no actual use
|
||||||
|
*
|
||||||
* @type {number}
|
* @type {number}
|
||||||
*/
|
*/
|
||||||
let totalClient = 0;
|
let totalClient = 0;
|
||||||
@ -234,6 +235,13 @@ try {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (isDev) {
|
||||||
|
app.post("/test-webhook", async (request, response) => {
|
||||||
|
log.debug("test", request.body);
|
||||||
|
response.send("OK");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Robots.txt
|
// Robots.txt
|
||||||
app.get("/robots.txt", async (_request, response) => {
|
app.get("/robots.txt", async (_request, response) => {
|
||||||
let txt = "User-agent: *\nDisallow:";
|
let txt = "User-agent: *\nDisallow:";
|
||||||
@ -379,7 +387,7 @@ try {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (data.token) {
|
if (data.token) {
|
||||||
let verify = notp.totp.verify(data.token, user.twofa_secret, twofa_verification_opts);
|
let verify = notp.totp.verify(data.token, user.twofa_secret, twoFAVerifyOptions);
|
||||||
|
|
||||||
if (user.twofa_last_token !== data.token && verify) {
|
if (user.twofa_last_token !== data.token && verify) {
|
||||||
afterLogin(socket, user);
|
afterLogin(socket, user);
|
||||||
@ -546,7 +554,7 @@ try {
|
|||||||
socket.userID,
|
socket.userID,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
let verify = notp.totp.verify(token, user.twofa_secret, twofa_verification_opts);
|
let verify = notp.totp.verify(token, user.twofa_secret, twoFAVerifyOptions);
|
||||||
|
|
||||||
if (user.twofa_last_token !== token && verify) {
|
if (user.twofa_last_token !== token && verify) {
|
||||||
callback({
|
callback({
|
||||||
@ -1239,7 +1247,7 @@ try {
|
|||||||
const exists = proxies.find(item => item.id === proxy.id);
|
const exists = proxies.find(item => item.id === proxy.id);
|
||||||
|
|
||||||
// Do not process when proxy already exists in import handle is skip and keep
|
// Do not process when proxy already exists in import handle is skip and keep
|
||||||
if (["skip", "keep"].includes(importHandle) && !exists) {
|
if ([ "skip", "keep" ].includes(importHandle) && !exists) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,6 +155,9 @@ module.exports.statusPageSocketHandler = (socket) => {
|
|||||||
//statusPage.search_engine_index = ;
|
//statusPage.search_engine_index = ;
|
||||||
statusPage.show_tags = config.showTags;
|
statusPage.show_tags = config.showTags;
|
||||||
//statusPage.password = null;
|
//statusPage.password = null;
|
||||||
|
statusPage.footer_text = config.footerText;
|
||||||
|
statusPage.custom_css = config.customCSS;
|
||||||
|
statusPage.show_powered_by = config.showPoweredBy;
|
||||||
statusPage.modified_date = R.isoDateTime();
|
statusPage.modified_date = R.isoDateTime();
|
||||||
|
|
||||||
await R.store(statusPage);
|
await R.store(statusPage);
|
||||||
|
@ -146,11 +146,11 @@ exports.mqttAsync = function (hostname, topic, okMessage, options = {}) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.dnsResolve = function (hostname, resolver_server, rrtype) {
|
exports.dnsResolve = function (hostname, resolverServer, rrtype) {
|
||||||
const resolver = new Resolver();
|
const resolver = new Resolver();
|
||||||
resolver.setServers([resolver_server]);
|
resolver.setServers([ resolverServer ]);
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
if (rrtype == "PTR") {
|
if (rrtype === "PTR") {
|
||||||
resolver.reverse(hostname, (err, records) => {
|
resolver.reverse(hostname, (err, records) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
reject(err);
|
reject(err);
|
||||||
@ -315,19 +315,19 @@ exports.checkCertificate = function (res) {
|
|||||||
// Return: true if the status code is within the accepted ranges, false otherwise
|
// Return: true if the status code is within the accepted ranges, false otherwise
|
||||||
// Will throw an error if the provided status code is not a valid range string or code string
|
// Will throw an error if the provided status code is not a valid range string or code string
|
||||||
|
|
||||||
exports.checkStatusCode = function (status, accepted_codes) {
|
exports.checkStatusCode = function (status, acceptedCodes) {
|
||||||
if (accepted_codes == null || accepted_codes.length === 0) {
|
if (acceptedCodes == null || acceptedCodes.length === 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const code_range of accepted_codes) {
|
for (const codeRange of acceptedCodes) {
|
||||||
const code_range_split = code_range.split("-").map(string => parseInt(string));
|
const codeRangeSplit = codeRange.split("-").map(string => parseInt(string));
|
||||||
if (code_range_split.length === 1) {
|
if (codeRangeSplit.length === 1) {
|
||||||
if (status === code_range_split[0]) {
|
if (status === codeRangeSplit[0]) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else if (code_range_split.length === 2) {
|
} else if (codeRangeSplit.length === 2) {
|
||||||
if (status >= code_range_split[0] && status <= code_range_split[1]) {
|
if (status >= codeRangeSplit[0] && status <= codeRangeSplit[1]) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -403,7 +403,7 @@ exports.doubleCheckPassword = async (socket, currentPassword) => {
|
|||||||
exports.startUnitTest = async () => {
|
exports.startUnitTest = async () => {
|
||||||
console.log("Starting unit test...");
|
console.log("Starting unit test...");
|
||||||
const npm = /^win/.test(process.platform) ? "npm.cmd" : "npm";
|
const npm = /^win/.test(process.platform) ? "npm.cmd" : "npm";
|
||||||
const child = childProcess.spawn(npm, ["run", "jest"]);
|
const child = childProcess.spawn(npm, [ "run", "jest" ]);
|
||||||
|
|
||||||
child.stdout.on("data", (data) => {
|
child.stdout.on("data", (data) => {
|
||||||
console.log(data.toString());
|
console.log(data.toString());
|
||||||
|
@ -469,6 +469,10 @@ textarea.form-control {
|
|||||||
color: $primary;
|
color: $primary;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.prism-editor__textarea {
|
||||||
|
outline: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
// Localization
|
// Localization
|
||||||
|
|
||||||
@import "localization.scss";
|
@import "localization.scss";
|
||||||
|
@ -42,6 +42,7 @@ export default {
|
|||||||
default: "No",
|
default: "No",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
emits: [ "yes" ],
|
||||||
data: () => ({
|
data: () => ({
|
||||||
modal: null,
|
modal: null,
|
||||||
}),
|
}),
|
||||||
|
@ -57,6 +57,7 @@ export default {
|
|||||||
default: undefined,
|
default: undefined,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
emits: [ "update:modelValue" ],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
visibility: "password",
|
visibility: "password",
|
||||||
|
@ -10,7 +10,7 @@ import { sleep } from "../util.ts";
|
|||||||
export default {
|
export default {
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
value: [String, Number],
|
value: [ String, Number ],
|
||||||
time: {
|
time: {
|
||||||
type: Number,
|
type: Number,
|
||||||
default: 0.3,
|
default: 0.3,
|
||||||
|
@ -48,6 +48,7 @@ export default {
|
|||||||
default: undefined,
|
default: undefined,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
emits: [ "update:modelValue" ],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
visibility: "password",
|
visibility: "password",
|
||||||
|
@ -78,7 +78,7 @@ export default {
|
|||||||
Confirm,
|
Confirm,
|
||||||
},
|
},
|
||||||
props: {},
|
props: {},
|
||||||
emits: ["added"],
|
emits: [ "added" ],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
model: null,
|
model: null,
|
||||||
|
@ -220,6 +220,7 @@ export default {
|
|||||||
if (newPeriod == "0") {
|
if (newPeriod == "0") {
|
||||||
newPeriod = null;
|
newPeriod = null;
|
||||||
this.heartbeatList = null;
|
this.heartbeatList = null;
|
||||||
|
this.$root.storage().removeItem(`chart-period-${this.monitorId}`);
|
||||||
} else {
|
} else {
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
|
|
||||||
@ -228,6 +229,7 @@ export default {
|
|||||||
toast.error(res.msg);
|
toast.error(res.msg);
|
||||||
} else {
|
} else {
|
||||||
this.heartbeatList = res.data;
|
this.heartbeatList = res.data;
|
||||||
|
this.$root.storage()[`chart-period-${this.monitorId}`] = newPeriod;
|
||||||
}
|
}
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
});
|
});
|
||||||
@ -248,6 +250,12 @@ export default {
|
|||||||
},
|
},
|
||||||
{ deep: true }
|
{ deep: true }
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Load chart period from storage if saved
|
||||||
|
let period = this.$root.storage()[`chart-period-${this.monitorId}`];
|
||||||
|
if (period != null) {
|
||||||
|
this.chartPeriodHrs = Math.min(period, 6);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
@ -105,7 +105,7 @@ export default {
|
|||||||
Confirm,
|
Confirm,
|
||||||
},
|
},
|
||||||
props: {},
|
props: {},
|
||||||
emits: ["added"],
|
emits: [ "added" ],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
model: null,
|
model: null,
|
||||||
|
19
src/components/notifications/PushDeer.vue
Normal file
19
src/components/notifications/PushDeer.vue
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<template>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="pushdeer-key" class="form-label">{{ $t("PushDeer Key") }}</label>
|
||||||
|
<HiddenInput id="pushdeer-key" v-model="$parent.notification.pushdeerKey" :required="true" autocomplete="one-time-code" placeholder="PDUxxxx"></HiddenInput>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<i18n-t tag="p" keypath="More info on:" style="margin-top: 8px;">
|
||||||
|
<a href="http://www.pushdeer.com/" rel="noopener noreferrer" target="_blank">http://www.pushdeer.com/</a>
|
||||||
|
</i18n-t>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import HiddenInput from "../HiddenInput.vue";
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
HiddenInput,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
@ -30,6 +30,7 @@ import GoogleChat from "./GoogleChat.vue";
|
|||||||
import Gorush from "./Gorush.vue";
|
import Gorush from "./Gorush.vue";
|
||||||
import Alerta from "./Alerta.vue";
|
import Alerta from "./Alerta.vue";
|
||||||
import OneBot from "./OneBot.vue";
|
import OneBot from "./OneBot.vue";
|
||||||
|
import PushDeer from "./PushDeer.vue";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manage all notification form.
|
* Manage all notification form.
|
||||||
@ -69,6 +70,7 @@ const NotificationFormList = {
|
|||||||
"gorush": Gorush,
|
"gorush": Gorush,
|
||||||
"alerta": Alerta,
|
"alerta": Alerta,
|
||||||
"OneBot": OneBot,
|
"OneBot": OneBot,
|
||||||
|
"PushDeer": PushDeer,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default NotificationFormList;
|
export default NotificationFormList;
|
||||||
|
@ -43,7 +43,7 @@ for (let lang in languageList) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const rtlLangs = ["fa"];
|
const rtlLangs = [ "fa" ];
|
||||||
|
|
||||||
export const currentLocale = () => localStorage.locale
|
export const currentLocale = () => localStorage.locale
|
||||||
|| languageList[navigator.language] && navigator.language
|
|| languageList[navigator.language] && navigator.language
|
||||||
|
@ -197,7 +197,7 @@ export default {
|
|||||||
line: "Line Messenger",
|
line: "Line Messenger",
|
||||||
mattermost: "Mattermost",
|
mattermost: "Mattermost",
|
||||||
"Status Page": "Статус страница",
|
"Status Page": "Статус страница",
|
||||||
"Status Pages": "Статус страница",
|
"Status Pages": "Статус страници",
|
||||||
"Primary Base URL": "Основен базов URL адрес",
|
"Primary Base URL": "Основен базов URL адрес",
|
||||||
"Push URL": "Генериран Push URL адрес",
|
"Push URL": "Генериран Push URL адрес",
|
||||||
needPushEvery: "Необходимо е да извършвате заявка към този URL адрес на всеки {0} секунди",
|
needPushEvery: "Необходимо е да извършвате заявка към този URL адрес на всеки {0} секунди",
|
||||||
@ -371,4 +371,75 @@ export default {
|
|||||||
alertaAlertState: "Състояние на тревога",
|
alertaAlertState: "Състояние на тревога",
|
||||||
alertaRecoverState: "Състояние на възстановяване",
|
alertaRecoverState: "Състояние на възстановяване",
|
||||||
deleteStatusPageMsg: "Сигурни ли сте, че желаете да изтриете тази статус страница?",
|
deleteStatusPageMsg: "Сигурни ли сте, че желаете да изтриете тази статус страница?",
|
||||||
|
Proxies: "Проксита",
|
||||||
|
default: "По подразбиране",
|
||||||
|
enabled: "Включено",
|
||||||
|
setAsDefault: "Зададен по подразбиране",
|
||||||
|
deleteProxyMsg: "Сигурни ли сте, че желаете да изтриете това прокси за всички монитори?",
|
||||||
|
proxyDescription: "Прокситата трябва да бъдат зададени към монитор за да функционират.",
|
||||||
|
enableProxyDescription: "Това прокси няма да има ефект върху заявките за мониторинг, докато не бъде активирано. Може да контролирате временното деактивиране на проксито от всички монитори чрез статуса на активиране.",
|
||||||
|
setAsDefaultProxyDescription: "Това проки ще бъде включено по подразбиране за новите монитори. Може да го изключите по отделно за всеки един монитор.",
|
||||||
|
"Certificate Chain": "Верига на сертификата",
|
||||||
|
Valid: "Валиден",
|
||||||
|
Invalid: "Невалиден",
|
||||||
|
AccessKeyId: "ID на ключ за достъп",
|
||||||
|
SecretAccessKey: "Тайна на ключа за достъп",
|
||||||
|
PhoneNumbers: "Телефонни номера",
|
||||||
|
TemplateCode: "Шаблон Код",
|
||||||
|
SignName: "Знак име",
|
||||||
|
"Sms template must contain parameters: ": "SMS шаблонът трябва да съдържа следните параметри: ",
|
||||||
|
"Bark Endpoint": "Bark крайна точка",
|
||||||
|
WebHookUrl: "URL адрес на уеб кука",
|
||||||
|
SecretKey: "Таен ключ",
|
||||||
|
"For safety, must use secret key": "За сигурност, трябва да се използва таен ключ",
|
||||||
|
"Device Token": "Токен за устройство",
|
||||||
|
Platform: "Платформа",
|
||||||
|
iOS: "iOS",
|
||||||
|
Android: "Android",
|
||||||
|
Huawei: "Huawei",
|
||||||
|
High: "Висок",
|
||||||
|
Retry: "Повтори",
|
||||||
|
Topic: "Тема",
|
||||||
|
"WeCom Bot Key": "WeCom бот ключ",
|
||||||
|
"Setup Proxy": "Настройка за прокси",
|
||||||
|
"Proxy Protocol": "Прокси протокол",
|
||||||
|
"Proxy Server": "Прокси сървър",
|
||||||
|
"Proxy server has authentication": "Прокси сървърът е с удостоверяване",
|
||||||
|
User: "Потребител",
|
||||||
|
Installed: "Инсталиран",
|
||||||
|
"Not installed": "Не е инсталиран",
|
||||||
|
Running: "Работи",
|
||||||
|
"Not running": "Не работи",
|
||||||
|
"Remove Token": "Премахни токен",
|
||||||
|
Start: "Старт",
|
||||||
|
Stop: "Стоп",
|
||||||
|
"Uptime Kuma": "Uptime Kuma",
|
||||||
|
"Add New Status Page": "Добави нова статус страница",
|
||||||
|
Slug: "Слъг",
|
||||||
|
"Accept characters:": "Приеми символи:",
|
||||||
|
startOrEndWithOnly: "Започва или завършва само с {0}",
|
||||||
|
"No consecutive dashes": "Без последователни тирета",
|
||||||
|
Next: "Следващ",
|
||||||
|
"The slug is already taken. Please choose another slug.": "Този слъг вече се използва. Моля изберете друг.",
|
||||||
|
"No Proxy": "Без прокси",
|
||||||
|
"HTTP Basic Auth": "HTTP основно удостоверяване",
|
||||||
|
"New Status Page": "Нова статус страница",
|
||||||
|
"Page Not Found": "Страницата не е открита",
|
||||||
|
"Reverse Proxy": "Ревърс прокси",
|
||||||
|
Backup: "Архивиране",
|
||||||
|
About: "Относно",
|
||||||
|
wayToGetCloudflaredURL: "(Свалете \"cloudflared\" от {0})",
|
||||||
|
cloudflareWebsite: "Cloudflare уебсайт",
|
||||||
|
"Message:": "Съобщение:",
|
||||||
|
"Don't know how to get the token? Please read the guide:": "Не знаете как да вземете токен? Моля, прочетете ръководството:",
|
||||||
|
"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.": "Текущата връзка може да прекъсне ако в момента сте свързани чрез \"Cloudflare Tunnel\". Сигурни ли сте, че желаете да го спрете? Въведете Вашата текуща парола за да потвърдите.",
|
||||||
|
"Other Software": "Друг софтуер",
|
||||||
|
"For example: nginx, Apache and Traefik.": "Например: Nginx, Apache и Traefik.",
|
||||||
|
"Please read": "Моля, прочетете",
|
||||||
|
"Subject:": "Тема:",
|
||||||
|
"Valid To:": "Валиден до:",
|
||||||
|
"Days Remaining:": "Оставащи дни:",
|
||||||
|
"Issuer:": "Издател:",
|
||||||
|
"Fingerprint:": "Пръстов отпечатък:",
|
||||||
|
"No status pages": "Няма статус страници",
|
||||||
};
|
};
|
||||||
|
@ -337,7 +337,7 @@ export default {
|
|||||||
"Hide Tags": "Tags ausblenden",
|
"Hide Tags": "Tags ausblenden",
|
||||||
Description: "Beschreibung",
|
Description: "Beschreibung",
|
||||||
"No monitors available.": "Keine Monitore verfügbar.",
|
"No monitors available.": "Keine Monitore verfügbar.",
|
||||||
"Add one": "Füge eins hinzu",
|
"Add one": "Hinzufügen",
|
||||||
"No Monitors": "Keine Monitore",
|
"No Monitors": "Keine Monitore",
|
||||||
"Untitled Group": "Gruppe ohne Titel",
|
"Untitled Group": "Gruppe ohne Titel",
|
||||||
Services: "Dienste",
|
Services: "Dienste",
|
||||||
@ -442,4 +442,7 @@ export default {
|
|||||||
"Issuer:": "Aussteller:",
|
"Issuer:": "Aussteller:",
|
||||||
"Fingerprint:": "Fingerabdruck:",
|
"Fingerprint:": "Fingerabdruck:",
|
||||||
"No status pages": "Keine Status-Seiten",
|
"No status pages": "Keine Status-Seiten",
|
||||||
|
Customize: "Anpassen",
|
||||||
|
"Custom Footer": "Eigener Footer",
|
||||||
|
"Custom CSS": "Eigenes CSS",
|
||||||
};
|
};
|
||||||
|
@ -358,6 +358,9 @@ export default {
|
|||||||
serwersmsPhoneNumber: "Phone number",
|
serwersmsPhoneNumber: "Phone number",
|
||||||
serwersmsSenderName: "SMS Sender Name (registered via customer portal)",
|
serwersmsSenderName: "SMS Sender Name (registered via customer portal)",
|
||||||
stackfield: "Stackfield",
|
stackfield: "Stackfield",
|
||||||
|
Customize: "Customize",
|
||||||
|
"Custom Footer": "Custom Footer",
|
||||||
|
"Custom CSS": "Custom CSS",
|
||||||
smtpDkimSettings: "DKIM Settings",
|
smtpDkimSettings: "DKIM Settings",
|
||||||
smtpDkimDesc: "Please refer to the Nodemailer DKIM {0} for usage.",
|
smtpDkimDesc: "Please refer to the Nodemailer DKIM {0} for usage.",
|
||||||
documentation: "documentation",
|
documentation: "documentation",
|
||||||
@ -455,4 +458,5 @@ export default {
|
|||||||
onebotPrivateMessage: "Private",
|
onebotPrivateMessage: "Private",
|
||||||
onebotUserOrGroupId: "Group/User ID",
|
onebotUserOrGroupId: "Group/User ID",
|
||||||
onebotSafetyTips: "For safety, must set access token",
|
onebotSafetyTips: "For safety, must set access token",
|
||||||
|
"PushDeer Key": "PushDeer Key",
|
||||||
};
|
};
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { io } from "socket.io-client";
|
import { io } from "socket.io-client";
|
||||||
import { useToast } from "vue-toastification";
|
import { useToast } from "vue-toastification";
|
||||||
import jwt_decode from "jwt-decode";
|
import jwtDecode from "jwt-decode";
|
||||||
import Favico from "favico.js";
|
import Favico from "favico.js";
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
|
|
||||||
@ -89,7 +89,7 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
socket = io(wsHost, {
|
socket = io(wsHost, {
|
||||||
transports: ["websocket"],
|
transports: [ "websocket" ],
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on("info", (info) => {
|
socket.on("info", (info) => {
|
||||||
@ -108,7 +108,7 @@ export default {
|
|||||||
|
|
||||||
socket.on("monitorList", (data) => {
|
socket.on("monitorList", (data) => {
|
||||||
// Add Helper function
|
// Add Helper function
|
||||||
Object.entries(data).forEach(([monitorID, monitor]) => {
|
Object.entries(data).forEach(([ monitorID, monitor ]) => {
|
||||||
monitor.getUrl = () => {
|
monitor.getUrl = () => {
|
||||||
try {
|
try {
|
||||||
return new URL(monitor.url);
|
return new URL(monitor.url);
|
||||||
@ -266,7 +266,7 @@ export default {
|
|||||||
const jwtToken = this.$root.storage().token;
|
const jwtToken = this.$root.storage().token;
|
||||||
|
|
||||||
if (jwtToken && jwtToken !== "autoLogin") {
|
if (jwtToken && jwtToken !== "autoLogin") {
|
||||||
return jwt_decode(jwtToken);
|
return jwtDecode(jwtToken);
|
||||||
}
|
}
|
||||||
return undefined;
|
return undefined;
|
||||||
},
|
},
|
||||||
|
@ -426,17 +426,17 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
bodyPlaceholder() {
|
bodyPlaceholder() {
|
||||||
return this.$t("Example:", [`
|
return this.$t("Example:", [ `
|
||||||
{
|
{
|
||||||
"key": "value"
|
"key": "value"
|
||||||
}`]);
|
}` ]);
|
||||||
},
|
},
|
||||||
|
|
||||||
headersPlaceholder() {
|
headersPlaceholder() {
|
||||||
return this.$t("Example:", [`
|
return this.$t("Example:", [ `
|
||||||
{
|
{
|
||||||
"HeaderName": "HeaderValue"
|
"HeaderName": "HeaderValue"
|
||||||
}`]);
|
}` ]);
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
@ -521,7 +521,7 @@ export default {
|
|||||||
upsideDown: false,
|
upsideDown: false,
|
||||||
expiryNotification: false,
|
expiryNotification: false,
|
||||||
maxredirects: 10,
|
maxredirects: 10,
|
||||||
accepted_statuscodes: ["200-299"],
|
accepted_statuscodes: [ "200-299" ],
|
||||||
dns_resolve_type: "A",
|
dns_resolve_type: "A",
|
||||||
dns_resolve_server: "1.1.1.1",
|
dns_resolve_server: "1.1.1.1",
|
||||||
proxyId: null,
|
proxyId: null,
|
||||||
|
@ -16,11 +16,18 @@
|
|||||||
<input id="title" v-model="config.title" type="text" class="form-control">
|
<input id="title" v-model="config.title" type="text" class="form-control">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Description -->
|
||||||
<div class="my-3">
|
<div class="my-3">
|
||||||
<label for="description" class="form-label">{{ $t("Description") }}</label>
|
<label for="description" class="form-label">{{ $t("Description") }}</label>
|
||||||
<textarea id="description" v-model="config.description" class="form-control"></textarea>
|
<textarea id="description" v-model="config.description" class="form-control"></textarea>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Footer Text -->
|
||||||
|
<div class="my-3">
|
||||||
|
<label for="footer-text" class="form-label">{{ $t("Footer Text") }}</label>
|
||||||
|
<textarea id="footer-text" v-model="config.footerText" class="form-control"></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="my-3 form-check form-switch">
|
<div class="my-3 form-check form-switch">
|
||||||
<input id="switch-theme" v-model="config.theme" class="form-check-input" type="checkbox" true-value="dark" false-value="light">
|
<input id="switch-theme" v-model="config.theme" class="form-check-input" type="checkbox" true-value="dark" false-value="light">
|
||||||
<label class="form-check-label" for="switch-theme">{{ $t("Switch to Dark Theme") }}</label>
|
<label class="form-check-label" for="switch-theme">{{ $t("Switch to Dark Theme") }}</label>
|
||||||
@ -31,6 +38,12 @@
|
|||||||
<label class="form-check-label" for="showTags">{{ $t("Show Tags") }}</label>
|
<label class="form-check-label" for="showTags">{{ $t("Show Tags") }}</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Show Powered By -->
|
||||||
|
<div class="my-3 form-check form-switch">
|
||||||
|
<input id="show-powered-by" v-model="config.showPoweredBy" class="form-check-input" type="checkbox">
|
||||||
|
<label class="form-check-label" for="show-powered-by">{{ $t("Show Powered By") }}</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div v-if="false" class="my-3">
|
<div v-if="false" class="my-3">
|
||||||
<label for="password" class="form-label">{{ $t("Password") }} <sup>Coming Soon</sup></label>
|
<label for="password" class="form-label">{{ $t("Password") }} <sup>Coming Soon</sup></label>
|
||||||
<input id="password" v-model="config.password" disabled type="password" autocomplete="new-password" class="form-control">
|
<input id="password" v-model="config.password" disabled type="password" autocomplete="new-password" class="form-control">
|
||||||
@ -51,6 +64,12 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Custom CSS -->
|
||||||
|
<div class="my-3">
|
||||||
|
<div class="mb-1">{{ $t("Custom CSS") }}</div>
|
||||||
|
<prism-editor v-model="config.customCSS" class="css-editor" :highlight="highlighter" line-numbers></prism-editor>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="danger-zone">
|
<div class="danger-zone">
|
||||||
<button class="btn btn-danger me-2" @click="deleteDialog">
|
<button class="btn btn-danger me-2" @click="deleteDialog">
|
||||||
<font-awesome-icon icon="trash" />
|
<font-awesome-icon icon="trash" />
|
||||||
@ -239,13 +258,24 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<footer class="mt-5 mb-4">
|
<footer class="mt-5 mb-4">
|
||||||
{{ $t("Powered by") }} <a target="_blank" href="https://github.com/louislam/uptime-kuma">{{ $t("Uptime Kuma" ) }}</a>
|
<div class="custom-footer-text text-start">
|
||||||
|
<strong v-if="enableEditMode">{{ $t("Custom Footer") }}:</strong>
|
||||||
|
</div>
|
||||||
|
<Editable v-model="config.footerText" tag="div" :contenteditable="enableEditMode" :noNL="false" class="alert-heading p-2" />
|
||||||
|
|
||||||
|
<p v-if="config.showPoweredBy">
|
||||||
|
{{ $t("Powered by") }} <a target="_blank" href="https://github.com/louislam/uptime-kuma">{{ $t("Uptime Kuma" ) }}</a>
|
||||||
|
</p>
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Confirm ref="confirmDelete" btn-style="btn-danger" :yes-text="$t('Yes')" :no-text="$t('No')" @yes="deleteStatusPage">
|
<Confirm ref="confirmDelete" btn-style="btn-danger" :yes-text="$t('Yes')" :no-text="$t('No')" @yes="deleteStatusPage">
|
||||||
{{ $t("deleteStatusPageMsg") }}
|
{{ $t("deleteStatusPageMsg") }}
|
||||||
</Confirm>
|
</Confirm>
|
||||||
|
|
||||||
|
<component is="style" v-if="config.customCSS" type="text/css">
|
||||||
|
{{ config.customCSS }}
|
||||||
|
</component>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -259,11 +289,20 @@ import dayjs from "dayjs";
|
|||||||
import Favico from "favico.js";
|
import Favico from "favico.js";
|
||||||
import { getResBaseURL } from "../util-frontend";
|
import { getResBaseURL } from "../util-frontend";
|
||||||
import Confirm from "../components/Confirm.vue";
|
import Confirm from "../components/Confirm.vue";
|
||||||
|
// import Prism Editor
|
||||||
|
import { PrismEditor } from "vue-prism-editor";
|
||||||
|
import "vue-prism-editor/dist/prismeditor.min.css"; // import the styles somewhere
|
||||||
|
|
||||||
|
// import highlighting library (you can use any library you want just return html string)
|
||||||
|
import { highlight, languages } from "prismjs/components/prism-core";
|
||||||
|
import "prismjs/components/prism-css";
|
||||||
|
import "prismjs/themes/prism-tomorrow.css"; // import syntax highlighting styles
|
||||||
|
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
|
|
||||||
const leavePageMsg = "Do you really want to leave? you have unsaved changes!";
|
const leavePageMsg = "Do you really want to leave? you have unsaved changes!";
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
let feedInterval;
|
let feedInterval;
|
||||||
|
|
||||||
const favicon = new Favico({
|
const favicon = new Favico({
|
||||||
@ -276,6 +315,7 @@ export default {
|
|||||||
PublicGroupList,
|
PublicGroupList,
|
||||||
ImageCropUpload,
|
ImageCropUpload,
|
||||||
Confirm,
|
Confirm,
|
||||||
|
PrismEditor,
|
||||||
},
|
},
|
||||||
|
|
||||||
// Leave Page for vue route change
|
// Leave Page for vue route change
|
||||||
@ -418,6 +458,13 @@ export default {
|
|||||||
this.$root.getSocket().emit("getStatusPage", this.slug, (res) => {
|
this.$root.getSocket().emit("getStatusPage", this.slug, (res) => {
|
||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
this.config = res.config;
|
this.config = res.config;
|
||||||
|
|
||||||
|
if (!this.config.customCSS) {
|
||||||
|
this.config.customCSS = "body {\n" +
|
||||||
|
" \n" +
|
||||||
|
"}\n";
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
toast.error(res.msg);
|
toast.error(res.msg);
|
||||||
}
|
}
|
||||||
@ -520,6 +567,10 @@ export default {
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
||||||
|
highlighter(code) {
|
||||||
|
return highlight(code, languages.css);
|
||||||
|
},
|
||||||
|
|
||||||
updateHeartbeatList() {
|
updateHeartbeatList() {
|
||||||
// If editMode, it will use the data from websocket.
|
// If editMode, it will use the data from websocket.
|
||||||
if (! this.editMode) {
|
if (! this.editMode) {
|
||||||
@ -893,4 +944,18 @@ footer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* required class */
|
||||||
|
.css-editor {
|
||||||
|
/* we dont use `language-` classes anymore so thats why we need to add background and text color manually */
|
||||||
|
|
||||||
|
border-radius: 1rem;
|
||||||
|
padding: 10px 5px;
|
||||||
|
border: 1px solid #ced4da;
|
||||||
|
|
||||||
|
.dark & {
|
||||||
|
background: $dark-bg;
|
||||||
|
border: 1px solid $dark-border-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user