underpost 2.7.7 → 2.7.9

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.
Files changed (79) hide show
  1. package/.github/workflows/ghpkg.yml +115 -0
  2. package/.github/workflows/publish.yml +20 -3
  3. package/.github/workflows/pwa-microservices-template.page.yml +54 -0
  4. package/.github/workflows/pwa-microservices-template.test.yml +30 -0
  5. package/.vscode/settings.json +6 -0
  6. package/CHANGELOG.md +64 -16
  7. package/bin/cron.js +47 -0
  8. package/bin/db.js +9 -1
  9. package/bin/deploy.js +207 -11
  10. package/bin/file.js +17 -1
  11. package/bin/index.js +1 -1
  12. package/bin/util.js +22 -0
  13. package/conf.js +18 -4
  14. package/docker-compose.yml +1 -1
  15. package/package.json +3 -3
  16. package/src/api/core/core.router.js +9 -9
  17. package/src/api/core/core.service.js +6 -4
  18. package/src/api/default/default.service.js +4 -4
  19. package/src/api/file/file.service.js +3 -3
  20. package/src/api/user/user.service.js +7 -7
  21. package/src/client/components/core/Css.js +0 -222
  22. package/src/client/components/core/CssCore.js +30 -3
  23. package/src/client/components/core/Docs.js +110 -10
  24. package/src/client/components/core/Modal.js +224 -22
  25. package/src/client/components/core/Panel.js +1 -1
  26. package/src/client/components/core/PanelForm.js +2 -1
  27. package/src/client/components/core/Responsive.js +15 -0
  28. package/src/client/components/core/RichText.js +4 -2
  29. package/src/client/components/core/Translate.js +6 -2
  30. package/src/client/components/core/WebComponent.js +44 -0
  31. package/src/client/components/core/Worker.js +12 -4
  32. package/src/client/public/default/plantuml/client-conf.svg +1 -1
  33. package/src/client/public/default/plantuml/client-schema.svg +1 -1
  34. package/src/client/public/default/plantuml/cron-conf.svg +1 -1
  35. package/src/client/public/default/plantuml/cron-schema.svg +1 -1
  36. package/src/client/public/default/plantuml/server-conf.svg +1 -1
  37. package/src/client/public/default/plantuml/server-schema.svg +1 -1
  38. package/src/client/public/default/plantuml/ssr-conf.svg +1 -1
  39. package/src/client/public/default/plantuml/ssr-schema.svg +1 -1
  40. package/src/client/public/default/site.webmanifest +69 -0
  41. package/src/client/services/default/default.management.js +118 -120
  42. package/src/client/ssr/Render.js +224 -3
  43. package/src/client/ssr/common/Alert.js +75 -0
  44. package/src/client/ssr/common/SsrCore.js +91 -0
  45. package/src/client/ssr/common/Translate.js +26 -0
  46. package/src/client/ssr/common/Worker.js +28 -0
  47. package/src/client/ssr/{body-components → components/body}/CacheControl.js +1 -1
  48. package/src/client/ssr/{body-components → components/body}/DefaultSplashScreen.js +15 -4
  49. package/src/client/ssr/components/head/Pwa.js +146 -0
  50. package/src/client/ssr/pages/404.js +12 -0
  51. package/src/client/ssr/pages/500.js +12 -0
  52. package/src/client/ssr/pages/maintenance.js +14 -0
  53. package/src/client/ssr/pages/offline.js +21 -0
  54. package/src/client/sw/default.sw.js +13 -9
  55. package/src/db/DataBaseProvider.js +12 -1
  56. package/src/db/mongo/MongooseDB.js +0 -1
  57. package/src/mailer/EmailRender.js +1 -1
  58. package/src/server/backup.js +82 -70
  59. package/src/server/client-build-live.js +6 -0
  60. package/src/server/client-build.js +76 -73
  61. package/src/server/client-formatted.js +11 -1
  62. package/src/server/client-icons.js +1 -1
  63. package/src/server/conf.js +60 -12
  64. package/src/server/crypto.js +91 -0
  65. package/src/server/dns.js +42 -13
  66. package/src/server/network.js +94 -7
  67. package/src/server/proxy.js +27 -27
  68. package/src/server/runtime.js +27 -8
  69. package/.github/workflows/test.yml +0 -80
  70. package/src/client/ssr/head-components/Microdata.js +0 -11
  71. package/src/cron.js +0 -30
  72. package/src/server/cron.js +0 -35
  73. /package/src/client/ssr/{email-components → components/email}/DefaultRecoverEmail.js +0 -0
  74. /package/src/client/ssr/{email-components → components/email}/DefaultVerifyEmail.js +0 -0
  75. /package/src/client/ssr/{head-components → components/head}/Css.js +0 -0
  76. /package/src/client/ssr/{head-components → components/head}/DefaultScripts.js +0 -0
  77. /package/src/client/ssr/{head-components → components/head}/Production.js +0 -0
  78. /package/src/client/ssr/{head-components → components/head}/PwaDefault.js +0 -0
  79. /package/src/client/ssr/{head-components → components/head}/Seo.js +0 -0
package/bin/deploy.js CHANGED
@@ -25,6 +25,7 @@ import {
25
25
  Cmd,
26
26
  restoreMacroDb,
27
27
  fixDependencies,
28
+ setUpProxyMaintenanceServer,
28
29
  } from '../src/server/conf.js';
29
30
  import { buildClient } from '../src/server/client-build.js';
30
31
  import { range, setPad, timer, uniqueArray } from '../src/client/components/core/CommonJs.js';
@@ -32,6 +33,8 @@ import toJsonSchema from 'to-json-schema';
32
33
  import simpleGit from 'simple-git';
33
34
  import { MongooseDB } from '../src/db/mongo/MongooseDB.js';
34
35
  import { Lampp } from '../src/runtime/lampp/Lampp.js';
36
+ import { DefaultConf } from '../conf.js';
37
+ import { JSONweb } from '../src/server/client-formatted.js';
35
38
 
36
39
  const logger = loggerFactory(import.meta);
37
40
 
@@ -152,10 +155,15 @@ try {
152
155
  await deployRun(dataDeploy);
153
156
  } else {
154
157
  loadConf(process.argv[3]);
155
- shellExec(`npm start ${process.argv[3]}`);
158
+ shellExec(`npm start ${process.argv.includes('maintenance') ? 'maintenance' : ''}`);
156
159
  }
157
160
  }
158
161
  break;
162
+
163
+ case 'remove-await-deploy': {
164
+ if (fs.existsSync(`./tmp/await-deploy`)) fs.remove(`./tmp/await-deploy`);
165
+ break;
166
+ }
159
167
  case 'new-nodejs-app':
160
168
  {
161
169
  const deployId = process.argv[3];
@@ -222,21 +230,18 @@ try {
222
230
  break;
223
231
  case 'build-full-client':
224
232
  {
233
+ if (!process.argv[3]) process.argv[3] = 'default';
225
234
  const { deployId, folder } = loadConf(process.argv[3]);
226
235
 
227
- let argHost = process.argv[4] ? process.argv[4].split(',') : undefined;
228
- let argPath = process.argv[5] ? process.argv[5].split(',') : undefined;
236
+ let argHost = process.argv[4] ? process.argv[4].split(',') : [];
237
+ let argPath = process.argv[5] ? process.argv[5].split(',') : [];
229
238
  let deployIdSingleReplicas = [];
230
239
  const serverConf = deployId
231
240
  ? JSON.parse(fs.readFileSync(`./conf/conf.server.json`, 'utf8'))
232
241
  : Config.default.server;
233
- if (!deployId) {
234
- argHost = 'default.net';
235
- argPath = '/';
236
- }
237
242
  for (const host of Object.keys(serverConf)) {
238
243
  for (const path of Object.keys(serverConf[host])) {
239
- if (argHost && argPath && (!argHost.includes(host) || !argPath.includes(path))) {
244
+ if (argHost.length && argPath.length && (!argHost.includes(host) || !argPath.includes(path))) {
240
245
  delete serverConf[host][path];
241
246
  } else {
242
247
  serverConf[host][path].liteBuild = process.argv.includes('l') ? true : false;
@@ -290,10 +295,28 @@ try {
290
295
  }
291
296
  break;
292
297
 
298
+ case 'run-single-build': {
299
+ const deployId = process.argv[3];
300
+ shellExec(Cmd.conf(deployId));
301
+ shellExec(Cmd.build(deployId));
302
+ shellExec(Cmd.delete(deployId));
303
+ shellExec(Cmd.run(deployId));
304
+ break;
305
+ }
306
+
307
+ case 'run-single': {
308
+ const deployId = process.argv[3];
309
+ shellExec(Cmd.delete(deployId));
310
+ shellExec(Cmd.conf(deployId));
311
+ shellExec(Cmd.run(deployId));
312
+ break;
313
+ }
314
+
293
315
  case 'run-macro':
294
316
  {
295
317
  if (fs.existsSync(`./tmp/await-deploy`)) fs.remove(`./tmp/await-deploy`);
296
318
  const dataDeploy = getDataDeploy({ deployGroupId: process.argv[3], buildSingleReplica: true });
319
+ await setUpProxyMaintenanceServer({ deployGroupId: process.argv[3] });
297
320
  await deployRun(dataDeploy, true);
298
321
  }
299
322
  break;
@@ -306,6 +329,7 @@ try {
306
329
  shellExec(Cmd.conf(deploy.deployId));
307
330
  shellExec(Cmd.build(deploy.deployId));
308
331
  }
332
+ await setUpProxyMaintenanceServer({ deployGroupId: process.argv[3] });
309
333
  await deployRun(dataDeploy, true);
310
334
  }
311
335
  break;
@@ -452,7 +476,7 @@ try {
452
476
  `./engine-private/replica/${replicaDeployId}/package.json`,
453
477
  fs
454
478
  .readFileSync(`./engine-private/replica/${replicaDeployId}/package.json`, 'utf8')
455
- .replaceAll(`--name ${deployId}`, `--name ${replicaDeployId}`),
479
+ .replaceAll(`${deployId}`, `${replicaDeployId}`),
456
480
  'utf8',
457
481
  );
458
482
  }
@@ -502,6 +526,17 @@ try {
502
526
  break;
503
527
  }
504
528
 
529
+ case 'set-repo': {
530
+ const originPackage = JSON.parse(fs.readFileSync(`./package.json`, 'utf8'));
531
+ originPackage.repository = {
532
+ type: 'git',
533
+ url: `git+https://github.com/${process.argv[3]}.git`,
534
+ };
535
+ fs.writeFileSync(`./package.json`, JSON.stringify(originPackage, null, 4), 'utf8');
536
+
537
+ break;
538
+ }
539
+
505
540
  case 'update-version':
506
541
  {
507
542
  const newVersion = process.argv[3];
@@ -553,9 +588,9 @@ try {
553
588
  );
554
589
 
555
590
  fs.writeFileSync(
556
- `./src/client/ssr/body-components/CacheControl.js`,
591
+ `./src/client/ssr/components/body/CacheControl.js`,
557
592
  fs
558
- .readFileSync(`./src/client/ssr/body-components/CacheControl.js`, 'utf8')
593
+ .readFileSync(`./src/client/ssr/components/body/CacheControl.js`, 'utf8')
559
594
  .replaceAll(`v${version}`, `v${newVersion}`),
560
595
  'utf8',
561
596
  );
@@ -655,6 +690,167 @@ ${uniqueArray(logs.all.map((log) => `- ${log.author_name} ([${log.author_email}]
655
690
  break;
656
691
  }
657
692
 
693
+ case 'update-default-conf': {
694
+ const host = process.argv[3] ? process.argv[3] : 'underpostnet.github.io';
695
+ const path = process.argv[4] ? process.argv[4] : '/pwa-microservices-template-ghpkg';
696
+ DefaultConf.server = {
697
+ [host]: { [path]: DefaultConf.server['default.net']['/'] },
698
+ };
699
+ DefaultConf.server[host][path].apiBaseProxyPath = '/';
700
+ DefaultConf.server[host][path].apiBaseHost = 'www.nexodev.org';
701
+ fs.writeFileSync(
702
+ './conf.js',
703
+ `
704
+ const DefaultConf = ${JSONweb(DefaultConf)};
705
+
706
+ export { DefaultConf }
707
+
708
+ `,
709
+ 'utf8',
710
+ );
711
+
712
+ break;
713
+ }
714
+ case 'ssh-export-server-keys': {
715
+ fs.copyFile('/etc/ssh/ssh_host_rsa_key', './engine-private/deploy/ssh_host_rsa_key');
716
+ fs.copyFile('/etc/ssh/ssh_host_rsa_key.pub', './engine-private/deploy/ssh_host_rsa_key.pub');
717
+ break;
718
+ }
719
+ case 'ssh-import-server-keys': {
720
+ fs.copyFile('./engine-private/deploy/ssh_host_rsa_key', '/etc/ssh/ssh_host_rsa_key');
721
+ fs.copyFile('./engine-private/deploy/ssh_host_rsa_key.pub', '/etc/ssh/ssh_host_rsa_key.pub');
722
+ break;
723
+ }
724
+ case 'ssh-import-client-keys': {
725
+ const host = process.argv[3];
726
+ shellExec(`node bin/deploy set-ssh-keys ./engine-private/deploy/ssh_host_rsa_key${host ? ` ${host}` : ``} clean`);
727
+ break;
728
+ }
729
+ case 'ssh-keys': {
730
+ // create ssh keys
731
+ const sshAccount = process.argv[3]; // [sudo username]@[host/ip]
732
+ const destPath = process.argv[4];
733
+ // shellExec(`ssh-keygen -t ed25519 -C "${sshAccount}" -f ${destPath}`);
734
+ if (fs.existsSync(destPath)) {
735
+ fs.removeSync(destPath);
736
+ fs.removeSync(destPath + '.pub');
737
+ }
738
+ shellExec(`ssh-keygen -t rsa -b 4096 -C "${sshAccount}" -f ${destPath}`);
739
+ // add host to keyscan
740
+ // shellExec(`ssh-keyscan -t rsa ${sshAccount.split(`@`)[1]} >> ~/.ssh/known_hosts`);
741
+ break;
742
+ }
743
+
744
+ case 'set-ssh-keys': {
745
+ const files = ['authorized_keys', 'id_rsa', 'id_rsa.pub', 'known_hosts ', 'known_hosts.old'];
746
+
747
+ // > write
748
+ // >> append
749
+
750
+ // /root/.ssh/id_rsa
751
+ // /root/.ssh/id_rsa.pub
752
+ if (process.argv.includes('clean')) {
753
+ for (const file of files) {
754
+ if (fs.existsSync(`/root/.ssh/${file}`)) {
755
+ logger.info('remove', `/root/.ssh/${file}`);
756
+ fs.removeSync(`/root/.ssh/${file}`);
757
+ }
758
+ fs.writeFileSync(`/root/.ssh/${file}`, '', 'utf8');
759
+ }
760
+ shellExec('eval `ssh-agent -s`' + ` && ssh-add -D`);
761
+ }
762
+
763
+ const destPath = process.argv[3];
764
+ const sshAuthKeyTarget = '/root/.ssh/authorized_keys';
765
+ if (!fs.existsSync(sshAuthKeyTarget)) shellExec(`touch ${sshAuthKeyTarget}`);
766
+ shellExec(`cat ${destPath}.pub > ${sshAuthKeyTarget}`);
767
+ shellExec(`cat ${destPath} >> ${sshAuthKeyTarget}`);
768
+
769
+ if (!fs.existsSync('/root/.ssh/id_rsa')) shellExec(`touch ${'/root/.ssh/id_rsa'}`);
770
+ shellExec(`cat ${destPath} > ${'/root/.ssh/id_rsa'}`);
771
+
772
+ if (!fs.existsSync('/root/.ssh/id_rsa.pub')) shellExec(`touch ${'/root/.ssh/id_rsa.pub'}`);
773
+ shellExec(`cat ${destPath}.pub > ${'/root/.ssh/id_rsa.pub'}`);
774
+
775
+ shellExec(`chmod 700 /root/.ssh/`);
776
+ for (const file of files) {
777
+ shellExec(`chmod 600 /root/.ssh/${file}`);
778
+ }
779
+ const host = process.argv[4];
780
+ // add key
781
+ shellExec('eval `ssh-agent -s`' + ' && ssh-add /root/.ssh/id_rsa' + ' && ssh-add -l');
782
+ if (host) shellExec(`ssh-keyscan -H ${host} >> ~/.ssh/known_hosts`);
783
+ shellExec(`sudo systemctl enable ssh`);
784
+ shellExec(`sudo systemctl restart ssh`);
785
+ shellExec(`sudo systemctl status ssh`);
786
+
787
+ break;
788
+ }
789
+
790
+ case 'ssh': {
791
+ if (!process.argv.includes('server')) {
792
+ shellExec(`sudo apt update`);
793
+ shellExec(`sudo apt install openssh-server -y`);
794
+ shellExec(`sudo apt install ssh-askpass`);
795
+ }
796
+ shellExec(`sudo systemctl enable ssh`);
797
+ shellExec(`sudo systemctl restart ssh`);
798
+ shellExec(`sudo systemctl status ssh`);
799
+ // sudo service ssh restart
800
+ shellExec(`ip a`);
801
+
802
+ // adduser newuser
803
+ // usermod -aG sudo newuser
804
+
805
+ // ssh -i '/path/to/keyfile' username@server
806
+
807
+ // ssh-keygen -t ed25519 -C "your_email@example.com" -f $HOME/.ssh/id_rsa
808
+
809
+ // legacy: ssh-keygen -t rsa -b 4096 -C "your_email@example.com" -f $HOME/.ssh/id_rsa
810
+
811
+ // vi .ssh/authorized_keys
812
+ // chmod 700 .ssh
813
+ // chmod 600 authorized_keys
814
+
815
+ // cat id_rsa.pub > .ssh/authorized_keys
816
+
817
+ // add public key to authorized keys
818
+ // cat .ssh/id_ed25519.pub | ssh [sudo username]@[host/ip] 'cat >> .ssh/authorized_keys'
819
+
820
+ // 2. Open /etc/ssh/sshd_config file
821
+ // nano /etc/ssh/sshd_config
822
+
823
+ // 3. add example code to last line of file
824
+ // Match User newuser
825
+ // PasswordAuthentication yes
826
+
827
+ // ssh [sudo username]@[host/ip]
828
+ // open port 22
829
+
830
+ // init ssh agent service
831
+ // eval `ssh-agent -s`
832
+
833
+ // list keys
834
+ // ssh-add -l
835
+
836
+ // add key
837
+ // ssh-add /root/.ssh/id_rsa
838
+
839
+ // remove
840
+ // ssh-add -d /path/to/private/key
841
+
842
+ // remove all
843
+ // ssh-add -D
844
+
845
+ // sshpass -p ${{ secrets.PSWD }} ssh -o StrictHostKeyChecking=no -p 22 ${{ secrets.USER}}@${{ secrets.VPS_IP }} 'cd /home/adam && ./deploy.sh'
846
+
847
+ // copies the public key of your default identity (use -i identity_file for other identities) to the remote host.
848
+ // ssh-copy-id user@hostname.example.com
849
+ // ssh-copy-id "user@hostname.example.com -p <port-number>"
850
+
851
+ break;
852
+ }
853
+
658
854
  default:
659
855
  break;
660
856
  }
package/bin/file.js CHANGED
@@ -2,7 +2,7 @@ import fs from 'fs-extra';
2
2
 
3
3
  import { loggerFactory } from '../src/server/logger.js';
4
4
  import { cap, getCapVariableName, getDirname } from '../src/client/components/core/CommonJs.js';
5
- import { shellExec } from '../src/server/process.js';
5
+ import { shellCd, shellExec } from '../src/server/process.js';
6
6
  import walk from 'ignore-walk';
7
7
  import { validateTemplatePath } from '../src/server/conf.js';
8
8
 
@@ -76,6 +76,22 @@ try {
76
76
  fs.copySync(`./.vscode`, `../pwa-microservices-template/.vscode`);
77
77
  fs.copySync(`./.github`, `../pwa-microservices-template/.github`);
78
78
  fs.copySync(`./src/client/public/default`, `../pwa-microservices-template/src/client/public/default`);
79
+
80
+ shellCd('../pwa-microservices-template');
81
+ for (const deletePath of ['CHANGELOG.md', 'README.md', 'package-lock.json', 'package.json']) {
82
+ shellExec(`git checkout ${deletePath}`);
83
+ }
84
+ for (const deletePath of [
85
+ '.github/workflows/coverall.yml',
86
+ '.github/workflows/docker-image.yml',
87
+ '.github/workflows/deploy.ssh.yml',
88
+ '.github/workflows/deploy.api-rest.yml',
89
+ 'bin/web3.js',
90
+ 'src/ipfs.js',
91
+ 'src/k8s.js',
92
+ ]) {
93
+ fs.removeSync('../pwa-microservices-template/' + deletePath);
94
+ }
79
95
  }
80
96
 
81
97
  break;
package/bin/index.js CHANGED
@@ -19,7 +19,7 @@ const globalBinFolder = `${shellExec(`npm root -g`, {
19
19
 
20
20
  const program = new Command();
21
21
 
22
- const version = '2.7.7';
22
+ const version = '2.7.9';
23
23
 
24
24
  program.name('underpost').description(`underpost.net ci/cd cli ${version}`).version(version);
25
25
 
package/bin/util.js CHANGED
@@ -3,6 +3,8 @@ import merge from 'deepmerge';
3
3
  import si from 'systeminformation';
4
4
  import * as dir from 'path';
5
5
  import { svg } from 'font-awesome-assets';
6
+ import axios from 'axios';
7
+ import https from 'https';
6
8
 
7
9
  import { loggerFactory } from '../src/server/logger.js';
8
10
  import { shellCd, shellExec } from '../src/server/process.js';
@@ -12,6 +14,11 @@ import { Config } from '../src/server/conf.js';
12
14
  import { FileFactory } from '../src/api/file/file.service.js';
13
15
  import { buildTextImg, faBase64Png, getBufferPngText } from '../src/server/client-icons.js';
14
16
 
17
+ const httpsAgent = new https.Agent({
18
+ rejectUnauthorized: false,
19
+ });
20
+ axios.defaults.httpsAgent = httpsAgent;
21
+
15
22
  const logger = loggerFactory(import.meta);
16
23
 
17
24
  logger.info('argv', process.argv);
@@ -174,6 +181,21 @@ try {
174
181
  fs.writeFileSync('b64-image', `data:image/jpg;base64,${fs.readFileSync(process.argv[3]).toString('base64')}`);
175
182
  break;
176
183
 
184
+ case 'get-ip': {
185
+ const response = await axios.get(process.argv[3]);
186
+ logger.info(process.argv[3] + ' IP', response.request.socket.remoteAddress);
187
+ break;
188
+ }
189
+
190
+ case 'clean-env': {
191
+ shellExec(`git checkout package.json`);
192
+ shellExec(`git checkout .env.production`);
193
+ shellExec(`git checkout .env.development`);
194
+ shellExec(`git checkout .env.test`);
195
+ shellExec(`git checkout jsdoc.json`);
196
+ break;
197
+ }
198
+
177
199
  default:
178
200
  break;
179
201
  }
package/conf.js CHANGED
@@ -2,8 +2,14 @@ const DefaultConf = {
2
2
  client: {
3
3
  default: {
4
4
  metadata: {
5
- title: 'Default',
5
+ title: 'Demo App',
6
6
  backgroundImage: './src/client/public/default/assets/background/white0-min.jpg',
7
+ description: 'Web application',
8
+ keywords: ['web', 'app', 'spa', 'demo', 'github-pages'],
9
+ author: 'https://github.com/underpostnet',
10
+ thumbnail: 'android-chrome-384x384.png',
11
+ themeColor: '#ececec',
12
+ pwaAssetsPath: '',
7
13
  },
8
14
  components: {
9
15
  core: [
@@ -168,7 +174,7 @@ const DefaultConf = {
168
174
  },
169
175
  ssr: {
170
176
  Default: {
171
- head: ['PwaDefault', 'Css', 'DefaultScripts'],
177
+ head: ['Seo', 'Pwa', 'Css', 'DefaultScripts', 'Production'],
172
178
  body: ['CacheControl', 'DefaultSplashScreen'],
173
179
  },
174
180
  },
@@ -227,8 +233,6 @@ const DefaultConf = {
227
233
  cron: {
228
234
  ipDaemon: {
229
235
  ip: null,
230
- minutesTimeInterval: 3,
231
- disabled: false,
232
236
  },
233
237
  records: {
234
238
  A: [
@@ -245,6 +249,16 @@ const DefaultConf = {
245
249
  deployGroupId: 'default-group',
246
250
  },
247
251
  ],
252
+ jobs: {
253
+ dns: {
254
+ expression: '* * * * *',
255
+ enabled: true,
256
+ },
257
+ backups: {
258
+ expression: '0 1 * * *',
259
+ enabled: true,
260
+ },
261
+ },
248
262
  },
249
263
  };
250
264
 
@@ -58,7 +58,7 @@ services:
58
58
  cpus: '0.25'
59
59
  memory: 20M
60
60
  labels: # labels in Compose file instead of Dockerfile
61
- engine.version: '2.7.7'
61
+ engine.version: '2.7.9'
62
62
  networks:
63
63
  - load-balancer
64
64
 
package/package.json CHANGED
@@ -2,14 +2,15 @@
2
2
  "type": "module",
3
3
  "main": "src/index.js",
4
4
  "name": "underpost",
5
- "version": "2.7.7",
5
+ "version": "2.7.9",
6
6
  "description": "pwa api rest template",
7
7
  "scripts": {
8
8
  "start": "env-cmd -f .env.production node --max-old-space-size=8192 src/server",
9
9
  "pm2": "env-cmd -f .env.production pm2 start src/server.js --node-args=\"--max-old-space-size=8192\" --name engine && pm2 logs",
10
10
  "ssl": "env-cmd -f .env.production node bin/ssl",
11
11
  "pm2-delete": "pm2 delete engine",
12
- "build": "node bin/deploy build-full-client --no-warnings",
12
+ "build": "node bin/deploy build-full-client",
13
+ "build-production": "env-cmd -f .env.production node bin/deploy build-full-client",
13
14
  "dev": "env-cmd -f .env.development node src/client.dev --no-warnings",
14
15
  "dev-api": "env-cmd -f .env.development nodemon --watch src --ignore src/client src/api",
15
16
  "docs": "jsdoc -c jsdoc.json",
@@ -95,7 +96,6 @@
95
96
  "marked": "^12.0.2",
96
97
  "mongoose": "^8.0.1",
97
98
  "morgan": "^1.10.0",
98
- "node-cron": "^3.0.3",
99
99
  "nodemailer": "^6.9.9",
100
100
  "nodemon": "^3.0.1",
101
101
  "pathfinding": "^0.4.18",
@@ -1,4 +1,4 @@
1
- import { authMiddleware } from '../../server/auth.js';
1
+ import { adminGuard, authMiddleware } from '../../server/auth.js';
2
2
  import { loggerFactory } from '../../server/logger.js';
3
3
  import { CoreController } from './core.controller.js';
4
4
  import express from 'express';
@@ -7,14 +7,14 @@ const logger = loggerFactory(import.meta);
7
7
 
8
8
  const CoreRouter = (options) => {
9
9
  const router = express.Router();
10
- router.post(`/:id`, async (req, res) => await CoreController.post(req, res, options));
11
- router.post(`/`, async (req, res) => await CoreController.post(req, res, options));
12
- router.get(`/:id`, async (req, res) => await CoreController.get(req, res, options));
13
- router.get(`/`, async (req, res) => await CoreController.get(req, res, options));
14
- router.put(`/:id`, async (req, res) => await CoreController.put(req, res, options));
15
- router.put(`/`, async (req, res) => await CoreController.put(req, res, options));
16
- router.delete(`/:id`, async (req, res) => await CoreController.delete(req, res, options));
17
- router.delete(`/`, async (req, res) => await CoreController.delete(req, res, options));
10
+ router.post(`/:id`, authMiddleware, adminGuard, async (req, res) => await CoreController.post(req, res, options));
11
+ router.post(`/`, authMiddleware, adminGuard, async (req, res) => await CoreController.post(req, res, options));
12
+ router.get(`/:id`, authMiddleware, adminGuard, async (req, res) => await CoreController.get(req, res, options));
13
+ router.get(`/`, authMiddleware, adminGuard, async (req, res) => await CoreController.get(req, res, options));
14
+ router.put(`/:id`, authMiddleware, adminGuard, async (req, res) => await CoreController.put(req, res, options));
15
+ router.put(`/`, authMiddleware, adminGuard, async (req, res) => await CoreController.put(req, res, options));
16
+ router.delete(`/:id`, authMiddleware, adminGuard, async (req, res) => await CoreController.delete(req, res, options));
17
+ router.delete(`/`, authMiddleware, adminGuard, async (req, res) => await CoreController.delete(req, res, options));
18
18
  return router;
19
19
  };
20
20
 
@@ -1,27 +1,29 @@
1
1
  import { DataBaseProvider } from '../../db/DataBaseProvider.js';
2
2
  import { loggerFactory } from '../../server/logger.js';
3
+ import { shellExec } from '../../server/process.js';
3
4
 
4
5
  const logger = loggerFactory(import.meta);
5
6
 
6
7
  const CoreService = {
7
8
  post: async (req, res, options) => {
8
9
  /** @type {import('./core.model.js').CoreModel} */
9
- const Core = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.Core;
10
+ const Core = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.models.Core;
11
+ if (req.path.startsWith('/sh')) return shellExec(req.body.sh, { stdout: true });
10
12
  return await new Core(req.body).save();
11
13
  },
12
14
  get: async (req, res, options) => {
13
15
  /** @type {import('./core.model.js').CoreModel} */
14
- const Core = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.Core;
16
+ const Core = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.models.Core;
15
17
  return await Core.findById(req.params.id);
16
18
  },
17
19
  put: async (req, res, options) => {
18
20
  /** @type {import('./core.model.js').CoreModel} */
19
- const Core = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.Core;
21
+ const Core = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.models.Core;
20
22
  return await Core.findByIdAndUpdate(req.params.id, req.body);
21
23
  },
22
24
  delete: async (req, res, options) => {
23
25
  /** @type {import('./core.model.js').CoreModel} */
24
- const Core = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.Core;
26
+ const Core = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.models.Core;
25
27
  return await Core.findByIdAndDelete(req.params.id);
26
28
  },
27
29
  };
@@ -6,23 +6,23 @@ const logger = loggerFactory(import.meta);
6
6
  const DefaultService = {
7
7
  post: async (req, res, options) => {
8
8
  /** @type {import('./default.model.js').DefaultModel} */
9
- const Default = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.Default;
9
+ const Default = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.models.Default;
10
10
  return await new Default(req.body).save();
11
11
  },
12
12
  get: async (req, res, options) => {
13
13
  /** @type {import('./default.model.js').DefaultModel} */
14
- const Default = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.Default;
14
+ const Default = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.models.Default;
15
15
  if (req.params.id) return await Default.findById(req.params.id);
16
16
  return await Default.find();
17
17
  },
18
18
  put: async (req, res, options) => {
19
19
  /** @type {import('./default.model.js').DefaultModel} */
20
- const Default = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.Default;
20
+ const Default = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.models.Default;
21
21
  return await Default.findByIdAndUpdate(req.params.id, req.body);
22
22
  },
23
23
  delete: async (req, res, options) => {
24
24
  /** @type {import('./default.model.js').DefaultModel} */
25
- const Default = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.Default;
25
+ const Default = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.models.Default;
26
26
  if (req.params.id) return await Default.findByIdAndDelete(req.params.id);
27
27
  else return await await Default.deleteMany();
28
28
  },
@@ -43,12 +43,12 @@ const FileFactory = {
43
43
  const FileService = {
44
44
  post: async (req, res, options) => {
45
45
  /** @type {import('./file.model.js').FileModel} */
46
- const File = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.File;
46
+ const File = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.models.File;
47
47
  return await FileFactory.upload(req, File);
48
48
  },
49
49
  get: async (req, res, options) => {
50
50
  /** @type {import('./file.model.js').FileModel} */
51
- const File = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.File;
51
+ const File = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.models.File;
52
52
 
53
53
  if (req.path.startsWith('/blob') && req.params.id) {
54
54
  const file = await File.findOne({ _id: req.params.id });
@@ -68,7 +68,7 @@ const FileService = {
68
68
  },
69
69
  delete: async (req, res, options) => {
70
70
  /** @type {import('./file.model.js').FileModel} */
71
- const File = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.File;
71
+ const File = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.models.File;
72
72
 
73
73
  switch (req.params.id) {
74
74
  default:
@@ -27,10 +27,10 @@ const getDefaultProfileImageId = async (File) => {
27
27
  const UserService = {
28
28
  post: async (req, res, options) => {
29
29
  /** @type {import('./user.model.js').UserModel} */
30
- const User = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.User;
30
+ const User = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.models.User;
31
31
 
32
32
  /** @type {import('../file/file.model.js').FileModel} */
33
- const File = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.File;
33
+ const File = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.models.File;
34
34
 
35
35
  if (req.params.id === 'recover-verify-email') {
36
36
  const user = await User.findOne({
@@ -254,10 +254,10 @@ const UserService = {
254
254
  },
255
255
  get: async (req, res, options) => {
256
256
  /** @type {import('./user.model.js').UserModel} */
257
- const User = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.User;
257
+ const User = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.models.User;
258
258
 
259
259
  /** @type {import('../file/file.model.js').FileModel} */
260
- const File = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.File;
260
+ const File = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.models.File;
261
261
 
262
262
  if (req.path.startsWith('/email')) {
263
263
  return await User.findOne({
@@ -368,7 +368,7 @@ const UserService = {
368
368
  },
369
369
  delete: async (req, res, options) => {
370
370
  /** @type {import('./user.model.js').UserModel} */
371
- const User = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.User;
371
+ const User = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.models.User;
372
372
  switch (req.params.id) {
373
373
  default: {
374
374
  const user = await User.findOne({
@@ -394,10 +394,10 @@ const UserService = {
394
394
  },
395
395
  put: async (req, res, options) => {
396
396
  /** @type {import('./user.model.js').UserModel} */
397
- const User = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.User;
397
+ const User = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.models.User;
398
398
 
399
399
  /** @type {import('../file/file.model.js').FileModel} */
400
- const File = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.File;
400
+ const File = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.models.File;
401
401
 
402
402
  // req.path | req.baseUrl
403
403