@saltcorn/server 0.6.1-beta.0 → 0.6.1

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 (53) hide show
  1. package/app.js +7 -0
  2. package/auth/admin.js +120 -5
  3. package/auth/index.js +7 -0
  4. package/auth/resetpw.js +22 -0
  5. package/auth/roleadmin.js +52 -0
  6. package/auth/routes.js +211 -2
  7. package/auth/testhelp.js +69 -0
  8. package/errors.js +14 -1
  9. package/fixture_persons.js +14 -0
  10. package/index.js +6 -0
  11. package/load_plugins.js +4 -3
  12. package/locales/en.json +7 -1
  13. package/markup/admin.js +97 -1
  14. package/markup/blockly.js +15 -0
  15. package/markup/expression_blurb.js +45 -0
  16. package/markup/forms.js +24 -0
  17. package/markup/index.js +7 -0
  18. package/markup/plugin-store.js +36 -0
  19. package/package.json +6 -6
  20. package/public/saltcorn-builder.css +1 -0
  21. package/public/saltcorn.js +5 -1
  22. package/routes/actions.js +53 -1
  23. package/routes/admin.js +97 -1
  24. package/routes/api.js +45 -10
  25. package/routes/config.js +18 -0
  26. package/routes/crashlog.js +31 -0
  27. package/routes/delete.js +19 -0
  28. package/routes/edit.js +19 -0
  29. package/routes/eventlog.js +65 -1
  30. package/routes/events.js +19 -0
  31. package/routes/fields.js +88 -0
  32. package/routes/files.js +62 -0
  33. package/routes/homepage.js +175 -80
  34. package/routes/index.js +7 -1
  35. package/routes/infoarch.js +56 -0
  36. package/routes/library.js +32 -0
  37. package/routes/list.js +28 -1
  38. package/routes/menu.js +45 -0
  39. package/routes/packs.js +53 -0
  40. package/routes/page.js +26 -0
  41. package/routes/pageedit.js +129 -3
  42. package/routes/plugins.js +156 -5
  43. package/routes/scapi.js +79 -23
  44. package/routes/search.js +51 -0
  45. package/routes/settings.js +27 -0
  46. package/routes/tables.js +148 -19
  47. package/routes/tenant.js +123 -31
  48. package/routes/utils.js +60 -1
  49. package/routes/view.js +37 -0
  50. package/routes/viewedit.js +114 -1
  51. package/serve.js +138 -88
  52. package/systemd.js +18 -1
  53. package/wrapper.js +4 -0
@@ -1,6 +1,8 @@
1
1
  /**
2
2
  * View Edit Router
3
- *
3
+ * @category server
4
+ * @module routes/viewedit
5
+ * @subcategory routes
4
6
  */
5
7
 
6
8
  const Router = require("express-promise-router");
@@ -40,9 +42,22 @@ const Page = require("@saltcorn/data/models/page");
40
42
  const { add_to_menu } = require("@saltcorn/data/models/pack");
41
43
  const { editRoleForm } = require("../markup/forms.js");
42
44
 
45
+ /**
46
+ * @type {object}
47
+ * @const
48
+ * @namespace vieweditRouter
49
+ * @category server
50
+ * @subcategory routes
51
+ */
43
52
  const router = new Router();
44
53
  module.exports = router;
45
54
 
55
+ /**
56
+ * @param {object} view
57
+ * @param {object[]} roles
58
+ * @param {object} req
59
+ * @returns {Form}
60
+ */
46
61
  const editViewRoleForm = (view, roles, req) =>
47
62
  editRoleForm({
48
63
  url: `/viewedit/setrole/${view.id}`,
@@ -51,6 +66,11 @@ const editViewRoleForm = (view, roles, req) =>
51
66
  req,
52
67
  });
53
68
 
69
+ /**
70
+ * @param {object} view
71
+ * @param {object} req
72
+ * @returns {div}
73
+ */
54
74
  const view_dropdown = (view, req) =>
55
75
  settingsDropdown(`dropdownMenuButton${view.id}`, [
56
76
  a(
@@ -86,6 +106,13 @@ const view_dropdown = (view, req) =>
86
106
  view.name
87
107
  ),
88
108
  ]);
109
+
110
+ /**
111
+ * @name get
112
+ * @function
113
+ * @memberof module:routes/viewedit~vieweditRouter
114
+ * @function
115
+ */
89
116
  router.get(
90
117
  "/",
91
118
  setTenant,
@@ -190,9 +217,22 @@ router.get(
190
217
  })
191
218
  );
192
219
 
220
+ /**
221
+ * @param {object} o
222
+ * @param {function} f
223
+ * @returns {object}
224
+ */
193
225
  const mapObjectValues = (o, f) =>
194
226
  Object.fromEntries(Object.entries(o).map(([k, v]) => [k, f(v)]));
195
227
 
228
+ /**
229
+ * @param {object} req
230
+ * @param {object} tableOptions
231
+ * @param {object[]} roles
232
+ * @param {object[]} pages
233
+ * @param {object} values
234
+ * @returns {Form}
235
+ */
196
236
  const viewForm = (req, tableOptions, roles, pages, values) => {
197
237
  const isEdit =
198
238
  values && values.id && !getState().getConfig("development_mode", false);
@@ -279,6 +319,13 @@ const viewForm = (req, tableOptions, roles, pages, values) => {
279
319
  values,
280
320
  });
281
321
  };
322
+
323
+ /**
324
+ * @name get/edit/:viewname
325
+ * @function
326
+ * @memberof module:routes/viewedit~vieweditRouter
327
+ * @function
328
+ */
282
329
  router.get(
283
330
  "/edit/:viewname",
284
331
  setTenant,
@@ -321,6 +368,12 @@ router.get(
321
368
  })
322
369
  );
323
370
 
371
+ /**
372
+ * @name get/new
373
+ * @function
374
+ * @memberof module:routes/viewedit~vieweditRouter
375
+ * @function
376
+ */
324
377
  router.get(
325
378
  "/new",
326
379
  setTenant,
@@ -353,6 +406,12 @@ router.get(
353
406
  })
354
407
  );
355
408
 
409
+ /**
410
+ * @name post/save
411
+ * @function
412
+ * @memberof module:routes/viewedit~vieweditRouter
413
+ * @function
414
+ */
356
415
  router.post(
357
416
  "/save",
358
417
  setTenant,
@@ -423,6 +482,15 @@ router.post(
423
482
  }
424
483
  })
425
484
  );
485
+
486
+ /**
487
+ * @param {object} view
488
+ * @param {Workflow} wf
489
+ * @param {object} wfres
490
+ * @param {object} req
491
+ * @param {object} res
492
+ * @returns {void}
493
+ */
426
494
  const respondWorkflow = (view, wf, wfres, req, res) => {
427
495
  const wrap = (contents, noCard) => ({
428
496
  above: [
@@ -455,6 +523,13 @@ const respondWorkflow = (view, wf, wfres, req, res) => {
455
523
  );
456
524
  } else res.redirect(wfres.redirect);
457
525
  };
526
+
527
+ /**
528
+ * @name get/config/:name
529
+ * @function
530
+ * @memberof module:routes/viewedit~vieweditRouter
531
+ * @function
532
+ */
458
533
  router.get(
459
534
  "/config/:name",
460
535
  setTenant,
@@ -482,6 +557,12 @@ router.get(
482
557
  })
483
558
  );
484
559
 
560
+ /**
561
+ * @name post/config/:name
562
+ * @function
563
+ * @memberof module:routes/viewedit~vieweditRouter
564
+ * @function
565
+ */
485
566
  router.post(
486
567
  "/config/:name",
487
568
  setTenant,
@@ -495,6 +576,13 @@ router.post(
495
576
  respondWorkflow(view, configFlow, wfres, req, res);
496
577
  })
497
578
  );
579
+
580
+ /**
581
+ * @name post/add-to-menu/:id
582
+ * @function
583
+ * @memberof module:routes/viewedit~vieweditRouter
584
+ * @function
585
+ */
498
586
  router.post(
499
587
  "/add-to-menu/:id",
500
588
  setTenant,
@@ -519,6 +607,12 @@ router.post(
519
607
  })
520
608
  );
521
609
 
610
+ /**
611
+ * @name post/clone/:id
612
+ * @function
613
+ * @memberof module:routes/viewedit~vieweditRouter
614
+ * @function
615
+ */
522
616
  router.post(
523
617
  "/clone/:id",
524
618
  setTenant,
@@ -535,6 +629,12 @@ router.post(
535
629
  })
536
630
  );
537
631
 
632
+ /**
633
+ * @name post/delete/:id
634
+ * @function
635
+ * @memberof module:routes/viewedit~vieweditRouter
636
+ * @function
637
+ */
538
638
  router.post(
539
639
  "/delete/:id",
540
640
  setTenant,
@@ -547,6 +647,12 @@ router.post(
547
647
  })
548
648
  );
549
649
 
650
+ /**
651
+ * @name post/savebuilder/:id
652
+ * @function
653
+ * @memberof module:routes/viewedit~vieweditRouter
654
+ * @function
655
+ */
550
656
  router.post(
551
657
  "/savebuilder/:id",
552
658
  setTenant,
@@ -564,6 +670,13 @@ router.post(
564
670
  }
565
671
  })
566
672
  );
673
+
674
+ /**
675
+ * @name post/setrole/:id
676
+ * @function
677
+ * @memberof module:routes/viewedit~vieweditRouter
678
+ * @function
679
+ */
567
680
  router.post(
568
681
  "/setrole/:id",
569
682
  setTenant,
package/serve.js CHANGED
@@ -1,8 +1,9 @@
1
1
  /**
2
2
  * Serve is Saltcorn server starter
3
3
  *
4
+ * @category server
5
+ * @module serve
4
6
  */
5
-
6
7
  const runScheduler = require("@saltcorn/data/models/scheduler");
7
8
  const User = require("@saltcorn/data/models/user");
8
9
  const Plugin = require("@saltcorn/data/models/plugin");
@@ -35,6 +36,12 @@ const View = require("@saltcorn/data/models/view");
35
36
 
36
37
  // helpful https://gist.github.com/jpoehls/2232358
37
38
 
39
+ /**
40
+ * @param {object} opts
41
+ * @param {object} opts
42
+ * @param {boolean} opts.disableMigrate
43
+ * @param {boolean} [useClusterAdaptor = true]
44
+ */
38
45
  const initMaster = async ({ disableMigrate }, useClusterAdaptor = true) => {
39
46
  let sql_log;
40
47
  try {
@@ -66,6 +73,12 @@ const initMaster = async ({ disableMigrate }, useClusterAdaptor = true) => {
66
73
  if (useClusterAdaptor) setupPrimary();
67
74
  };
68
75
 
76
+ /**
77
+ * @param {object} opts
78
+ * @param {object} opts.tenant
79
+ * @param {...*} opts.msg
80
+ * @returns {void}
81
+ */
69
82
  const workerDispatchMsg = ({ tenant, ...msg }) => {
70
83
  if (tenant) {
71
84
  db.runWithTenant(tenant, () => workerDispatchMsg(msg));
@@ -77,14 +90,29 @@ const workerDispatchMsg = ({ tenant, ...msg }) => {
77
90
  });
78
91
  }
79
92
  if (msg.refresh) getState()[`refresh_${msg.refresh}`](true);
80
- if (msg.createTenant)
93
+ if (msg.createTenant) {
81
94
  create_tenant(msg.createTenant, loadAllPlugins, "", true);
95
+ db.runWithTenant(msg.createTenant, async () => {
96
+ getState().refresh(true);
97
+ });
98
+ }
82
99
  if (msg.installPlugin) {
83
100
  loadAndSaveNewPlugin(msg.installPlugin, msg.force, true);
84
101
  }
85
102
  if (msg.restart_tenant) restart_tenant(loadAllPlugins);
86
103
  if (msg.removePlugin) getState().remove_plugin(msg.removePlugin, true);
87
104
  };
105
+
106
+ /**
107
+ *
108
+ * @param {*} masterState
109
+ * @param {object} opts
110
+ * @param {string} opts.port
111
+ * @param {boolean} opts.watchReaper
112
+ * @param {boolean} opts.disableScheduler
113
+ * @param {number} opts.pid
114
+ * @returns {function}
115
+ */
88
116
  const onMessageFromWorker = (
89
117
  masterState,
90
118
  { port, watchReaper, disableScheduler, pid }
@@ -109,105 +137,122 @@ const onMessageFromWorker = (
109
137
  }
110
138
  };
111
139
 
112
- module.exports = async ({
113
- port = 3000,
114
- watchReaper,
115
- disableScheduler,
116
- defaultNCPUs,
117
- ...appargs
118
- } = {}) => {
119
- const useNCpus = process.env.SALTCORN_NWORKERS
120
- ? +process.env.SALTCORN_NWORKERS
121
- : defaultNCPUs;
140
+ module.exports =
141
+ /**
142
+ * @function
143
+ * @name "module.exports function"
144
+ * @param {object} [opts = {}]
145
+ * @param {number} [opts.port = 3000]
146
+ * @param {boolean} opts.watchReaper
147
+ * @param {boolean} opts.disableScheduler
148
+ * @param {number} opts.defaultNCPUs
149
+ * @param {...*} opts.appargs
150
+ * @returns {Promise<void>}
151
+ */
152
+ async ({
153
+ port = 3000,
154
+ watchReaper,
155
+ disableScheduler,
156
+ defaultNCPUs,
157
+ ...appargs
158
+ } = {}) => {
159
+ const useNCpus = process.env.SALTCORN_NWORKERS
160
+ ? +process.env.SALTCORN_NWORKERS
161
+ : defaultNCPUs;
122
162
 
123
- const letsEncrypt = await getConfig("letsencrypt", false);
124
- const masterState = {
125
- started: false,
126
- listeningTo: new Set([]),
127
- };
163
+ const letsEncrypt = await getConfig("letsencrypt", false);
164
+ const masterState = {
165
+ started: false,
166
+ listeningTo: new Set([]),
167
+ };
128
168
 
129
- const addWorker = (worker) => {
130
- worker.on(
131
- "message",
132
- onMessageFromWorker(masterState, {
133
- port,
134
- watchReaper,
135
- disableScheduler,
136
- pid: worker.process.pid,
137
- })
138
- );
139
- };
169
+ const addWorker = (worker) => {
170
+ worker.on(
171
+ "message",
172
+ onMessageFromWorker(masterState, {
173
+ port,
174
+ watchReaper,
175
+ disableScheduler,
176
+ pid: worker.process.pid,
177
+ })
178
+ );
179
+ };
140
180
 
141
- if (port === 80 && letsEncrypt) {
142
- const admin_users = await User.find({ role_id: 1 }, { orderBy: "id" });
143
- const file_store = db.connectObj.file_store;
144
- const Greenlock = require("greenlock");
145
- const greenlock = Greenlock.create({
146
- packageRoot: __dirname,
147
- configDir: path.join(file_store, "greenlock.d"),
148
- maintainerEmail: admin_users[0].email,
149
- });
150
- const certs = await greenlock._find({});
151
- console.log("Certificates:", certs);
181
+ if (port === 80 && letsEncrypt) {
182
+ const admin_users = await User.find({ role_id: 1 }, { orderBy: "id" });
183
+ const file_store = db.connectObj.file_store;
184
+ const Greenlock = require("greenlock");
185
+ const greenlock = Greenlock.create({
186
+ packageRoot: __dirname,
187
+ configDir: path.join(file_store, "greenlock.d"),
188
+ maintainerEmail: admin_users[0].email,
189
+ });
190
+ const certs = await greenlock._find({});
191
+ console.log("Certificates:", certs);
152
192
 
153
- if (certs && certs.length > 0) {
154
- const app = await getApp(appargs);
155
- const timeout = +getState().getConfig("timeout", 120);
156
- const initMasterListeners = () => {
157
- Object.entries(cluster.workers).forEach(([id, w]) => {
158
- if (!masterState.listeningTo.has(id)) {
159
- addWorker(w);
160
- masterState.listeningTo.add(id);
161
- }
162
- });
163
- if (masterState.listeningTo.size < useNCpus)
164
- setTimeout(initMasterListeners, 250);
165
- };
166
- require("greenlock-express")
167
- .init({
168
- packageRoot: __dirname,
169
- configDir: path.join(file_store, "greenlock.d"),
170
- maintainerEmail: admin_users[0].email,
171
- cluster: true,
172
- workers: useNCpus,
173
- })
174
- .ready((glx) => {
175
- const httpsServer = glx.httpsServer();
176
- setupSocket(httpsServer);
177
- httpsServer.setTimeout(timeout * 1000);
178
- process.on("message", workerDispatchMsg);
179
- glx.serveApp(app);
180
- process.send && process.send("Start");
181
- })
182
- .master(() => {
183
- initMaster(appargs).then(initMasterListeners);
184
- });
193
+ if (certs && certs.length > 0) {
194
+ const app = await getApp(appargs);
195
+ const timeout = +getState().getConfig("timeout", 120);
196
+ const initMasterListeners = () => {
197
+ Object.entries(cluster.workers).forEach(([id, w]) => {
198
+ if (!masterState.listeningTo.has(id)) {
199
+ addWorker(w);
200
+ masterState.listeningTo.add(id);
201
+ }
202
+ });
203
+ if (masterState.listeningTo.size < useNCpus)
204
+ setTimeout(initMasterListeners, 250);
205
+ };
206
+ require("greenlock-express")
207
+ .init({
208
+ packageRoot: __dirname,
209
+ configDir: path.join(file_store, "greenlock.d"),
210
+ maintainerEmail: admin_users[0].email,
211
+ cluster: true,
212
+ workers: useNCpus,
213
+ })
214
+ .ready((glx) => {
215
+ const httpsServer = glx.httpsServer();
216
+ setupSocket(httpsServer);
217
+ httpsServer.setTimeout(timeout * 1000);
218
+ process.on("message", workerDispatchMsg);
219
+ glx.serveApp(app);
220
+ process.send && process.send("Start");
221
+ })
222
+ .master(() => {
223
+ initMaster(appargs).then(initMasterListeners);
224
+ });
185
225
 
186
- return; // none of stuff below will execute
226
+ return; // none of stuff below will execute
227
+ }
187
228
  }
188
- }
189
- // No greenlock!
229
+ // No greenlock!
190
230
 
191
- if (cluster.isMaster) {
192
- const forkAnyWorkers = useNCpus > 1 && process.platform !== "win32";
193
- await initMaster(appargs, forkAnyWorkers);
231
+ if (cluster.isMaster) {
232
+ const forkAnyWorkers = useNCpus > 1 && process.platform !== "win32";
233
+ await initMaster(appargs, forkAnyWorkers);
194
234
 
195
- if (forkAnyWorkers) {
196
- for (let i = 0; i < useNCpus; i++) addWorker(cluster.fork());
235
+ if (forkAnyWorkers) {
236
+ for (let i = 0; i < useNCpus; i++) addWorker(cluster.fork());
197
237
 
198
- cluster.on("exit", (worker, code, signal) => {
199
- console.log(`worker ${worker.process.pid} died`);
200
- addWorker(cluster.fork());
201
- });
238
+ cluster.on("exit", (worker, code, signal) => {
239
+ console.log(`worker ${worker.process.pid} died`);
240
+ addWorker(cluster.fork());
241
+ });
242
+ } else {
243
+ await nonGreenlockWorkerSetup(appargs, port);
244
+ }
245
+ Trigger.emitEvent("Startup");
202
246
  } else {
203
247
  await nonGreenlockWorkerSetup(appargs, port);
204
248
  }
205
- Trigger.emitEvent("Startup");
206
- } else {
207
- await nonGreenlockWorkerSetup(appargs, port);
208
- }
209
- };
249
+ };
210
250
 
251
+ /**
252
+ * @param {*} appargs
253
+ * @param {*} port
254
+ * @returns {Promise<void>}
255
+ */
211
256
  const nonGreenlockWorkerSetup = async (appargs, port) => {
212
257
  process.send && process.on("message", workerDispatchMsg);
213
258
 
@@ -251,6 +296,11 @@ const nonGreenlockWorkerSetup = async (appargs, port) => {
251
296
  }
252
297
  process.send && process.send("Start");
253
298
  };
299
+
300
+ /**
301
+ *
302
+ * @param {...*} servers
303
+ */
254
304
  const setupSocket = (...servers) => {
255
305
  // https://socket.io/docs/v4/middlewares/
256
306
  const wrap = (middleware) => (socket, next) =>
package/systemd.js CHANGED
@@ -1,5 +1,16 @@
1
+ /**
2
+ * @category server
3
+ * @module systemd
4
+ */
1
5
  const fetch = require("node-fetch");
2
6
 
7
+ /**
8
+ * @param {number} interval
9
+ * @param {object} notify
10
+ * @param {object} opts
11
+ * @param {string} opts.port
12
+ * @returns {void}
13
+ */
3
14
  const watchDog = (interval, notify, { port }) => {
4
15
  //we want to do a request / db check every 5 mins
5
16
  const pings_per_5_min = (5 * 60000) / interval;
@@ -37,7 +48,13 @@ const watchDog = (interval, notify, { port }) => {
37
48
  }
38
49
  };
39
50
 
40
- module.exports = (opts) => {
51
+ module.exports =
52
+ /**
53
+ * @function
54
+ * @name "module.exports function"
55
+ * @param {object} opts
56
+ */
57
+ (opts) => {
41
58
  try {
42
59
  const notify = require("sd-notify");
43
60
  notify.ready();
package/wrapper.js CHANGED
@@ -1,3 +1,7 @@
1
+ /**
2
+ * @category server
3
+ * @module wrapper
4
+ */
1
5
  const { getState } = require("@saltcorn/data/db/state");
2
6
  const db = require("@saltcorn/data/db");
3
7
  const { ul, li, h3, div, small } = require("@saltcorn/markup/tags");