mirror of
https://github.com/OneUptime/oneuptime.git
synced 2026-04-06 00:32:12 +02:00
11
.gitignore
vendored
11
.gitignore
vendored
@@ -8,7 +8,7 @@ node_modules
|
||||
*/build/dist/*
|
||||
|
||||
# Build Dist
|
||||
*/dist/*
|
||||
**/dist/*
|
||||
|
||||
.idea
|
||||
# testing
|
||||
@@ -70,3 +70,12 @@ config.env.tmp
|
||||
config.env.temp
|
||||
docker-compose.yml
|
||||
logs.txt
|
||||
|
||||
*/Cert.crt
|
||||
*/Key.key
|
||||
Nginx/default.conf
|
||||
|
||||
Certs/StatusPageCerts/*.crt
|
||||
Certs/StatusPageCerts/*.key
|
||||
|
||||
Backups/*.backup
|
||||
|
||||
14
.vscode/launch.json
vendored
14
.vscode/launch.json
vendored
@@ -97,6 +97,20 @@
|
||||
"restart": true,
|
||||
"autoAttachChildProcesses": true
|
||||
},
|
||||
{
|
||||
"address": "127.0.0.1",
|
||||
"localRoot": "${workspaceFolder}/StatusPage",
|
||||
"name": "Status Page API${cwd}: Debug with Docker",
|
||||
"port": 9764,
|
||||
"remoteRoot": "/usr/src/app",
|
||||
"request": "attach",
|
||||
"skipFiles": [
|
||||
"<node_internals>/**"
|
||||
],
|
||||
"type": "node",
|
||||
"restart": true,
|
||||
"autoAttachChildProcesses": true
|
||||
},
|
||||
{
|
||||
"address": "127.0.0.1",
|
||||
"localRoot": "${workspaceFolder}/ProbeAPI",
|
||||
|
||||
@@ -16,11 +16,6 @@ app.use(ExpressStatic(path.join(__dirname, 'public')));
|
||||
|
||||
app.use(`/${APP_NAME}`, ExpressStatic(path.join(__dirname, 'public')));
|
||||
|
||||
app.use(
|
||||
[`/${APP_NAME}/assets`, `/${APP_NAME}/${APP_NAME}/assets`],
|
||||
ExpressStatic(path.join(__dirname, 'dist'))
|
||||
);
|
||||
|
||||
app.get('/*', (_req: ExpressRequest, res: ExpressResponse) => {
|
||||
res.sendFile(path.join(__dirname, 'public', 'index.html'));
|
||||
});
|
||||
4
Accounts/nodemon.json
Normal file
4
Accounts/nodemon.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"watch": ["webpack.config.js"],
|
||||
"exec": "export DEBUG=express:* && webpack-dev-server --port=3003 --mode=development"
|
||||
}
|
||||
366
Accounts/package-lock.json
generated
366
Accounts/package-lock.json
generated
@@ -102,8 +102,9 @@
|
||||
"pg": "^8.7.3",
|
||||
"redis": "^4.2.0",
|
||||
"socket.io": "^4.4.1",
|
||||
"typeorm": "^0.3.6",
|
||||
"typeorm-extension": "^2.1.0",
|
||||
"stripe": "^10.17.0",
|
||||
"typeorm": "^0.3.10",
|
||||
"typeorm-extension": "^2.2.13",
|
||||
"winston": "^3.6.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -159,7 +160,7 @@
|
||||
"react-router-dom": "^6.3.0",
|
||||
"react-select": "^5.4.0",
|
||||
"react-simple-code-editor": "^0.13.0",
|
||||
"react-spinners": "^0.12.0",
|
||||
"react-spinners": "^0.13.6",
|
||||
"react-toggle": "^4.1.3",
|
||||
"reactstrap": "^9.1.1",
|
||||
"redux": "^4.2.0",
|
||||
@@ -2375,6 +2376,11 @@
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/eslintrc/node_modules/argparse": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
|
||||
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
|
||||
},
|
||||
"node_modules/@eslint/eslintrc/node_modules/globals": {
|
||||
"version": "13.15.0",
|
||||
"resolved": "https://registry.npmjs.org/globals/-/globals-13.15.0.tgz",
|
||||
@@ -5364,6 +5370,11 @@
|
||||
"ms": "2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/compression/node_modules/ms": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
|
||||
},
|
||||
"node_modules/concat-map": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||
@@ -5678,6 +5689,11 @@
|
||||
"ajv": "^8.8.2"
|
||||
}
|
||||
},
|
||||
"node_modules/css-minimizer-webpack-plugin/node_modules/json-schema-traverse": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
|
||||
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="
|
||||
},
|
||||
"node_modules/css-minimizer-webpack-plugin/node_modules/schema-utils": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz",
|
||||
@@ -6529,6 +6545,18 @@
|
||||
"source-map": "~0.6.1"
|
||||
}
|
||||
},
|
||||
"node_modules/escodegen/node_modules/levn": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
|
||||
"integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==",
|
||||
"dependencies": {
|
||||
"prelude-ls": "~1.1.2",
|
||||
"type-check": "~0.3.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/escodegen/node_modules/optionator": {
|
||||
"version": "0.8.3",
|
||||
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz",
|
||||
@@ -7247,6 +7275,11 @@
|
||||
"ms": "2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/express/node_modules/ms": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
|
||||
},
|
||||
"node_modules/express/node_modules/safe-buffer": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||
@@ -9444,6 +9477,17 @@
|
||||
"@types/yargs-parser": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/jest-watch-typeahead/node_modules/ansi-styles": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
|
||||
"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/jest-watch-typeahead/node_modules/emittery": {
|
||||
"version": "0.10.2",
|
||||
"resolved": "https://registry.npmjs.org/emittery/-/emittery-0.10.2.tgz",
|
||||
@@ -9455,6 +9499,33 @@
|
||||
"url": "https://github.com/sindresorhus/emittery?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/jest-watch-typeahead/node_modules/jest-message-util": {
|
||||
"version": "28.1.3",
|
||||
"resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.1.3.tgz",
|
||||
"integrity": "sha512-PFdn9Iewbt575zKPf1286Ht9EPoJmYT7P0kY+RibeYZ2XtOr53pDLEFoTWXbd1h4JiGiWpTBC84fc8xMXQMb7g==",
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.12.13",
|
||||
"@jest/types": "^28.1.3",
|
||||
"@types/stack-utils": "^2.0.0",
|
||||
"chalk": "^4.0.0",
|
||||
"graceful-fs": "^4.2.9",
|
||||
"micromatch": "^4.0.4",
|
||||
"pretty-format": "^28.1.3",
|
||||
"slash": "^3.0.0",
|
||||
"stack-utils": "^2.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/jest-watch-typeahead/node_modules/jest-message-util/node_modules/slash": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
|
||||
"integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/jest-watch-typeahead/node_modules/jest-regex-util": {
|
||||
"version": "28.0.2",
|
||||
"resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-28.0.2.tgz",
|
||||
@@ -9520,6 +9591,25 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/jest-watch-typeahead/node_modules/pretty-format": {
|
||||
"version": "28.1.3",
|
||||
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.3.tgz",
|
||||
"integrity": "sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q==",
|
||||
"dependencies": {
|
||||
"@jest/schemas": "^28.1.3",
|
||||
"ansi-regex": "^5.0.1",
|
||||
"ansi-styles": "^5.0.0",
|
||||
"react-is": "^18.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/jest-watch-typeahead/node_modules/react-is": {
|
||||
"version": "18.2.0",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
|
||||
"integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w=="
|
||||
},
|
||||
"node_modules/jest-watch-typeahead/node_modules/slash": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz",
|
||||
@@ -10748,6 +10838,42 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/pkg-dir/node_modules/locate-path": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
|
||||
"integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
|
||||
"dependencies": {
|
||||
"p-locate": "^4.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/pkg-dir/node_modules/p-limit": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
|
||||
"integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
|
||||
"dependencies": {
|
||||
"p-try": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/pkg-dir/node_modules/p-locate": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
|
||||
"integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
|
||||
"dependencies": {
|
||||
"p-limit": "^2.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/pkg-up": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz",
|
||||
@@ -10770,6 +10896,51 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/pkg-up/node_modules/locate-path": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
|
||||
"integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
|
||||
"dependencies": {
|
||||
"p-locate": "^3.0.0",
|
||||
"path-exists": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/pkg-up/node_modules/p-limit": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
|
||||
"integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
|
||||
"dependencies": {
|
||||
"p-try": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/pkg-up/node_modules/p-locate": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
|
||||
"integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
|
||||
"dependencies": {
|
||||
"p-limit": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/pkg-up/node_modules/path-exists": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
|
||||
"integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==",
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/postcss": {
|
||||
"version": "8.4.14",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz",
|
||||
@@ -11783,6 +11954,14 @@
|
||||
"postcss": "^8.2.15"
|
||||
}
|
||||
},
|
||||
"node_modules/postcss-svgo/node_modules/commander": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
|
||||
"integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==",
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/postcss-svgo/node_modules/css-tree": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz",
|
||||
@@ -12935,6 +13114,14 @@
|
||||
"ms": "2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/serve-index/node_modules/depd": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
|
||||
"integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/serve-index/node_modules/http-errors": {
|
||||
"version": "1.6.3",
|
||||
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz",
|
||||
@@ -13525,6 +13712,17 @@
|
||||
"nth-check": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/svgo/node_modules/css-what": {
|
||||
"version": "3.4.2",
|
||||
"resolved": "https://registry.npmjs.org/css-what/-/css-what-3.4.2.tgz",
|
||||
"integrity": "sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ==",
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/fb55"
|
||||
}
|
||||
},
|
||||
"node_modules/svgo/node_modules/dom-serializer": {
|
||||
"version": "0.2.2",
|
||||
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz",
|
||||
@@ -14650,6 +14848,14 @@
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/webpack/node_modules/estraverse": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
|
||||
"integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
|
||||
"engines": {
|
||||
"node": ">=4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/websocket-driver": {
|
||||
"version": "0.7.4",
|
||||
"resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz",
|
||||
@@ -16626,6 +16832,11 @@
|
||||
"strip-json-comments": "^3.1.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"argparse": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
|
||||
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
|
||||
},
|
||||
"globals": {
|
||||
"version": "13.15.0",
|
||||
"resolved": "https://registry.npmjs.org/globals/-/globals-13.15.0.tgz",
|
||||
@@ -18892,9 +19103,10 @@
|
||||
"pg": "^8.7.3",
|
||||
"redis": "^4.2.0",
|
||||
"socket.io": "^4.4.1",
|
||||
"stripe": "^10.17.0",
|
||||
"ts-jest": "^27.1.4",
|
||||
"typeorm": "^0.3.6",
|
||||
"typeorm-extension": "^2.1.0",
|
||||
"typeorm": "^0.3.10",
|
||||
"typeorm-extension": "^2.2.13",
|
||||
"winston": "^3.6.0"
|
||||
}
|
||||
},
|
||||
@@ -18950,7 +19162,7 @@
|
||||
"react-router-dom": "^6.3.0",
|
||||
"react-select": "^5.4.0",
|
||||
"react-simple-code-editor": "^0.13.0",
|
||||
"react-spinners": "^0.12.0",
|
||||
"react-spinners": "^0.13.6",
|
||||
"react-test-renderer": "^18.2.0",
|
||||
"react-toggle": "^4.1.3",
|
||||
"reactstrap": "^9.1.1",
|
||||
@@ -18994,6 +19206,11 @@
|
||||
"requires": {
|
||||
"ms": "2.0.0"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -19199,6 +19416,11 @@
|
||||
"fast-deep-equal": "^3.1.3"
|
||||
}
|
||||
},
|
||||
"json-schema-traverse": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
|
||||
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="
|
||||
},
|
||||
"schema-utils": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz",
|
||||
@@ -19832,6 +20054,15 @@
|
||||
"source-map": "~0.6.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"levn": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
|
||||
"integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==",
|
||||
"requires": {
|
||||
"prelude-ls": "~1.1.2",
|
||||
"type-check": "~0.3.2"
|
||||
}
|
||||
},
|
||||
"optionator": {
|
||||
"version": "0.8.3",
|
||||
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz",
|
||||
@@ -20366,6 +20597,11 @@
|
||||
"ms": "2.0.0"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
|
||||
},
|
||||
"safe-buffer": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||
@@ -21955,11 +22191,39 @@
|
||||
"@types/yargs-parser": "*"
|
||||
}
|
||||
},
|
||||
"ansi-styles": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
|
||||
"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="
|
||||
},
|
||||
"emittery": {
|
||||
"version": "0.10.2",
|
||||
"resolved": "https://registry.npmjs.org/emittery/-/emittery-0.10.2.tgz",
|
||||
"integrity": "sha512-aITqOwnLanpHLNXZJENbOgjUBeHocD+xsSJmNrjovKBW5HbSpW3d1pEls7GFQPUWXiwG9+0P4GtHfEqC/4M0Iw=="
|
||||
},
|
||||
"jest-message-util": {
|
||||
"version": "28.1.3",
|
||||
"resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.1.3.tgz",
|
||||
"integrity": "sha512-PFdn9Iewbt575zKPf1286Ht9EPoJmYT7P0kY+RibeYZ2XtOr53pDLEFoTWXbd1h4JiGiWpTBC84fc8xMXQMb7g==",
|
||||
"requires": {
|
||||
"@babel/code-frame": "^7.12.13",
|
||||
"@jest/types": "^28.1.3",
|
||||
"@types/stack-utils": "^2.0.0",
|
||||
"chalk": "^4.0.0",
|
||||
"graceful-fs": "^4.2.9",
|
||||
"micromatch": "^4.0.4",
|
||||
"pretty-format": "^28.1.3",
|
||||
"slash": "^3.0.0",
|
||||
"stack-utils": "^2.0.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"slash": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
|
||||
"integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"jest-regex-util": {
|
||||
"version": "28.0.2",
|
||||
"resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-28.0.2.tgz",
|
||||
@@ -22012,6 +22276,22 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"pretty-format": {
|
||||
"version": "28.1.3",
|
||||
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.3.tgz",
|
||||
"integrity": "sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q==",
|
||||
"requires": {
|
||||
"@jest/schemas": "^28.1.3",
|
||||
"ansi-regex": "^5.0.1",
|
||||
"ansi-styles": "^5.0.0",
|
||||
"react-is": "^18.0.0"
|
||||
}
|
||||
},
|
||||
"react-is": {
|
||||
"version": "18.2.0",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
|
||||
"integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w=="
|
||||
},
|
||||
"slash": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz",
|
||||
@@ -22929,6 +23209,30 @@
|
||||
"locate-path": "^5.0.0",
|
||||
"path-exists": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"locate-path": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
|
||||
"integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
|
||||
"requires": {
|
||||
"p-locate": "^4.1.0"
|
||||
}
|
||||
},
|
||||
"p-limit": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
|
||||
"integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
|
||||
"requires": {
|
||||
"p-try": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"p-locate": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
|
||||
"integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
|
||||
"requires": {
|
||||
"p-limit": "^2.2.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -22947,6 +23251,36 @@
|
||||
"requires": {
|
||||
"locate-path": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"locate-path": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
|
||||
"integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
|
||||
"requires": {
|
||||
"p-locate": "^3.0.0",
|
||||
"path-exists": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"p-limit": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
|
||||
"integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
|
||||
"requires": {
|
||||
"p-try": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"p-locate": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
|
||||
"integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
|
||||
"requires": {
|
||||
"p-limit": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"path-exists": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
|
||||
"integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ=="
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -23533,6 +23867,11 @@
|
||||
"svgo": "^2.7.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"commander": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
|
||||
"integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw=="
|
||||
},
|
||||
"css-tree": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz",
|
||||
@@ -24381,6 +24720,11 @@
|
||||
"ms": "2.0.0"
|
||||
}
|
||||
},
|
||||
"depd": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
|
||||
"integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ=="
|
||||
},
|
||||
"http-errors": {
|
||||
"version": "1.6.3",
|
||||
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz",
|
||||
@@ -24833,6 +25177,11 @@
|
||||
"nth-check": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"css-what": {
|
||||
"version": "3.4.2",
|
||||
"resolved": "https://registry.npmjs.org/css-what/-/css-what-3.4.2.tgz",
|
||||
"integrity": "sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ=="
|
||||
},
|
||||
"dom-serializer": {
|
||||
"version": "0.2.2",
|
||||
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz",
|
||||
@@ -25451,6 +25800,11 @@
|
||||
"esrecurse": "^4.3.0",
|
||||
"estraverse": "^4.1.1"
|
||||
}
|
||||
},
|
||||
"estraverse": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
|
||||
"integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw=="
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -18,11 +18,11 @@
|
||||
"typescript": "^4.6.4"
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "webpack-dev-server --port=3003 --mode=development",
|
||||
"dev": "nodemon",
|
||||
"build": "webpack build --mode=production",
|
||||
"test": "",
|
||||
"compile": "tsc",
|
||||
"start": "node --require ts-node/register Index.ts",
|
||||
"start": "node --require ts-node/register Serve.ts",
|
||||
"audit": "npm audit --audit-level=low",
|
||||
"preinstall": "npx npm-force-resolutions || echo 'No package-lock.json file. Skipping force resolutions'",
|
||||
"dep-check": "depcheck ./ --skip-missing=true'"
|
||||
|
||||
@@ -66,6 +66,6 @@
|
||||
To begin the development, run `npm start` or `yarn start`.
|
||||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
<script src="/accounts/accounts/assets/bundle.js"></script>
|
||||
<script src="/accounts/dist/bundle.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -11,11 +11,9 @@ import NotFound from './Pages/NotFound';
|
||||
import SsoLoginPage from './Pages/SsoLogin';
|
||||
import ForgotPasswordPage from './Pages/ForgotPassword';
|
||||
import RegisterPage from './Pages/Register';
|
||||
import { DASHBOARD_URL } from 'CommonUI/src/Config';
|
||||
import 'CommonUI/src/Styles/theme.scss';
|
||||
import Navigation from 'CommonUI/src/Utils/Navigation';
|
||||
import VerifyEmail from './Pages/VerifyEmail';
|
||||
import User from 'CommonUI/src/Utils/User';
|
||||
import ResetPasswordPage from './Pages/ResetPassword';
|
||||
|
||||
function App(): ReactElement {
|
||||
@@ -23,10 +21,6 @@ function App(): ReactElement {
|
||||
Navigation.setLocation(useLocation());
|
||||
Navigation.setParams(useParams());
|
||||
|
||||
if (User.isLoggedIn()) {
|
||||
Navigation.navigate(DASHBOARD_URL);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="App">
|
||||
<Routes>
|
||||
|
||||
@@ -30,7 +30,7 @@ const ForgotPassword: FunctionComponent = () => {
|
||||
>
|
||||
<img
|
||||
style={{ height: '40px' }}
|
||||
src={`/accounts/public/${OneUptimeLogo}`}
|
||||
src={`${OneUptimeLogo}`}
|
||||
/>
|
||||
</div>
|
||||
<div className="text-center">
|
||||
|
||||
@@ -9,10 +9,17 @@ import { LOGIN_API_URL } from '../Utils/ApiPaths';
|
||||
import URL from 'Common/Types/API/URL';
|
||||
import { JSONObject } from 'Common/Types/JSON';
|
||||
import LoginUtil from '../Utils/Login';
|
||||
import UserUtil from 'CommonUI/src/Utils/User';
|
||||
import Navigation from 'CommonUI/src/Utils/Navigation';
|
||||
import { DASHBOARD_URL } from 'CommonUI/src/Config';
|
||||
|
||||
const LoginPage: FunctionComponent = () => {
|
||||
const apiUrl: URL = LOGIN_API_URL;
|
||||
|
||||
if (UserUtil.isLoggedIn()) {
|
||||
Navigation.navigate(DASHBOARD_URL);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="auth-page">
|
||||
<div className="container-fluid p-0">
|
||||
@@ -30,7 +37,7 @@ const LoginPage: FunctionComponent = () => {
|
||||
>
|
||||
<img
|
||||
style={{ height: '40px' }}
|
||||
src={`/accounts/public/${OneUptimeLogo}`}
|
||||
src={`${OneUptimeLogo}`}
|
||||
/>
|
||||
</div>
|
||||
<div className="text-center">
|
||||
|
||||
@@ -7,13 +7,19 @@ import FormFieldSchemaType from 'CommonUI/src/Components/Forms/Types/FormFieldSc
|
||||
import OneUptimeLogo from 'CommonUI/src/Images/logos/OneUptimePNG/7.png';
|
||||
import LoginUtil from '../Utils/Login';
|
||||
import { JSONObject } from 'Common/Types/JSON';
|
||||
|
||||
import UserUtil from 'CommonUI/src/Utils/User';
|
||||
import Navigation from 'CommonUI/src/Utils/Navigation';
|
||||
import { DASHBOARD_URL } from 'CommonUI/src/Config';
|
||||
import URL from 'Common/Types/API/URL';
|
||||
import { SIGNUP_API_URL } from '../Utils/ApiPaths';
|
||||
|
||||
const RegisterPage: FunctionComponent = () => {
|
||||
const apiUrl: URL = SIGNUP_API_URL;
|
||||
|
||||
if (UserUtil.isLoggedIn()) {
|
||||
Navigation.navigate(DASHBOARD_URL);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="auth-page">
|
||||
<div className="container-fluid p-0">
|
||||
@@ -31,7 +37,7 @@ const RegisterPage: FunctionComponent = () => {
|
||||
>
|
||||
<img
|
||||
style={{ height: '40px' }}
|
||||
src={`/accounts/public/${OneUptimeLogo}`}
|
||||
src={`${OneUptimeLogo}`}
|
||||
/>
|
||||
</div>
|
||||
<div className="text-center">
|
||||
|
||||
@@ -31,7 +31,7 @@ const RegisterPage: FunctionComponent = () => {
|
||||
>
|
||||
<img
|
||||
style={{ height: '40px' }}
|
||||
src={`/accounts/public/${OneUptimeLogo}`}
|
||||
src={`${OneUptimeLogo}`}
|
||||
/>
|
||||
</div>
|
||||
<div className="text-center">
|
||||
|
||||
@@ -27,7 +27,7 @@ const SsoLoginPage: FunctionComponent = () => {
|
||||
>
|
||||
<img
|
||||
style={{ height: '40px' }}
|
||||
src={`/accounts/public/${OneUptimeLogo}`}
|
||||
src={`${OneUptimeLogo}`}
|
||||
/>
|
||||
</div>
|
||||
<div className="text-center">
|
||||
|
||||
@@ -75,7 +75,7 @@ const VerifyEmail: FunctionComponent = () => {
|
||||
>
|
||||
<img
|
||||
style={{ height: '40px' }}
|
||||
src={`/accounts/public/${OneUptimeLogo}`}
|
||||
src={`${OneUptimeLogo}`}
|
||||
/>
|
||||
</div>
|
||||
{!error && (
|
||||
|
||||
@@ -1,15 +1,19 @@
|
||||
const path = require("path");
|
||||
const webpack = require("webpack");
|
||||
const dotenv = require('dotenv');
|
||||
const express = require('express');
|
||||
|
||||
const readEnvFile = (pathToFile) => {
|
||||
|
||||
const parsed = dotenv.config({ path: pathToFile }).parsed;
|
||||
|
||||
const env = {};
|
||||
|
||||
for (const key in parsed) {
|
||||
env[key] = JSON.stringify(parsed[key]);
|
||||
}
|
||||
|
||||
|
||||
return env;
|
||||
}
|
||||
|
||||
@@ -18,8 +22,8 @@ module.exports = {
|
||||
mode: "development",
|
||||
output: {
|
||||
filename: "bundle.js",
|
||||
path: path.resolve(__dirname, "dist"),
|
||||
publicPath: "/assets/",
|
||||
path: path.resolve(__dirname, "public", "dist"),
|
||||
publicPath: "/accounts/dist/",
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['.ts', '.tsx', '.js', '.jsx', '.json', '.css', '.scss'],
|
||||
@@ -56,7 +60,7 @@ module.exports = {
|
||||
use: ['style-loader', 'css-loader']
|
||||
},
|
||||
{
|
||||
test: /\.(jpe?g|png|gif|svg)$/i,
|
||||
test: /\.(jpe?g|png|gif|svg)$/i,
|
||||
loader: 'file-loader'
|
||||
}
|
||||
],
|
||||
@@ -66,6 +70,11 @@ module.exports = {
|
||||
devMiddleware: {
|
||||
writeToDisk: true,
|
||||
},
|
||||
allowedHosts: "all",
|
||||
setupMiddlewares: (middlewares, devServer) => {
|
||||
devServer.app.use('/accounts/assets', express.static(path.resolve(__dirname, 'public', 'assets')));
|
||||
return middlewares;
|
||||
}
|
||||
},
|
||||
devtool: 'eval-source-map',
|
||||
}
|
||||
@@ -1 +1 @@
|
||||
ONEUPTIME_SECRET=ae60cf8f0cec2df8d05aaf0b
|
||||
ONEUPTIME_SECRET=fd57b59aa8f3f516d2f6cb06
|
||||
1
Backups/README.md
Normal file
1
Backups/README.md
Normal file
@@ -0,0 +1 @@
|
||||
This is where all the database backups will be stored.
|
||||
3
Certs/Readme.md
Normal file
3
Certs/Readme.md
Normal file
@@ -0,0 +1,3 @@
|
||||
This directory is used for hosting SSL Certs for nginx.
|
||||
|
||||
If you need a new certificate. Please have Cert.pem and Key.pem in this folder.
|
||||
1
Certs/StatusPageCerts/Readme.md
Normal file
1
Certs/StatusPageCerts/Readme.md
Normal file
@@ -0,0 +1 @@
|
||||
Certs for Status page with custom domains.
|
||||
30
Certs/StatusPageCerts/status.genosyn.com.crt
Normal file
30
Certs/StatusPageCerts/status.genosyn.com.crt
Normal file
@@ -0,0 +1,30 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFKTCCBBGgAwIBAgISBI+ZMOTLreLlsVt7PF9qX1u2MA0GCSqGSIb3DQEBCwUA
|
||||
MDIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQD
|
||||
EwJSMzAeFw0yMjEyMTAxMjA2MTJaFw0yMzAzMTAxMjA2MTFaMB0xGzAZBgNVBAMT
|
||||
EnN0YXR1cy5nZW5vc3luLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
|
||||
ggEBAMgb7+Qhe/f9YCIATTMF7kVGO4Zwd2nJ167vEczBOsHkNspiVD9UPdL0KpFV
|
||||
L37sqiclcVbUds5QO0h81ckBMNwsRiqSeEj5V5FcRII1PdduROBB7mVfgtuwG2jQ
|
||||
NtU2IEDAIuxQVTOep3ciZBK4iiwgYttOKbvw5EtjlYKMk2+ZJy2eUjvEstNGkm5b
|
||||
iekNEvt5ZTInYfWoyCaD9gsjMEaB/ueL21M7jbgJ049n64CYv2robhU9JEQW5p8h
|
||||
B849YvO+nzhGdCuWRU4FPXzI4aDPs6ONceodg0IIeEbEZMntc1AKXyL7TJp3+kLI
|
||||
eBpmtwXqQvNuCeqV7QXMK7X7QEsCAwEAAaOCAkwwggJIMA4GA1UdDwEB/wQEAwIF
|
||||
oDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADAd
|
||||
BgNVHQ4EFgQUvnstsk3lPsOYn1nKiQGwdeXVGscwHwYDVR0jBBgwFoAUFC6zF7dY
|
||||
VsuuUAlA5h+vnYsUwsYwVQYIKwYBBQUHAQEESTBHMCEGCCsGAQUFBzABhhVodHRw
|
||||
Oi8vcjMuby5sZW5jci5vcmcwIgYIKwYBBQUHMAKGFmh0dHA6Ly9yMy5pLmxlbmNy
|
||||
Lm9yZy8wHQYDVR0RBBYwFIISc3RhdHVzLmdlbm9zeW4uY29tMEwGA1UdIARFMEMw
|
||||
CAYGZ4EMAQIBMDcGCysGAQQBgt8TAQEBMCgwJgYIKwYBBQUHAgEWGmh0dHA6Ly9j
|
||||
cHMubGV0c2VuY3J5cHQub3JnMIIBAwYKKwYBBAHWeQIEAgSB9ASB8QDvAHYAtz77
|
||||
JN+cTbp18jnFulj0bF38Qs96nzXEnh0JgSXttJkAAAGE/CSqhwAABAMARzBFAiAm
|
||||
PBXbjWWdkehEstdTQ5LoAS1omXJQNnuo1nt2YsoL3gIhAJSewh6nfHL+lXhckXtk
|
||||
pSkI2qNdq2otCyq3Z9W/Z4YpAHUArfe++nz/EMiLnT2cHj4YarRnKV3PsQwkyoWG
|
||||
NOvcgooAAAGE/CSqvQAABAMARjBEAiAwAB2istEPxzNrMuw04guD5NyOt/RKDX5l
|
||||
0y71+H9ekQIgaBg24zPbRNw01G5Y7WUsS9/vBgAEpEtfqpMcedNVwXAwDQYJKoZI
|
||||
hvcNAQELBQADggEBALU11dZ+HIWxGUz0Q4IqVLfN9dP4cTVdee5GOX8KNh2rmIBv
|
||||
7YZtuGJVVbILW+D5w/r+3l3z3MFg1ocEHUtfDCtmZes4WyBHXntaJe9JuqY6/ArN
|
||||
VUIR1r0S6iKmZ17S0/FjruyHOyOw5Zhxix1Q5dMCpuCIfOtOaG8cAf8Qi1re3br9
|
||||
6dwDpgW5mUQBLA9DGnnXYKvkd/EcEUnf39o2UaDCfFSeQgSu46/98GcOQQ0SpN6c
|
||||
OqEJ4Dnc6NP/Trmb1nDQbIMx4c5y/q7miDb8URdK3H+EGdmmBie7M46se3i11oGC
|
||||
u7agSvvW32dShImvoC8pJFAS0cEaAPdODHgg5U0=
|
||||
-----END CERTIFICATE-----
|
||||
27
Certs/StatusPageCerts/status.genosyn.com.key
Normal file
27
Certs/StatusPageCerts/status.genosyn.com.key
Normal file
@@ -0,0 +1,27 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpQIBAAKCAQEAyBvv5CF79/1gIgBNMwXuRUY7hnB3acnXru8RzME6weQ2ymJU
|
||||
P1Q90vQqkVUvfuyqJyVxVtR2zlA7SHzVyQEw3CxGKpJ4SPlXkVxEgjU9125E4EHu
|
||||
ZV+C27AbaNA21TYgQMAi7FBVM56ndyJkEriKLCBi204pu/DkS2OVgoyTb5knLZ5S
|
||||
O8Sy00aSbluJ6Q0S+3llMidh9ajIJoP2CyMwRoH+54vbUzuNuAnTj2frgJi/auhu
|
||||
FT0kRBbmnyEHzj1i876fOEZ0K5ZFTgU9fMjhoM+zo41x6h2DQgh4RsRkye1zUApf
|
||||
IvtMmnf6Qsh4Gma3BepC824J6pXtBcwrtftASwIDAQABAoIBABmBohq4f+Y0uCet
|
||||
VSm/REc1NAonVLk5vpGwLFsmeBhVv/wc+3MVCEpW0AQ1UPgDL48M0T0JmNkkVeIf
|
||||
81oLGlC+HfV4NPfMPHKtSZg1NBw9FG9nR/1I5tOcx2mdPJgBravDMdBgTvPk8aCY
|
||||
VBwkxIvqVt9wP5aSlm7bkyeQRoyvRYP+cWnLo1sR6sIEO4SyjtoFzKtp/CrP8MBs
|
||||
67mVyLPurEqCB0wVDCAr/G2SkJhCUXGvqSzfDU0oGEVGWmb95PQGsOe1KjqegY7A
|
||||
BTFKMNjbOyncYau4EkZcPAKpv/9Qgo+52bYDKekSxk/ZHitE0TmW4WlC73UMkIQK
|
||||
yG+Si+kCgYEA8R7+roCHqaxT30bNlJe+FCkVQuXsBJp3TAPUxBSnZZCp0mifEhQc
|
||||
WGvvG9AOSVmoCPDMGw1xUo+zsUNkxmi+FcLUeAM5hdiV68D1QfjhUlrPidEv74l9
|
||||
0WlW3+z1tJVbN2WYdXD1JHg5nyq/hEMg4Q/FLEAMj6daIK1PFc+INuMCgYEA1HUS
|
||||
6q89LzFMSGrGxksxQIoT4cgg1pUA3QLWijEnnT2YDk3Z5iB7F+a1jYQFH1SXBYMx
|
||||
pIwiHM+qXsumcg0upLPj+ulqGKMt0qPkJTb4w1rGr73BKygDdmFbym3jQxbAqpIY
|
||||
gW1ZvuOBgR8hstBc0gLUOsgl5TeSel1h/swzpXkCgYEA4ZsmoRAR32gmcdtFr6rr
|
||||
ZuGpyxZmZ0hAJxfOlEje9+ELhJvvenLmsrUK3PMm6urAltz3nLhPN/jNISb1u891
|
||||
S9coBcK+p8WnQRciY8AC05O0bDcWqwHyf2YYqxyEKZs15fdhV0GBncX/5DWTTKWi
|
||||
tfKTgnvLRP5JDhoazUWJJhECgYEAwJaf3z2bKPx3Oe4Q4g+nRenku/a+TcYkUjQQ
|
||||
ZpTIZDFBdTX9IC6xZqksSmwyeIQlokma5p5hDdzxg5z39MseTQ8Eyp5sHolNMHSA
|
||||
i3uZZP0Uvpo0UPqkqNr4ajfSmy402Go27JxDjlaNPo8J7R4UBguqdt6X+4C0t1eP
|
||||
TXmuF4ECgYEAzK8INorcqp4a+rHrtIrBqS6I6q/NtBydZ6QC03qOL/6/6ITdf894
|
||||
6+S5cksZZqr8HC86f/FOxjGvtLFuuuWoHLTgEra2Blm9lAwrSXIRIgbTDI19rQGq
|
||||
WaNnUaRke0jQMkNXndToTlU2j7OBI1vGMA5UwrXAD8LWAMrkgzPeKUc=
|
||||
-----END RSA PRIVATE KEY-----
|
||||
@@ -6,7 +6,7 @@ e2e_docker_compose_enterprise_test:
|
||||
# Install Docker Compose.
|
||||
- sudo curl -L "https://github.com/docker/compose/releases/download/1.25.4/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
|
||||
- sudo chmod +x /usr/local/bin/docker-compose
|
||||
- sudo docker-compose down -v
|
||||
- sudo docker compose down -v
|
||||
# Install the cluster.
|
||||
- chmod +x ./env-setup.sh
|
||||
- ./env-setup.sh
|
||||
|
||||
@@ -7,7 +7,7 @@ e2e_docker_compose_test:
|
||||
# Install Docker Compose.
|
||||
- sudo curl -L "https://github.com/docker/compose/releases/download/1.25.4/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
|
||||
- sudo chmod +x /usr/local/bin/docker-compose
|
||||
- sudo docker-compose down -v
|
||||
- sudo docker compose down -v
|
||||
- export BILLING_ENABLED=true
|
||||
# Install the cluster.
|
||||
- chmod +x ./env-setup.sh
|
||||
|
||||
@@ -4,6 +4,7 @@ enum Protocol {
|
||||
MONGO_DB = 'mongodb://',
|
||||
WS = 'ws://',
|
||||
WSS = 'wss://',
|
||||
MAIL = 'mailto:',
|
||||
}
|
||||
|
||||
export default Protocol;
|
||||
|
||||
@@ -5,6 +5,7 @@ import DatabaseProperty from '../Database/DatabaseProperty';
|
||||
import { FindOperator } from 'typeorm';
|
||||
import Dictionary from '../Dictionary';
|
||||
import Typeof from '../Typeof';
|
||||
import Email from '../Email';
|
||||
|
||||
export default class URL extends DatabaseProperty {
|
||||
private _route: Route = new Route();
|
||||
@@ -23,6 +24,14 @@ export default class URL extends DatabaseProperty {
|
||||
this._params = v;
|
||||
}
|
||||
|
||||
private _email!: Email;
|
||||
public get email(): Email {
|
||||
return this._email;
|
||||
}
|
||||
public set email(v: Email) {
|
||||
this._email = v;
|
||||
}
|
||||
|
||||
private _hostname!: Hostname;
|
||||
public get hostname(): Hostname {
|
||||
return this._hostname;
|
||||
@@ -41,12 +50,20 @@ export default class URL extends DatabaseProperty {
|
||||
|
||||
public constructor(
|
||||
protocol: Protocol,
|
||||
hostname: Hostname | string,
|
||||
hostname: Hostname | string | Email,
|
||||
route?: Route,
|
||||
queryString?: string
|
||||
) {
|
||||
super();
|
||||
if (hostname instanceof Hostname) {
|
||||
|
||||
if (
|
||||
typeof hostname === Typeof.String &&
|
||||
Email.isValid(hostname as string)
|
||||
) {
|
||||
this.email = new Email(hostname as string);
|
||||
} else if (hostname instanceof Email) {
|
||||
this.email = hostname;
|
||||
} else if (hostname instanceof Hostname) {
|
||||
this.hostname = hostname;
|
||||
} else if (typeof hostname === Typeof.String) {
|
||||
this.hostname = Hostname.fromString(hostname);
|
||||
@@ -77,21 +94,25 @@ export default class URL extends DatabaseProperty {
|
||||
}
|
||||
|
||||
public override toString(): string {
|
||||
let urlString: string = `${this.protocol}${this.hostname}`;
|
||||
if (this.route.toString().startsWith('/')) {
|
||||
urlString += this.route.toString();
|
||||
} else {
|
||||
urlString += '/' + this.route.toString();
|
||||
}
|
||||
|
||||
if (Object.keys(this.params).length > 0) {
|
||||
urlString += '?';
|
||||
|
||||
for (const key of Object.keys(this.params)) {
|
||||
urlString += key + '=' + this.params[key] + '&';
|
||||
let urlString: string = `${this.protocol}${
|
||||
this.hostname || this.email
|
||||
}`;
|
||||
if (!this.email) {
|
||||
if (this.route && this.route.toString().startsWith('/')) {
|
||||
urlString += this.route.toString();
|
||||
} else {
|
||||
urlString += '/' + this.route.toString();
|
||||
}
|
||||
|
||||
urlString = urlString.substring(0, urlString.length - 1); // remove last &
|
||||
if (Object.keys(this.params).length > 0) {
|
||||
urlString += '?';
|
||||
|
||||
for (const key of Object.keys(this.params)) {
|
||||
urlString += key + '=' + this.params[key] + '&';
|
||||
}
|
||||
|
||||
urlString = urlString.substring(0, urlString.length - 1); // remove last &
|
||||
}
|
||||
}
|
||||
|
||||
return urlString;
|
||||
@@ -129,6 +150,11 @@ export default class URL extends DatabaseProperty {
|
||||
url = url.replace('mongodb://', '');
|
||||
}
|
||||
|
||||
if (url.startsWith('mailto:')) {
|
||||
protocol = Protocol.MAIL;
|
||||
url = url.replace('mailto:', '');
|
||||
}
|
||||
|
||||
const hostname: Hostname = new Hostname(url.split('/')[0] || '');
|
||||
|
||||
let route: Route | undefined;
|
||||
|
||||
@@ -31,6 +31,7 @@ enum ColumnType {
|
||||
BigNumber = 'bigint',
|
||||
Markdown = 'text',
|
||||
File = 'bytea',
|
||||
JSON = 'jsonb',
|
||||
}
|
||||
|
||||
export default ColumnType;
|
||||
|
||||
@@ -32,6 +32,7 @@ enum ColumnType {
|
||||
BigNumber,
|
||||
Entity,
|
||||
EntityArray,
|
||||
JSON,
|
||||
}
|
||||
|
||||
export default ColumnType;
|
||||
|
||||
@@ -4,6 +4,7 @@ enum EmailTemplateType {
|
||||
EmailVerified = 'EmailVerified.hbs',
|
||||
PasswordChanged = 'PasswordChanged.hbs',
|
||||
InviteMember = 'InviteMember.hbs',
|
||||
EmailChanged = 'EmailChanged.hbs',
|
||||
}
|
||||
|
||||
export default EmailTemplateType;
|
||||
|
||||
@@ -9,6 +9,7 @@ enum ExceptionCode {
|
||||
NotAuthorizedException = 403,
|
||||
NotAuthenticatedxception = 401,
|
||||
PaymentRequiredException = 402,
|
||||
NotFoundException = 404,
|
||||
}
|
||||
|
||||
export default ExceptionCode;
|
||||
|
||||
8
Common/Types/Exception/NotFoundException.ts
Normal file
8
Common/Types/Exception/NotFoundException.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import Exception from './Exception';
|
||||
import ExceptionCode from './ExceptionCode';
|
||||
|
||||
export default class NotFoundException extends Exception {
|
||||
public constructor(message: string) {
|
||||
super(ExceptionCode.NotFoundException, message);
|
||||
}
|
||||
}
|
||||
@@ -227,6 +227,13 @@ export class PermissionHelper {
|
||||
permissions1: Array<Permission>,
|
||||
permissions2: Array<Permission>
|
||||
): boolean {
|
||||
if (!permissions1) {
|
||||
permissions1 = [];
|
||||
}
|
||||
|
||||
if (!permissions2) {
|
||||
permissions2 = [];
|
||||
}
|
||||
return (
|
||||
permissions1.filter((value: Permission) => {
|
||||
return permissions2.includes(value);
|
||||
|
||||
@@ -21,6 +21,7 @@ PROBE_API_HOSTNAME={{ .Env.DATA_INGESTOR_HOSTNAME }}
|
||||
DATA_INGESTOR_HOSTNAME={{ .Env.DATA_INGESTOR_HOSTNAME }}
|
||||
ACCOUNTS_HOSTNAME={{ .Env.ACCOUNTS_HOSTNAME }}
|
||||
HOME_HOSTNAME={{ .Env.HOME_HOSTNAME }}
|
||||
WORKER_HOSTNAME={{ .Env.WORKER_HOSTNAME }}
|
||||
|
||||
BILLING_PRIVATE_KEY={{ .Env.BILLING_PRIVATE_KEY }}
|
||||
BILLING_PUBLIC_KEY={{ .Env.BILLING_PUBLIC_KEY }}
|
||||
@@ -41,4 +42,6 @@ HELMCHARTS_ROUTE={{ .Env.HELMCHARTS_ROUTE }}
|
||||
APIDOCS_ROUTE={{ .Env.APIDOCS_ROUTE }}
|
||||
IDENTITY_ROUTE={{ .Env.IDENTITY_ROUTE }}
|
||||
FILE_ROUTE={{ .Env.FILE_ROUTE }}
|
||||
STATUS_PAGE_ROUTE={{ .Env.STATUS_PAGE_ROUTE }}
|
||||
STATUS_PAGE_ROUTE={{ .Env.STATUS_PAGE_ROUTE }}
|
||||
|
||||
IS_SERVER=true
|
||||
@@ -14,21 +14,24 @@ export const BillingPrivateKey: string =
|
||||
process.env['BILLING_PRIVATE_KEY'] || '';
|
||||
|
||||
export const DatabaseHost: Hostname = Hostname.fromString(
|
||||
process.env['DATABASE_HOST'] || ''
|
||||
process.env['DATABASE_HOST'] || 'postgres'
|
||||
);
|
||||
|
||||
export const DatabasePort: Port = new Port(process.env['DATABASE_PORT'] || '');
|
||||
export const DatabasePort: Port = new Port(
|
||||
process.env['DATABASE_PORT'] || '5432'
|
||||
);
|
||||
|
||||
export const DatabaseUsername: string =
|
||||
process.env['DATABASE_USERNAME'] || 'oneuptimedbuser';
|
||||
|
||||
export const DatabasePassword: string = process.env['DATABASE_PASSWORD'] || '';
|
||||
export const DatabasePassword: string =
|
||||
process.env['DATABASE_PASSWORD'] || 'password';
|
||||
|
||||
export const DatabaseName: string =
|
||||
process.env['DATABASE_NAME'] || 'oneuptimedb';
|
||||
|
||||
export const EncryptionSecret: ObjectID = new ObjectID(
|
||||
process.env['ENCRYPTION_SECRET'] || ''
|
||||
process.env['ENCRYPTION_SECRET'] || 'secret'
|
||||
);
|
||||
|
||||
export const AirtableApiKey: string = process.env['AIRTABLE_API_KEY'] || '';
|
||||
@@ -36,93 +39,100 @@ export const AirtableApiKey: string = process.env['AIRTABLE_API_KEY'] || '';
|
||||
export const AirtableBaseId: string = process.env['AIRTABLE_BASE_ID'] || '';
|
||||
|
||||
export const ClusterKey: ObjectID = new ObjectID(
|
||||
process.env['ONEUPTIME_SECRET'] || ''
|
||||
process.env['ONEUPTIME_SECRET'] || 'secret'
|
||||
);
|
||||
|
||||
export const Domain: Hostname = Hostname.fromString(
|
||||
process.env['DOMAIN'] || ''
|
||||
process.env['DOMAIN'] || 'localhost'
|
||||
);
|
||||
|
||||
export const RealtimeHostname: Hostname = Hostname.fromString(
|
||||
process.env['REALTIME_HOSTNAME'] || ''
|
||||
process.env['REALTIME_HOSTNAME'] || 'realtime'
|
||||
);
|
||||
|
||||
export const MailHostname: Hostname = Hostname.fromString(
|
||||
process.env['MAIL_HOSTNAME'] || ''
|
||||
process.env['MAIL_HOSTNAME'] || 'mail'
|
||||
);
|
||||
|
||||
export const WorkerHostname: Hostname = Hostname.fromString(
|
||||
process.env['WORKER_HOSTNAME'] || 'mail'
|
||||
);
|
||||
|
||||
export const DashboardApiHostname: Hostname = Hostname.fromString(
|
||||
process.env['DASHBOARD_API_HOSTNAME'] || ''
|
||||
process.env['DASHBOARD_API_HOSTNAME'] || 'dashboard-api'
|
||||
);
|
||||
|
||||
export const ProbeApiHostname: Hostname = Hostname.fromString(
|
||||
process.env['PROBE_API_HOSTNAME'] || ''
|
||||
process.env['PROBE_API_HOSTNAME'] || 'probe-api'
|
||||
);
|
||||
|
||||
export const DataIngestorHostname: Hostname = Hostname.fromString(
|
||||
process.env['DATA_INGESTOR_HOSTNAME'] || ''
|
||||
process.env['DATA_INGESTOR_HOSTNAME'] || 'daat-ingestor'
|
||||
);
|
||||
|
||||
export const AccountsHostname: Hostname = Hostname.fromString(
|
||||
process.env['ACCOUNTS_HOSTNAME'] || ''
|
||||
process.env['ACCOUNTS_HOSTNAME'] || 'accounts'
|
||||
);
|
||||
|
||||
export const HomeHostname: Hostname = Hostname.fromString(
|
||||
process.env['HOME_HOSTNAME'] || ''
|
||||
process.env['HOME_HOSTNAME'] || 'home'
|
||||
);
|
||||
|
||||
export const DashboardHostname: Hostname = Hostname.fromString(
|
||||
process.env['DASHBOARD_HOSTNAME'] || ''
|
||||
process.env['DASHBOARD_HOSTNAME'] || 'dashboard'
|
||||
);
|
||||
|
||||
export const Env: string = process.env['NODE_ENV'] || '';
|
||||
export const Env: string = process.env['NODE_ENV'] || 'production';
|
||||
|
||||
export const Version: string = process.env['npm_package_version'] || '';
|
||||
export const Version: string = process.env['npm_package_version'] || '1.0.0';
|
||||
|
||||
export const HttpProtocol: Protocol = (
|
||||
process.env['HTTP_PROTOCOL'] || ''
|
||||
process.env['HTTP_PROTOCOL'] || 'https'
|
||||
).includes('https')
|
||||
? Protocol.HTTPS
|
||||
: Protocol.HTTP;
|
||||
|
||||
// Redis does not require password.
|
||||
export const RedisHostname: string = process.env['REDIS_HOST'] || '';
|
||||
export const RedisPassword: string = process.env['REDIS_PASSWORD'] || '';
|
||||
export const RedisPort: Port = new Port(process.env['REDIS_PORT'] || '');
|
||||
export const RedisHostname: string = process.env['REDIS_HOST'] || 'redis';
|
||||
export const RedisPassword: string =
|
||||
process.env['REDIS_PASSWORD'] || 'password';
|
||||
export const RedisPort: Port = new Port(process.env['REDIS_PORT'] || '6379');
|
||||
|
||||
export const DashboardApiRoute: Route = new Route(
|
||||
process.env['DASHBOARD_API_ROUTE'] || ''
|
||||
process.env['DASHBOARD_API_ROUTE'] || '/dashboard-api'
|
||||
);
|
||||
|
||||
export const IdentityRoute: Route = new Route(
|
||||
process.env['IDENTITY_ROUTE'] || ''
|
||||
process.env['IDENTITY_ROUTE'] || '/identity'
|
||||
);
|
||||
|
||||
export const FileRoute: Route = new Route(process.env['FILE_ROUTE'] || '');
|
||||
export const FileRoute: Route = new Route(process.env['FILE_ROUTE'] || '/file');
|
||||
|
||||
export const StausPageRoute: Route = new Route(
|
||||
process.env['STATUS_PAGE_ROUTE'] || ''
|
||||
process.env['STATUS_PAGE_ROUTE'] || '/status-page'
|
||||
);
|
||||
|
||||
export const DashboardRoute: Route = new Route(
|
||||
process.env['DASHBOARD_ROUTE'] || ''
|
||||
process.env['DASHBOARD_ROUTE'] || '/dashboard'
|
||||
);
|
||||
|
||||
export const IntegrationRoute: Route = new Route(
|
||||
process.env['INTEGRATION_ROUTE'] || ''
|
||||
process.env['INTEGRATION_ROUTE'] || '/integration'
|
||||
);
|
||||
|
||||
export const HelmRoute: Route = new Route(process.env['HELMCHART_ROUTE'] || '');
|
||||
export const HelmRoute: Route = new Route(
|
||||
process.env['HELMCHART_ROUTE'] || '/helm-chart'
|
||||
);
|
||||
export const AccountsRoute: Route = new Route(
|
||||
process.env['ACCOUNTS_ROUTE'] || ''
|
||||
process.env['ACCOUNTS_ROUTE'] || '/accounts'
|
||||
);
|
||||
|
||||
export const ApiDocsRoute: Route = new Route(
|
||||
process.env['APIDOCS_ROUTE'] || ''
|
||||
process.env['APIDOCS_ROUTE'] || '/api-docs'
|
||||
);
|
||||
|
||||
export const AdminDashboardRoute: Route = new Route(
|
||||
process.env['ADMINDASHBOARD_ROUTE'] || ''
|
||||
process.env['ADMINDASHBOARD_ROUTE'] || '/admin-dashboard'
|
||||
);
|
||||
|
||||
export const IsProduction: boolean =
|
||||
|
||||
@@ -26,7 +26,7 @@ export default class Database {
|
||||
password: DatabasePassword,
|
||||
database: DatabaseName,
|
||||
entities: Entities,
|
||||
logging: 'all',
|
||||
//logging: 'all',
|
||||
synchronize:
|
||||
Env === AppEnvironment.Test ||
|
||||
Env === AppEnvironment.Development,
|
||||
|
||||
@@ -17,7 +17,6 @@ export class Service extends DatabaseService<Model> {
|
||||
): Promise<OnCreate<Model>> {
|
||||
createBy.data.domainVerificationText =
|
||||
'oneuptime-verification-' + Text.generateRandomText(20);
|
||||
createBy.data.isVerified = false;
|
||||
return Promise.resolve({ createBy, carryForward: null });
|
||||
}
|
||||
|
||||
|
||||
11
CommonServer/Services/GreenlockCertificateService.ts
Normal file
11
CommonServer/Services/GreenlockCertificateService.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import PostgresDatabase from '../Infrastructure/PostgresDatabase';
|
||||
import Model from 'Model/Models/GreenlockCertificate';
|
||||
import DatabaseService from './DatabaseService';
|
||||
|
||||
export class Service extends DatabaseService<Model> {
|
||||
public constructor(postgresDatabase?: PostgresDatabase) {
|
||||
super(Model, postgresDatabase);
|
||||
}
|
||||
}
|
||||
|
||||
export default new Service();
|
||||
11
CommonServer/Services/GreenlockChallengeService.ts
Normal file
11
CommonServer/Services/GreenlockChallengeService.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import PostgresDatabase from '../Infrastructure/PostgresDatabase';
|
||||
import Model from 'Model/Models/GreenlockChallenge';
|
||||
import DatabaseService from './DatabaseService';
|
||||
|
||||
export class Service extends DatabaseService<Model> {
|
||||
public constructor(postgresDatabase?: PostgresDatabase) {
|
||||
super(Model, postgresDatabase);
|
||||
}
|
||||
}
|
||||
|
||||
export default new Service();
|
||||
@@ -7,6 +7,13 @@ import DeleteBy from '../Types/Database/DeleteBy';
|
||||
import ObjectID from 'Common/Types/ObjectID';
|
||||
import PositiveNumber from 'Common/Types/PositiveNumber';
|
||||
import SortOrder from 'Common/Types/Database/SortOrder';
|
||||
import IncidentState from 'Model/Models/IncidentState';
|
||||
import IncidentStateService from './IncidentStateService';
|
||||
import Incident from 'Model/Models/Incident';
|
||||
import MonitorStatusService from './MonitorStatusService';
|
||||
import MonitorStatus from 'Model/Models/MonitorStatus';
|
||||
import MonitorStatusTimeline from 'Model/Models/MonitorStatusTimeline';
|
||||
import MonitorStatusTimelineService from './MonitorStatusTimelineService';
|
||||
|
||||
export class Service extends DatabaseService<IncidentStateTimeline> {
|
||||
public constructor(postgresDatabase?: PostgresDatabase) {
|
||||
@@ -35,6 +42,79 @@ export class Service extends DatabaseService<IncidentStateTimeline> {
|
||||
props: onCreate.createBy.props,
|
||||
});
|
||||
|
||||
// TODO: DELETE THIS WHEN WORKFLOW IS IMPLEMENMTED.
|
||||
// check if this is resolved state, and if it is then resolve all the monitors.
|
||||
|
||||
const isResolvedState: IncidentState | null =
|
||||
await IncidentStateService.findOneBy({
|
||||
query: {
|
||||
_id: createdItem.incidentStateId.toString()!,
|
||||
isResolvedState: true,
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
select: {
|
||||
_id: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (isResolvedState) {
|
||||
// resolve all the monitors.
|
||||
const incident: Incident | null = await IncidentService.findOneBy({
|
||||
query: {
|
||||
_id: createdItem.incidentId?.toString(),
|
||||
},
|
||||
select: {
|
||||
_id: true,
|
||||
projectId: true,
|
||||
},
|
||||
populate: {
|
||||
monitors: {
|
||||
_id: true,
|
||||
},
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (incident && incident.monitors && incident.monitors.length > 0) {
|
||||
// get resolved monitor state.
|
||||
const resolvedMonitorState: MonitorStatus | null =
|
||||
await MonitorStatusService.findOneBy({
|
||||
query: {
|
||||
projectId: incident.projectId!,
|
||||
isOperationalState: true,
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
select: {
|
||||
_id: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (resolvedMonitorState) {
|
||||
for (const monitor of incident.monitors) {
|
||||
const monitorStausTimeline: MonitorStatusTimeline =
|
||||
new MonitorStatusTimeline();
|
||||
monitorStausTimeline.monitorId = monitor.id!;
|
||||
monitorStausTimeline.projectId = incident.projectId!;
|
||||
monitorStausTimeline.monitorStatusId =
|
||||
resolvedMonitorState.id!;
|
||||
|
||||
await MonitorStatusTimelineService.create({
|
||||
data: monitorStausTimeline,
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return createdItem;
|
||||
}
|
||||
|
||||
|
||||
@@ -537,6 +537,15 @@ export class Service extends DatabaseService<Model> {
|
||||
},
|
||||
});
|
||||
|
||||
await TeamMemberService.refreshTokens(
|
||||
createdItem.createdByUserId!,
|
||||
createdItem.id!
|
||||
);
|
||||
|
||||
await TeamMemberService.updateSubscriptionSeatsByUnqiqueTeamMembersInProject(
|
||||
createdItem.id!
|
||||
);
|
||||
|
||||
return createdItem;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,13 @@ import DeleteBy from '../Types/Database/DeleteBy';
|
||||
import ObjectID from 'Common/Types/ObjectID';
|
||||
import PositiveNumber from 'Common/Types/PositiveNumber';
|
||||
import SortOrder from 'Common/Types/Database/SortOrder';
|
||||
import ScheduledMaintenanceState from 'Model/Models/ScheduledMaintenanceState';
|
||||
import ScheduledMaintenanceStateService from './ScheduledMaintenanceStateService';
|
||||
import ScheduledMaintenance from 'Model/Models/ScheduledMaintenance';
|
||||
import MonitorStatus from 'Model/Models/MonitorStatus';
|
||||
import MonitorStatusService from './MonitorStatusService';
|
||||
import MonitorStatusTimeline from 'Model/Models/MonitorStatusTimeline';
|
||||
import MonitorStatusTimelineService from './MonitorStatusTimelineService';
|
||||
|
||||
export class Service extends DatabaseService<ScheduledMaintenanceStateTimeline> {
|
||||
public constructor(postgresDatabase?: PostgresDatabase) {
|
||||
@@ -14,7 +21,7 @@ export class Service extends DatabaseService<ScheduledMaintenanceStateTimeline>
|
||||
}
|
||||
|
||||
protected override async onCreateSuccess(
|
||||
onCreate: OnCreate<ScheduledMaintenanceStateTimeline>,
|
||||
_onCreate: OnCreate<ScheduledMaintenanceStateTimeline>,
|
||||
createdItem: ScheduledMaintenanceStateTimeline
|
||||
): Promise<ScheduledMaintenanceStateTimeline> {
|
||||
if (!createdItem.scheduledMaintenanceId) {
|
||||
@@ -33,9 +40,90 @@ export class Service extends DatabaseService<ScheduledMaintenanceStateTimeline>
|
||||
currentScheduledMaintenanceStateId:
|
||||
createdItem.scheduledMaintenanceStateId,
|
||||
},
|
||||
props: onCreate.createBy.props,
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
// TODO: DELETE THIS WHEN WORKFLOW IS IMPLEMENMTED.
|
||||
// check if this is resolved state, and if it is then resolve all the monitors.
|
||||
|
||||
const isResolvedState: ScheduledMaintenanceState | null =
|
||||
await ScheduledMaintenanceStateService.findOneBy({
|
||||
query: {
|
||||
_id: createdItem.scheduledMaintenanceStateId.toString()!,
|
||||
isResolvedState: true,
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
select: {
|
||||
_id: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (isResolvedState) {
|
||||
// resolve all the monitors.
|
||||
const scheduledMaintenanceService: ScheduledMaintenance | null =
|
||||
await ScheduledMaintenanceService.findOneBy({
|
||||
query: {
|
||||
_id: createdItem.scheduledMaintenanceId?.toString(),
|
||||
},
|
||||
select: {
|
||||
_id: true,
|
||||
projectId: true,
|
||||
},
|
||||
populate: {
|
||||
monitors: {
|
||||
_id: true,
|
||||
},
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (
|
||||
scheduledMaintenanceService &&
|
||||
scheduledMaintenanceService.monitors &&
|
||||
scheduledMaintenanceService.monitors.length > 0
|
||||
) {
|
||||
// get resolved monitor state.
|
||||
const resolvedMonitorState: MonitorStatus | null =
|
||||
await MonitorStatusService.findOneBy({
|
||||
query: {
|
||||
projectId: scheduledMaintenanceService.projectId!,
|
||||
isOperationalState: true,
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
select: {
|
||||
_id: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (resolvedMonitorState) {
|
||||
for (const monitor of scheduledMaintenanceService.monitors) {
|
||||
const monitorStausTimeline: MonitorStatusTimeline =
|
||||
new MonitorStatusTimeline();
|
||||
monitorStausTimeline.monitorId = monitor.id!;
|
||||
monitorStausTimeline.projectId =
|
||||
scheduledMaintenanceService.projectId!;
|
||||
monitorStausTimeline.monitorStatusId =
|
||||
resolvedMonitorState.id!;
|
||||
|
||||
await MonitorStatusTimelineService.create({
|
||||
data: monitorStausTimeline,
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return createdItem;
|
||||
}
|
||||
|
||||
|
||||
46
CommonServer/Services/StatusPageCertificateService.ts
Normal file
46
CommonServer/Services/StatusPageCertificateService.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import EmptyResponseData from 'Common/Types/API/EmptyResponse';
|
||||
import HTTPResponse from 'Common/Types/API/HTTPResponse';
|
||||
import Route from 'Common/Types/API/Route';
|
||||
import URL from 'Common/Types/API/URL';
|
||||
import { JSONObject } from 'Common/Types/JSON';
|
||||
import API from 'Common/Utils/API';
|
||||
import { HttpProtocol, WorkerHostname } from '../Config';
|
||||
|
||||
export default class StatusPageCertificateService {
|
||||
public static async add(
|
||||
domain: string
|
||||
): Promise<HTTPResponse<EmptyResponseData>> {
|
||||
const body: JSONObject = {
|
||||
domain: domain,
|
||||
};
|
||||
|
||||
return await API.post<EmptyResponseData>(
|
||||
new URL(HttpProtocol, WorkerHostname, new Route('/cert')),
|
||||
body
|
||||
);
|
||||
}
|
||||
|
||||
public static async remove(
|
||||
domain: string
|
||||
): Promise<HTTPResponse<EmptyResponseData>> {
|
||||
const body: JSONObject = {
|
||||
domain: domain,
|
||||
};
|
||||
|
||||
return await API.delete<EmptyResponseData>(
|
||||
new URL(HttpProtocol, WorkerHostname, new Route('/cert')),
|
||||
body
|
||||
);
|
||||
}
|
||||
|
||||
public static async get(domain: string): Promise<HTTPResponse<JSONObject>> {
|
||||
const body: JSONObject = {
|
||||
domain: domain,
|
||||
};
|
||||
|
||||
return await API.get<JSONObject>(
|
||||
new URL(HttpProtocol, WorkerHostname, new Route('/cert')),
|
||||
body
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,14 @@
|
||||
import PostgresDatabase from '../Infrastructure/PostgresDatabase';
|
||||
import Model from 'Model/Models/StatusPageDomain';
|
||||
import DatabaseService, { OnCreate } from './DatabaseService';
|
||||
import DatabaseService, { OnCreate, OnDelete } from './DatabaseService';
|
||||
import CreateBy from '../Types/Database/CreateBy';
|
||||
import DomainService from './DomainService';
|
||||
import Domain from 'Model/Models/Domain';
|
||||
import BadDataException from 'Common/Types/Exception/BadDataException';
|
||||
import StatusPageCertificateService from './StatusPageCertificateService';
|
||||
import DeleteBy from '../Types/Database/DeleteBy';
|
||||
import LIMIT_MAX from 'Common/Types/Database/LimitMax';
|
||||
import ObjectID from 'Common/Types/ObjectID';
|
||||
|
||||
export class Service extends DatabaseService<Model> {
|
||||
public constructor(postgresDatabase?: PostgresDatabase) {
|
||||
@@ -21,18 +26,59 @@ export class Service extends DatabaseService<Model> {
|
||||
'',
|
||||
},
|
||||
populate: {},
|
||||
select: { domain: true },
|
||||
select: { domain: true, isVerified: true },
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!domain?.isVerified) {
|
||||
throw new BadDataException(
|
||||
'This domain is not verified. Please verify it by going to Settings > Domains'
|
||||
);
|
||||
}
|
||||
|
||||
if (domain) {
|
||||
createBy.data.fullDomain =
|
||||
createBy.data.subdomain + '.' + domain.domain;
|
||||
}
|
||||
|
||||
createBy.data.cnameVerificationToken = ObjectID.generate().toString();
|
||||
|
||||
return { createBy, carryForward: null };
|
||||
}
|
||||
|
||||
protected override async onBeforeDelete(
|
||||
deleteBy: DeleteBy<Model>
|
||||
): Promise<OnDelete<Model>> {
|
||||
const domains: Array<Model> = await this.findBy({
|
||||
query: {
|
||||
...deleteBy.query,
|
||||
isAddedtoGreenlock: true,
|
||||
},
|
||||
populate: {},
|
||||
skip: 0,
|
||||
limit: LIMIT_MAX,
|
||||
select: { fullDomain: true },
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
return { deleteBy, carryForward: domains };
|
||||
}
|
||||
|
||||
protected override async onDeleteSuccess(
|
||||
onDelete: OnDelete<Model>,
|
||||
_itemIdsBeforeDelete: ObjectID[]
|
||||
): Promise<OnDelete<Model>> {
|
||||
for (const domain of onDelete.carryForward) {
|
||||
await StatusPageCertificateService.remove(
|
||||
domain.fullDomain as string
|
||||
);
|
||||
}
|
||||
|
||||
return onDelete;
|
||||
}
|
||||
}
|
||||
export default new Service();
|
||||
|
||||
@@ -40,9 +40,7 @@ export class Service extends DatabaseService<TeamMember> {
|
||||
protected override async onBeforeCreate(
|
||||
createBy: CreateBy<TeamMember>
|
||||
): Promise<OnCreate<TeamMember>> {
|
||||
if (!createBy.data.hasAcceptedInvitation) {
|
||||
createBy.data.hasAcceptedInvitation = false;
|
||||
}
|
||||
createBy.data.hasAcceptedInvitation = false;
|
||||
|
||||
if (createBy.miscDataProps && createBy.miscDataProps['email']) {
|
||||
const email: Email = new Email(
|
||||
@@ -91,10 +89,31 @@ export class Service extends DatabaseService<TeamMember> {
|
||||
}
|
||||
}
|
||||
|
||||
//check if this user is already ivnited.
|
||||
|
||||
const member: TeamMember | null = await this.findOneBy({
|
||||
query: {
|
||||
userId: createBy.data.userId!,
|
||||
teamId: createBy.data.teamId!,
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
select: {
|
||||
_id: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (member) {
|
||||
throw new BadDataException(
|
||||
'This user has already been invited to this team'
|
||||
);
|
||||
}
|
||||
|
||||
return { createBy, carryForward: null };
|
||||
}
|
||||
|
||||
private async refreshTokens(
|
||||
public async refreshTokens(
|
||||
userId: ObjectID,
|
||||
projectId: ObjectID
|
||||
): Promise<void> {
|
||||
@@ -161,6 +180,7 @@ export class Service extends DatabaseService<TeamMember> {
|
||||
projectId: true,
|
||||
team: true,
|
||||
teamId: true,
|
||||
hasAcceptedInvitation: true,
|
||||
},
|
||||
limit: LIMIT_MAX,
|
||||
skip: 0,
|
||||
@@ -178,9 +198,14 @@ export class Service extends DatabaseService<TeamMember> {
|
||||
// check if there's one member in the team.
|
||||
for (const member of members) {
|
||||
if (member.team?.shouldHaveAtleastOneMember) {
|
||||
if (!member.hasAcceptedInvitation) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const membersInTeam: PositiveNumber = await this.countBy({
|
||||
query: {
|
||||
_id: member.teamId?.toString() as string,
|
||||
teamId: member.teamId!,
|
||||
hasAcceptedInvitation: true,
|
||||
},
|
||||
skip: 0,
|
||||
limit: LIMIT_MAX,
|
||||
@@ -191,7 +216,7 @@ export class Service extends DatabaseService<TeamMember> {
|
||||
|
||||
if (membersInTeam.toNumber() <= 1) {
|
||||
throw new BadDataException(
|
||||
'This team should have atleast 1 member'
|
||||
'This team should have atleast 1 member who has accepted the invitation.'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,20 @@
|
||||
import PostgresDatabase from '../Infrastructure/PostgresDatabase';
|
||||
import Model from 'Model/Models/User';
|
||||
import DatabaseService from './DatabaseService';
|
||||
import DatabaseService, { OnUpdate } from './DatabaseService';
|
||||
import DatabaseCommonInteractionProps from 'Common/Types/Database/DatabaseCommonInteractionProps';
|
||||
import Email from 'Common/Types/Email';
|
||||
import ObjectID from 'Common/Types/ObjectID';
|
||||
import MailService from './MailService';
|
||||
import UpdateBy from '../Types/Database/UpdateBy';
|
||||
import LIMIT_MAX from 'Common/Types/Database/LimitMax';
|
||||
import EmailTemplateType from 'Common/Types/Email/EmailTemplateType';
|
||||
import { AccountsRoute, Domain, HttpProtocol } from '../Config';
|
||||
import logger from '../Utils/Logger';
|
||||
import URL from 'Common/Types/API/URL';
|
||||
import EmailVerificationToken from 'Model/Models/EmailVerificationToken';
|
||||
import OneUptimeDate from 'Common/Types/Date';
|
||||
import EmailVerificationTokenService from './EmailVerificationTokenService';
|
||||
import Route from 'Common/Types/API/Route';
|
||||
|
||||
export class Service extends DatabaseService<Model> {
|
||||
public constructor(postgresDatabase?: PostgresDatabase) {
|
||||
@@ -24,6 +36,129 @@ export class Service extends DatabaseService<Model> {
|
||||
});
|
||||
}
|
||||
|
||||
protected override async onBeforeUpdate(
|
||||
updateBy: UpdateBy<Model>
|
||||
): Promise<OnUpdate<Model>> {
|
||||
if (updateBy.data.password || updateBy.data.email) {
|
||||
const users: Array<Model> = await this.findBy({
|
||||
query: updateBy.query,
|
||||
select: {
|
||||
_id: true,
|
||||
email: true,
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
limit: LIMIT_MAX,
|
||||
skip: 0,
|
||||
});
|
||||
|
||||
return { updateBy, carryForward: users };
|
||||
}
|
||||
return { updateBy, carryForward: [] };
|
||||
}
|
||||
|
||||
protected override async onUpdateSuccess(
|
||||
onUpdate: OnUpdate<Model>,
|
||||
_updatedItemIds: ObjectID[]
|
||||
): Promise<OnUpdate<Model>> {
|
||||
if (onUpdate && onUpdate.updateBy.data.password) {
|
||||
for (const user of onUpdate.carryForward) {
|
||||
// password changed, send password changed mail
|
||||
MailService.sendMail({
|
||||
toEmail: user.email!,
|
||||
subject: 'Password Changed.',
|
||||
templateType: EmailTemplateType.PasswordChanged,
|
||||
vars: {
|
||||
homeURL: new URL(HttpProtocol, Domain).toString(),
|
||||
},
|
||||
}).catch((err: Error) => {
|
||||
logger.error(err);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (onUpdate && onUpdate.updateBy.data.email) {
|
||||
const newUsers: Array<Model> = await this.findBy({
|
||||
query: onUpdate.updateBy.query,
|
||||
select: {
|
||||
_id: true,
|
||||
email: true,
|
||||
name: true,
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
limit: LIMIT_MAX,
|
||||
skip: 0,
|
||||
});
|
||||
|
||||
for (const user of onUpdate.carryForward) {
|
||||
const newUser: Model | undefined = newUsers.find((u: Model) => {
|
||||
return u._id?.toString() === user._id.toString();
|
||||
});
|
||||
|
||||
if (
|
||||
newUser &&
|
||||
newUser.email?.toString() !== user.email.toString()
|
||||
) {
|
||||
// password changed, send password changed mail
|
||||
const generatedToken: ObjectID = ObjectID.generate();
|
||||
|
||||
const emailVerificationToken: EmailVerificationToken =
|
||||
new EmailVerificationToken();
|
||||
emailVerificationToken.userId = user?.id!;
|
||||
emailVerificationToken.email = newUser?.email!;
|
||||
emailVerificationToken.token = generatedToken;
|
||||
emailVerificationToken.expires =
|
||||
OneUptimeDate.getOneDayAfter();
|
||||
|
||||
await EmailVerificationTokenService.create({
|
||||
data: emailVerificationToken,
|
||||
props: {
|
||||
isRoot: true,
|
||||
},
|
||||
});
|
||||
|
||||
MailService.sendMail({
|
||||
toEmail: newUser.email!,
|
||||
subject:
|
||||
'You have changed your email. Please verify your email.',
|
||||
templateType: EmailTemplateType.EmailChanged,
|
||||
vars: {
|
||||
name: newUser.name!.toString(),
|
||||
tokenVerifyUrl: new URL(
|
||||
HttpProtocol,
|
||||
Domain,
|
||||
new Route(AccountsRoute.toString()).addRoute(
|
||||
'/verify-email/' + generatedToken.toString()
|
||||
)
|
||||
).toString(),
|
||||
homeUrl: new URL(HttpProtocol, Domain).toString(),
|
||||
},
|
||||
}).catch((err: Error) => {
|
||||
logger.error(err);
|
||||
});
|
||||
|
||||
await this.updateBy({
|
||||
query: {
|
||||
_id: user.id.toString(),
|
||||
},
|
||||
data: {
|
||||
isEmailVerified: false,
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
ignoreHooks: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return onUpdate;
|
||||
}
|
||||
|
||||
public async createByEmail(
|
||||
email: Email,
|
||||
props: DatabaseCommonInteractionProps
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
} from 'Common/Types/Permission';
|
||||
import UserType from 'Common/Types/UserType';
|
||||
import Dictionary from 'Common/Types/Dictionary';
|
||||
import Port from 'Common/Types/Port';
|
||||
|
||||
export type RequestHandler = express.RequestHandler;
|
||||
export type NextFunction = express.NextFunction;
|
||||
@@ -63,16 +64,17 @@ class Express {
|
||||
}
|
||||
|
||||
public static async launchApplication(
|
||||
appName: string
|
||||
appName: string,
|
||||
port?: Port
|
||||
): Promise<express.Application> {
|
||||
return new Promise<express.Application>((resolve: Function) => {
|
||||
if (!this.app) {
|
||||
this.setupExpress();
|
||||
}
|
||||
if (!this.app) {
|
||||
this.setupExpress();
|
||||
}
|
||||
|
||||
this.app.listen(this.app.get('port'), () => {
|
||||
return new Promise<express.Application>((resolve: Function) => {
|
||||
this.app.listen(port?.toNumber() || this.app.get('port'), () => {
|
||||
// eslint-disable-next-line
|
||||
logger.info(`${appName} server started on port: ${this.app.get('port')}`);
|
||||
logger.info(`${appName} server started on port: ${port?.toNumber() || this.app.get('port')}`);
|
||||
return resolve(this.app);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -243,4 +243,24 @@ export default class Response {
|
||||
oneUptimeResponse.status(200).send(item);
|
||||
this.logResponse(req, res, item as JSONObject);
|
||||
}
|
||||
|
||||
public static sendTextResponse(
|
||||
req: ExpressRequest,
|
||||
res: ExpressResponse,
|
||||
text: string
|
||||
): void {
|
||||
const oneUptimeRequest: OneUptimeRequest = req as OneUptimeRequest;
|
||||
const oneUptimeResponse: OneUptimeResponse = res as OneUptimeResponse;
|
||||
|
||||
oneUptimeResponse.set(
|
||||
'ExpressRequest-Id',
|
||||
oneUptimeRequest.id.toString()
|
||||
);
|
||||
|
||||
oneUptimeResponse.set('Pod-Id', process.env['POD_NAME']);
|
||||
|
||||
oneUptimeResponse.logBody = { text: text as string };
|
||||
oneUptimeResponse.status(200).send(text);
|
||||
this.logResponse(req, res, { text: text as string });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import './Envrionment';
|
||||
import './Process';
|
||||
import logger from './Logger';
|
||||
import cors from 'cors';
|
||||
|
||||
import Port from 'Common/Types/Port';
|
||||
import Express, {
|
||||
ExpressRequest,
|
||||
ExpressResponse,
|
||||
@@ -16,6 +16,7 @@ import Express, {
|
||||
|
||||
// Connect common api's.
|
||||
import CommonAPI from '../API/Index';
|
||||
import NotFoundException from 'Common/Types/Exception/NotFoundException';
|
||||
|
||||
import OneUptimeDate from 'Common/Types/Date';
|
||||
import LocalCache from '../Infrastructure/LocalCache';
|
||||
@@ -23,6 +24,7 @@ import Exception from 'Common/Types/Exception/Exception';
|
||||
import ObjectID from 'Common/Types/ObjectID';
|
||||
import StatusCode from 'Common/Types/API/StatusCode';
|
||||
import Typeof from 'Common/Types/Typeof';
|
||||
import Response from './Response';
|
||||
// import OpenTelemetrySDK from "./OpenTelemetry";
|
||||
|
||||
const app: ExpressApplication = Express.getExpressApp();
|
||||
@@ -89,8 +91,11 @@ app.use(ExpressUrlEncoded({ limit: '50mb' }));
|
||||
|
||||
app.use(logRequest);
|
||||
|
||||
const init: Function = async (appName: string): Promise<ExpressApplication> => {
|
||||
await Express.launchApplication(appName);
|
||||
const init: Function = async (
|
||||
appName: string,
|
||||
port?: Port
|
||||
): Promise<ExpressApplication> => {
|
||||
await Express.launchApplication(appName, port);
|
||||
LocalCache.setString('app', 'name', appName);
|
||||
CommonAPI(appName);
|
||||
|
||||
@@ -132,20 +137,36 @@ const init: Function = async (appName: string): Promise<ExpressApplication> => {
|
||||
}
|
||||
);
|
||||
|
||||
app.post('*', (_req: ExpressRequest, res: ExpressResponse) => {
|
||||
res.status(404).json({ error: '404 - Not Found.' });
|
||||
app.post('*', (req: ExpressRequest, res: ExpressResponse) => {
|
||||
return Response.sendErrorResponse(
|
||||
req,
|
||||
res,
|
||||
new NotFoundException('Not found')
|
||||
);
|
||||
});
|
||||
|
||||
app.put('*', (_req: ExpressRequest, res: ExpressResponse) => {
|
||||
res.status(404).json({ error: '404 - Not Found.' });
|
||||
app.put('*', (req: ExpressRequest, res: ExpressResponse) => {
|
||||
return Response.sendErrorResponse(
|
||||
req,
|
||||
res,
|
||||
new NotFoundException('Not found')
|
||||
);
|
||||
});
|
||||
|
||||
app.delete('*', (_req: ExpressRequest, res: ExpressResponse) => {
|
||||
res.status(404).json({ error: '404 - Not Found.' });
|
||||
app.delete('*', (req: ExpressRequest, res: ExpressResponse) => {
|
||||
return Response.sendErrorResponse(
|
||||
req,
|
||||
res,
|
||||
new NotFoundException('Not found')
|
||||
);
|
||||
});
|
||||
|
||||
app.get('*', (_req: ExpressRequest, res: ExpressResponse) => {
|
||||
res.status(404).json({ error: '404 - Not Found.' });
|
||||
app.get('*', (req: ExpressRequest, res: ExpressResponse) => {
|
||||
return Response.sendErrorResponse(
|
||||
req,
|
||||
res,
|
||||
new NotFoundException('Not found')
|
||||
);
|
||||
});
|
||||
|
||||
// await OpenTelemetrySDK.start();
|
||||
|
||||
@@ -6,4 +6,4 @@ cd ..
|
||||
# Run Preinstall.
|
||||
npm run prerun
|
||||
# Run Postgres
|
||||
docker-compose up -d postgres
|
||||
docker compose up -d postgres
|
||||
@@ -11,4 +11,6 @@ APIDOCS_ROUTE={{ .Env.APIDOCS_ROUTE }}
|
||||
IDENTITY_ROUTE={{ .Env.IDENTITY_ROUTE }}
|
||||
FILE_ROUTE={{ .Env.FILE_ROUTE }}
|
||||
STATUS_PAGE_ROUTE={{ .Env.STATUS_PAGE_ROUTE }}
|
||||
IS_SERVER=false
|
||||
STATUS_PAGE_CNAME_RECORD={{ .Env.STATUS_PAGE_CNAME_RECORD }}
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ export interface ComponentProps {
|
||||
size?: undefined | AlertSize;
|
||||
color?: undefined | Color;
|
||||
dataTestId?: string;
|
||||
style?: React.CSSProperties | undefined;
|
||||
}
|
||||
|
||||
const Alert: FunctionComponent<ComponentProps> = (
|
||||
@@ -63,7 +64,7 @@ const Alert: FunctionComponent<ComponentProps> = (
|
||||
const rgb: RGB = Color.colorToRgb(props.color || Black);
|
||||
|
||||
return (
|
||||
<div className="row">
|
||||
<div className="row" style={props.style}>
|
||||
<div className="col-xl-12">
|
||||
<div
|
||||
data-testid={props.dataTestId}
|
||||
|
||||
@@ -18,6 +18,8 @@ export interface ComponentProps {
|
||||
buttons?: undefined | Array<CardButtonSchema>;
|
||||
children?: undefined | Array<ReactElement> | ReactElement;
|
||||
cardBodyStyle?: undefined | CSSProperties;
|
||||
className?: string | undefined;
|
||||
style?: React.CSSProperties | undefined;
|
||||
}
|
||||
|
||||
const Card: FunctionComponent<ComponentProps> = (
|
||||
@@ -25,7 +27,7 @@ const Card: FunctionComponent<ComponentProps> = (
|
||||
): ReactElement => {
|
||||
return (
|
||||
<React.Fragment>
|
||||
<div className="row">
|
||||
<div className={`${props.className || ''} row`} style={props.style}>
|
||||
<div className="col-xl-12">
|
||||
<div className="card">
|
||||
<div className="card-header justify-space-between">
|
||||
|
||||
@@ -15,6 +15,7 @@ export interface ComponentProps<TBaseModel extends BaseModel> {
|
||||
onCountFetchInit?: (() => void) | undefined;
|
||||
onClick?: (() => void) | undefined;
|
||||
refreshToggle?: boolean | undefined;
|
||||
style?: React.CSSProperties | undefined;
|
||||
}
|
||||
|
||||
const CounterModelAlert: Function = <TBaseModel extends BaseModel>(
|
||||
@@ -78,6 +79,7 @@ const CounterModelAlert: Function = <TBaseModel extends BaseModel>(
|
||||
|
||||
return (
|
||||
<Alert
|
||||
style={props.style}
|
||||
onClick={props.onClick}
|
||||
type={props.alertType}
|
||||
title={`${count} ${
|
||||
|
||||
@@ -58,6 +58,7 @@ export const DefaultValidateFunction: Function = (
|
||||
|
||||
export interface ComponentProps<T extends Object> {
|
||||
id: string;
|
||||
submitButtonStyleType?: ButtonStyleType | undefined;
|
||||
initialValues: FormValues<T>;
|
||||
onSubmit: (values: FormValues<T>) => void;
|
||||
onValidate?: undefined | ((values: FormValues<T>) => JSONObject);
|
||||
@@ -1102,7 +1103,10 @@ const BasicForm: Function = <T extends Object>(
|
||||
type={ButtonTypes.Submit}
|
||||
id={`${props.id}-submit-button`}
|
||||
isLoading={props.isLoading || false}
|
||||
buttonStyle={ButtonStyleType.PRIMARY}
|
||||
buttonStyle={
|
||||
props.submitButtonStyleType ||
|
||||
ButtonStyleType.PRIMARY
|
||||
}
|
||||
style={{
|
||||
width: props.maxPrimaryButtonWidth
|
||||
? '100%'
|
||||
|
||||
@@ -4,6 +4,7 @@ import BaseModel from 'Common/Models/BaseModel';
|
||||
import FormValues from './Types/FormValues';
|
||||
import Fields from './Types/Fields';
|
||||
import BasicForm, { DefaultValidateFunction } from './BasicForm';
|
||||
import { ButtonStyleType } from '../Button/Button';
|
||||
|
||||
export interface ComponentProps<TBaseModel extends BaseModel> {
|
||||
model: TBaseModel;
|
||||
@@ -16,6 +17,7 @@ export interface ComponentProps<TBaseModel extends BaseModel> {
|
||||
) => FormikErrors<FormValues<TBaseModel>>);
|
||||
fields: Fields<TBaseModel>;
|
||||
submitButtonText?: undefined | string;
|
||||
submitButtonStyleType?: ButtonStyleType | undefined;
|
||||
title?: undefined | string;
|
||||
description?: undefined | string;
|
||||
showAsColumns?: undefined | number;
|
||||
@@ -77,6 +79,7 @@ const BasicModelForm: Function = <TBaseModel extends BaseModel>(
|
||||
onValidate={
|
||||
props.onValidate ? props.onValidate : DefaultValidateFunction
|
||||
}
|
||||
submitButtonStyleType={props.submitButtonStyleType}
|
||||
onSubmit={props.onSubmit}
|
||||
initialValues={initialValues}
|
||||
submitButtonText={props.submitButtonText || 'Save'}
|
||||
|
||||
@@ -36,6 +36,7 @@ import FileModel from 'Common/Models/FileModel';
|
||||
import TableColumnType from 'Common/Types/Database/TableColumnType';
|
||||
import Typeof from 'Common/Types/Typeof';
|
||||
import { TableColumnMetadata } from 'Common/Types/Database/TableColumn';
|
||||
import { ButtonStyleType } from '../Button/Button';
|
||||
|
||||
export enum FormType {
|
||||
Create,
|
||||
@@ -65,6 +66,7 @@ export interface ComponentProps<TBaseModel extends BaseModel> {
|
||||
apiUrl?: undefined | URL;
|
||||
formType: FormType;
|
||||
hideSubmitButton?: undefined | boolean;
|
||||
submitButtonStyleType?: ButtonStyleType | undefined;
|
||||
formRef?: undefined | MutableRefObject<FormikProps<FormikValues>>;
|
||||
onLoadingChange?: undefined | ((isLoading: boolean) => void);
|
||||
initialValues?: FormValues<TBaseModel> | undefined;
|
||||
@@ -72,6 +74,7 @@ export interface ComponentProps<TBaseModel extends BaseModel> {
|
||||
onError?: ((error: string) => void) | undefined;
|
||||
onBeforeCreate?: ((item: TBaseModel) => Promise<TBaseModel>) | undefined;
|
||||
saveRequestOptions?: RequestOptions | undefined;
|
||||
doNotFetchExistingModel?: boolean | undefined;
|
||||
}
|
||||
|
||||
const ModelForm: Function = <TBaseModel extends BaseModel>(
|
||||
@@ -316,7 +319,11 @@ const ModelForm: Function = <TBaseModel extends BaseModel>(
|
||||
};
|
||||
|
||||
useAsyncEffect(async () => {
|
||||
if (props.modelIdToEdit && props.formType === FormType.Update) {
|
||||
if (
|
||||
props.modelIdToEdit &&
|
||||
props.formType === FormType.Update &&
|
||||
!props.doNotFetchExistingModel
|
||||
) {
|
||||
// get item.
|
||||
setLoading(true);
|
||||
setIsFetching(true);
|
||||
@@ -476,26 +483,29 @@ const ModelForm: Function = <TBaseModel extends BaseModel>(
|
||||
}
|
||||
|
||||
return (
|
||||
<BasicModelForm<TBaseModel>
|
||||
title={props.title}
|
||||
description={props.description}
|
||||
model={model}
|
||||
id={props.id}
|
||||
fields={fields}
|
||||
showAsColumns={props.showAsColumns}
|
||||
footer={props.footer}
|
||||
isLoading={isLoading}
|
||||
submitButtonText={props.submitButtonText}
|
||||
cancelButtonText={props.cancelButtonText}
|
||||
onSubmit={onSubmit}
|
||||
onValidate={props.onValidate}
|
||||
onCancel={props.onCancel}
|
||||
maxPrimaryButtonWidth={props.maxPrimaryButtonWidth}
|
||||
error={error}
|
||||
hideSubmitButton={props.hideSubmitButton}
|
||||
formRef={props.formRef}
|
||||
initialValues={itemToEdit || props.initialValues}
|
||||
></BasicModelForm>
|
||||
<div>
|
||||
<BasicModelForm<TBaseModel>
|
||||
title={props.title}
|
||||
description={props.description}
|
||||
model={model}
|
||||
id={props.id}
|
||||
fields={fields}
|
||||
showAsColumns={props.showAsColumns}
|
||||
footer={props.footer}
|
||||
isLoading={isLoading}
|
||||
submitButtonText={props.submitButtonText}
|
||||
cancelButtonText={props.cancelButtonText}
|
||||
onSubmit={onSubmit}
|
||||
submitButtonStyleType={props.submitButtonStyleType}
|
||||
onValidate={props.onValidate}
|
||||
onCancel={props.onCancel}
|
||||
maxPrimaryButtonWidth={props.maxPrimaryButtonWidth}
|
||||
error={error}
|
||||
hideSubmitButton={props.hideSubmitButton}
|
||||
formRef={props.formRef}
|
||||
initialValues={itemToEdit || props.initialValues}
|
||||
></BasicModelForm>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -3,11 +3,13 @@ import Name from 'Common/Types/Name';
|
||||
import React, { FunctionComponent, ReactElement } from 'react';
|
||||
import Icon, { IconProp } from '../../Icon/Icon';
|
||||
import useComponentOutsideClick from '../../../Types/UseComponentOutsideClick';
|
||||
import Route from 'Common/Types/API/Route';
|
||||
import Image from '../../Image/Image';
|
||||
|
||||
export interface ComponentProps {
|
||||
userFullName: Name;
|
||||
children: ReactElement | Array<ReactElement>;
|
||||
userProfilePicture: URL;
|
||||
userProfilePicture: URL | Route;
|
||||
}
|
||||
|
||||
const UserProfile: FunctionComponent<ComponentProps> = (
|
||||
@@ -30,11 +32,11 @@ const UserProfile: FunctionComponent<ComponentProps> = (
|
||||
alignItems: 'center',
|
||||
}}
|
||||
>
|
||||
<img
|
||||
<Image
|
||||
className="rounded-circle header-profile-user"
|
||||
src={props.userProfilePicture.toString()}
|
||||
alt="Header Avatar"
|
||||
imageUrl={props.userProfilePicture}
|
||||
/>
|
||||
|
||||
<span className="d-none d-xl-inline-block ms-2 me-1">
|
||||
{props.userFullName.toString()}
|
||||
</span>
|
||||
|
||||
@@ -7,7 +7,8 @@ import Link from '../../Link/Link';
|
||||
export interface ComponentProps {
|
||||
title: string;
|
||||
badge?: undefined | number;
|
||||
route: Route;
|
||||
route?: Route | undefined;
|
||||
onClick?: (() => void) | undefined;
|
||||
icon: IconProp;
|
||||
iconColor?: undefined | Color;
|
||||
}
|
||||
@@ -18,7 +19,7 @@ const UserProfile: FunctionComponent<ComponentProps> = (
|
||||
return (
|
||||
<Link
|
||||
to={props.route}
|
||||
onClick={undefined}
|
||||
onClick={props.onClick}
|
||||
className="dropdown-item flex"
|
||||
>
|
||||
{props.badge ? (
|
||||
|
||||
@@ -2,12 +2,14 @@ import Route from 'Common/Types/API/Route';
|
||||
import BadDataException from 'Common/Types/Exception/BadDataException';
|
||||
import File from 'Model/Models/File';
|
||||
import React, { FunctionComponent, ReactElement } from 'react';
|
||||
import URLFromProject from 'Common/Types/API/URL';
|
||||
|
||||
export interface ComponentProps {
|
||||
onClick: () => void;
|
||||
imageUrl?: URL | Route | undefined;
|
||||
onClick?: () => void | undefined;
|
||||
imageUrl?: URLFromProject | Route | undefined;
|
||||
height?: number | undefined;
|
||||
file?: File | undefined;
|
||||
className?: string | undefined;
|
||||
}
|
||||
|
||||
export class ImageFunctions {
|
||||
@@ -32,6 +34,7 @@ const Image: FunctionComponent<ComponentProps> = (
|
||||
}}
|
||||
src={props.imageUrl.toString()}
|
||||
height={props.height}
|
||||
className={props.className}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -46,6 +49,7 @@ const Image: FunctionComponent<ComponentProps> = (
|
||||
}}
|
||||
src={url}
|
||||
height={props.height}
|
||||
className={props.className}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ export interface ComponentProps<TBaseModel extends BaseModel> {
|
||||
isEditable?: undefined | boolean;
|
||||
editButtonText?: undefined | string;
|
||||
formFields?: undefined | Fields<TBaseModel>;
|
||||
className?: string | undefined;
|
||||
}
|
||||
|
||||
const CardModelDetail: Function = <TBaseModel extends BaseModel>(
|
||||
@@ -67,7 +68,11 @@ const CardModelDetail: Function = <TBaseModel extends BaseModel>(
|
||||
|
||||
return (
|
||||
<>
|
||||
<Card {...props.cardProps} buttons={cardButtons}>
|
||||
<Card
|
||||
{...props.cardProps}
|
||||
className={props.className}
|
||||
buttons={cardButtons}
|
||||
>
|
||||
<ModelDetail
|
||||
refresher={refresher}
|
||||
{...props.modelDetailProps}
|
||||
|
||||
@@ -36,15 +36,10 @@ const ModelDetail: Function = <TBaseModel extends BaseModel>(
|
||||
const [error, setError] = useState<string>('');
|
||||
const [item, setItem] = useState<TBaseModel | null>(null);
|
||||
|
||||
const model: TBaseModel = new props.modelType();
|
||||
const [onBeforeFetchData, setOnBeforeFetchData] = useState<
|
||||
JSONObject | undefined
|
||||
>(undefined);
|
||||
|
||||
useEffect(() => {
|
||||
fetchItem();
|
||||
}, [props.refresher]);
|
||||
|
||||
const getSelectFields: Function = (): Select<TBaseModel> => {
|
||||
const select: Select<TBaseModel> = {};
|
||||
for (const field of props.fields) {
|
||||
@@ -68,14 +63,14 @@ const ModelDetail: Function = <TBaseModel extends BaseModel>(
|
||||
? (Object.keys(field.field)[0] as string)
|
||||
: null;
|
||||
|
||||
if (key && model.isFileColumn(key)) {
|
||||
if (key && new props.modelType()?.isFileColumn(key)) {
|
||||
(populate as JSONObject)[key] = {
|
||||
file: true,
|
||||
_id: true,
|
||||
type: true,
|
||||
name: true,
|
||||
};
|
||||
} else if (key && model.isEntityColumn(key)) {
|
||||
} else if (key && new props.modelType()?.isEntityColumn(key)) {
|
||||
(populate as JSONObject)[key] = (field.field as any)[key];
|
||||
}
|
||||
}
|
||||
@@ -89,8 +84,10 @@ const ModelDetail: Function = <TBaseModel extends BaseModel>(
|
||||
const userPermissions: Array<Permission> =
|
||||
PermissionUtil.getAllPermissions();
|
||||
|
||||
const model: BaseModel = new props.modelType();
|
||||
|
||||
const accessControl: Dictionary<ColumnAccessControl> =
|
||||
model.getColumnAccessControlForAllColumns();
|
||||
model.getColumnAccessControlForAllColumns() || {};
|
||||
|
||||
const fieldsToSet: Array<Field<TBaseModel>> = [];
|
||||
|
||||
@@ -147,12 +144,10 @@ const ModelDetail: Function = <TBaseModel extends BaseModel>(
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setDetailFields();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
setDetailFields();
|
||||
}, [onBeforeFetchData]);
|
||||
if (props.modelType) {
|
||||
setDetailFields();
|
||||
}
|
||||
}, [onBeforeFetchData, props.modelType]);
|
||||
|
||||
const fetchItem: Function = async (): Promise<void> => {
|
||||
// get item.
|
||||
@@ -175,9 +170,9 @@ const ModelDetail: Function = <TBaseModel extends BaseModel>(
|
||||
if (!item) {
|
||||
setError(
|
||||
`Cannot load ${(
|
||||
model.singularName || 'item'
|
||||
new props.modelType()?.singularName || 'item'
|
||||
).toLowerCase()}. It could be because you don't have enough permissions to read this ${(
|
||||
model.singularName || 'item'
|
||||
new props.modelType()?.singularName || 'item'
|
||||
).toLowerCase()}.`
|
||||
);
|
||||
}
|
||||
@@ -204,8 +199,10 @@ const ModelDetail: Function = <TBaseModel extends BaseModel>(
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchItem();
|
||||
}, []);
|
||||
if (props.modelId && props.modelType) {
|
||||
fetchItem();
|
||||
}
|
||||
}, [props.modelId, props.refresher, props.modelType]);
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
|
||||
@@ -22,6 +22,7 @@ export default interface Columns<TEntity> {
|
||||
isFilterable: boolean;
|
||||
filterEntityType?: { new (): BaseModel } | undefined;
|
||||
filterQuery?: Query<BaseModel> | undefined;
|
||||
tooltipText?: ((item: TEntity) => string) | undefined;
|
||||
filterDropdownField?:
|
||||
| {
|
||||
label: string;
|
||||
|
||||
@@ -322,6 +322,14 @@ const ModelTable: Function = <TBaseModel extends BaseModel>(
|
||||
) as string,
|
||||
});
|
||||
}
|
||||
|
||||
if (column.tooltipText) {
|
||||
classicColumn.tooltipText = (item: JSONObject): string => {
|
||||
return column.tooltipText!(
|
||||
BaseModel.fromJSONObject(item, props.modelType)
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
setColumns(classicColumns);
|
||||
@@ -642,12 +650,24 @@ const ModelTable: Function = <TBaseModel extends BaseModel>(
|
||||
const key: string | null = getColumnKey(column);
|
||||
|
||||
if (hasPermission) {
|
||||
let tooltipText: ((item: JSONObject) => string) | undefined =
|
||||
undefined;
|
||||
|
||||
if (column.tooltipText) {
|
||||
tooltipText = (item: JSONObject): string => {
|
||||
return column.tooltipText!(
|
||||
BaseModel.fromJSONObject(item, props.modelType)
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
columns.push({
|
||||
...column,
|
||||
disableSort: column.disableSort || shouldDisableSort(key),
|
||||
key: column.selectedProperty
|
||||
? key + '.' + column.selectedProperty
|
||||
: key,
|
||||
tooltipText,
|
||||
});
|
||||
|
||||
if (key) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import OneUptimeDate from 'Common/Types/Date';
|
||||
import { JSONObject } from 'Common/Types/JSON';
|
||||
import React, { FunctionComponent, ReactElement, useState } from 'react';
|
||||
import Button, { ButtonSize } from '../Button/Button';
|
||||
import Button, { ButtonSize, ButtonStyleType } from '../Button/Button';
|
||||
import Icon, { IconProp, ThickProp } from '../Icon/Icon';
|
||||
import ActionButtonSchema from '../ActionButton/ActionButtonSchema';
|
||||
import Column from './Types/Column';
|
||||
@@ -30,199 +30,229 @@ const TableRow: FunctionComponent<ComponentProps> = (
|
||||
}) || []
|
||||
);
|
||||
|
||||
const [tooltipModalText, setTooltipModalText] = useState<string>('');
|
||||
|
||||
const [error, setError] = useState<string>('');
|
||||
|
||||
const getRow: Function = (provided?: DraggableProvided): ReactElement => {
|
||||
return (
|
||||
<tr
|
||||
className="table-row"
|
||||
{...provided?.draggableProps}
|
||||
ref={provided?.innerRef}
|
||||
>
|
||||
{props.enableDragAndDrop && (
|
||||
<td
|
||||
style={{ width: '20px' }}
|
||||
className="grabbable"
|
||||
{...provided?.dragHandleProps}
|
||||
>
|
||||
<Icon
|
||||
icon={IconProp.Drag}
|
||||
thick={ThickProp.Thick}
|
||||
<>
|
||||
<tr
|
||||
className="table-row"
|
||||
{...provided?.draggableProps}
|
||||
ref={provided?.innerRef}
|
||||
>
|
||||
{props.enableDragAndDrop && (
|
||||
<td
|
||||
style={{ width: '20px' }}
|
||||
className="grabbable"
|
||||
/>
|
||||
</td>
|
||||
)}
|
||||
{props.columns &&
|
||||
props.columns.map((column: Column, i: number) => {
|
||||
return (
|
||||
<td
|
||||
key={i}
|
||||
style={{
|
||||
textAlign:
|
||||
column.type === FieldType.Actions
|
||||
? 'right'
|
||||
: 'left',
|
||||
}}
|
||||
>
|
||||
{column.key && !column.getElement ? (
|
||||
column.type === FieldType.Date ? (
|
||||
props.item[column.key] ? (
|
||||
OneUptimeDate.getDateAsLocalFormattedString(
|
||||
props.item[
|
||||
column.key
|
||||
] as string,
|
||||
true
|
||||
{...provided?.dragHandleProps}
|
||||
>
|
||||
<Icon
|
||||
icon={IconProp.Drag}
|
||||
thick={ThickProp.Thick}
|
||||
className="grabbable"
|
||||
/>
|
||||
</td>
|
||||
)}
|
||||
{props.columns &&
|
||||
props.columns.map((column: Column, i: number) => {
|
||||
return (
|
||||
<td
|
||||
key={i}
|
||||
style={{
|
||||
textAlign:
|
||||
column.type === FieldType.Actions
|
||||
? 'right'
|
||||
: 'left',
|
||||
}}
|
||||
onClick={() => {
|
||||
if (column.tooltipText) {
|
||||
setTooltipModalText(
|
||||
column.tooltipText(props.item)
|
||||
);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{column.key && !column.getElement ? (
|
||||
column.type === FieldType.Date ? (
|
||||
props.item[column.key] ? (
|
||||
OneUptimeDate.getDateAsLocalFormattedString(
|
||||
props.item[
|
||||
column.key
|
||||
] as string,
|
||||
true
|
||||
)
|
||||
) : (
|
||||
''
|
||||
)
|
||||
) : column.type ===
|
||||
FieldType.DateTime ? (
|
||||
props.item[column.key] ? (
|
||||
OneUptimeDate.getDateAsLocalFormattedString(
|
||||
props.item[
|
||||
column.key
|
||||
] as string,
|
||||
false
|
||||
)
|
||||
) : (
|
||||
''
|
||||
)
|
||||
) : column.type ===
|
||||
FieldType.Boolean ? (
|
||||
props.item[column.key] ? (
|
||||
<Icon
|
||||
icon={IconProp.True}
|
||||
thick={ThickProp.Thick}
|
||||
/>
|
||||
) : (
|
||||
<Icon
|
||||
icon={IconProp.False}
|
||||
thick={ThickProp.Thick}
|
||||
/>
|
||||
)
|
||||
) : (
|
||||
''
|
||||
)
|
||||
) : column.type === FieldType.DateTime ? (
|
||||
props.item[column.key] ? (
|
||||
OneUptimeDate.getDateAsLocalFormattedString(
|
||||
props.item[
|
||||
column.key
|
||||
] as string,
|
||||
false
|
||||
)
|
||||
) : (
|
||||
''
|
||||
)
|
||||
) : column.type === FieldType.Boolean ? (
|
||||
props.item[column.key] ? (
|
||||
<Icon
|
||||
icon={IconProp.True}
|
||||
thick={ThickProp.Thick}
|
||||
/>
|
||||
) : (
|
||||
<Icon
|
||||
icon={IconProp.False}
|
||||
thick={ThickProp.Thick}
|
||||
/>
|
||||
_.get(
|
||||
props.item,
|
||||
column.key,
|
||||
''
|
||||
)?.toString() || ''
|
||||
)
|
||||
) : (
|
||||
_.get(
|
||||
props.item,
|
||||
column.key,
|
||||
''
|
||||
)?.toString() || ''
|
||||
)
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
<></>
|
||||
)}
|
||||
|
||||
{column.key && column.getElement ? (
|
||||
column.getElement(props.item)
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{column.type === FieldType.Actions && (
|
||||
<div>
|
||||
{error && (
|
||||
<div className="text-align-left">
|
||||
<ConfirmModal
|
||||
title={`Error`}
|
||||
description={error}
|
||||
submitButtonText={'Close'}
|
||||
onSubmit={() => {
|
||||
return setError('');
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{props.actionButtons?.map(
|
||||
(
|
||||
button: ActionButtonSchema,
|
||||
i: number
|
||||
) => {
|
||||
if (
|
||||
button.isVisible &&
|
||||
!button.isVisible(
|
||||
props.item
|
||||
)
|
||||
) {
|
||||
return <></>;
|
||||
}
|
||||
|
||||
return (
|
||||
<span
|
||||
style={
|
||||
i > 0
|
||||
? {
|
||||
marginLeft:
|
||||
'10px',
|
||||
}
|
||||
: {}
|
||||
{column.key && column.getElement ? (
|
||||
column.getElement(props.item)
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{column.type === FieldType.Actions && (
|
||||
<div>
|
||||
{error && (
|
||||
<div className="text-align-left">
|
||||
<ConfirmModal
|
||||
title={`Error`}
|
||||
description={error}
|
||||
submitButtonText={
|
||||
'Close'
|
||||
}
|
||||
key={i}
|
||||
>
|
||||
<Button
|
||||
buttonSize={
|
||||
ButtonSize.Small
|
||||
onSubmit={() => {
|
||||
return setError('');
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{props.actionButtons?.map(
|
||||
(
|
||||
button: ActionButtonSchema,
|
||||
i: number
|
||||
) => {
|
||||
if (
|
||||
button.isVisible &&
|
||||
!button.isVisible(
|
||||
props.item
|
||||
)
|
||||
) {
|
||||
return <></>;
|
||||
}
|
||||
|
||||
return (
|
||||
<span
|
||||
style={
|
||||
i > 0
|
||||
? {
|
||||
marginLeft:
|
||||
'10px',
|
||||
}
|
||||
: {}
|
||||
}
|
||||
title={button.title}
|
||||
icon={button.icon}
|
||||
buttonStyle={
|
||||
button.buttonStyleType
|
||||
}
|
||||
isLoading={
|
||||
isButtonLoading[
|
||||
i
|
||||
]
|
||||
}
|
||||
onClick={() => {
|
||||
if (
|
||||
button.onClick
|
||||
) {
|
||||
key={i}
|
||||
>
|
||||
<Button
|
||||
buttonSize={
|
||||
ButtonSize.Small
|
||||
}
|
||||
title={
|
||||
button.title
|
||||
}
|
||||
icon={
|
||||
button.icon
|
||||
}
|
||||
buttonStyle={
|
||||
button.buttonStyleType
|
||||
}
|
||||
isLoading={
|
||||
isButtonLoading[
|
||||
i
|
||||
] = true;
|
||||
setIsButtonLoading(
|
||||
isButtonLoading
|
||||
);
|
||||
|
||||
button.onClick(
|
||||
props.item,
|
||||
() => {
|
||||
// on aciton complete
|
||||
isButtonLoading[
|
||||
i
|
||||
] =
|
||||
false;
|
||||
setIsButtonLoading(
|
||||
isButtonLoading
|
||||
);
|
||||
},
|
||||
(
|
||||
err: Error
|
||||
) => {
|
||||
isButtonLoading[
|
||||
i
|
||||
] =
|
||||
false;
|
||||
setIsButtonLoading(
|
||||
isButtonLoading
|
||||
);
|
||||
setError(
|
||||
(
|
||||
err as Error
|
||||
)
|
||||
.message
|
||||
);
|
||||
}
|
||||
);
|
||||
]
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</td>
|
||||
);
|
||||
})}
|
||||
</tr>
|
||||
onClick={() => {
|
||||
if (
|
||||
button.onClick
|
||||
) {
|
||||
isButtonLoading[
|
||||
i
|
||||
] = true;
|
||||
setIsButtonLoading(
|
||||
isButtonLoading
|
||||
);
|
||||
|
||||
button.onClick(
|
||||
props.item,
|
||||
() => {
|
||||
// on aciton complete
|
||||
isButtonLoading[
|
||||
i
|
||||
] =
|
||||
false;
|
||||
setIsButtonLoading(
|
||||
isButtonLoading
|
||||
);
|
||||
},
|
||||
(
|
||||
err: Error
|
||||
) => {
|
||||
isButtonLoading[
|
||||
i
|
||||
] =
|
||||
false;
|
||||
setIsButtonLoading(
|
||||
isButtonLoading
|
||||
);
|
||||
setError(
|
||||
(
|
||||
err as Error
|
||||
)
|
||||
.message
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</td>
|
||||
);
|
||||
})}
|
||||
</tr>
|
||||
{tooltipModalText && (
|
||||
<ConfirmModal
|
||||
title={`Help`}
|
||||
description={`${tooltipModalText}`}
|
||||
submitButtonText={'Close'}
|
||||
onSubmit={() => {
|
||||
setTooltipModalText('');
|
||||
}}
|
||||
submitButtonType={ButtonStyleType.NORMAL}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ export default interface Column {
|
||||
title: string;
|
||||
description?: string | undefined;
|
||||
disableSort?: boolean;
|
||||
tooltipText?: ((item: JSONObject) => string) | undefined;
|
||||
type: FieldType;
|
||||
isFilterable?: boolean;
|
||||
filterDropdownOptions?: Array<DropdownOption> | undefined;
|
||||
|
||||
@@ -140,3 +140,6 @@ export const HOME_URL: URL = new URL(HTTP_PROTOCOL, HOME_HOSTNAME, HOME_ROUTE);
|
||||
|
||||
export const SubscriptionPlans: Array<SubscriptionPlan> =
|
||||
SubscriptionPlan.getSubscriptionPlans();
|
||||
|
||||
export const StatusPageCNameRecord: string =
|
||||
env('STATUS_PAGE_CNAME_RECORD') || '';
|
||||
|
||||
8
CommonUI/src/Images/users/blank-profile.svg
Normal file
8
CommonUI/src/Images/users/blank-profile.svg
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="401px" height="401px" enable-background="new 312.809 0 401 401" version="1.1" viewBox="312.809 0 401 401">
|
||||
<g transform="matrix(1.223 0 0 1.223 -467.5 -843.44)">
|
||||
<rect x="601.45" y="653.07" width="401" height="401" fill="#E4E6E7"/>
|
||||
<path d="m802.38 908.08c-84.515 0-153.52 48.185-157.38 108.62h314.79c-3.87-60.44-72.9-108.62-157.41-108.62z" fill="#AEB4B7"/>
|
||||
<path d="m881.37 818.86c0 46.746-35.106 84.641-78.41 84.641s-78.41-37.895-78.41-84.641 35.106-84.641 78.41-84.641c43.31 0 78.41 37.9 78.41 84.64z" fill="#AEB4B7"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 622 B |
@@ -212,6 +212,11 @@
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
.width-half {
|
||||
width: 50% !important;
|
||||
}
|
||||
|
||||
|
||||
.text-center {
|
||||
text-align: center;
|
||||
justify-content: center;
|
||||
|
||||
@@ -16,11 +16,6 @@ app.use(ExpressStatic(path.join(__dirname, 'public')));
|
||||
|
||||
app.use(`/${APP_NAME}`, ExpressStatic(path.join(__dirname, 'public')));
|
||||
|
||||
app.use(
|
||||
[`/${APP_NAME}/assets`, `/${APP_NAME}/${APP_NAME}/assets`],
|
||||
ExpressStatic(path.join(__dirname, 'dist'))
|
||||
);
|
||||
|
||||
app.get('/*', (_req: ExpressRequest, res: ExpressResponse) => {
|
||||
res.sendFile(path.join(__dirname, 'public', 'index.html'));
|
||||
});
|
||||
4
Dashboard/nodemon.json
Normal file
4
Dashboard/nodemon.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"watch": ["webpack.config.js"],
|
||||
"exec": "export DEBUG=express:* && webpack-dev-server --port=3009 --mode=development"
|
||||
}
|
||||
263
Dashboard/package-lock.json
generated
263
Dashboard/package-lock.json
generated
@@ -42,6 +42,7 @@
|
||||
"sass": "^1.51.0",
|
||||
"sass-loader": "^12.6.0",
|
||||
"ts-loader": "^9.3.0",
|
||||
"ts-node": "^10.9.1",
|
||||
"webpack": "^5.72.1",
|
||||
"webpack-cli": "^4.9.2",
|
||||
"webpack-dev-server": "^4.9.0"
|
||||
@@ -104,8 +105,8 @@
|
||||
"redis": "^4.2.0",
|
||||
"socket.io": "^4.4.1",
|
||||
"stripe": "^10.17.0",
|
||||
"typeorm": "^0.3.6",
|
||||
"typeorm-extension": "^2.1.0",
|
||||
"typeorm": "^0.3.10",
|
||||
"typeorm-extension": "^2.2.13",
|
||||
"winston": "^3.6.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -161,7 +162,7 @@
|
||||
"react-router-dom": "^6.3.0",
|
||||
"react-select": "^5.4.0",
|
||||
"react-simple-code-editor": "^0.13.0",
|
||||
"react-spinners": "^0.12.0",
|
||||
"react-spinners": "^0.13.6",
|
||||
"react-toggle": "^4.1.3",
|
||||
"reactstrap": "^9.1.1",
|
||||
"redux": "^4.2.0",
|
||||
@@ -2383,6 +2384,28 @@
|
||||
"dev": true,
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@cspotcode/source-map-support": {
|
||||
"version": "0.8.1",
|
||||
"resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
|
||||
"integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@jridgewell/trace-mapping": "0.3.9"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": {
|
||||
"version": "0.3.9",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
|
||||
"integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@jridgewell/resolve-uri": "^3.0.3",
|
||||
"@jridgewell/sourcemap-codec": "^1.4.10"
|
||||
}
|
||||
},
|
||||
"node_modules/@csstools/normalize.css": {
|
||||
"version": "12.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@csstools/normalize.css/-/normalize.css-12.0.0.tgz",
|
||||
@@ -3776,6 +3799,30 @@
|
||||
"node": ">=10.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tsconfig/node10": {
|
||||
"version": "1.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz",
|
||||
"integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@tsconfig/node12": {
|
||||
"version": "1.0.11",
|
||||
"resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz",
|
||||
"integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@tsconfig/node14": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz",
|
||||
"integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@tsconfig/node16": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz",
|
||||
"integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/aria-query": {
|
||||
"version": "4.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.2.tgz",
|
||||
@@ -6242,6 +6289,12 @@
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/create-require": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
|
||||
"integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/cross-spawn": {
|
||||
"version": "7.0.3",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
|
||||
@@ -6930,6 +6983,15 @@
|
||||
"dev": true,
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/diff": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
|
||||
"integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.3.1"
|
||||
}
|
||||
},
|
||||
"node_modules/diff-sequences": {
|
||||
"version": "27.5.1",
|
||||
"resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz",
|
||||
@@ -11450,6 +11512,12 @@
|
||||
"semver": "bin/semver.js"
|
||||
}
|
||||
},
|
||||
"node_modules/make-error": {
|
||||
"version": "1.3.6",
|
||||
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
|
||||
"integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/makeerror": {
|
||||
"version": "1.0.12",
|
||||
"resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz",
|
||||
@@ -16084,6 +16152,64 @@
|
||||
"webpack": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ts-node": {
|
||||
"version": "10.9.1",
|
||||
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz",
|
||||
"integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@cspotcode/source-map-support": "^0.8.0",
|
||||
"@tsconfig/node10": "^1.0.7",
|
||||
"@tsconfig/node12": "^1.0.7",
|
||||
"@tsconfig/node14": "^1.0.0",
|
||||
"@tsconfig/node16": "^1.0.2",
|
||||
"acorn": "^8.4.1",
|
||||
"acorn-walk": "^8.1.1",
|
||||
"arg": "^4.1.0",
|
||||
"create-require": "^1.1.0",
|
||||
"diff": "^4.0.1",
|
||||
"make-error": "^1.1.1",
|
||||
"v8-compile-cache-lib": "^3.0.1",
|
||||
"yn": "3.1.1"
|
||||
},
|
||||
"bin": {
|
||||
"ts-node": "dist/bin.js",
|
||||
"ts-node-cwd": "dist/bin-cwd.js",
|
||||
"ts-node-esm": "dist/bin-esm.js",
|
||||
"ts-node-script": "dist/bin-script.js",
|
||||
"ts-node-transpile-only": "dist/bin-transpile.js",
|
||||
"ts-script": "dist/bin-script-deprecated.js"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@swc/core": ">=1.2.50",
|
||||
"@swc/wasm": ">=1.2.50",
|
||||
"@types/node": "*",
|
||||
"typescript": ">=2.7"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@swc/core": {
|
||||
"optional": true
|
||||
},
|
||||
"@swc/wasm": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/ts-node/node_modules/acorn-walk": {
|
||||
"version": "8.2.0",
|
||||
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz",
|
||||
"integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ts-node/node_modules/arg": {
|
||||
"version": "4.1.3",
|
||||
"resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
|
||||
"integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/tsconfig-paths": {
|
||||
"version": "3.14.1",
|
||||
"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz",
|
||||
@@ -16428,6 +16554,12 @@
|
||||
"dev": true,
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/v8-compile-cache-lib": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
|
||||
"integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/v8-to-istanbul": {
|
||||
"version": "8.1.1",
|
||||
"resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz",
|
||||
@@ -17511,6 +17643,15 @@
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/yn": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
|
||||
"integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/yocto-queue": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
|
||||
@@ -19088,6 +19229,27 @@
|
||||
"dev": true,
|
||||
"peer": true
|
||||
},
|
||||
"@cspotcode/source-map-support": {
|
||||
"version": "0.8.1",
|
||||
"resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
|
||||
"integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@jridgewell/trace-mapping": "0.3.9"
|
||||
},
|
||||
"dependencies": {
|
||||
"@jridgewell/trace-mapping": {
|
||||
"version": "0.3.9",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
|
||||
"integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@jridgewell/resolve-uri": "^3.0.3",
|
||||
"@jridgewell/sourcemap-codec": "^1.4.10"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@csstools/normalize.css": {
|
||||
"version": "12.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@csstools/normalize.css/-/normalize.css-12.0.0.tgz",
|
||||
@@ -20061,6 +20223,30 @@
|
||||
"dev": true,
|
||||
"peer": true
|
||||
},
|
||||
"@tsconfig/node10": {
|
||||
"version": "1.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz",
|
||||
"integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==",
|
||||
"dev": true
|
||||
},
|
||||
"@tsconfig/node12": {
|
||||
"version": "1.0.11",
|
||||
"resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz",
|
||||
"integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==",
|
||||
"dev": true
|
||||
},
|
||||
"@tsconfig/node14": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz",
|
||||
"integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==",
|
||||
"dev": true
|
||||
},
|
||||
"@tsconfig/node16": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz",
|
||||
"integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/aria-query": {
|
||||
"version": "4.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.2.tgz",
|
||||
@@ -21932,8 +22118,8 @@
|
||||
"socket.io": "^4.4.1",
|
||||
"stripe": "^10.17.0",
|
||||
"ts-jest": "^27.1.4",
|
||||
"typeorm": "^0.3.6",
|
||||
"typeorm-extension": "^2.1.0",
|
||||
"typeorm": "^0.3.10",
|
||||
"typeorm-extension": "^2.2.13",
|
||||
"winston": "^3.6.0"
|
||||
}
|
||||
},
|
||||
@@ -21989,7 +22175,7 @@
|
||||
"react-router-dom": "^6.3.0",
|
||||
"react-select": "^5.4.0",
|
||||
"react-simple-code-editor": "^0.13.0",
|
||||
"react-spinners": "^0.12.0",
|
||||
"react-spinners": "^0.13.6",
|
||||
"react-test-renderer": "^18.2.0",
|
||||
"react-toggle": "^4.1.3",
|
||||
"reactstrap": "^9.1.1",
|
||||
@@ -22163,6 +22349,12 @@
|
||||
"yaml": "^1.10.0"
|
||||
}
|
||||
},
|
||||
"create-require": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
|
||||
"integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
|
||||
"dev": true
|
||||
},
|
||||
"cross-spawn": {
|
||||
"version": "7.0.3",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
|
||||
@@ -22667,6 +22859,12 @@
|
||||
"dev": true,
|
||||
"peer": true
|
||||
},
|
||||
"diff": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
|
||||
"integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
|
||||
"dev": true
|
||||
},
|
||||
"diff-sequences": {
|
||||
"version": "27.5.1",
|
||||
"resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz",
|
||||
@@ -26140,6 +26338,12 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"make-error": {
|
||||
"version": "1.3.6",
|
||||
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
|
||||
"integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
|
||||
"dev": true
|
||||
},
|
||||
"makeerror": {
|
||||
"version": "1.0.12",
|
||||
"resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz",
|
||||
@@ -29505,6 +29709,41 @@
|
||||
"semver": "^7.3.4"
|
||||
}
|
||||
},
|
||||
"ts-node": {
|
||||
"version": "10.9.1",
|
||||
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz",
|
||||
"integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@cspotcode/source-map-support": "^0.8.0",
|
||||
"@tsconfig/node10": "^1.0.7",
|
||||
"@tsconfig/node12": "^1.0.7",
|
||||
"@tsconfig/node14": "^1.0.0",
|
||||
"@tsconfig/node16": "^1.0.2",
|
||||
"acorn": "^8.4.1",
|
||||
"acorn-walk": "^8.1.1",
|
||||
"arg": "^4.1.0",
|
||||
"create-require": "^1.1.0",
|
||||
"diff": "^4.0.1",
|
||||
"make-error": "^1.1.1",
|
||||
"v8-compile-cache-lib": "^3.0.1",
|
||||
"yn": "3.1.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"acorn-walk": {
|
||||
"version": "8.2.0",
|
||||
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz",
|
||||
"integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==",
|
||||
"dev": true
|
||||
},
|
||||
"arg": {
|
||||
"version": "4.1.3",
|
||||
"resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
|
||||
"integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"tsconfig-paths": {
|
||||
"version": "3.14.1",
|
||||
"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz",
|
||||
@@ -29764,6 +30003,12 @@
|
||||
"dev": true,
|
||||
"peer": true
|
||||
},
|
||||
"v8-compile-cache-lib": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
|
||||
"integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==",
|
||||
"dev": true
|
||||
},
|
||||
"v8-to-istanbul": {
|
||||
"version": "8.1.1",
|
||||
"resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz",
|
||||
@@ -30631,6 +30876,12 @@
|
||||
"dev": true,
|
||||
"peer": true
|
||||
},
|
||||
"yn": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
|
||||
"integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
|
||||
"dev": true
|
||||
},
|
||||
"yocto-queue": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
|
||||
|
||||
@@ -22,12 +22,12 @@
|
||||
"use-async-effect": "^2.2.6"
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "webpack-dev-server --port=3009 --mode=development",
|
||||
"dev": "nodemon",
|
||||
"build": "webpack build --mode=production",
|
||||
"test": "react-app-rewired test",
|
||||
"eject": "webpack eject",
|
||||
"compile": "tsc",
|
||||
"start": "node --require ts-node/register Index.ts",
|
||||
"start": "node --require ts-node/register Serve.ts",
|
||||
"audit": "npm audit --audit-level=low",
|
||||
"preinstall": "npx npm-force-resolutions || echo 'No package-lock.json file. Skipping force resolutions'",
|
||||
"dep-check": "depcheck ./ --skip-missing=true'"
|
||||
@@ -59,6 +59,7 @@
|
||||
"sass": "^1.51.0",
|
||||
"sass-loader": "^12.6.0",
|
||||
"ts-loader": "^9.3.0",
|
||||
"ts-node": "^10.9.1",
|
||||
"webpack": "^5.72.1",
|
||||
"webpack-cli": "^4.9.2",
|
||||
"webpack-dev-server": "^4.9.0"
|
||||
|
||||
@@ -65,6 +65,6 @@
|
||||
To begin the development, run `npm start` or `yarn start`.
|
||||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
<script src="/dashboard/dashboard/assets/bundle.js"></script>
|
||||
<script src="/dashboard/dist/bundle.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -28,6 +28,7 @@ import Navigation from 'CommonUI/src/Utils/Navigation';
|
||||
import RouteMap, { RouteUtil } from '../../Utils/RouteMap';
|
||||
import PageMap from '../../Utils/PageMap';
|
||||
import Route from 'Common/Types/API/Route';
|
||||
import UserProfileModal from './UserProfileModal';
|
||||
|
||||
export interface ComponentProps {
|
||||
projects: Array<Project>;
|
||||
@@ -57,6 +58,8 @@ const DashboardHeader: FunctionComponent<ComponentProps> = (
|
||||
null
|
||||
);
|
||||
|
||||
const [showProfileModal, setShowProfileModal] = useState<boolean>(false);
|
||||
|
||||
useAsyncEffect(async () => {
|
||||
if (
|
||||
props.selectedProject &&
|
||||
@@ -93,6 +96,7 @@ const DashboardHeader: FunctionComponent<ComponentProps> = (
|
||||
onChange={(_value: string) => {}}
|
||||
/> */}
|
||||
<div
|
||||
className="flex"
|
||||
style={{
|
||||
marginLeft: '15px',
|
||||
marginTop: '15px',
|
||||
@@ -114,6 +118,9 @@ const DashboardHeader: FunctionComponent<ComponentProps> = (
|
||||
onClick={() => {
|
||||
setShowProjectInvitationModal(true);
|
||||
}}
|
||||
style={{
|
||||
marginRight: '10px',
|
||||
}}
|
||||
/>
|
||||
<CounterModelAlert<Incident>
|
||||
alertType={AlertType.DANGER}
|
||||
@@ -131,6 +138,9 @@ const DashboardHeader: FunctionComponent<ComponentProps> = (
|
||||
onClick={() => {
|
||||
setShowActiveIncidentsModal(true);
|
||||
}}
|
||||
style={{
|
||||
marginRight: '10px',
|
||||
}}
|
||||
/>
|
||||
|
||||
{props.selectedProject?.trialEndsAt &&
|
||||
@@ -153,6 +163,9 @@ const DashboardHeader: FunctionComponent<ComponentProps> = (
|
||||
? 'days'
|
||||
: 'day'
|
||||
}`}
|
||||
style={{
|
||||
marginRight: '10px',
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
@@ -203,7 +216,11 @@ const DashboardHeader: FunctionComponent<ComponentProps> = (
|
||||
<></>
|
||||
)}
|
||||
<Help />
|
||||
<UserProfile />
|
||||
<UserProfile
|
||||
onClickUserProfle={() => {
|
||||
setShowProfileModal(true);
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
@@ -228,6 +245,14 @@ const DashboardHeader: FunctionComponent<ComponentProps> = (
|
||||
/>
|
||||
)}
|
||||
|
||||
{showProfileModal && (
|
||||
<UserProfileModal
|
||||
onClose={() => {
|
||||
setShowProfileModal(false);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
{showActiveIncidentsModal && (
|
||||
<ActiveIncidentsModal
|
||||
onClose={() => {
|
||||
|
||||
@@ -14,12 +14,14 @@ const Help: FunctionComponent = (): ReactElement => {
|
||||
<IconDropdwonItem
|
||||
title="Support Email"
|
||||
icon={IconProp.Email}
|
||||
url={URL.fromString('https://google.com')}
|
||||
url={URL.fromString('mailto:support@oneuptime.com')}
|
||||
/>
|
||||
<IconDropdwonItem
|
||||
title="Chat on Slack"
|
||||
icon={IconProp.Slack}
|
||||
url={URL.fromString('https://google.com')}
|
||||
url={URL.fromString(
|
||||
'https://join.slack.com/t/oneuptimesupport/shared_invite/zt-1kavkds2f-gegm_wePorvwvM3M_SaoCQ'
|
||||
)}
|
||||
/>
|
||||
</IconDropdwonRow>
|
||||
</IconDropdwonMenu>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { FunctionComponent, ReactElement } from 'react';
|
||||
import FullLogo from 'CommonUI/src/Components/Image/Image';
|
||||
import Image from 'CommonUI/src/Components/Image/Image';
|
||||
import OneUptimeLogo from 'CommonUI/src/Images/logos/OneUptimePNG/7.png';
|
||||
import Route from 'Common/Types/API/Route';
|
||||
|
||||
@@ -12,14 +12,12 @@ const Logo: FunctionComponent<ComponentProps> = (
|
||||
): ReactElement => {
|
||||
return (
|
||||
<div className="flex items-center" style={{ marginLeft: '-25px' }}>
|
||||
<FullLogo
|
||||
<Image
|
||||
height={30}
|
||||
onClick={() => {
|
||||
props.onClick && props.onClick();
|
||||
}}
|
||||
imageUrl={Route.fromString(
|
||||
`/dashboard/public/${OneUptimeLogo}`
|
||||
)}
|
||||
imageUrl={Route.fromString(`${OneUptimeLogo}`)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -4,46 +4,44 @@ import UserProfileMenu from 'CommonUI/src/Components/Header/UserProfile/UserProf
|
||||
import UserProfileMenuItem from 'CommonUI/src/Components/Header/UserProfile/UserProfileMenuItem';
|
||||
import UserProfileDropdownDivider from 'CommonUI/src/Components/Header/UserProfile/UserProfileDropdownDivider';
|
||||
import { IconProp } from 'CommonUI/src/Components/Icon/Icon';
|
||||
import URL from 'Common/Types/API/URL';
|
||||
import Route from 'Common/Types/API/Route';
|
||||
import { Red } from 'Common/Types/BrandColors';
|
||||
import RouteMap from '../../Utils/RouteMap';
|
||||
import PageMap from '../../Utils/PageMap';
|
||||
import UserUtil from 'CommonUI/src/Utils/User';
|
||||
import OneUptimeLogo from 'CommonUI/src/Images/users/blank-profile.svg';
|
||||
|
||||
const DashboardUserProfile: FunctionComponent = (): ReactElement => {
|
||||
export interface ComponentProps {
|
||||
onClickUserProfle: () => void;
|
||||
}
|
||||
|
||||
const DashboardUserProfile: FunctionComponent<ComponentProps> = (
|
||||
props: ComponentProps
|
||||
): ReactElement => {
|
||||
return (
|
||||
<UserProfile
|
||||
userFullName={UserUtil.getName()}
|
||||
userProfilePicture={URL.fromString(
|
||||
'https://blog.media.io/images/images2021/cool-good-tiktok-profile-pictures.jpg'
|
||||
)}
|
||||
>
|
||||
<UserProfileMenu>
|
||||
<UserProfileMenuItem
|
||||
title="Profile"
|
||||
route={new Route('/logout')}
|
||||
icon={IconProp.User}
|
||||
/>
|
||||
{/* <UserProfileMenuItem
|
||||
title="Billing"
|
||||
route={new Route('/logout')}
|
||||
icon={IconProp.Billing}
|
||||
/>
|
||||
<UserProfileMenuItem
|
||||
title="User Settings"
|
||||
route={new Route('/logout')}
|
||||
icon={IconProp.Settings}
|
||||
/> */}
|
||||
<UserProfileDropdownDivider />
|
||||
<UserProfileMenuItem
|
||||
title="Log out"
|
||||
route={RouteMap[PageMap.LOGOUT] as Route}
|
||||
icon={IconProp.Logout}
|
||||
iconColor={Red}
|
||||
/>
|
||||
</UserProfileMenu>
|
||||
</UserProfile>
|
||||
<>
|
||||
<UserProfile
|
||||
userFullName={UserUtil.getName()}
|
||||
userProfilePicture={Route.fromString(`${OneUptimeLogo}`)}
|
||||
>
|
||||
<UserProfileMenu>
|
||||
<UserProfileMenuItem
|
||||
title="Profile"
|
||||
onClick={() => {
|
||||
props.onClickUserProfle();
|
||||
}}
|
||||
icon={IconProp.User}
|
||||
/>
|
||||
<UserProfileDropdownDivider />
|
||||
<UserProfileMenuItem
|
||||
title="Log out"
|
||||
route={RouteMap[PageMap.LOGOUT] as Route}
|
||||
icon={IconProp.Logout}
|
||||
iconColor={Red}
|
||||
/>
|
||||
</UserProfileMenu>
|
||||
</UserProfile>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
220
Dashboard/src/Components/Header/UserProfileModal.tsx
Normal file
220
Dashboard/src/Components/Header/UserProfileModal.tsx
Normal file
@@ -0,0 +1,220 @@
|
||||
import React, { FunctionComponent, ReactElement, useState } from 'react';
|
||||
import User from 'Model/Models/User';
|
||||
import UserUtil from 'CommonUI/src/Utils/User';
|
||||
import FullPageModal from 'CommonUI/src/Components/FullPageModal/FullPageModal';
|
||||
import { IconProp } from 'CommonUI/src/Components/Icon/Icon';
|
||||
import CardModelDetail from 'CommonUI/src/Components/ModelDetail/CardModelDetail';
|
||||
import FormFieldSchemaType from 'CommonUI/src/Components/Forms/Types/FormFieldSchemaType';
|
||||
import ModelForm, { FormType } from 'CommonUI/src/Components/Forms/ModelForm';
|
||||
import FieldType from 'CommonUI/src/Components/Types/FieldType';
|
||||
import Card from 'CommonUI/src/Components/Card/Card';
|
||||
import { ButtonStyleType } from 'CommonUI/src/Components/Button/Button';
|
||||
|
||||
export interface ComponentProps {
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
const UserProfileModal: FunctionComponent<ComponentProps> = (
|
||||
props: ComponentProps
|
||||
): ReactElement => {
|
||||
const [hasPasswordChanged, setHasPasswordChanged] =
|
||||
useState<boolean>(false);
|
||||
|
||||
return (
|
||||
<>
|
||||
<FullPageModal
|
||||
onClose={() => {
|
||||
props.onClose && props.onClose();
|
||||
}}
|
||||
>
|
||||
<CardModelDetail
|
||||
cardProps={{
|
||||
title: 'Basic Info',
|
||||
description: "Here's are some of your details.",
|
||||
icon: IconProp.User,
|
||||
}}
|
||||
isEditable={true}
|
||||
formFields={[
|
||||
{
|
||||
field: {
|
||||
email: true,
|
||||
},
|
||||
fieldType: FormFieldSchemaType.Email,
|
||||
placeholder: 'jeff@example.com',
|
||||
required: true,
|
||||
title: 'Email',
|
||||
description:
|
||||
'You will have to verify your email again if you change it',
|
||||
},
|
||||
{
|
||||
field: {
|
||||
name: true,
|
||||
},
|
||||
fieldType: FormFieldSchemaType.Text,
|
||||
placeholder: 'Jeff Smith',
|
||||
required: true,
|
||||
title: 'Full Name',
|
||||
},
|
||||
{
|
||||
field: {
|
||||
companyName: true,
|
||||
},
|
||||
fieldType: FormFieldSchemaType.Text,
|
||||
placeholder: 'Acme, Inc.',
|
||||
required: true,
|
||||
title: 'Company Name',
|
||||
},
|
||||
{
|
||||
field: {
|
||||
companyPhoneNumber: true,
|
||||
},
|
||||
fieldType: FormFieldSchemaType.Phone,
|
||||
required: true,
|
||||
placeholder: '+1-123-456-7890',
|
||||
title: 'Phone Number',
|
||||
},
|
||||
]}
|
||||
modelDetailProps={{
|
||||
showDetailsInNumberOfColumns: 2,
|
||||
modelType: User,
|
||||
id: 'user-profile',
|
||||
fields: [
|
||||
{
|
||||
field: {
|
||||
name: true,
|
||||
},
|
||||
title: 'Name',
|
||||
},
|
||||
{
|
||||
field: {
|
||||
email: true,
|
||||
},
|
||||
title: 'Email',
|
||||
},
|
||||
{
|
||||
field: {
|
||||
companyName: true,
|
||||
},
|
||||
title: 'Company Name',
|
||||
},
|
||||
{
|
||||
field: {
|
||||
companyPhoneNumber: true,
|
||||
},
|
||||
title: 'Company Phone Number',
|
||||
},
|
||||
],
|
||||
modelId: UserUtil.getUserId(),
|
||||
}}
|
||||
/>
|
||||
|
||||
<div className="flex width-max">
|
||||
<CardModelDetail<User>
|
||||
cardProps={{
|
||||
title: 'Profile Picture',
|
||||
description: 'Please update your profile pic here.',
|
||||
icon: IconProp.Image,
|
||||
}}
|
||||
isEditable={true}
|
||||
editButtonText={'Update Profile Picture'}
|
||||
formFields={[
|
||||
{
|
||||
field: {
|
||||
profilePictureFile: true,
|
||||
},
|
||||
title: 'Profile Picture',
|
||||
fieldType: FormFieldSchemaType.ImageFile,
|
||||
required: false,
|
||||
placeholder:
|
||||
'Please upload your profile picture here.',
|
||||
},
|
||||
]}
|
||||
modelDetailProps={{
|
||||
showDetailsInNumberOfColumns: 1,
|
||||
modelType: User,
|
||||
id: 'model-detail-user-profile-picture',
|
||||
fields: [
|
||||
{
|
||||
field: {
|
||||
profilePictureFile: {
|
||||
file: true,
|
||||
type: true,
|
||||
},
|
||||
},
|
||||
fieldType: FieldType.ImageFile,
|
||||
title: 'Profile Picture',
|
||||
placeholder: 'No profile picture uploaded.',
|
||||
},
|
||||
],
|
||||
modelId: UserUtil.getUserId(),
|
||||
}}
|
||||
className="width-half"
|
||||
/>
|
||||
|
||||
<Card
|
||||
style={{ marginLeft: '30px' }}
|
||||
className="width-half"
|
||||
title={'Update Password'}
|
||||
description={
|
||||
'You can set a new password here if you wish to do so.'
|
||||
}
|
||||
icon={IconProp.Lock}
|
||||
>
|
||||
{!hasPasswordChanged ? (
|
||||
<ModelForm<User>
|
||||
modelType={User}
|
||||
onSuccess={() => {
|
||||
setHasPasswordChanged(true);
|
||||
}}
|
||||
submitButtonStyleType={ButtonStyleType.OUTLINE}
|
||||
id="change-password-form"
|
||||
showAsColumns={1}
|
||||
doNotFetchExistingModel={true}
|
||||
modelIdToEdit={UserUtil.getUserId()}
|
||||
maxPrimaryButtonWidth={true}
|
||||
initialValues={{
|
||||
password: '',
|
||||
confirmPassword: '',
|
||||
}}
|
||||
fields={[
|
||||
{
|
||||
field: {
|
||||
password: true,
|
||||
},
|
||||
fieldType: FormFieldSchemaType.Password,
|
||||
validation: {
|
||||
minLength: 6,
|
||||
},
|
||||
placeholder: 'Password',
|
||||
title: 'Password',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
field: {
|
||||
password: true,
|
||||
},
|
||||
validation: {
|
||||
minLength: 6,
|
||||
toMatchField: 'password',
|
||||
},
|
||||
fieldType: FormFieldSchemaType.Password,
|
||||
placeholder: 'Confirm Password',
|
||||
title: 'Confirm Password',
|
||||
overideFieldKey: 'confirmPassword',
|
||||
required: true,
|
||||
},
|
||||
]}
|
||||
formType={FormType.Update}
|
||||
submitButtonText={'Update Password'}
|
||||
/>
|
||||
) : (
|
||||
<p>Your password has been updated.</p>
|
||||
)}
|
||||
</Card>
|
||||
</div>
|
||||
</FullPageModal>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default UserProfileModal;
|
||||
@@ -4,7 +4,6 @@ import Monitor from 'Model/Models/Monitor';
|
||||
import FieldType from 'CommonUI/src/Components/Types/FieldType';
|
||||
import FormFieldSchemaType from 'CommonUI/src/Components/Forms/Types/FormFieldSchemaType';
|
||||
import { IconProp } from 'CommonUI/src/Components/Icon/Icon';
|
||||
import MonitorTypeUtil from '../../Utils/MonitorType';
|
||||
import Label from 'Model/Models/Label';
|
||||
import { JSONArray, JSONObject } from 'Common/Types/JSON';
|
||||
import LabelsElement from '../../Components/Label/Labels';
|
||||
@@ -15,6 +14,7 @@ import MonitorStatus from 'Model/Models/MonitorStatus';
|
||||
import Query from 'CommonUI/src/Utils/ModelAPI/Query';
|
||||
import Route from 'Common/Types/API/Route';
|
||||
import Project from 'Model/Models/Project';
|
||||
import MonitorType from 'Common/Types/Monitor/MonitorType';
|
||||
|
||||
export interface ComponentProps {
|
||||
query?: Query<Monitor> | undefined;
|
||||
@@ -37,6 +37,10 @@ const MonitorsTable: FunctionComponent<ComponentProps> = (
|
||||
isCreateable={true}
|
||||
isViewable={true}
|
||||
query={props.query}
|
||||
onBeforeCreate={async (item: Monitor) => {
|
||||
item.monitorType = MonitorType.Manual;
|
||||
return item;
|
||||
}}
|
||||
cardProps={{
|
||||
icon: IconProp.Activity,
|
||||
title: props.title || 'Monitors',
|
||||
@@ -67,17 +71,17 @@ const MonitorsTable: FunctionComponent<ComponentProps> = (
|
||||
required: true,
|
||||
placeholder: 'Description',
|
||||
},
|
||||
{
|
||||
field: {
|
||||
monitorType: true,
|
||||
},
|
||||
title: 'Monitor Type',
|
||||
fieldType: FormFieldSchemaType.Dropdown,
|
||||
required: true,
|
||||
placeholder: 'Select Monitor Type',
|
||||
dropdownOptions:
|
||||
MonitorTypeUtil.monitorTypesAsDropdownOptions(),
|
||||
},
|
||||
// {
|
||||
// field: {
|
||||
// monitorType: true,
|
||||
// },
|
||||
// title: 'Monitor Type',
|
||||
// fieldType: FormFieldSchemaType.Dropdown,
|
||||
// required: true,
|
||||
// placeholder: 'Select Monitor Type',
|
||||
// dropdownOptions:
|
||||
// MonitorTypeUtil.monitorTypesAsDropdownOptions(),
|
||||
// },
|
||||
{
|
||||
field: {
|
||||
labels: true,
|
||||
@@ -107,14 +111,14 @@ const MonitorsTable: FunctionComponent<ComponentProps> = (
|
||||
type: FieldType.Text,
|
||||
isFilterable: true,
|
||||
},
|
||||
{
|
||||
field: {
|
||||
monitorType: true,
|
||||
},
|
||||
title: 'Monitor Type',
|
||||
type: FieldType.Text,
|
||||
isFilterable: true,
|
||||
},
|
||||
// {
|
||||
// field: {
|
||||
// monitorType: true,
|
||||
// },
|
||||
// title: 'Monitor Type',
|
||||
// type: FieldType.Text,
|
||||
// isFilterable: true,
|
||||
// },
|
||||
{
|
||||
field: {
|
||||
currentMonitorStatus: {
|
||||
|
||||
@@ -136,7 +136,7 @@ const ScheduledMaintenancesTable: FunctionComponent<ComponentProps> = (
|
||||
labelField: 'name',
|
||||
valueField: '_id',
|
||||
},
|
||||
required: true,
|
||||
required: false,
|
||||
placeholder: 'Select Status Pages',
|
||||
},
|
||||
{
|
||||
|
||||
@@ -11,7 +11,7 @@ const StatusPagesElement: FunctionComponent<ComponentProps> = (
|
||||
props: ComponentProps
|
||||
): ReactElement => {
|
||||
if (!props.statusPages || props.statusPages.length === 0) {
|
||||
return <p>No statusPages.</p>;
|
||||
return <p>No Status Pages.</p>;
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@@ -143,7 +143,7 @@ const ScheduledMaintenanceView: FunctionComponent<PageComponentProps> = (
|
||||
labelField: 'name',
|
||||
valueField: '_id',
|
||||
},
|
||||
required: true,
|
||||
required: false,
|
||||
placeholder: 'Select Status Pages',
|
||||
},
|
||||
{
|
||||
|
||||
@@ -189,7 +189,8 @@ const Settings: FunctionComponent<ComponentProps> = (
|
||||
<></>
|
||||
)}
|
||||
|
||||
{item['status'] !== 'paid' ? (
|
||||
{item['status'] !== 'paid' &&
|
||||
item['status'] !== 'draft' ? (
|
||||
<Button
|
||||
icon={IconProp.Billing}
|
||||
onClick={async () => {
|
||||
|
||||
@@ -15,6 +15,7 @@ import { IconProp } from 'CommonUI/src/Components/Icon/Icon';
|
||||
import ModelTable from 'CommonUI/src/Components/ModelTable/ModelTable';
|
||||
import BadDataException from 'Common/Types/Exception/BadDataException';
|
||||
import StatusPagePreviewLink from './StatusPagePreviewLink';
|
||||
import { StatusPageCNameRecord } from 'CommonUI/src/Config';
|
||||
|
||||
const StatusPageDelete: FunctionComponent<PageComponentProps> = (
|
||||
props: PageComponentProps
|
||||
@@ -71,8 +72,7 @@ const StatusPageDelete: FunctionComponent<PageComponentProps> = (
|
||||
cardProps={{
|
||||
icon: IconProp.Globe,
|
||||
title: 'Custom Domains',
|
||||
description:
|
||||
'Important: Please add status-page.oneuptime.com as your CNAME for these domains for this to work.',
|
||||
description: `Important: Please add ${StatusPageCNameRecord} as your CNAME for these domains for this to work.`,
|
||||
}}
|
||||
onBeforeCreate={(
|
||||
item: StatusPageDomain
|
||||
@@ -127,6 +127,31 @@ const StatusPageDelete: FunctionComponent<PageComponentProps> = (
|
||||
type: FieldType.Text,
|
||||
isFilterable: true,
|
||||
},
|
||||
{
|
||||
field: {
|
||||
isCnameVerified: true,
|
||||
},
|
||||
title: 'CNAME Valid',
|
||||
type: FieldType.Boolean,
|
||||
isFilterable: true,
|
||||
tooltipText: (item: StatusPageDomain): string => {
|
||||
if (item['isCnameVerified']) {
|
||||
return 'We have verified your CNAME record.';
|
||||
}
|
||||
return `Please add a new CNAME record to your domain ${item['fullDomain']}. It should look like CNAME ${item['fullDomain']} ${StatusPageCNameRecord}`;
|
||||
},
|
||||
},
|
||||
{
|
||||
field: {
|
||||
isSslProvisioned: true,
|
||||
},
|
||||
title: 'SSL Provisioned',
|
||||
type: FieldType.Boolean,
|
||||
isFilterable: true,
|
||||
tooltipText: (_item: StatusPageDomain): string => {
|
||||
return 'This will happen automatically after CNAME is verified. Please allow 24 hours for SSL to be provisioned after CNAME is verified. If it does not happen in 24 hours, please contact support.';
|
||||
},
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</Page>
|
||||
|
||||
@@ -1,15 +1,19 @@
|
||||
const path = require("path");
|
||||
const webpack = require("webpack");
|
||||
const dotenv = require('dotenv');
|
||||
const express = require('express');
|
||||
|
||||
const readEnvFile = (pathToFile) => {
|
||||
|
||||
const parsed = dotenv.config({ path: pathToFile }).parsed;
|
||||
|
||||
const env = {};
|
||||
|
||||
for (const key in parsed) {
|
||||
env[key] = JSON.stringify(parsed[key]);
|
||||
}
|
||||
|
||||
|
||||
return env;
|
||||
}
|
||||
|
||||
@@ -18,8 +22,8 @@ module.exports = {
|
||||
mode: "development",
|
||||
output: {
|
||||
filename: "bundle.js",
|
||||
path: path.resolve(__dirname, "dist"),
|
||||
publicPath: "/assets/",
|
||||
path: path.resolve(__dirname, "public", "dist"),
|
||||
publicPath: "/dashboard/dist/",
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['.ts', '.tsx', '.js', '.jsx', '.json', '.css', '.scss'],
|
||||
@@ -56,7 +60,7 @@ module.exports = {
|
||||
use: ['style-loader', 'css-loader']
|
||||
},
|
||||
{
|
||||
test: /\.(jpe?g|png|gif|svg)$/i,
|
||||
test: /\.(jpe?g|png|gif|svg)$/i,
|
||||
loader: 'file-loader'
|
||||
}
|
||||
],
|
||||
@@ -66,6 +70,11 @@ module.exports = {
|
||||
devMiddleware: {
|
||||
writeToDisk: true,
|
||||
},
|
||||
allowedHosts: "all",
|
||||
setupMiddlewares: (middlewares, devServer) => {
|
||||
devServer.app.use('/dashboard/assets', express.static(path.resolve(__dirname, 'public', 'assets')));
|
||||
return middlewares;
|
||||
}
|
||||
},
|
||||
devtool: 'eval-source-map',
|
||||
}
|
||||
20540
DashboardAPI/package-lock.json
generated
20540
DashboardAPI/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -43,7 +43,7 @@ npm run logs-dev accounts
|
||||
## Running on: on-prem, staging, or production.
|
||||
|
||||
### Running with Docker Compose:
|
||||
- Run `docker-compose up`
|
||||
- Run `docker compose up`
|
||||
|
||||
### Running with Kubernetes and Helm
|
||||
- Please check `README.md` in the `HelmChart` folder.
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
# oneuptime-gl-manager
|
||||
|
||||
Manages SSL Certificate issuance and renewal for [Greenlock](https://git.rootprojects.org/root/greenlock-manager.js) on [OneUptime](https://oneuptime.com) platform.
|
||||
|
||||
Saves global and per-site config to a local File Sytem (current).
|
||||
|
||||
## Install
|
||||
|
||||
```bash
|
||||
npm install --save oneuptime-gl-manager
|
||||
```
|
||||
|
||||
# Usage
|
||||
|
||||
## Initialize the Manager
|
||||
|
||||
```js
|
||||
Greenlock.create({
|
||||
...
|
||||
manager: "oneuptime-gl-manager",
|
||||
configDir: "./greenlock.d",
|
||||
packageRoot: __dirname
|
||||
...
|
||||
});
|
||||
```
|
||||
|
||||
# Site Management
|
||||
|
||||
By "site" we mean a primary domain and, optionally, secondary domains, to be listed on an ssl certificate,
|
||||
along with any configuration that is necessary for getting and renewing those certificates.
|
||||
|
||||
## Add a sites - domains and SSL certificates
|
||||
|
||||
```js
|
||||
greenlock.add({
|
||||
subject: 'example.com',
|
||||
altnames: ['example.com', 'www.example.com'],
|
||||
});
|
||||
```
|
||||
|
||||
## View site config
|
||||
|
||||
```js
|
||||
greenlock.get({
|
||||
servername: 'www.example.com',
|
||||
wildname: '*.example.com',
|
||||
});
|
||||
```
|
||||
|
||||
## Update site config
|
||||
|
||||
```js
|
||||
greenlock.update({
|
||||
subject: 'www.example.com',
|
||||
challenges: {
|
||||
'dns-01': {
|
||||
module: 'acme-dns-01-ovh',
|
||||
token: 'xxxx',
|
||||
},
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
## Remove a site
|
||||
|
||||
To stop automatic renewal of SSL certificates for a particular site.
|
||||
You to restart renewal you must use `add()`.
|
||||
|
||||
```js
|
||||
greenlock.remove({
|
||||
subject: 'example.com',
|
||||
});
|
||||
```
|
||||
@@ -1,141 +0,0 @@
|
||||
import axios from 'axios';
|
||||
const BASE_URL: string = `${process.env['BACKEND_PROTOCOL']}://${process.env['ONEUPTIME_HOST']}`;
|
||||
|
||||
const Manager: $TSFixMe = module.exports;
|
||||
|
||||
//eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
Manager.create = function (_opts: $TSFixMe): void {
|
||||
const manager: $TSFixMe = {};
|
||||
|
||||
/*
|
||||
*
|
||||
* REQUIRED (basic issuance)
|
||||
*
|
||||
*/
|
||||
|
||||
manager.get = async function ({ servername }: $TSFixMe): void {
|
||||
const url: string = `${BASE_URL}/api/manager/site?servername=${servername}`;
|
||||
const response: $TSFixMe = await axios({
|
||||
url,
|
||||
method: 'get',
|
||||
});
|
||||
|
||||
return response.data;
|
||||
};
|
||||
|
||||
/*
|
||||
*
|
||||
* REQUIRED (basic issuance)
|
||||
*
|
||||
*/
|
||||
|
||||
manager.set = async function (opts: $TSFixMe): void {
|
||||
const url: string = `${BASE_URL}/api/manager/site?subject=${opts.subject}`;
|
||||
const response: $TSFixMe = await axios({
|
||||
url,
|
||||
method: 'put',
|
||||
data: opts,
|
||||
});
|
||||
|
||||
return response.data;
|
||||
};
|
||||
|
||||
/*
|
||||
*
|
||||
* Optional (Fully Automatic Renewal)
|
||||
*
|
||||
*/
|
||||
|
||||
manager.find = async function (opts: $TSFixMe): void {
|
||||
// { subject, servernames, altnames, renewBefore }
|
||||
if (opts.subject) {
|
||||
const url: string = `${BASE_URL}/api/manager/site?subject=${opts.subject}`;
|
||||
const response: $TSFixMe = await axios({
|
||||
url,
|
||||
method: 'get',
|
||||
});
|
||||
if (!response.data || response.data.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return [response.data];
|
||||
}
|
||||
|
||||
if (Array.isArray(opts.servernames) && opts.servernames.length > 0) {
|
||||
const url: string = `${BASE_URL}/api/manager/site/servernames`;
|
||||
const response: $TSFixMe = await axios({
|
||||
url,
|
||||
method: 'post',
|
||||
data: opts.servernames,
|
||||
});
|
||||
|
||||
return response.data;
|
||||
}
|
||||
|
||||
// I.e. find certs more than 30 days old as default
|
||||
opts.issuedBefore =
|
||||
opts.issuedBefore || Date.now() - 30 * 24 * 60 * 60 * 1000;
|
||||
// I.e. find certs that will expire in less than 45 days as default
|
||||
opts.expiresBefore =
|
||||
opts.expiresBefore || Date.now() + 45 * 24 * 60 * 60 * 1000;
|
||||
// I.e. find certs that should be renewed within 21 days as default
|
||||
opts.renewBefore =
|
||||
opts.renewBefore || Date.now() + 21 * 24 * 60 * 60 * 1000;
|
||||
|
||||
const url: string = `${BASE_URL}/api/manager/site/opts`;
|
||||
const response: $TSFixMe = await axios({
|
||||
url,
|
||||
method: 'post',
|
||||
data: opts,
|
||||
});
|
||||
|
||||
return response.data;
|
||||
};
|
||||
|
||||
/*
|
||||
*
|
||||
* Optional (Special Remove Functionality)
|
||||
* The default behavior is to set `deletedAt`
|
||||
*
|
||||
*/
|
||||
|
||||
manager.remove = async function (opts: $TSFixMe): void {
|
||||
const url: string = `${BASE_URL}/api/manager/site?subject=${opts.subject}`;
|
||||
const response: $TSFixMe = await axios({
|
||||
url,
|
||||
method: 'delete',
|
||||
});
|
||||
|
||||
return response.data;
|
||||
};
|
||||
|
||||
/*
|
||||
*
|
||||
* Optional (special settings save)
|
||||
* Implemented here because this module IS the fallback
|
||||
* This is a setter/getter function
|
||||
*
|
||||
*/
|
||||
|
||||
manager.defaults = async function (opts: $TSFixMe): void {
|
||||
if (!opts) {
|
||||
const url: string = `${BASE_URL}/api/manager/default`;
|
||||
const response: $TSFixMe = await axios({
|
||||
url,
|
||||
method: 'get',
|
||||
});
|
||||
return response.data ? response.data : {};
|
||||
}
|
||||
|
||||
const url: string = `${BASE_URL}/api/manager/default`;
|
||||
const response: $TSFixMe = await axios({
|
||||
url,
|
||||
method: 'put',
|
||||
data: opts,
|
||||
});
|
||||
|
||||
return response.data || {};
|
||||
};
|
||||
|
||||
return manager;
|
||||
};
|
||||
58
GlManager/package-lock.json
generated
58
GlManager/package-lock.json
generated
@@ -1,58 +0,0 @@
|
||||
{
|
||||
"name": "oneuptime-gl-manager",
|
||||
"version": "3.0.0",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "oneuptime-gl-manager",
|
||||
"version": "3.0.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"axios": "^0.26.1"
|
||||
}
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "0.26.1",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz",
|
||||
"integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.14.8"
|
||||
}
|
||||
},
|
||||
"node_modules/follow-redirects": {
|
||||
"version": "1.14.9",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz",
|
||||
"integrity": "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://github.com/sponsors/RubenVerborgh"
|
||||
}
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=4.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"debug": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": {
|
||||
"version": "0.26.1",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz",
|
||||
"integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==",
|
||||
"requires": {
|
||||
"follow-redirects": "^1.14.8"
|
||||
}
|
||||
},
|
||||
"follow-redirects": {
|
||||
"version": "1.14.9",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz",
|
||||
"integrity": "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w=="
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
{
|
||||
"name": "oneuptime-gl-manager",
|
||||
"version": "3.0.0",
|
||||
"description": "FileSytem-based Manager with optional encrypted Cloud backup for Greenlock SSL",
|
||||
"main": "manager.js",
|
||||
"files": [
|
||||
"*.js"
|
||||
],
|
||||
"scripts": {
|
||||
"test": "node tests"
|
||||
},
|
||||
"keywords": [
|
||||
"greenlock",
|
||||
"manager",
|
||||
"cloud",
|
||||
"fs",
|
||||
"ssl",
|
||||
"oneuptime"
|
||||
],
|
||||
"author": "OneUptime Limited. <hello@oneuptime.com>",
|
||||
"contributors": [
|
||||
"OneUptime Limited. <hello@oneuptime.com>"
|
||||
],
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"axios": "^0.26.1"
|
||||
}
|
||||
}
|
||||
@@ -1,110 +0,0 @@
|
||||
{
|
||||
"ts-node": {
|
||||
// these options are overrides used only by ts-node
|
||||
// same as the --compilerOptions flag and the TS_NODE_COMPILER_OPTIONS environment variable
|
||||
"compilerOptions": {
|
||||
"module": "commonjs"
|
||||
}
|
||||
},
|
||||
"compilerOptions": {
|
||||
/* Visit https://aka.ms/tsconfig.json to read more about this file */
|
||||
|
||||
/* Projects */
|
||||
// "incremental": true, /* Enable incremental compilation */
|
||||
// "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
|
||||
// "tsBuildInfoFile": "./", /* Specify the folder for .tsbuildinfo incremental compilation files. */
|
||||
// "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects */
|
||||
// "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
|
||||
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
|
||||
|
||||
/* Language and Environment */
|
||||
"target": "es2017" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
|
||||
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
|
||||
"jsx": "react" /* Specify what JSX code is generated. */,
|
||||
"experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */
|
||||
"emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
|
||||
// "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h' */
|
||||
// "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
|
||||
// "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using `jsx: react-jsx*`.` */
|
||||
// "reactNamespace": "", /* Specify the object invoked for `createElement`. This only applies when targeting `react` JSX emit. */
|
||||
// "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
|
||||
// "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
|
||||
|
||||
/* Modules */
|
||||
// "module": "es2022" /* Specify what module code is generated. */,
|
||||
// "rootDir": "./", /* Specify the root folder within your source files. */
|
||||
"moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */
|
||||
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
|
||||
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
|
||||
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
|
||||
"typeRoots": [
|
||||
|
||||
], /* Specify multiple folders that act like `./node_modules/@types`. */
|
||||
"types": ["node"], /* Specify type package names to be included without being referenced in a source file. */
|
||||
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
|
||||
// "resolveJsonModule": true, /* Enable importing .json files */
|
||||
// "noResolve": true, /* Disallow `import`s, `require`s or `<reference>`s from expanding the number of files TypeScript should add to a project. */
|
||||
|
||||
/* JavaScript Support */
|
||||
// "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */
|
||||
// "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
|
||||
// "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */
|
||||
|
||||
/* Emit */
|
||||
// "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
|
||||
// "declarationMap": true, /* Create sourcemaps for d.ts files. */
|
||||
// "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
|
||||
"sourceMap": true, /* Create source map files for emitted JavaScript files. */
|
||||
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */
|
||||
"outDir": "./build/dist", /* Specify an output folder for all emitted files. */
|
||||
// "removeComments": true, /* Disable emitting comments. */
|
||||
// "noEmit": true, /* Disable emitting files from a compilation. */
|
||||
// "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
|
||||
// "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types */
|
||||
// "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
|
||||
// "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
|
||||
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
|
||||
// "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
|
||||
// "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
|
||||
// "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
|
||||
// "newLine": "crlf", /* Set the newline character for emitting files. */
|
||||
// "stripInternal": true, /* Disable emitting declarations that have `@internal` in their JSDoc comments. */
|
||||
// "noEmitHelpers": true, /* Disable generating custom helper functions like `__extends` in compiled output. */
|
||||
// "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
|
||||
// "preserveConstEnums": true, /* Disable erasing `const enum` declarations in generated code. */
|
||||
// "declarationDir": "./", /* Specify the output directory for generated declaration files. */
|
||||
// "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
|
||||
|
||||
/* Interop Constraints */
|
||||
// "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
|
||||
// "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
|
||||
"esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */,
|
||||
// "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
|
||||
"forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */,
|
||||
|
||||
/* Type Checking */
|
||||
"strict": true /* Enable all strict type-checking options. */,
|
||||
"noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied `any` type.. */
|
||||
"strictNullChecks": true, /* When type checking, take into account `null` and `undefined`. */
|
||||
"strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
|
||||
"strictBindCallApply": true, /* Check that the arguments for `bind`, `call`, and `apply` methods match the original function. */
|
||||
"strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
|
||||
"noImplicitThis": true, /* Enable error reporting when `this` is given the type `any`. */
|
||||
"useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */
|
||||
"alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
|
||||
"noUnusedLocals": true, /* Enable error reporting when a local variables aren't read. */
|
||||
"noUnusedParameters": true, /* Raise an error when a function parameter isn't read */
|
||||
"exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
|
||||
"noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
|
||||
"noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
|
||||
"noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */
|
||||
"noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
|
||||
"noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type */
|
||||
// "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
|
||||
// "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
|
||||
|
||||
/* Completeness */
|
||||
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
|
||||
"skipLibCheck": true /* Skip type checking all .d.ts files. */
|
||||
}
|
||||
}
|
||||
@@ -414,6 +414,7 @@ router.post(
|
||||
email: true,
|
||||
isMasterAdmin: true,
|
||||
isEmailVerified: true,
|
||||
profilePictureId: true,
|
||||
},
|
||||
props: {
|
||||
isRoot: true,
|
||||
|
||||
1
LetsEncyptStore/.gitignore
vendored
1
LetsEncyptStore/.gitignore
vendored
@@ -1 +0,0 @@
|
||||
/node_modules
|
||||
@@ -1,19 +0,0 @@
|
||||
# oneuptime-le-store Package for Greenlock
|
||||
|
||||
This module implements a dead-simple, api call to OneUptime backend to store account or certificate details. This allows us to persist our [Let's Encrypt](https://letsencrypt.org/) data in mongo for automated TLS certificate issuance and use.
|
||||
|
||||
## Install
|
||||
|
||||
npm install oneuptime-le-store
|
||||
|
||||
## Usage
|
||||
|
||||
// make sure greenlock is already installed
|
||||
import Greenlock from 'greenlock'
|
||||
|
||||
Greenlock.create({
|
||||
store: {
|
||||
module: 'oneuptime-le-store',
|
||||
},
|
||||
// ...
|
||||
});
|
||||
@@ -1,143 +0,0 @@
|
||||
import axios from 'axios';
|
||||
const BASE_URL: string = `${process.env['BACKEND_PROTOCOL']}://${process.env['ONEUPTIME_HOST']}`;
|
||||
|
||||
/*
|
||||
* Make api call to designated endpoints
|
||||
* To make the necessary updates to the db
|
||||
*/
|
||||
module.exports.create = function (config: $TSFixMe): void {
|
||||
const store: $TSFixMe = {};
|
||||
|
||||
store.options = config;
|
||||
|
||||
store.accounts = {
|
||||
setKeypair: function (opts: $TSFixMe): void {
|
||||
const id: $TSFixMe =
|
||||
(opts.account && opts.account.id) || opts.email || 'default';
|
||||
|
||||
const url: string = `${BASE_URL}/api/account/store/${id}`;
|
||||
const data: $TSFixMe = {
|
||||
id: id,
|
||||
privateKeyPem: opts.keypair.privateKeyPem,
|
||||
privateKeyJwk: opts.keypair.privateKeyJwk,
|
||||
publickKeyPem: opts.keypair.publickeyPem,
|
||||
publicKeyJwk: opts.keypair.publicKeyJwk,
|
||||
key: opts.keypair.key,
|
||||
};
|
||||
return axios({
|
||||
url,
|
||||
method: 'put',
|
||||
data,
|
||||
})
|
||||
.then((res: $TSFixMe) => {
|
||||
return res.data;
|
||||
})
|
||||
.finally(() => {
|
||||
return null;
|
||||
});
|
||||
},
|
||||
checkKeypair: function (opts: $TSFixMe): void {
|
||||
const id: $TSFixMe =
|
||||
(opts.account && opts.account.id) || opts.email || 'default';
|
||||
|
||||
const url: string = `${BASE_URL}/api/account/store/${id}`;
|
||||
return axios({
|
||||
url,
|
||||
method: 'get',
|
||||
})
|
||||
.then((res: $TSFixMe) => {
|
||||
return res.data;
|
||||
})
|
||||
.finally(() => {
|
||||
return null;
|
||||
});
|
||||
},
|
||||
options: config,
|
||||
};
|
||||
|
||||
store.certificates = {
|
||||
setKeypair: function (opts: $TSFixMe): void {
|
||||
const id: $TSFixMe =
|
||||
(opts.certificate &&
|
||||
(opts.certificate.kid || opts.certificate.id)) ||
|
||||
opts.subject;
|
||||
|
||||
const url: string = `${BASE_URL}/api/certificate/store/${id}`;
|
||||
const data: $TSFixMe = {
|
||||
id: id,
|
||||
deleted: false,
|
||||
...opts.keypair,
|
||||
};
|
||||
return axios({
|
||||
url,
|
||||
method: 'put',
|
||||
data,
|
||||
})
|
||||
.then((res: $TSFixMe) => {
|
||||
return res.data;
|
||||
})
|
||||
.finally(() => {
|
||||
return null;
|
||||
});
|
||||
},
|
||||
checkKeypair: function (opts: $TSFixMe): void {
|
||||
const id: $TSFixMe =
|
||||
(opts.certificate &&
|
||||
(opts.certificate.kid || opts.certificate.id)) ||
|
||||
opts.subject;
|
||||
|
||||
const url: string = `${BASE_URL}/api/certificate/store/${id}`;
|
||||
return axios({
|
||||
url,
|
||||
method: 'get',
|
||||
})
|
||||
.then((res: $TSFixMe) => {
|
||||
return res.data;
|
||||
})
|
||||
.finally(() => {
|
||||
return null;
|
||||
});
|
||||
},
|
||||
set: function (opts: $TSFixMe): void {
|
||||
const id: $TSFixMe =
|
||||
(opts.certificate && opts.certificate.id) || opts.subject;
|
||||
|
||||
const url: string = `${BASE_URL}/api/certificate/store/${id}`;
|
||||
const data: $TSFixMe = {
|
||||
id: id,
|
||||
deleted: false,
|
||||
...opts.pems,
|
||||
};
|
||||
return axios({
|
||||
url,
|
||||
method: 'put',
|
||||
data,
|
||||
})
|
||||
.then((res: $TSFixMe) => {
|
||||
return res.data;
|
||||
})
|
||||
.finally(() => {
|
||||
return null;
|
||||
});
|
||||
},
|
||||
check: function (opts: $TSFixMe): void {
|
||||
const id: $TSFixMe =
|
||||
(opts.certificate && opts.certificate.id) || opts.subject;
|
||||
|
||||
const url: string = `${BASE_URL}/api/certificate/store/${id}`;
|
||||
return axios({
|
||||
url,
|
||||
method: 'get',
|
||||
})
|
||||
.then((res: $TSFixMe) => {
|
||||
return res.data;
|
||||
})
|
||||
.finally(() => {
|
||||
return null;
|
||||
});
|
||||
},
|
||||
options: config,
|
||||
};
|
||||
|
||||
return store;
|
||||
};
|
||||
58
LetsEncyptStore/package-lock.json
generated
58
LetsEncyptStore/package-lock.json
generated
@@ -1,58 +0,0 @@
|
||||
{
|
||||
"name": "oneuptime-le-store",
|
||||
"version": "3.0.0",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "oneuptime-le-store",
|
||||
"version": "3.0.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"axios": "^0.26.1"
|
||||
}
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "0.26.1",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz",
|
||||
"integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.14.8"
|
||||
}
|
||||
},
|
||||
"node_modules/follow-redirects": {
|
||||
"version": "1.14.9",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz",
|
||||
"integrity": "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://github.com/sponsors/RubenVerborgh"
|
||||
}
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=4.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"debug": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": {
|
||||
"version": "0.26.1",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz",
|
||||
"integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==",
|
||||
"requires": {
|
||||
"follow-redirects": "^1.14.8"
|
||||
}
|
||||
},
|
||||
"follow-redirects": {
|
||||
"version": "1.14.9",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz",
|
||||
"integrity": "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w=="
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
{
|
||||
"name": "oneuptime-le-store",
|
||||
"version": "3.0.0",
|
||||
"description": "Greenlock store module ported for OneUptime",
|
||||
"main": "index.ts",
|
||||
"keywords": [
|
||||
"le-store",
|
||||
"greenlock",
|
||||
"letsencrypt",
|
||||
"mongodb",
|
||||
"mongo",
|
||||
"oneuptime"
|
||||
],
|
||||
"author": "OneUptime Limited. <hello@oneuptime.com>",
|
||||
"contributors": [
|
||||
"OneUptime Limited. <hello@oneuptime.com>"
|
||||
],
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"axios": "^0.26.1"
|
||||
}
|
||||
}
|
||||
@@ -1,110 +0,0 @@
|
||||
{
|
||||
"ts-node": {
|
||||
// these options are overrides used only by ts-node
|
||||
// same as the --compilerOptions flag and the TS_NODE_COMPILER_OPTIONS environment variable
|
||||
"compilerOptions": {
|
||||
"module": "commonjs"
|
||||
}
|
||||
},
|
||||
"compilerOptions": {
|
||||
/* Visit https://aka.ms/tsconfig.json to read more about this file */
|
||||
|
||||
/* Projects */
|
||||
// "incremental": true, /* Enable incremental compilation */
|
||||
// "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
|
||||
// "tsBuildInfoFile": "./", /* Specify the folder for .tsbuildinfo incremental compilation files. */
|
||||
// "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects */
|
||||
// "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
|
||||
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
|
||||
|
||||
/* Language and Environment */
|
||||
"target": "es2017" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
|
||||
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
|
||||
"jsx": "react" /* Specify what JSX code is generated. */,
|
||||
"experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */
|
||||
"emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
|
||||
// "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h' */
|
||||
// "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
|
||||
// "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using `jsx: react-jsx*`.` */
|
||||
// "reactNamespace": "", /* Specify the object invoked for `createElement`. This only applies when targeting `react` JSX emit. */
|
||||
// "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
|
||||
// "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
|
||||
|
||||
/* Modules */
|
||||
// "module": "es2022" /* Specify what module code is generated. */,
|
||||
// "rootDir": "./", /* Specify the root folder within your source files. */
|
||||
"moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */
|
||||
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
|
||||
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
|
||||
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
|
||||
"typeRoots": [
|
||||
|
||||
], /* Specify multiple folders that act like `./node_modules/@types`. */
|
||||
"types": ["node"], /* Specify type package names to be included without being referenced in a source file. */
|
||||
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
|
||||
// "resolveJsonModule": true, /* Enable importing .json files */
|
||||
// "noResolve": true, /* Disallow `import`s, `require`s or `<reference>`s from expanding the number of files TypeScript should add to a project. */
|
||||
|
||||
/* JavaScript Support */
|
||||
// "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */
|
||||
// "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
|
||||
// "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */
|
||||
|
||||
/* Emit */
|
||||
// "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
|
||||
// "declarationMap": true, /* Create sourcemaps for d.ts files. */
|
||||
// "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
|
||||
"sourceMap": true, /* Create source map files for emitted JavaScript files. */
|
||||
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */
|
||||
"outDir": "./build/dist", /* Specify an output folder for all emitted files. */
|
||||
// "removeComments": true, /* Disable emitting comments. */
|
||||
// "noEmit": true, /* Disable emitting files from a compilation. */
|
||||
// "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
|
||||
// "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types */
|
||||
// "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
|
||||
// "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
|
||||
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
|
||||
// "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
|
||||
// "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
|
||||
// "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
|
||||
// "newLine": "crlf", /* Set the newline character for emitting files. */
|
||||
// "stripInternal": true, /* Disable emitting declarations that have `@internal` in their JSDoc comments. */
|
||||
// "noEmitHelpers": true, /* Disable generating custom helper functions like `__extends` in compiled output. */
|
||||
// "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
|
||||
// "preserveConstEnums": true, /* Disable erasing `const enum` declarations in generated code. */
|
||||
// "declarationDir": "./", /* Specify the output directory for generated declaration files. */
|
||||
// "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
|
||||
|
||||
/* Interop Constraints */
|
||||
// "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
|
||||
// "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
|
||||
"esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */,
|
||||
// "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
|
||||
"forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */,
|
||||
|
||||
/* Type Checking */
|
||||
"strict": true /* Enable all strict type-checking options. */,
|
||||
"noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied `any` type.. */
|
||||
"strictNullChecks": true, /* When type checking, take into account `null` and `undefined`. */
|
||||
"strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
|
||||
"strictBindCallApply": true, /* Check that the arguments for `bind`, `call`, and `apply` methods match the original function. */
|
||||
"strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
|
||||
"noImplicitThis": true, /* Enable error reporting when `this` is given the type `any`. */
|
||||
"useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */
|
||||
"alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
|
||||
"noUnusedLocals": true, /* Enable error reporting when a local variables aren't read. */
|
||||
"noUnusedParameters": true, /* Raise an error when a function parameter isn't read */
|
||||
"exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
|
||||
"noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
|
||||
"noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
|
||||
"noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */
|
||||
"noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
|
||||
"noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type */
|
||||
// "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
|
||||
// "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
|
||||
|
||||
/* Completeness */
|
||||
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
|
||||
"skipLibCheck": true /* Skip type checking all .d.ts files. */
|
||||
}
|
||||
}
|
||||
595
Mail/Templates/EmailChanged.hbs
Normal file
595
Mail/Templates/EmailChanged.hbs
Normal file
@@ -0,0 +1,595 @@
|
||||
<!DOCTYPE html
|
||||
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
|
||||
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=3Dutf-8">
|
||||
<meta name="viewport" content="width=3Ddevice-width">
|
||||
<title>You have changed your email.</title>
|
||||
<style>
|
||||
/**
|
||||
* IMPORTANT:
|
||||
* Please read before changing anything, CSS involved in our HTML emails is
|
||||
* extremely specific and written a certain way for a reason. It might not make
|
||||
* sense in a normal setting but Outlook loves it this way.
|
||||
*
|
||||
* !!! [override] prevents Yahoo Mail breaking media queries. It must be used
|
||||
* !!! at the beginning of every line of CSS inside a media query.
|
||||
* !!! Do not remove.
|
||||
*
|
||||
* !!! div[style*="margin: 16px 0"] allows us to target a weird margin
|
||||
* !!! bug in Android's email client.
|
||||
* !!! Do not remove.
|
||||
*
|
||||
* Also, the img files are hosted on S3. Please don't break these URLs!
|
||||
* The images are also versioned by date, so please update the URLs accordingly
|
||||
* if you create new versions
|
||||
*
|
||||
***/
|
||||
|
||||
|
||||
/**
|
||||
* # Root
|
||||
* - CSS resets and general styles go here.
|
||||
**/
|
||||
|
||||
html,
|
||||
body,
|
||||
a,
|
||||
span,
|
||||
div[style*="margin: 16px 0"] {
|
||||
border: 0 !important;
|
||||
margin: 0 !important;
|
||||
outline: 0 !important;
|
||||
padding: 0 !important;
|
||||
text-decoration: none !important;
|
||||
}
|
||||
|
||||
a,
|
||||
span,
|
||||
td,
|
||||
th {
|
||||
-webkit-font-smoothing: antialiased !important;
|
||||
-moz-osx-font-smoothing: grayscale !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* # Delink
|
||||
* - Classes for overriding clients which creates links out of things like
|
||||
* emails, addresses, phone numbers, etc.
|
||||
**/
|
||||
|
||||
span.st-Delink a {
|
||||
color: #000000 !important;
|
||||
text-decoration: none !important;
|
||||
}
|
||||
|
||||
/** Modifier: preheader */
|
||||
span.st-Delink.st-Delink--preheader a {
|
||||
color: white !important;
|
||||
text-decoration: none !important;
|
||||
}
|
||||
|
||||
/** */
|
||||
|
||||
/** Modifier: title */
|
||||
span.st-Delink.st-Delink--title a {
|
||||
color: #000000 !important;
|
||||
text-decoration: none !important;
|
||||
}
|
||||
|
||||
/** */
|
||||
|
||||
/** Modifier: footer */
|
||||
span.st-Delink.st-Delink--footer a {
|
||||
color: #8898aa !important;
|
||||
text-decoration: none !important;
|
||||
}
|
||||
|
||||
/** */
|
||||
|
||||
.ii a[href] {
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
/**
|
||||
* # Mobile
|
||||
* - This affects emails views in clients less than 600px wide.
|
||||
**/
|
||||
|
||||
@media all and (max-width: 600px) {
|
||||
|
||||
/**
|
||||
* # Wrapper
|
||||
**/
|
||||
|
||||
body[override] table.st-Wrapper,
|
||||
body[override] table.st-Width.st-Width--mobile {
|
||||
min-width: 100% !important;
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* # Spacer
|
||||
**/
|
||||
|
||||
/** Modifier: gutter */
|
||||
body[override] td.st-Spacer.st-Spacer--gutter {
|
||||
width: 32px !important;
|
||||
}
|
||||
|
||||
/** */
|
||||
|
||||
/** Modifier: kill */
|
||||
body[override] td.st-Spacer.st-Spacer--kill {
|
||||
width: 0 !important;
|
||||
}
|
||||
|
||||
/** */
|
||||
|
||||
/** Modifier: emailEnd */
|
||||
body[override] td.st-Spacer.st-Spacer--emailEnd {
|
||||
height: 32px !important;
|
||||
}
|
||||
|
||||
/** */
|
||||
|
||||
/**
|
||||
* # Font
|
||||
**/
|
||||
|
||||
/** Modifier: title */
|
||||
body[override] td.st-Font.st-Font--title,
|
||||
body[override] td.st-Font.st-Font--title span,
|
||||
body[override] td.st-Font.st-Font--title a {
|
||||
font-size: 28px !important;
|
||||
line-height: 36px !important;
|
||||
}
|
||||
|
||||
/** */
|
||||
|
||||
/** Modifier: header */
|
||||
body[override] td.st-Font.st-Font--header,
|
||||
body[override] td.st-Font.st-Font--header span,
|
||||
body[override] td.st-Font.st-Font--header a {
|
||||
font-size: 24px !important;
|
||||
line-height: 32px !important;
|
||||
}
|
||||
|
||||
/** */
|
||||
|
||||
/** Modifier: body */
|
||||
body[override] td.st-Font.st-Font--body,
|
||||
body[override] td.st-Font.st-Font--body span,
|
||||
body[override] td.st-Font.st-Font--body a {
|
||||
font-size: 18px !important;
|
||||
line-height: 28px !important;
|
||||
}
|
||||
|
||||
/** */
|
||||
|
||||
/** Modifier: caption */
|
||||
body[override] td.st-Font.st-Font--caption,
|
||||
body[override] td.st-Font.st-Font--caption span,
|
||||
body[override] td.st-Font.st-Font--caption a {
|
||||
font-size: 14px !important;
|
||||
line-height: 20px !important;
|
||||
}
|
||||
|
||||
/** */
|
||||
|
||||
/** Modifier: simplified */
|
||||
body[override] table.st-Header.st-Header--simplified td.st-Header-logo {
|
||||
width: auto !important;
|
||||
}
|
||||
|
||||
body[override] table.st-Header.st-Header--simplified td.st-Header-spacing {
|
||||
width: 0 !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* # Divider
|
||||
**/
|
||||
|
||||
body[override] table.st-Divider td.st-Spacer.st-Spacer--gutter,
|
||||
body[override] tr.st-Divider td.st-Spacer.st-Spacer--gutter {
|
||||
background-color: #000000;
|
||||
}
|
||||
|
||||
/**
|
||||
* # Blocks
|
||||
**/
|
||||
|
||||
body[override] table.st-Blocks table.st-Blocks-inner {
|
||||
border-radius: 0 !important;
|
||||
}
|
||||
|
||||
body[override] table.st-Blocks table.st-Blocks-inner table.st-Blocks-item td.st-Blocks-item-cell {
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* # Button
|
||||
**/
|
||||
|
||||
body[override] table.st-Button {
|
||||
margin: 0 auto !important;
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
body[override] table.st-Button td.st-Button-area,
|
||||
body[override] table.st-Button td.st-Button-area a.st-Button-link,
|
||||
body[override] table.st-Button td.st-Button-area span.st-Button-internal {
|
||||
height: 44px !important;
|
||||
line-height: 44px !important;
|
||||
font-size: 18px !important;
|
||||
vertical-align: middle !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body class="st-Email" bgcolor="f7f7f7"
|
||||
style="border: 0; margin: 0; padding: 0; -webkit-text-size-adjust: 100%; -ms-text-size-adjust: 100%; min-width: 100%; width: 100%;"
|
||||
override="fix">
|
||||
|
||||
<!-- Background -->
|
||||
<table class="st-Background" bgcolor="f7f7f7" border="0" cellpadding="0" cellspacing="0" width="100%"
|
||||
style="border: 0; margin: 0; padding: 0;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="border: 0; margin: 0; padding: 0;">
|
||||
|
||||
<!-- Wrapper -->
|
||||
<table class="st-Wrapper" align="center" bgcolor="ffffff" border="0" cellpadding="0" cellspacing="0"
|
||||
width="600"
|
||||
style="border-bottom-left-radius: 5px; border-bottom-right-radius: 5px; margin: 0 auto; min-width: 600px;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="border: 0; margin: 0; padding: 0;">
|
||||
|
||||
|
||||
|
||||
<table class="st-Header st-Header--simplified st-Width st-Width--mobile" border="0" cellpadding="0"
|
||||
cellspacing="0" width="600" style="min-width: 600px;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="st-Spacer st-Spacer--divider" colspan="4" height="19"
|
||||
style="border: 0; margin: 0; padding: 0; font-size: 1px; line-height: 1px; mso-line-height-rule: exactly;">
|
||||
<div class="st-Spacer st-Spacer--filler"></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="st-Spacer st-Spacer--gutter"
|
||||
style="border: 0; margin:0; padding: 0; font-size: 1px; line-height: 1px; mso-line-height-rule: exactly;"
|
||||
width="64">
|
||||
<div class="st-Spacer st-Spacer--filler"></div>
|
||||
</td>
|
||||
<td align="left" style="height:80px; border: 0; margin: 0; padding: 0;">
|
||||
<div>
|
||||
<a style="border: 0; margin: 0; padding: 0; text-decoration: none;" href={{homeURL}}>
|
||||
|
||||
<img alt="OneUptime" border="0"
|
||||
style="height:70px; width:70px; border: 0; margin: 0; padding: 0; color: #000000; display: block; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Ubuntu, sans-serif; font-size: 12px; font-weight: normal;"
|
||||
src="https://res.cloudinary.com/deityhub/image/upload/v1637736803/1png.png">
|
||||
</a>
|
||||
</div>
|
||||
</td>
|
||||
<td class="st-Header-spacing" width="423" style="border: 0; margin: 0; padding: 0;">
|
||||
<div class="st-Spacer st-Spacer--filler"></div>
|
||||
</td>
|
||||
<td class="st-Spacer st-Spacer--gutter"
|
||||
style="border: 0; margin:0; padding: 0; font-size: 1px; line-height: 1px; mso-line-height-rule: exactly;"
|
||||
width="64">
|
||||
<div class="st-Spacer st-Spacer--filler"></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="st-Spacer st-Spacer--divider" colspan="4" height="19"
|
||||
style="border: 0; margin: 0; padding: 0; font-size: 1px; line-height: 1px; mso-line-height-rule: exactly;">
|
||||
<div class="st-Spacer st-Spacer--filler"></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="st-Divider">
|
||||
<td class="st-Spacer st-Spacer--gutter"
|
||||
style="border: 0; margin:0; padding: 0; font-size: 1px; line-height: 1px; max-height: 1px; mso-line-height-rule: exactly;"
|
||||
width="64">
|
||||
<div class="st-Spacer st-Spacer--filler"></div>
|
||||
</td>
|
||||
<td bgcolor="#fdfdfd" colspan="2" height="1"
|
||||
style="border: 0; margin: 0; padding: 0; font-size: 1px; line-height: 1px; max-height: 1px; mso-line-height-rule: exactly;">
|
||||
<div class="st-Spacer st-Spacer--filler"></div>
|
||||
</td>
|
||||
<td class="st-Spacer st-Spacer--gutter"
|
||||
style="border: 0; margin:0; padding: 0; font-size: 1px; line-height: 1px; max-height: 1px; mso-line-height-rule: exactly;"
|
||||
width="64">
|
||||
<div class="st-Spacer st-Spacer--filler"></div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table class="st-Copy st-Width st-Width--mobile" border="0" cellpadding="0" cellspacing="0"
|
||||
width="600" style="min-width: 600px;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="st-Spacer st-Spacer--gutter"
|
||||
style="border: 0; margin:0; padding: 0; font-size: 1px; line-height: 1px; mso-line-height-rule: exactly;"
|
||||
width="64">
|
||||
<div class="st-Spacer st-Spacer--filler"></div>
|
||||
</td>
|
||||
<td class="st-Font st-Font--body"
|
||||
style="color: #000000 !important; border:0;margin:0;padding:0; font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,'Helvetica Neue',Ubuntu,sans-serif;font-size:16px;line-height:24px">
|
||||
|
||||
<h3>You have changed your email. Please verify your email.</h3>
|
||||
|
||||
</td>
|
||||
<td class="st-Spacer st-Spacer--gutter"
|
||||
style="border: 0; margin:0; padding: 0; font-size: 1px; line-height: 1px; mso-line-height-rule: exactly;"
|
||||
width="64">
|
||||
<div class="st-Spacer st-Spacer--filler"></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="st-Spacer st-Spacer--stacked" colspan="3" height="12"
|
||||
style="border: 0; margin: 0; padding: 0; font-size: 1px; line-height: 1px; mso-line-height-rule: exactly;">
|
||||
<div class="st-Spacer st-Spacer--filler"></div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table class="st-Copy st-Width st-Width--mobile" border="0" cellpadding="0" cellspacing="0"
|
||||
width="600" style="min-width: 600px;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="st-Spacer st-Spacer--gutter"
|
||||
style="border: 0; margin:0; padding: 0; font-size: 1px; line-height: 1px; mso-line-height-rule: exactly;"
|
||||
width="64">
|
||||
<div class="st-Spacer st-Spacer--filler"></div>
|
||||
</td>
|
||||
|
||||
<td class="st-Font st-Font--body"
|
||||
style="border: 0; margin: 0; padding: 0; color: #000000 !important; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Ubuntu, sans-serif; font-size: 16px; line-height: 24px;">
|
||||
|
||||
|
||||
|
||||
Next step would be to verify your email account. Can you please click on 'Verify Email' button which will help us to get your email verified.
|
||||
|
||||
|
||||
</td>
|
||||
<td class="st-Spacer st-Spacer--gutter"
|
||||
style="border: 0; margin:0; padding: 0; font-size: 1px; line-height: 1px; mso-line-height-rule: exactly;"
|
||||
width="64">
|
||||
<div class="st-Spacer st-Spacer--filler"></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="st-Spacer st-Spacer--stacked" colspan="3" height="12"
|
||||
style="border: 0; margin: 0; padding: 0; font-size: 1px; line-height: 1px; mso-line-height-rule: exactly;">
|
||||
<div class="st-Spacer st-Spacer--filler"></div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table class="st-Copy st-Width st-Width--mobile" border="0" cellpadding="0" cellspacing="0"
|
||||
width="600" style="min-width: 600px;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="st-Spacer st-Spacer--gutter"
|
||||
style="border: 0; margin:0; padding: 0; font-size: 1px; line-height: 1px; mso-line-height-rule: exactly;"
|
||||
width="64">
|
||||
<div class="st-Spacer st-Spacer--filler"></div>
|
||||
</td>
|
||||
<td class="st-Font st-Font--body"
|
||||
style="border: 0; margin: 0; padding: 0; color: #000000; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Ubuntu, sans-serif; font-size: 16px; line-height: 24px;">
|
||||
|
||||
<!-- Button & Modifier: fullWidth -->
|
||||
<table class="st-Button st-Button--fullWidth" border="0" cellpadding="0" cellspacing="0"
|
||||
width="100%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center" class="st-Button-area" height="38" valign="middle"
|
||||
style="border: 0; margin: 0; padding: 0; background-color: #000000; border-radius: 5px; text-align: center;">
|
||||
<a class="st-Button-link"
|
||||
style="border: 0; margin: 0; padding: 0; color: #ffffff; display: block; height: 38px; text-align: center; text-decoration: none;"
|
||||
href={{tokenVerifyUrl}}>
|
||||
<span class="st-Button-internal"
|
||||
style="border: 0; margin: 0; padding: 0; color: #ffffff; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Ubuntu, sans-serif; font-size: 16px; font-weight: bold; height: 38px; line-height: 38px; mso-line-height-rule: exactly; text-decoration: none; vertical-align: middle; white-space: nowrap; width: 100%;">Verify Email</span>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<!-- /Button & Modifier: fullWidth -->
|
||||
|
||||
</td>
|
||||
<td class="st-Spacer st-Spacer--gutter"
|
||||
style="border: 0; margin:0; padding: 0; font-size: 1px; line-height: 1px; mso-line-height-rule: exactly;"
|
||||
width="64">
|
||||
<div class="st-Spacer st-Spacer--filler"></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="st-Spacer st-Spacer--stacked" colspan="3" height="12"
|
||||
style="border: 0; margin: 0; padding: 0; font-size: 1px; line-height: 1px; mso-line-height-rule: exactly;">
|
||||
<div class="st-Spacer st-Spacer--filler"></div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table class="st-Copy st-Width st-Width--mobile" border="0" cellpadding="0" cellspacing="0"
|
||||
width="600" style="min-width: 600px;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="st-Spacer st-Spacer--gutter"
|
||||
style="border: 0; margin:0; padding: 0; font-size: 1px; line-height: 1px; mso-line-height-rule: exactly;"
|
||||
width="64">
|
||||
<div class="st-Spacer st-Spacer--filler"></div>
|
||||
</td>
|
||||
<td class="st-Font st-Font--body link-content"
|
||||
style="border: 0; margin: 0; padding: 0; color: #000000 !important; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Ubuntu, sans-serif; font-size: 16px; line-height: 24px;">
|
||||
|
||||
|
||||
You can also copy and paste this link: {{tokenVerifyUrl}} on any browser of your choice if the button above does not work.<br/><br/><br/>If you have not signed up for the account, please send us an email at <a
|
||||
style="color: #000000; text-decoration: none; font-weight: bold"
|
||||
href="mailto:support@oneuptime.com" target="_blank">support@oneuptime.com</a> and let us
|
||||
know.
|
||||
|
||||
|
||||
</td>
|
||||
<td class="st-Spacer st-Spacer--gutter"
|
||||
style="border: 0; margin:0; padding: 0; font-size: 1px; line-height: 1px; mso-line-height-rule: exactly;"
|
||||
width="64">
|
||||
<div class="st-Spacer st-Spacer--filler"></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="st-Spacer st-Spacer--stacked" colspan="3" height="12"
|
||||
style="border: 0; margin: 0; padding: 0; font-size: 1px; line-height: 1px; mso-line-height-rule: exactly;">
|
||||
<div class="st-Spacer st-Spacer--filler"></div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table class="st-Copy st-Width st-Width--mobile" border="0" cellpadding="0" cellspacing="0"
|
||||
width="600" style="min-width: 600px;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="st-Spacer st-Spacer--gutter"
|
||||
style="border: 0; margin:0; padding: 0; font-size: 1px; line-height: 1px; mso-line-height-rule: exactly;"
|
||||
width="64">
|
||||
<div class="st-Spacer st-Spacer--filler"></div>
|
||||
</td>
|
||||
<td class="st-Font st-Font--body"
|
||||
style="border: 0; margin: 0; padding: 0; color: #000000 !important; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Ubuntu, sans-serif; font-size: 16px; line-height: 24px;">
|
||||
|
||||
|
||||
Thanks, have a great day.
|
||||
|
||||
|
||||
</td>
|
||||
<td class="st-Spacer st-Spacer--gutter"
|
||||
style="border: 0; margin:0; padding: 0; font-size: 1px; line-height: 1px; mso-line-height-rule: exactly;"
|
||||
width="64">
|
||||
<div class="st-Spacer st-Spacer--filler"></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="st-Spacer st-Spacer--stacked" colspan="3" height="12"
|
||||
style="border: 0; margin: 0; padding: 0; font-size: 1px; line-height: 1px; mso-line-height-rule: exactly;">
|
||||
<div class="st-Spacer st-Spacer--filler"></div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table class="st-Copy st-Width st-Width--mobile" border="0" cellpadding="0" cellspacing="0"
|
||||
width="600" style="min-width: 600px;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="st-Spacer st-Spacer--gutter"
|
||||
style="border: 0; margin:0; padding: 0; font-size: 1px; line-height: 1px; mso-line-height-rule: exactly;"
|
||||
width="64">
|
||||
<div class="st-Spacer st-Spacer--filler"></div>
|
||||
</td>
|
||||
<td class="st-Font st-Font--body"
|
||||
style="border: 0; margin: 0; padding: 0; color: #000000 !important; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Ubuntu, sans-serif; font-size: 16px; line-height: 24px;">
|
||||
|
||||
|
||||
OneUptime Team.
|
||||
|
||||
|
||||
</td>
|
||||
<td class="st-Spacer st-Spacer--gutter"
|
||||
style="border: 0; margin:0; padding: 0; font-size: 1px; line-height: 1px; mso-line-height-rule: exactly;"
|
||||
width="64">
|
||||
<div class="st-Spacer st-Spacer--filler"></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="st-Spacer st-Spacer--stacked" colspan="3" height="12"
|
||||
style="border: 0; margin: 0; padding: 0; font-size: 1px; line-height: 1px; mso-line-height-rule: exactly;">
|
||||
<div class="st-Spacer st-Spacer--filler"></div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<table class="st-Footer st-Width st-Width--mobile" border="0" cellpadding="0" cellspacing="0"
|
||||
width="600" style="min-width: 600px;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="st-Spacer st-Spacer--divider" colspan="3" height="20"
|
||||
style="border: 0; margin: 0; padding: 0; font-size: 1px; line-height: 1px; max-height: 1px; mso-line-height-rule: exactly;">
|
||||
<div class="st-Spacer st-Spacer--filler"></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="st-Divider">
|
||||
<td class="st-Spacer st-Spacer--gutter"
|
||||
style="border: 0; margin:0; padding: 0; font-size: 1px; line-height: 1px; max-height: 1px; mso-line-height-rule: exactly;"
|
||||
width="64">
|
||||
<div class="st-Spacer st-Spacer--filler"></div>
|
||||
</td>
|
||||
<td bgcolor="#fdfdfd" colspan="2" height="1"
|
||||
style="border: 0; margin: 0; padding: 0; font-size: 1px; line-height: 1px; max-height: 1px; mso-line-height-rule: exactly;">
|
||||
<div class="st-Spacer st-Spacer--filler"></div>
|
||||
</td>
|
||||
<td class="st-Spacer st-Spacer--gutter"
|
||||
style="border: 0; margin:0; padding: 0; font-size: 1px; line-height: 1px; max-height: 1px; mso-line-height-rule: exactly;"
|
||||
width="64">
|
||||
<div class="st-Spacer st-Spacer--filler"></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="st-Spacer st-Spacer--divider" colspan="3" height="31"
|
||||
style="border: 0; margin: 0; padding: 0; font-size: 1px; line-height: 1px; mso-line-height-rule: exactly;">
|
||||
<div class="st-Spacer st-Spacer--filler"></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="st-Spacer st-Spacer--gutter"
|
||||
style="border: 0; margin:0; padding: 0; font-size: 1px; line-height: 1px; mso-line-height-rule: exactly;"
|
||||
width="64">
|
||||
<div class="st-Spacer st-Spacer--filler"></div>
|
||||
</td>
|
||||
<td class="st-Font st-Font--caption"
|
||||
style="border: 0; margin: 0;padding: 0; color: #8898aa; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Ubuntu, sans-serif; font-size: 12px; line-height: 16px;">
|
||||
<span class="st-Delink st-Delink--footer"
|
||||
style="border: 0; margin: 0; padding: 0; color: #8898aa; text-decoration: none;">
|
||||
© {{year}} OneUptime Inc.
|
||||
</span>
|
||||
</td>
|
||||
<td class="st-Spacer st-Spacer--gutter"
|
||||
style="border: 0; margin:0; padding: 0; font-size: 1px; line-height: 1px; mso-line-height-rule: exactly;"
|
||||
width="64">
|
||||
<div class="st-Spacer st-Spacer--filler"></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="st-Spacer st-Spacer--emailEnd" colspan="3" height="64"
|
||||
style="border: 0; margin: 0; padding: 0; font-size: 1px; line-height: 1px; mso-line-height-rule: exactly;">
|
||||
<div class="st-Spacer st-Spacer--filler"></div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<!-- /Wrapper -->
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="st-Spacer st-Spacer--emailEnd" height="64"
|
||||
style="border: 0; margin: 0; padding: 0; font-size: 1px; line-height: 1px; mso-line-height-rule: exactly;">
|
||||
<div class="st-Spacer st-Spacer--filler"> </div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<!-- /Background -->
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -193,7 +193,7 @@ export default class Domain extends BaseModel {
|
||||
public isVerified?: boolean = undefined;
|
||||
|
||||
@ColumnAccessControl({
|
||||
create: [],
|
||||
create: [Permission.ProjectOwner, Permission.CanCreateProjectDomain],
|
||||
read: [Permission.ProjectOwner, Permission.CanReadProjectDomain],
|
||||
update: [],
|
||||
})
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user