@underpostnet/underpost 2.8.0 → 2.8.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.dockerignore +1 -0
- package/.github/workflows/ghpkg.yml +14 -11
- package/.github/workflows/pwa-microservices-template.page.yml +10 -3
- package/.vscode/extensions.json +17 -71
- package/.vscode/settings.json +12 -5
- package/AUTHORS.md +16 -5
- package/CHANGELOG.md +63 -3
- package/Dockerfile +41 -62
- package/README.md +1 -28
- package/bin/build.js +278 -0
- package/bin/db.js +2 -24
- package/bin/deploy.js +107 -71
- package/bin/file.js +33 -4
- package/bin/index.js +35 -54
- package/bin/ssl.js +19 -11
- package/bin/util.js +27 -89
- package/bin/vs.js +25 -2
- package/conf.js +32 -132
- package/docker-compose.yml +1 -1
- package/manifests/core/kustomization.yaml +11 -0
- package/manifests/core/underpost-engine-backup-access.yaml +16 -0
- package/manifests/core/underpost-engine-backup-pv-pvc.yaml +22 -0
- package/manifests/core/underpost-engine-headless-service.yaml +10 -0
- package/manifests/core/underpost-engine-mongodb-backup-cronjob.yaml +40 -0
- package/manifests/core/underpost-engine-mongodb-configmap.yaml +26 -0
- package/manifests/core/underpost-engine-pv-pvc.yaml +23 -0
- package/manifests/core/underpost-engine-statefulset.yaml +91 -0
- package/manifests/deployment/mongo-express.yaml +60 -0
- package/manifests/deployment/phpmyadmin.yaml +54 -0
- package/manifests/kind-config.yaml +12 -0
- package/manifests/letsencrypt-prod.yaml +15 -0
- package/manifests/mariadb/config.yaml +10 -0
- package/manifests/mariadb/kustomization.yaml +9 -0
- package/manifests/mariadb/pv.yaml +12 -0
- package/manifests/mariadb/pvc.yaml +10 -0
- package/manifests/mariadb/secret.yaml +8 -0
- package/manifests/mariadb/service.yaml +10 -0
- package/manifests/mariadb/statefulset.yaml +55 -0
- package/manifests/valkey/kustomization.yaml +7 -0
- package/manifests/valkey/underpost-engine-valkey-service.yaml +17 -0
- package/manifests/valkey/underpost-engine-valkey-statefulset.yaml +39 -0
- package/package.json +16 -35
- package/src/api/user/user.model.js +16 -3
- package/src/api/user/user.service.js +1 -1
- package/src/client/components/core/Account.js +4 -2
- package/src/client/components/core/Auth.js +2 -2
- package/src/client/components/core/CalendarCore.js +115 -49
- package/src/client/components/core/CommonJs.js +150 -19
- package/src/client/components/core/Css.js +1 -1
- package/src/client/components/core/CssCore.js +6 -0
- package/src/client/components/core/Docs.js +2 -1
- package/src/client/components/core/DropDown.js +5 -1
- package/src/client/components/core/Input.js +17 -3
- package/src/client/components/core/JoyStick.js +8 -5
- package/src/client/components/core/Modal.js +17 -11
- package/src/client/components/core/Panel.js +85 -25
- package/src/client/components/core/PanelForm.js +11 -19
- package/src/client/components/core/SignUp.js +4 -1
- package/src/client/components/core/Translate.js +57 -9
- package/src/client/components/core/Validator.js +9 -1
- package/src/client/public/default/plantuml/client-conf.svg +1 -1
- package/src/client/public/default/plantuml/server-conf.svg +1 -1
- package/src/client/public/default/plantuml/server-schema.svg +1 -1
- package/src/client/public/default/plantuml/ssr-conf.svg +1 -1
- package/src/client/public/default/plantuml/ssr-schema.svg +1 -1
- package/src/client/services/core/core.service.js +2 -0
- package/src/client/services/default/default.management.js +4 -2
- package/src/client/ssr/body/CacheControl.js +2 -1
- package/src/client/ssr/body/DefaultSplashScreen.js +3 -3
- package/src/client/ssr/offline/Maintenance.js +63 -0
- package/src/client/sw/default.sw.js +23 -3
- package/src/db/mongo/MongooseDB.js +13 -1
- package/src/index.js +15 -0
- package/src/runtime/lampp/Lampp.js +1 -13
- package/src/runtime/xampp/Xampp.js +0 -13
- package/src/server/auth.js +3 -3
- package/src/server/client-build.js +8 -17
- package/src/server/client-icons.js +1 -1
- package/src/server/conf.js +299 -32
- package/src/server/dns.js +2 -3
- package/src/server/logger.js +18 -11
- package/src/server/network.js +0 -36
- package/src/server/process.js +25 -2
- package/src/server/project.js +39 -0
- package/src/server/proxy.js +4 -26
- package/src/server/runtime.js +6 -7
- package/src/server/ssl.js +1 -1
- package/src/server/valkey.js +3 -0
- package/startup.cjs +12 -0
- package/src/server/prompt-optimizer.js +0 -28
- package/startup.js +0 -11
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
const s = (el) => document.querySelector(el);
|
|
2
|
+
|
|
3
|
+
const append = (el, html) => s(el).insertAdjacentHTML('beforeend', html);
|
|
4
|
+
|
|
5
|
+
const getLang = () =>
|
|
6
|
+
(localStorage.getItem('lang') || navigator.language || navigator.userLanguage || s('html').lang)
|
|
7
|
+
.slice(0, 2)
|
|
8
|
+
.toLowerCase();
|
|
9
|
+
|
|
10
|
+
const main = () => {
|
|
11
|
+
const Translate = {
|
|
12
|
+
Data: {
|
|
13
|
+
['server-maintenance']: {
|
|
14
|
+
en: "The server is under maintenance <br> we'll be back soon.",
|
|
15
|
+
es: 'El servidor está en mantenimiento <br> volveremos pronto.',
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
Render: function (id) {
|
|
19
|
+
return this.Data[id][getLang()] ? this.Data[id][getLang()] : this.Data[id]['en'];
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
const icon = html`<svg xmlns="http://www.w3.org/2000/svg" width="80" height="80" viewBox="0 0 24 24">
|
|
23
|
+
<path
|
|
24
|
+
fill="none"
|
|
25
|
+
stroke="currentColor"
|
|
26
|
+
stroke-linecap="round"
|
|
27
|
+
stroke-linejoin="round"
|
|
28
|
+
stroke-width="2"
|
|
29
|
+
d="M3 7a3 3 0 0 1 3-3h12a3 3 0 0 1 3 3v2a3 3 0 0 1-3 3H6a3 3 0 0 1-3-3zm9 13H6a3 3 0 0 1-3-3v-2a3 3 0 0 1 3-3h10.5m-.5 6a2 2 0 1 0 4 0a2 2 0 1 0-4 0m2-3.5V16m0 4v1.5m3.032-5.25l-1.299.75m-3.463 2l-1.3.75m0-3.5l1.3.75m3.463 2l1.3.75M7 8v.01M7 16v.01"
|
|
30
|
+
/>
|
|
31
|
+
</svg>`;
|
|
32
|
+
|
|
33
|
+
append(
|
|
34
|
+
'body',
|
|
35
|
+
html` <style>
|
|
36
|
+
body {
|
|
37
|
+
font-family: arial;
|
|
38
|
+
font-size: 20px;
|
|
39
|
+
background-color: #d8d8d8;
|
|
40
|
+
color: #333;
|
|
41
|
+
}
|
|
42
|
+
a {
|
|
43
|
+
color: black;
|
|
44
|
+
}
|
|
45
|
+
</style>
|
|
46
|
+
|
|
47
|
+
<div class="abs center" style="top: 45%">
|
|
48
|
+
${icon}
|
|
49
|
+
<br />
|
|
50
|
+
<br />${Translate.Render('server-maintenance')}
|
|
51
|
+
</div>`,
|
|
52
|
+
);
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
SrrComponent = () => html`<script>
|
|
56
|
+
{
|
|
57
|
+
const s = ${s};
|
|
58
|
+
const append = ${append};
|
|
59
|
+
const getLang = ${getLang};
|
|
60
|
+
const main = ${main};
|
|
61
|
+
window.onload = main;
|
|
62
|
+
}
|
|
63
|
+
</script>`;
|
|
@@ -62,15 +62,35 @@ self.addEventListener('fetch', (event) => {
|
|
|
62
62
|
if (!preCachedResponse) throw new Error(error.message);
|
|
63
63
|
return preCachedResponse;
|
|
64
64
|
} catch (error) {
|
|
65
|
-
console.error('Error opening cache for pre cached page',
|
|
65
|
+
console.error('Error opening cache for pre cached page', {
|
|
66
|
+
url: event.request.url,
|
|
67
|
+
error,
|
|
68
|
+
onLine: navigator.onLine,
|
|
69
|
+
});
|
|
66
70
|
try {
|
|
71
|
+
if (!navigator.onLine) {
|
|
72
|
+
if (event.request.method.toUpperCase() === 'GET') {
|
|
73
|
+
const cache = await caches.open(CACHE_NAME);
|
|
74
|
+
const preCachedResponse = await cache.match(
|
|
75
|
+
`${PROXY_PATH === '/' ? '' : PROXY_PATH}/offline/index.html`,
|
|
76
|
+
);
|
|
77
|
+
if (!preCachedResponse) throw new Error(error.message);
|
|
78
|
+
return preCachedResponse;
|
|
79
|
+
}
|
|
80
|
+
const response = new Response(JSON.stringify({ status: 'error', message: 'offline test response' }));
|
|
81
|
+
// response.status = 200;
|
|
82
|
+
response.headers.set('Content-Type', 'application/json');
|
|
83
|
+
return response;
|
|
84
|
+
}
|
|
67
85
|
if (event.request.method.toUpperCase() === 'GET') {
|
|
68
86
|
const cache = await caches.open(CACHE_NAME);
|
|
69
|
-
const preCachedResponse = await cache.match(
|
|
87
|
+
const preCachedResponse = await cache.match(
|
|
88
|
+
`${PROXY_PATH === '/' ? '' : PROXY_PATH}/maintenance/index.html`,
|
|
89
|
+
);
|
|
70
90
|
if (!preCachedResponse) throw new Error(error.message);
|
|
71
91
|
return preCachedResponse;
|
|
72
92
|
}
|
|
73
|
-
const response = new Response(JSON.stringify({ status: 'error', message: '
|
|
93
|
+
const response = new Response(JSON.stringify({ status: 'error', message: 'server in maintenance' }));
|
|
74
94
|
// response.status = 200;
|
|
75
95
|
response.headers.set('Content-Type', 'application/json');
|
|
76
96
|
return response;
|
|
@@ -9,7 +9,12 @@ const MongooseDB = {
|
|
|
9
9
|
connect: async (host, name) => {
|
|
10
10
|
const uri = `${host}/${name}`;
|
|
11
11
|
// logger.info('MongooseDB connect', { host, name, uri });
|
|
12
|
-
return await mongoose
|
|
12
|
+
return await mongoose
|
|
13
|
+
.createConnection(uri, {
|
|
14
|
+
// useNewUrlParser: true,
|
|
15
|
+
// useUnifiedTopology: true,
|
|
16
|
+
})
|
|
17
|
+
.asPromise();
|
|
13
18
|
return new Promise((resolve, reject) =>
|
|
14
19
|
mongoose
|
|
15
20
|
.connect(
|
|
@@ -67,8 +72,15 @@ const MongooseDB = {
|
|
|
67
72
|
shellExec(`sudo rm -r /var/lib/mongodb`);
|
|
68
73
|
// restore lib
|
|
69
74
|
// shellExec(`sudo chown -R mongodb:mongodb /var/lib/mongodb/*`);
|
|
75
|
+
// mongod --repair
|
|
70
76
|
|
|
71
77
|
if (process.argv.includes('legacy')) {
|
|
78
|
+
// TODO:
|
|
79
|
+
if (process.argv.includes('rocky')) {
|
|
80
|
+
// https://github.com/mongodb/mongodb-selinux
|
|
81
|
+
// https://www.mongodb.com/docs/v7.0/tutorial/install-mongodb-enterprise-on-red-hat/
|
|
82
|
+
shellExec(`sudo chown -R mongod:mongod /var/lib/mongo`);
|
|
83
|
+
}
|
|
72
84
|
logger.info('install legacy 4.4');
|
|
73
85
|
shellExec(`wget -qO - https://www.mongodb.org/static/pgp/server-4.4.asc | sudo apt-key add -`);
|
|
74
86
|
|
package/src/index.js
CHANGED
|
@@ -4,7 +4,9 @@
|
|
|
4
4
|
* @namespace Underpost
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
import { runTest } from './server/conf.js';
|
|
7
8
|
import { loggerFactory, setUpInfo } from './server/logger.js';
|
|
9
|
+
import Project from './server/project.js';
|
|
8
10
|
|
|
9
11
|
const logger = loggerFactory(import.meta);
|
|
10
12
|
|
|
@@ -14,6 +16,15 @@ const logger = loggerFactory(import.meta);
|
|
|
14
16
|
* @memberof Underpost
|
|
15
17
|
*/
|
|
16
18
|
class Underpost {
|
|
19
|
+
/**
|
|
20
|
+
* Underpost engine version
|
|
21
|
+
* @static
|
|
22
|
+
* @type {String}
|
|
23
|
+
* @memberof Underpost
|
|
24
|
+
*/
|
|
25
|
+
static version = 'v2.8.4';
|
|
26
|
+
static project = Project;
|
|
27
|
+
|
|
17
28
|
constructor() {}
|
|
18
29
|
|
|
19
30
|
/**
|
|
@@ -32,6 +43,10 @@ class Underpost {
|
|
|
32
43
|
static async setUpInfo() {
|
|
33
44
|
return await setUpInfo(logger);
|
|
34
45
|
}
|
|
46
|
+
|
|
47
|
+
static runTest() {
|
|
48
|
+
return runTest(Underpost.version);
|
|
49
|
+
}
|
|
35
50
|
}
|
|
36
51
|
|
|
37
52
|
const up = Underpost;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import fs from 'fs-extra';
|
|
2
|
-
import { network } from '../../server/network.js';
|
|
3
2
|
import { shellCd, shellExec } from '../../server/process.js';
|
|
4
3
|
import { timer } from '../../client/components/core/CommonJs.js';
|
|
5
4
|
import { loggerFactory } from '../../server/logger.js';
|
|
@@ -39,20 +38,9 @@ const Lampp = {
|
|
|
39
38
|
);
|
|
40
39
|
|
|
41
40
|
shellExec(cmd);
|
|
42
|
-
await network.port.portClean(3306);
|
|
43
|
-
for (const port of this.ports) await network.port.portClean(port);
|
|
44
41
|
cmd = `sudo /opt/lampp/lampp start`;
|
|
45
42
|
if (this.router) fs.writeFileSync(`./tmp/lampp-router.conf`, this.router, 'utf-8');
|
|
46
|
-
shellExec(cmd
|
|
47
|
-
if (options && options.daemon) this.daemon();
|
|
48
|
-
},
|
|
49
|
-
daemon: async function () {
|
|
50
|
-
await timer(1000 * 60 * 2); // 2 minutes
|
|
51
|
-
for (const port of this.ports) {
|
|
52
|
-
const [portStatus] = await network.port.status([port]);
|
|
53
|
-
if (!portStatus.open) return await this.initService();
|
|
54
|
-
}
|
|
55
|
-
this.daemon();
|
|
43
|
+
shellExec(cmd);
|
|
56
44
|
},
|
|
57
45
|
enabled: () => fs.existsSync(`/opt/lampp/apache2/conf/httpd.conf`),
|
|
58
46
|
appendRouter: function (render) {
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import fs from 'fs-extra';
|
|
2
|
-
import { network } from '../../server/network.js';
|
|
3
2
|
import { shellExec } from '../../server/process.js';
|
|
4
|
-
import { timer } from '../../client/components/core/CommonJs.js';
|
|
5
3
|
|
|
6
4
|
const Xampp = {
|
|
7
5
|
ports: [],
|
|
@@ -16,20 +14,9 @@ const Xampp = {
|
|
|
16
14
|
fs.writeFileSync(`C:/xampp/apache/conf/extra/httpd-ssl.conf`, this.router || '', 'utf8');
|
|
17
15
|
cmd = `C:/xampp/xampp_stop.exe`;
|
|
18
16
|
shellExec(cmd);
|
|
19
|
-
await network.port.portClean(3306);
|
|
20
|
-
for (const port of this.ports) await network.port.portClean(port);
|
|
21
17
|
cmd = `C:/xampp/xampp_start.exe`;
|
|
22
18
|
if (this.router) fs.writeFileSync(`./tmp/xampp-router.conf`, this.router, 'utf-8');
|
|
23
19
|
shellExec(cmd);
|
|
24
|
-
if (options && options.daemon) this.daemon();
|
|
25
|
-
},
|
|
26
|
-
daemon: async function () {
|
|
27
|
-
await timer(1000 * 60 * 2); // 2 minutes
|
|
28
|
-
for (const port of this.ports) {
|
|
29
|
-
const [portStatus] = await network.port.status([port]);
|
|
30
|
-
if (!portStatus.open) return await this.initService();
|
|
31
|
-
}
|
|
32
|
-
this.daemon();
|
|
33
20
|
},
|
|
34
21
|
enabled: () => fs.existsSync(`C:/xampp/apache/conf/httpd.conf`),
|
|
35
22
|
appendRouter: function (render) {
|
package/src/server/auth.js
CHANGED
|
@@ -9,7 +9,7 @@ import jwt from 'jsonwebtoken';
|
|
|
9
9
|
import { loggerFactory } from './logger.js';
|
|
10
10
|
import crypto from 'crypto';
|
|
11
11
|
import { userRoleEnum } from '../api/user/user.model.js';
|
|
12
|
-
import { validatePassword } from '../client/components/core/CommonJs.js';
|
|
12
|
+
import { commonAdminGuard, commonModeratorGuard, validatePassword } from '../client/components/core/CommonJs.js';
|
|
13
13
|
|
|
14
14
|
dotenv.config();
|
|
15
15
|
|
|
@@ -162,7 +162,7 @@ const authMiddleware = (req, res, next) => {
|
|
|
162
162
|
*/
|
|
163
163
|
const adminGuard = (req, res, next) => {
|
|
164
164
|
try {
|
|
165
|
-
if (!(
|
|
165
|
+
if (!commonAdminGuard(req.auth.user.role))
|
|
166
166
|
return res.status(403).json({ status: 'error', message: 'Insufficient permission' });
|
|
167
167
|
return next();
|
|
168
168
|
} catch (error) {
|
|
@@ -194,7 +194,7 @@ const adminGuard = (req, res, next) => {
|
|
|
194
194
|
*/
|
|
195
195
|
const moderatorGuard = (req, res, next) => {
|
|
196
196
|
try {
|
|
197
|
-
if (!(
|
|
197
|
+
if (!commonModeratorGuard(req.auth.user.role))
|
|
198
198
|
return res.status(403).json({ status: 'error', message: 'Insufficient permission' });
|
|
199
199
|
return next();
|
|
200
200
|
} catch (error) {
|
|
@@ -50,10 +50,10 @@ const fullBuild = async ({
|
|
|
50
50
|
buildAcmeChallengePath(acmeChallengeFullPath);
|
|
51
51
|
|
|
52
52
|
if (publicClientId && publicClientId.startsWith('html-website-templates')) {
|
|
53
|
-
if (!fs.existsSync(`/dd/html-website-templates/`))
|
|
54
|
-
shellExec(`cd /dd && git clone https://github.com/designmodo/html-website-templates.git`);
|
|
53
|
+
if (!fs.existsSync(`/home/dd/html-website-templates/`))
|
|
54
|
+
shellExec(`cd /home/dd && git clone https://github.com/designmodo/html-website-templates.git`);
|
|
55
55
|
if (!fs.existsSync(`${rootClientPath}/index.php`)) {
|
|
56
|
-
fs.copySync(`/dd/html-website-templates/${publicClientId.split('-publicClientId-')[1]}`, rootClientPath);
|
|
56
|
+
fs.copySync(`/home/dd/html-website-templates/${publicClientId.split('-publicClientId-')[1]}`, rootClientPath);
|
|
57
57
|
shellExec(`cd ${rootClientPath} && git init && git add . && git commit -m "Base template implementation"`);
|
|
58
58
|
// git remote add origin git@github.com:<username>/<repo>.git
|
|
59
59
|
fs.writeFileSync(`${rootClientPath}/.git/.htaccess`, `Deny from all`, 'utf8');
|
|
@@ -465,10 +465,11 @@ const buildClient = async (options = { liveClientBuildPaths: [], instances: [] }
|
|
|
465
465
|
case 'DefaultSplashScreen':
|
|
466
466
|
if (backgroundImage) {
|
|
467
467
|
ssrHeadComponents += SrrComponent({
|
|
468
|
-
|
|
469
|
-
.readFileSync(backgroundImage)
|
|
470
|
-
.toString('base64')}`,
|
|
468
|
+
backgroundImage: (path === '/' ? path : `${path}/`) + backgroundImage,
|
|
471
469
|
});
|
|
470
|
+
// `data:image/${backgroundImage.split('.').pop()};base64,${fs
|
|
471
|
+
// .readFileSync()
|
|
472
|
+
// .toString('base64')}`,
|
|
472
473
|
break;
|
|
473
474
|
} else {
|
|
474
475
|
ssrHeadComponents += SrrComponent({ metadata });
|
|
@@ -480,7 +481,7 @@ const buildClient = async (options = { liveClientBuildPaths: [], instances: [] }
|
|
|
480
481
|
bgColor: metadata?.themeColor ? metadata.themeColor : '#ececec',
|
|
481
482
|
});
|
|
482
483
|
ssrHeadComponents += SrrComponent({
|
|
483
|
-
|
|
484
|
+
backgroundImage: `data:image/png;base64,${bufferBackgroundImage.toString('base64')}`,
|
|
484
485
|
});
|
|
485
486
|
}
|
|
486
487
|
|
|
@@ -544,17 +545,7 @@ const buildClient = async (options = { liveClientBuildPaths: [], instances: [] }
|
|
|
544
545
|
let siteMapSrc = await new Promise((resolve) =>
|
|
545
546
|
streamToPromise(Readable.from(siteMapLinks).pipe(siteMapStream)).then((data) => resolve(data.toString())),
|
|
546
547
|
);
|
|
547
|
-
switch (publicClientId) {
|
|
548
|
-
case 'underpost':
|
|
549
|
-
siteMapSrc = siteMapSrc.replaceAll(
|
|
550
|
-
`</urlset>`,
|
|
551
|
-
`${fs.readFileSync(`./src/client/public/underpost/sitemap-template.txt`, 'utf8')} </urlset>`,
|
|
552
|
-
);
|
|
553
|
-
break;
|
|
554
548
|
|
|
555
|
-
default:
|
|
556
|
-
break;
|
|
557
|
-
}
|
|
558
549
|
// Return a promise that resolves with your XML string
|
|
559
550
|
fs.writeFileSync(`${rootClientPath}/sitemap.xml`, siteMapSrc, 'utf8');
|
|
560
551
|
if (xslUrl)
|
|
@@ -141,7 +141,7 @@ const buildIcons = async ({
|
|
|
141
141
|
for (const file of response.files)
|
|
142
142
|
fs.writeFileSync(`./src/client/public/${publicClientId}/${file.name}`, file.contents, 'utf8');
|
|
143
143
|
|
|
144
|
-
const ssrPath = `./src/client/ssr/
|
|
144
|
+
const ssrPath = `./src/client/ssr/head/Pwa${getCapVariableName(publicClientId)}.js`;
|
|
145
145
|
if (!fs.existsSync(ssrPath))
|
|
146
146
|
fs.writeFileSync(ssrPath, 'SrrComponent = () => html`' + response.html.join(`\n`) + '`;', 'utf8');
|
|
147
147
|
} catch (error) {
|