diff --git a/.github/ISSUE_TEMPLATE/--please-go-to--discussion--tab-if-you-want-to-ask-or-share-something.md b/.github/ISSUE_TEMPLATE/--please-go-to--discussion--tab-if-you-want-to-ask-or-share-something.md new file mode 100644 index 000000000..eb8623709 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/--please-go-to--discussion--tab-if-you-want-to-ask-or-share-something.md @@ -0,0 +1,10 @@ +--- +name: ⚠ Please go to "Discussions" Tab if you want to ask or share something +about: BUG REPORT ONLY HERE +title: '' +labels: '' +assignees: '' + +--- + +BUG REPORT ONLY HERE diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 000000000..cea1fc16e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,34 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: bug +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Desktop (please complete the following information):** + - Uptime Kuma Version: + - Using Docker?: Yes/No + - OS: + - Browser: + + +**Additional context** +Add any other context about the problem here. diff --git a/README.md b/README.md index 35bfeb8ab..7777cb2c5 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ It is a self-hosted monitoring tool like "Uptime Robot". docker volume create uptime-kuma # Start the container -docker run -d --restart=always -p 3001:3001 -v uptime-kuma:/app/data --name uptime-kuma louislam/uptime-kuma +docker run -d --restart=always -p 3001:3001 -v uptime-kuma:/app/data --name uptime-kuma louislam/uptime-kuma:1 ``` Browse to http://localhost:3001 after started. @@ -35,7 +35,7 @@ Browse to http://localhost:3001 after started. Change Port and Volume ```bash -docker run -d --restart=always -p :3001 -v :/app/data --name uptime-kuma louislam/uptime-kuma +docker run -d --restart=always -p :3001 -v :/app/data --name uptime-kuma louislam/uptime-kuma:1 ``` ### Without Docker @@ -80,12 +80,17 @@ PS: For every new release, it takes some time to build the docker image, please ```bash git fetch --all -git checkout 1.0.5 --force +git checkout 1.0.6 --force npm install npm run build pm2 restart uptime-kuma ``` +# What's Next? + +I will mark requests/issues to the next milestone. +https://github.com/louislam/uptime-kuma/milestones + # More Screenshots Settings Page: @@ -109,3 +114,11 @@ Telegram Notification Sample: If you love this project, please consider giving me a ⭐. + +# Contribute + +If you want to report a bug or request a new feature. Free feel to open a new issue. + +If you want to modify Uptime Kuma, this guideline maybe useful for you: https://github.com/louislam/uptime-kuma/wiki/%5BDev%5D-Setup-Development-Environment + +English proofreading is needed too, because my grammar is not that great sadly. Feel free to correct my grammar in this Readme, source code or wiki. diff --git a/db/patch1.sql b/db/patch1.sql new file mode 100644 index 000000000..1ab6cc0cf --- /dev/null +++ b/db/patch1.sql @@ -0,0 +1,37 @@ +-- You should not modify if this have pushed to Github, unless it do serious wrong with the db. +-- Change Monitor.created_date from "TIMESTAMP" to "DATETIME" +-- SQL Generated by Intellij Idea +PRAGMA foreign_keys=off; + +BEGIN TRANSACTION; + +create table monitor_dg_tmp +( + id INTEGER not null + primary key autoincrement, + name VARCHAR(150), + active BOOLEAN default 1 not null, + user_id INTEGER + references user + on update cascade on delete set null, + interval INTEGER default 20 not null, + url TEXT, + type VARCHAR(20), + weight INTEGER default 2000, + hostname VARCHAR(255), + port INTEGER, + created_date DATETIME, + keyword VARCHAR(255) +); + +insert into monitor_dg_tmp(id, name, active, user_id, interval, url, type, weight, hostname, port, created_date, keyword) select id, name, active, user_id, interval, url, type, weight, hostname, port, created_date, keyword from monitor; + +drop table monitor; + +alter table monitor_dg_tmp rename to monitor; + +create index user_id on monitor (user_id); + +COMMIT; + +PRAGMA foreign_keys=on; diff --git a/package-lock.json b/package-lock.json index 5b4f4d4aa..92c91a935 100644 --- a/package-lock.json +++ b/package-lock.json @@ -40,37 +40,43 @@ "integrity": "sha512-bsjleuRKWmGqajMerkzox19aGbscQX5rmmvvXl3wlIp5gMG1HgkiwPxsN5p070fBDKTNSPgojVbuY1+HWMbFhg==" }, "@types/cookie": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.0.tgz", - "integrity": "sha512-y7mImlc/rNkvCRmg8gC3/lj87S7pTUIJ6QGjwHR9WQJcFs+ZMTOaoPrkdFA/YdbuqVEmEbb5RdhVxMkAcgOnpg==" + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==" }, "@types/cors": { - "version": "2.8.10", - "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.10.tgz", - "integrity": "sha512-C7srjHiVG3Ey1nR6d511dtDkCEjxuN9W1HWAEjGq8kpcwmNM6JJkpC0xvabM7BXTG2wDq8Eu33iH9aQKa7IvLQ==" + "version": "2.8.12", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.12.tgz", + "integrity": "sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw==" + }, + "@types/estree": { + "version": "0.0.48", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.48.tgz", + "integrity": "sha512-LfZwXoGUDo0C3me81HXgkBg5CTQYb6xzEl+fNmbO4JdRiSKQ8A0GD1OBBvKAIsbCUgoyAty7m99GqqMQe784ew==", + "dev": true }, "@types/node": { - "version": "15.12.4", - "resolved": "https://registry.npmjs.org/@types/node/-/node-15.12.4.tgz", - "integrity": "sha512-zrNj1+yqYF4WskCMOHwN+w9iuD12+dGm0rQ35HLl9/Ouuq52cEtd0CH9qMgrdNmi5ejC1/V7vKEXYubB+65DkA==" + "version": "16.3.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.3.3.tgz", + "integrity": "sha512-8h7k1YgQKxKXWckzFCMfsIwn0Y61UK6tlD6y2lOb3hTOIMlK3t9/QwHOhc81TwU+RMf0As5fj7NPjroERCnejQ==" }, "@vitejs/plugin-legacy": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-legacy/-/plugin-legacy-1.4.3.tgz", - "integrity": "sha512-lxZUJaMWYMQuqvZM1wPzDP6KABQgA/drVL5fnaygEPcz9adc2OHhfFNN/SvvHQ1V0rP8gybIc7uA+iI1gAdkVQ==", + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-legacy/-/plugin-legacy-1.4.4.tgz", + "integrity": "sha512-pVYeQUDPG5InWwrTu7acy187WWjGonJnL/GMqMLmeKCFiwkZ6UcsoUjojiKmCUI0nAJTrrKH5lhjTqkccY9Iow==", "dev": true, "requires": { "@babel/standalone": "^7.14.7", - "core-js": "^3.15.1", + "core-js": "^3.15.2", "magic-string": "^0.25.7", "regenerator-runtime": "^0.13.7", - "systemjs": "^6.10.1" + "systemjs": "^6.10.2" } }, "@vitejs/plugin-vue": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-1.2.3.tgz", - "integrity": "sha512-LlnLpObkGKZ+b7dcpL4T24l13nPSHLjo+6Oc7MbZiKz5PMAUzADfNJ3EKfYIQ0l0969nxf2jp/9vsfnuJ7h6fw==", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-1.2.5.tgz", + "integrity": "sha512-GIR31mdXTEfvElmBUaRhDc5v7lfdkEdawWQqJRiaRL/5qKsH+xusukglkvJz5y7+c6dEpxgmvcATv2BbB7+fzQ==", "dev": true }, "@vue/compiler-core": { @@ -95,17 +101,18 @@ } }, "@vue/compiler-sfc": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.1.1.tgz", - "integrity": "sha512-lSgMsZaYHF+bAgryq5aUqpvyfhu52GJI2/4LoiJCE5uaxc6FCZfxfgqgw/d9ltiZghv+HiISFtmQVAVvlsk+/w==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.1.5.tgz", + "integrity": "sha512-mtMY6xMvZeSRx9MTa1+NgJWndrkzVTdJ1pQAmAKQuxyb5LsHVvrgP7kcQFvxPHVpLVTORbTJWHaiqoKrJvi1iA==", "dev": true, "requires": { "@babel/parser": "^7.13.9", "@babel/types": "^7.13.0", - "@vue/compiler-core": "3.1.1", - "@vue/compiler-dom": "3.1.1", - "@vue/compiler-ssr": "3.1.1", - "@vue/shared": "3.1.1", + "@types/estree": "^0.0.48", + "@vue/compiler-core": "3.1.5", + "@vue/compiler-dom": "3.1.5", + "@vue/compiler-ssr": "3.1.5", + "@vue/shared": "3.1.5", "consolidate": "^0.16.0", "estree-walker": "^2.0.1", "hash-sum": "^2.0.0", @@ -116,16 +123,78 @@ "postcss-modules": "^4.0.0", "postcss-selector-parser": "^6.0.4", "source-map": "^0.6.1" + }, + "dependencies": { + "@vue/compiler-core": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.1.5.tgz", + "integrity": "sha512-TXBhFinoBaXKDykJzY26UEuQU1K07FOp/0Ie+OXySqqk0bS0ZO7Xvl7UmiTUPYcLrWbxWBR7Bs/y55AI0MNc2Q==", + "dev": true, + "requires": { + "@babel/parser": "^7.12.0", + "@babel/types": "^7.12.0", + "@vue/shared": "3.1.5", + "estree-walker": "^2.0.1", + "source-map": "^0.6.1" + } + }, + "@vue/compiler-dom": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.1.5.tgz", + "integrity": "sha512-ZsL3jqJ52OjGU/YiT/9XiuZAmWClKInZM2aFJh9gnsAPqOrj2JIELMbkIFpVKR/CrVO/f2VxfPiiQdQTr65jcQ==", + "dev": true, + "requires": { + "@vue/compiler-core": "3.1.5", + "@vue/shared": "3.1.5" + } + }, + "@vue/shared": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.1.5.tgz", + "integrity": "sha512-oJ4F3TnvpXaQwZJNF3ZK+kLPHKarDmJjJ6jyzVNDKH9md1dptjC7lWR//jrGuLdek/U6iltWxqAnYOu8gCiOvA==", + "dev": true + } } }, "@vue/compiler-ssr": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.1.1.tgz", - "integrity": "sha512-7H6krZtVt3h/YzfNp7eYK41hMDz8ZskiBy+Wby+EDRINX6BD9JQ5C8zyy2xAa7T6Iz2VrQzsaJ/Bb52lTPSS5A==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.1.5.tgz", + "integrity": "sha512-CU5N7Di/a4lyJ18LGJxJYZS2a8PlLdWpWHX9p/XcsjT2TngMpj3QvHVRkuik2u8QrIDZ8OpYmTyj1WDNsOV+Dg==", "dev": true, "requires": { - "@vue/compiler-dom": "3.1.1", - "@vue/shared": "3.1.1" + "@vue/compiler-dom": "3.1.5", + "@vue/shared": "3.1.5" + }, + "dependencies": { + "@vue/compiler-core": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.1.5.tgz", + "integrity": "sha512-TXBhFinoBaXKDykJzY26UEuQU1K07FOp/0Ie+OXySqqk0bS0ZO7Xvl7UmiTUPYcLrWbxWBR7Bs/y55AI0MNc2Q==", + "dev": true, + "requires": { + "@babel/parser": "^7.12.0", + "@babel/types": "^7.12.0", + "@vue/shared": "3.1.5", + "estree-walker": "^2.0.1", + "source-map": "^0.6.1" + } + }, + "@vue/compiler-dom": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.1.5.tgz", + "integrity": "sha512-ZsL3jqJ52OjGU/YiT/9XiuZAmWClKInZM2aFJh9gnsAPqOrj2JIELMbkIFpVKR/CrVO/f2VxfPiiQdQTr65jcQ==", + "dev": true, + "requires": { + "@vue/compiler-core": "3.1.5", + "@vue/shared": "3.1.5" + } + }, + "@vue/shared": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.1.5.tgz", + "integrity": "sha512-oJ4F3TnvpXaQwZJNF3ZK+kLPHKarDmJjJ6jyzVNDKH9md1dptjC7lWR//jrGuLdek/U6iltWxqAnYOu8gCiOvA==", + "dev": true + } } }, "@vue/devtools-api": { @@ -531,9 +600,9 @@ } }, "bootstrap": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.0.1.tgz", - "integrity": "sha512-Fl79+wsLOZKoiU345KeEaWD0ik8WKRI5zm0YSPj2oF1Qr+BO7z0fco6GbUtqjoG1h4VI89PeKJnMsMMVQdKKTw==" + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.0.2.tgz", + "integrity": "sha512-1Ge963tyEQWJJ+8qtXFU6wgmAVj9gweEjibUdbmcCEYsn38tVwRk8107rk2vzt6cfQcRr3SlZ8aQBqaD8aqf+Q==" }, "brace-expansion": { "version": "1.1.11", @@ -758,9 +827,9 @@ } }, "dayjs": { - "version": "1.10.5", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.10.5.tgz", - "integrity": "sha512-BUFis41ikLz+65iH6LHQCDm4YPMj5r1YFLdupPIyM4SGcXMmtiLQ7U37i+hGS8urIuqe7I/ou3IS1jVc4nbN4g==" + "version": "1.10.6", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.10.6.tgz", + "integrity": "sha512-AztC/IOW4L1Q41A86phW5Thhcrco3xuAA+YX/BLpLWWjRcTj5TOt/QImBLmCKlrF7u7k47arTnOyL6GnbG8Hvw==" }, "debug": { "version": "4.3.1", @@ -903,9 +972,9 @@ } }, "engine.io-client": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-5.1.1.tgz", - "integrity": "sha512-jPFpw2HLL0lhZ2KY0BpZhIJdleQcUO9W1xkIpo0h3d6s+5D6+EV/xgQw9qWOmymszv2WXef/6KUUehyxEKomlQ==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-5.1.2.tgz", + "integrity": "sha512-blRrgXIE0A/eurWXRzvfCLG7uUFJqfTGFsyJzXSK71srMMGJ2VraBLg8Mdw28uUxSpVicepBN9X7asqpD1mZcQ==", "requires": { "base64-arraybuffer": "0.1.4", "component-emitter": "~1.3.0", @@ -927,9 +996,9 @@ } }, "esbuild": { - "version": "0.12.9", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.12.9.tgz", - "integrity": "sha512-MWRhAbMOJ9RJygCrt778rz/qNYgA4ZVj6aXnNPxFjs7PmIpb0fuB9Gmg5uWrr6n++XKwwm/RmSz6RR5JL2Ocsw==", + "version": "0.12.15", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.12.15.tgz", + "integrity": "sha512-72V4JNd2+48eOVCXx49xoSWHgC3/cCy96e7mbXKY+WOWghN00cCmlGnwVLRhRHorvv0dgCyuMYBZlM2xDM5OQw==", "dev": true }, "escape-html": { @@ -2425,9 +2494,9 @@ } }, "nodemailer": { - "version": "6.6.2", - "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.6.2.tgz", - "integrity": "sha512-YSzu7TLbI+bsjCis/TZlAXBoM4y93HhlIgo0P5oiA2ua9Z4k+E2Fod//ybIzdJxOlXGRcHIh/WaeCBehvxZb/Q==" + "version": "6.6.3", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.6.3.tgz", + "integrity": "sha512-faZFufgTMrphYoDjvyVpbpJcYzwyFnbAMmQtj1lVBYAUSm3SOy2fIdd9+Mr4UxPosBa0JRw9bJoIwQn+nswiew==" }, "nopt": { "version": "3.0.6", @@ -2980,9 +3049,9 @@ } }, "rollup": { - "version": "2.52.2", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.52.2.tgz", - "integrity": "sha512-4RlFC3k2BIHlUsJ9mGd8OO+9Lm2eDF5P7+6DNQOp5sx+7N/1tFM01kELfbxlMX3MxT6owvLB1ln4S3QvvQlbUA==", + "version": "2.53.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.53.2.tgz", + "integrity": "sha512-1CtEYuS5CRCzFZ7SNW5528SlDlk4VDXIRGwbm/2POQxA/G4+7/crIqJwkmnj8Q/74hGx4oVlNvh4E1CJQ5hZ6w==", "dev": true, "requires": { "fsevents": "~2.3.2" @@ -3007,9 +3076,9 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "sass": { - "version": "1.35.1", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.35.1.tgz", - "integrity": "sha512-oCisuQJstxMcacOPmxLNiLlj4cUyN2+8xJnG7VanRoh2GOLr9RqkvI4AxA4a6LHVg/rsu+PmxXeGhrdSF9jCiQ==", + "version": "1.35.2", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.35.2.tgz", + "integrity": "sha512-jhO5KAR+AMxCEwIH3v+4zbB2WB0z67V1X0jbapfVwQQdjHZUGUyukpnoM6+iCMfsIUC016w9OPKQ5jrNOS9uXw==", "dev": true, "requires": { "chokidar": ">=3.0.0 <4.0.0" @@ -3230,19 +3299,19 @@ } }, "socket.io": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.1.2.tgz", - "integrity": "sha512-xK0SD1C7hFrh9+bYoYCdVt+ncixkSLKtNLCax5aEy1o3r5PaO5yQhVb97exIe67cE7lAK+EpyMytXWTWmyZY8w==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.1.3.tgz", + "integrity": "sha512-tLkaY13RcO4nIRh1K2hT5iuotfTaIQw7cVIe0FUykN3SuQi0cm7ALxuyT5/CtDswOMWUzMGTibxYNx/gU7In+Q==", "requires": { "@types/cookie": "^0.4.0", - "@types/cors": "^2.8.8", + "@types/cors": "^2.8.10", "@types/node": ">=10.0.0", "accepts": "~1.3.4", "base64id": "~2.0.0", "debug": "~4.3.1", - "engine.io": "~5.1.0", - "socket.io-adapter": "~2.3.0", - "socket.io-parser": "~4.0.3" + "engine.io": "~5.1.1", + "socket.io-adapter": "~2.3.1", + "socket.io-parser": "~4.0.4" } }, "socket.io-adapter": { @@ -3251,15 +3320,15 @@ "integrity": "sha512-8cVkRxI8Nt2wadkY6u60Y4rpW3ejA1rxgcK2JuyIhmF+RMNpTy1QRtkHIDUOf3B4HlQwakMsWbKftMv/71VMmw==" }, "socket.io-client": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.1.2.tgz", - "integrity": "sha512-RDpWJP4DQT1XeexmeDyDkm0vrFc0+bUsHDKiVGaNISJvJonhQQOMqV9Vwfg0ZpPJ27LCdan7iqTI92FRSOkFWQ==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.1.3.tgz", + "integrity": "sha512-hISFn6PDpgDifVUiNklLHVPTMv1LAk8poHArfIUdXa+gKgbr0MZbAlquDFqCqsF30yBqa+jg42wgos2FK50BHA==", "requires": { "@types/component-emitter": "^1.2.10", "backo2": "~1.0.2", "component-emitter": "~1.3.0", "debug": "~4.3.1", - "engine.io-client": "~5.1.1", + "engine.io-client": "~5.1.2", "parseuri": "0.0.6", "socket.io-parser": "~4.0.4" } @@ -3654,14 +3723,14 @@ } }, "vite": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/vite/-/vite-2.3.8.tgz", - "integrity": "sha512-QiEx+iqNnJntSgSF2fWRQvRey9pORIrtNJzNyBJXwc+BdzWs83FQolX84cTBo393cfhObrtWa6180dAa4NLDiQ==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/vite/-/vite-2.4.2.tgz", + "integrity": "sha512-2MifxD2I9fjyDmmEzbULOo3kOUoqX90A58cT6mECxoVQlMYFuijZsPQBuA14mqSwvV3ydUsqnq+BRWXyO9Qa+w==", "dev": true, "requires": { "esbuild": "^0.12.8", "fsevents": "~2.3.2", - "postcss": "^8.3.4", + "postcss": "^8.3.5", "resolve": "^1.20.0", "rollup": "^2.38.5" } diff --git a/package.json b/package.json index cad491dc7..d4fe68885 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "uptime-kuma", - "version": "1.0.5", + "version": "1.0.6", "license": "MIT", "repository": { "type": "git", @@ -12,10 +12,10 @@ "update": "", "build": "vite build", "vite-preview-dist": "vite preview --host", - "build-docker": "docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma -t louislam/uptime-kuma:1 -t louislam/uptime-kuma:1.0.5 --target release . --push", + "build-docker": "docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma -t louislam/uptime-kuma:1 -t louislam/uptime-kuma:1.0.6 --target release . --push", "build-docker-nightly": "docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t louislam/uptime-kuma:nightly --target nightly . --push", "build-docker-nightly-amd64": "docker buildx build --platform linux/amd64 -t louislam/uptime-kuma:nightly-amd64 --target nightly . --push", - "setup": "git checkout 1.0.5 && npm install && npm run build", + "setup": "git checkout 1.0.6 && npm install && npm run build", "version-global-replace": "node extra/version-global-replace.js", "mark-as-nightly": "node extra/mark-as-nightly.js" }, diff --git a/server/database.js b/server/database.js new file mode 100644 index 000000000..49659e613 --- /dev/null +++ b/server/database.js @@ -0,0 +1,119 @@ +const fs = require("fs"); +const {sleep} = require("./util"); +const {R} = require("redbean-node"); +const {setSetting, setting} = require("./util-server"); + + +class Database { + + static templatePath = "./db/kuma.db" + static path = './data/kuma.db'; + static latestVersion = 1; + static noReject = true; + + static async patch() { + let version = parseInt(await setting("database_version")); + + if (! version) { + version = 0; + } + + console.info("Your database version: " + version); + console.info("Latest database version: " + this.latestVersion); + + if (version === this.latestVersion) { + console.info("Database no need to patch"); + } else { + console.info("Database patch is needed") + + console.info("Backup the db") + const backupPath = "./data/kuma.db.bak" + version; + fs.copyFileSync(Database.path, backupPath); + + // Try catch anything here, if gone wrong, restore the backup + try { + for (let i = version + 1; i <= this.latestVersion; i++) { + const sqlFile = `./db/patch${i}.sql`; + console.info(`Patching ${sqlFile}`); + await Database.importSQLFile(sqlFile); + console.info(`Patched ${sqlFile}`); + await setSetting("database_version", i); + } + console.log("Database Patched Successfully"); + } catch (ex) { + await Database.close(); + console.error("Patch db failed!!! Restoring the backup") + fs.copyFileSync(backupPath, Database.path); + console.error(ex) + + console.error("Start Uptime-Kuma failed due to patch db failed") + console.error("Please submit the bug report if you still encounter the problem after restart: https://github.com/louislam/uptime-kuma/issues") + process.exit(1); + } + } + } + + /** + * Sadly, multi sql statements is not supported by many sqlite libraries, I have to implement it myself + * @param filename + * @returns {Promise} + */ + static async importSQLFile(filename) { + + await R.getCell("SELECT 1"); + + let text = fs.readFileSync(filename).toString(); + + // Remove all comments (--) + let lines = text.split("\n"); + lines = lines.filter((line) => { + return ! line.startsWith("--") + }); + + // Split statements by semicolon + // Filter out empty line + text = lines.join("\n") + + let statements = text.split(";") + .map((statement) => { + return statement.trim(); + }) + .filter((statement) => { + return statement !== ""; + }) + + for (let statement of statements) { + await R.exec(statement); + } + } + + /** + * Special handle, because tarn.js throw a promise reject that cannot be caught + * @returns {Promise} + */ + static async close() { + const listener = (reason, p) => { + Database.noReject = false; + }; + process.addListener('unhandledRejection', listener); + + console.log("Closing DB") + + while (true) { + Database.noReject = true; + await R.close() + await sleep(2000) + + if (Database.noReject) { + break; + } else { + console.log("Waiting to close the db") + } + } + console.log("SQLite closed") + + process.removeListener('unhandledRejection', listener); + } +} + +module.exports = Database; diff --git a/server/model/monitor.js b/server/model/monitor.js index 162772875..f81f6e00e 100644 --- a/server/model/monitor.js +++ b/server/model/monitor.js @@ -48,8 +48,6 @@ class Monitor extends BeanModel { let previousBeat = null; const beat = async () => { - console.log(`Monitor ${this.id}: Heartbeat`) - if (! previousBeat) { previousBeat = await R.findOne("heartbeat", " monitor_id = ? ORDER BY time DESC", [ this.id @@ -145,6 +143,12 @@ class Monitor extends BeanModel { bean.important = false; } + if (bean.status === 1) { + console.info(`Monitor #${this.id} '${this.name}': Successful Response: ${bean.ping} ms | Interval: ${this.interval} seconds | Type: ${this.type}`) + } else { + console.warn(`Monitor #${this.id} '${this.name}': Failing: ${bean.msg} | Type: ${this.type}`) + } + io.to(this.user_id).emit("heartbeat", bean.toJSON()); await R.store(bean) diff --git a/server/server.js b/server/server.js index bd5894775..342397cfc 100644 --- a/server/server.js +++ b/server/server.js @@ -12,6 +12,7 @@ const fs = require("fs"); const {getSettings} = require("./util-server"); const {Notification} = require("./notification") const gracefulShutdown = require('http-graceful-shutdown'); +const Database = require("./database"); const {sleep} = require("./util"); const args = require('args-parser')(process.argv); @@ -27,9 +28,28 @@ const server = http.createServer(app); const io = new Server(server); app.use(express.json()) +/** + * Total WebSocket client connected to server currently, no actual use + * @type {number} + */ let totalClient = 0; + +/** + * Use for decode the auth object + * @type {null} + */ let jwtSecret = null; + +/** + * Main monitor list + * @type {{}} + */ let monitorList = {}; + +/** + * Show Setup Page + * @type {boolean} + */ let needSetup = false; (async () => { @@ -50,7 +70,6 @@ let needSetup = false; version, }) - console.log('a user connected'); totalClient++; if (needSetup) { @@ -59,7 +78,6 @@ let needSetup = false; } socket.on('disconnect', () => { - console.log('user disconnected'); totalClient--; }); @@ -557,19 +575,21 @@ function checkLogin(socket) { } async function initDatabase() { - const path = './data/kuma.db'; - - if (! fs.existsSync(path)) { + if (! fs.existsSync(Database.path)) { console.log("Copying Database") - fs.copyFileSync("./db/kuma.db", path); + fs.copyFileSync(Database.templatePath, Database.path); } console.log("Connecting to Database") R.setup('sqlite', { - filename: path + filename: Database.path }); console.log("Connected") + // Patch the database + await Database.patch() + + // Auto map the model to a bean object R.freeze(true) await R.autoloadModels("./server/model"); @@ -589,6 +609,7 @@ async function initDatabase() { console.log("Load JWT secret from database.") } + // If there is no record in user table, it is a new Uptime Kuma instance, need to setup if ((await R.count("user")) === 0) { console.log("No user, need setup") needSetup = true; @@ -707,11 +728,6 @@ const startGracefulShutdown = async () => { } -let noReject = true; -process.on('unhandledRejection', (reason, p) => { - noReject = false; -}); - async function shutdownFunction(signal) { console.log('Called signal: ' + signal); @@ -720,24 +736,8 @@ async function shutdownFunction(signal) { let monitor = monitorList[id] monitor.stop() } - await sleep(2000) - - console.log("Closing DB") - - // Special handle, because tarn.js throw a promise reject that cannot be caught - while (true) { - noReject = true; - await R.close() - await sleep(2000) - - if (noReject) { - break; - } else { - console.log("Waiting...") - } - } - - console.log("OK") + await sleep(2000); + await Database.close(); } function finalFunction() { diff --git a/server/util-server.js b/server/util-server.js index 6904a65a4..b387f4c7c 100644 --- a/server/util-server.js +++ b/server/util-server.js @@ -45,6 +45,18 @@ exports.setting = async function (key) { ]) } +exports.setSetting = async function (key, value) { + let bean = await R.findOne("setting", " `key` = ? ", [ + key + ]) + if (! bean) { + bean = R.dispense("setting") + bean.key = key; + } + bean.value = value; + await R.store(bean) +} + exports.getSettings = async function (type) { let list = await R.getAll("SELECT * FROM setting WHERE `type` = ? ", [ type diff --git a/src/components/NotificationDialog.vue b/src/components/NotificationDialog.vue index 6477ef766..fa99a19f2 100644 --- a/src/components/NotificationDialog.vue +++ b/src/components/NotificationDialog.vue @@ -55,7 +55,7 @@