@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
package/routes/fields.js CHANGED
@@ -1,6 +1,9 @@
1
1
  /**
2
2
  *
3
3
  * Field Router
4
+ * @category server
5
+ * @module routes/fields
6
+ * @subcategory routes
4
7
  */
5
8
 
6
9
  const Router = require("express-promise-router");
@@ -23,9 +26,25 @@ const { setTenant, isAdmin, error_catcher } = require("./utils.js");
23
26
  const expressionBlurb = require("../markup/expression_blurb");
24
27
  const { readState } = require("@saltcorn/data/plugin-helper");
25
28
  const { wizardCardTitle } = require("../markup/forms.js");
29
+
30
+ /**
31
+ * @type {object}
32
+ * @const
33
+ * @namespace fieldsRouter
34
+ * @category server
35
+ * @subcategory routes
36
+ */
26
37
  const router = new Router();
27
38
  module.exports = router;
28
39
 
40
+ /**
41
+ * @param {object} req
42
+ * @param {*} fkey_opts
43
+ * @param {*} existing_names
44
+ * @param {*} id
45
+ * @param {*} hasData
46
+ * @returns {Promise<Form>}
47
+ */
29
48
  const fieldForm = async (req, fkey_opts, existing_names, id, hasData) => {
30
49
  let isPrimary = false;
31
50
  let primaryTypes = Object.entries(getState().types)
@@ -116,22 +135,41 @@ const fieldForm = async (req, fkey_opts, existing_names, id, hasData) => {
116
135
  ],
117
136
  });
118
137
  };
138
+
139
+ /**
140
+ * @param {string} ctxType
141
+ * @returns {object}
142
+ */
119
143
  const calcFieldType = (ctxType) =>
120
144
  ctxType.startsWith("Key to")
121
145
  ? { type: "Key", reftable_name: ctxType.replace("Key to ", "") }
122
146
  : { type: ctxType };
123
147
 
148
+ /**
149
+ * @param {*} attrs
150
+ * @param {object} req
151
+ * @returns {*}
152
+ */
124
153
  const translateAttributes = (attrs, req) =>
125
154
  Array.isArray(attrs)
126
155
  ? attrs.map((attr) => translateAttribute(attr, req))
127
156
  : attrs;
128
157
 
158
+ /**
159
+ * @param {*} attr
160
+ * @param {*} req
161
+ * @returns {object}
162
+ */
129
163
  const translateAttribute = (attr, req) => {
130
164
  const res = { ...attr };
131
165
  if (res.sublabel) res.sublabel = req.__(res.sublabel);
132
166
  return res;
133
167
  };
134
168
 
169
+ /**
170
+ * @param {*} req
171
+ * @returns {Workflow}
172
+ */
135
173
  const fieldFlow = (req) =>
136
174
  new Workflow({
137
175
  action: "/field",
@@ -372,6 +410,13 @@ const fieldFlow = (req) =>
372
410
  },
373
411
  ],
374
412
  });
413
+
414
+ /**
415
+ * @name get/:id
416
+ * @function
417
+ * @memberof module:routes/fields~fieldsRouter
418
+ * @function
419
+ */
375
420
  router.get(
376
421
  "/:id",
377
422
  setTenant,
@@ -419,6 +464,12 @@ router.get(
419
464
  })
420
465
  );
421
466
 
467
+ /**
468
+ * @name get/new/:table_id
469
+ * @function
470
+ * @memberof module:routes/fields~fieldsRouter
471
+ * @function
472
+ */
422
473
  router.get(
423
474
  "/new/:table_id",
424
475
  setTenant,
@@ -450,6 +501,12 @@ router.get(
450
501
  })
451
502
  );
452
503
 
504
+ /**
505
+ * @name post/delete/:id
506
+ * @function
507
+ * @memberof module:routes/fields~fieldsRouter
508
+ * @function
509
+ */
453
510
  router.post(
454
511
  "/delete/:id",
455
512
  setTenant,
@@ -470,6 +527,12 @@ router.post(
470
527
  })
471
528
  );
472
529
 
530
+ /**
531
+ * @name post
532
+ * @function
533
+ * @memberof module:routes/fields~fieldsRouter
534
+ * @function
535
+ */
473
536
  router.post(
474
537
  "/",
475
538
  setTenant,
@@ -513,6 +576,12 @@ router.post(
513
576
  })
514
577
  );
515
578
 
579
+ /**
580
+ * @name post/test-formula
581
+ * @function
582
+ * @memberof module:routes/fields~fieldsRouter
583
+ * @function
584
+ */
516
585
  router.post(
517
586
  "/test-formula",
518
587
  setTenant,
@@ -544,6 +613,13 @@ router.post(
544
613
  }
545
614
  })
546
615
  );
616
+
617
+ /**
618
+ * @name post/show-calculated/:tableName/:fieldName/:fieldview
619
+ * @function
620
+ * @memberof module:routes/fields~fieldsRouter
621
+ * @function
622
+ */
547
623
  router.post(
548
624
  "/show-calculated/:tableName/:fieldName/:fieldview",
549
625
  setTenant,
@@ -573,6 +649,12 @@ router.post(
573
649
  })
574
650
  );
575
651
 
652
+ /**
653
+ * @name post/preview/:tableName/:fieldName/:fieldview
654
+ * @function
655
+ * @memberof module:routes/fields~fieldsRouter
656
+ * @function
657
+ */
576
658
  router.post(
577
659
  "/preview/:tableName/:fieldName/:fieldview",
578
660
  setTenant,
@@ -632,6 +714,12 @@ router.post(
632
714
  })
633
715
  );
634
716
 
717
+ /**
718
+ * @name post/preview/:tableName/:fieldName/
719
+ * @function
720
+ * @memberof module:routes/fields~fieldsRouter
721
+ * @function
722
+ */
635
723
  router.post(
636
724
  "/preview/:tableName/:fieldName/",
637
725
  setTenant,
package/routes/files.js CHANGED
@@ -1,3 +1,9 @@
1
+ /**
2
+ * @category server
3
+ * @module routes/files
4
+ * @subcategory routes
5
+ */
6
+
1
7
  const Router = require("express-promise-router");
2
8
  const File = require("@saltcorn/data/models/file");
3
9
  const User = require("@saltcorn/data/models/user");
@@ -32,9 +38,22 @@ const { csrfField } = require("./utils");
32
38
  const { editRoleForm, fileUploadForm } = require("../markup/forms.js");
33
39
  const { strictParseInt } = require("@saltcorn/data/plugin-helper");
34
40
 
41
+ /**
42
+ * @type {object}
43
+ * @const
44
+ * @namespace filesRouter
45
+ * @category server
46
+ * @subcategory routes
47
+ */
35
48
  const router = new Router();
36
49
  module.exports = router;
37
50
 
51
+ /**
52
+ * @param {*} file
53
+ * @param {*} roles
54
+ * @param {*} req
55
+ * @returns {Form}
56
+ */
38
57
  const editFileRoleForm = (file, roles, req) =>
39
58
  editRoleForm({
40
59
  url: `/files/setrole/${file.id}`,
@@ -43,6 +62,12 @@ const editFileRoleForm = (file, roles, req) =>
43
62
  req,
44
63
  });
45
64
 
65
+ /**
66
+ * @name get
67
+ * @function
68
+ * @memberof module:routes/files~filesRouter
69
+ * @function
70
+ */
46
71
  router.get(
47
72
  "/",
48
73
  setTenant,
@@ -104,6 +129,12 @@ router.get(
104
129
  })
105
130
  );
106
131
 
132
+ /**
133
+ * @name get/download/:id
134
+ * @function
135
+ * @memberof module:routes/files~filesRouter
136
+ * @function
137
+ */
107
138
  router.get(
108
139
  "/download/:id",
109
140
  setTenant,
@@ -122,6 +153,12 @@ router.get(
122
153
  })
123
154
  );
124
155
 
156
+ /**
157
+ * @name get/serve/:id
158
+ * @function
159
+ * @memberof module:routes/files~filesRouter
160
+ * @function
161
+ */
125
162
  router.get(
126
163
  "/serve/:id",
127
164
  setTenant,
@@ -152,6 +189,12 @@ router.get(
152
189
  })
153
190
  );
154
191
 
192
+ /**
193
+ * @name post/setrole/:id
194
+ * @function
195
+ * @memberof module:routes/files~filesRouter
196
+ * @function
197
+ */
155
198
  router.post(
156
199
  "/setrole/:id",
157
200
  setTenant,
@@ -173,6 +216,13 @@ router.post(
173
216
  res.redirect("/files");
174
217
  })
175
218
  );
219
+
220
+ /**
221
+ * @name post/setname/:id
222
+ * @function
223
+ * @memberof module:routes/files~filesRouter
224
+ * @function
225
+ */
176
226
  router.post(
177
227
  "/setname/:id",
178
228
  setTenant,
@@ -186,6 +236,12 @@ router.post(
186
236
  })
187
237
  );
188
238
 
239
+ /**
240
+ * @name post/upload
241
+ * @function
242
+ * @memberof module:routes/files~filesRouter
243
+ * @function
244
+ */
189
245
  router.post(
190
246
  "/upload",
191
247
  setTenant,
@@ -233,6 +289,12 @@ router.post(
233
289
  })
234
290
  );
235
291
 
292
+ /**
293
+ * @name post/delete/:id
294
+ * @function
295
+ * @memberof module:routes/files~filesRouter
296
+ * @function
297
+ */
236
298
  router.post(
237
299
  "/delete/:id",
238
300
  setTenant,
@@ -1,3 +1,9 @@
1
+ /**
2
+ * @category server
3
+ * @module routes/homepage
4
+ * @subcategory routes
5
+ */
6
+
1
7
  const { getState } = require("@saltcorn/data/db/state");
2
8
  const db = require("@saltcorn/data/db");
3
9
  const View = require("@saltcorn/data/models/view");
@@ -14,6 +20,11 @@ const packagejson = require("../package.json");
14
20
  const Trigger = require("@saltcorn/data/models/trigger");
15
21
  const { fileUploadForm } = require("../markup/forms");
16
22
 
23
+ /**
24
+ * @param {*} tables
25
+ * @param {object} req
26
+ * @returns {Table}
27
+ */
17
28
  const tableTable = (tables, req) =>
18
29
  mkTable(
19
30
  [
@@ -26,6 +37,11 @@ const tableTable = (tables, req) =>
26
37
  tables
27
38
  );
28
39
 
40
+ /**
41
+ * @param {*} tables
42
+ * @param {object} req
43
+ * @returns {object}
44
+ */
29
45
  const tableCard = (tables, req) => ({
30
46
  type: "card",
31
47
  class: "welcome-page-entity-list",
@@ -50,6 +66,11 @@ const tableCard = (tables, req) => ({
50
66
  ),
51
67
  });
52
68
 
69
+ /**
70
+ * @param {*} views
71
+ * @param {object} req
72
+ * @returns {Table}
73
+ */
53
74
  const viewTable = (views, req) =>
54
75
  mkTable(
55
76
  [
@@ -66,6 +87,11 @@ const viewTable = (views, req) =>
66
87
  views
67
88
  );
68
89
 
90
+ /**
91
+ * @param {*} views
92
+ * @param {object} req
93
+ * @returns {object}
94
+ */
69
95
  const viewCard = (views, req) => ({
70
96
  type: "card",
71
97
  title: link("/viewedit", req.__("Views")),
@@ -91,6 +117,12 @@ const viewCard = (views, req) => ({
91
117
  )
92
118
  ),
93
119
  });
120
+
121
+ /**
122
+ * @param {*} pages
123
+ * @param {object} req
124
+ * @returns {Table}
125
+ */
94
126
  const pageTable = (pages, req) =>
95
127
  mkTable(
96
128
  [
@@ -106,6 +138,12 @@ const pageTable = (pages, req) =>
106
138
  ],
107
139
  pages
108
140
  );
141
+
142
+ /**
143
+ * @param {*} pages
144
+ * @param {object} req
145
+ * @returns {object}
146
+ */
109
147
  const pageCard = (pages, req) => ({
110
148
  type: "card",
111
149
  title: link("/pageedit", req.__("Pages")),
@@ -133,8 +171,12 @@ const pageCard = (pages, req) => ({
133
171
  ),
134
172
  });
135
173
 
174
+ /**
175
+ * @param {object} req
176
+ * @returns {Promise<div>}
177
+ */
136
178
  const filesTab = async (req) => {
137
- const files = await File.find({}, { orderBy: "filename" });
179
+ const files = await File.find({}, { orderBy: "filename", cached: true });
138
180
  return div(
139
181
  files.length == 0
140
182
  ? p(req.__("No files"))
@@ -152,13 +194,12 @@ const filesTab = async (req) => {
152
194
  fileUploadForm(req)
153
195
  );
154
196
  };
155
- const usersTab = async (req) => {
156
- const users = await User.find({}, { orderBy: "id" });
157
- const roles = await User.get_roles();
158
- var roleMap = {};
159
- roles.forEach((r) => {
160
- roleMap[r.id] = r.role;
161
- });
197
+
198
+ /**
199
+ * @param {object} req
200
+ * @returns {Promise<div>}
201
+ */
202
+ const usersTab = async (req, users, roleMap) => {
162
203
  return div(
163
204
  mkTable(
164
205
  [
@@ -172,15 +213,19 @@ const usersTab = async (req) => {
172
213
  users
173
214
  ),
174
215
  a(
175
- { href: `/useradmin/new`, class: "btn btn-secondary" },
216
+ { href: `/useradmin/new`, class: "btn btn-secondary my-3" },
176
217
  req.__("Create user")
177
218
  )
178
219
  );
179
220
  };
180
- const actionsTab = async (req) => {
181
- const triggers = await Trigger.findAllWithTableName();
182
221
 
222
+ /**
223
+ * @param {object} req
224
+ * @returns {Promise<div>}
225
+ */
226
+ const actionsTab = async (req, triggers) => {
183
227
  return div(
228
+ { class: "pb-3" },
184
229
  triggers.length <= 1 &&
185
230
  p(
186
231
  { class: "mt-2 pr-2" },
@@ -207,21 +252,91 @@ const actionsTab = async (req) => {
207
252
  triggers
208
253
  ),
209
254
  a(
210
- { href: "/actions/new", class: "btn btn-secondary btn-smj" },
255
+ { href: "/actions/new", class: "btn btn-secondary my-3" },
211
256
  req.__("Add trigger")
212
257
  )
213
258
  );
214
259
  };
260
+ const packTab = (req, packlist) =>
261
+ div(
262
+ { class: "pb-3 pt-2 pr-4" },
263
+ p(req.__("Instead of building, get up and running in no time with packs")),
264
+ p(
265
+ { class: "font-italic" },
266
+ req.__(
267
+ "Packs are collections of tables, views and plugins that give you a full application which you can then edit to suit your needs."
268
+ )
269
+ ),
270
+ mkTable(
271
+ [
272
+ { label: req.__("Name"), key: "name" },
273
+ {
274
+ label: req.__("Description"),
275
+ key: "description",
276
+ },
277
+ ],
278
+ packlist,
279
+ { noHeader: true }
280
+ ),
281
+ a(
282
+ { href: `/plugins?set=packs`, class: "btn btn-primary" },
283
+ req.__("Go to pack store »")
284
+ )
285
+ );
286
+
287
+ const helpCard = (req) =>
288
+ div(
289
+ { class: "pb-3 pt-2 pr-4" },
290
+ p(req.__("Confused?")),
291
+ p(
292
+ req.__(
293
+ "The Wiki contains the documentation and tutorials on installing and using Saltcorn"
294
+ )
295
+ ),
296
+ a(
297
+ {
298
+ href: `https://wiki.saltcorn.com/`,
299
+ class: "btn btn-primary",
300
+ },
301
+ req.__("Go to Wiki »")
302
+ ),
303
+ p(req.__("The YouTube channel has some video tutorials")),
304
+ a(
305
+ {
306
+ href: `https://www.youtube.com/channel/UCBOpAcH8ep7ESbuocxcq0KQ`,
307
+ class: "btn btn-secondary",
308
+ },
309
+ req.__("Go to YouTube »")
310
+ ),
311
+ div(
312
+ { class: "mt-3" },
313
+ a(
314
+ { href: `https://blog.saltcorn.com/` },
315
+ req.__("What's new? Read the blog »")
316
+ )
317
+ )
318
+ );
319
+
320
+ /**
321
+ * @param {object} req
322
+ * @returns {Promise<object>}
323
+ */
215
324
  const welcome_page = async (req) => {
216
325
  const packs_available = await fetch_available_packs();
217
326
  const packlist = [
218
327
  ...packs_available.slice(0, 5),
219
328
  { name: req.__("More..."), description: "" },
220
329
  ];
221
- const tables = await Table.find({}, { orderBy: "name" });
222
- const views = await View.find({});
223
- const pages = await Page.find({});
224
-
330
+ const tables = await Table.find({}, { cached: true });
331
+ const views = await View.find({}, { cached: true });
332
+ const pages = await Page.find({}, { cached: true });
333
+ const triggers = await Trigger.findAllWithTableName();
334
+ const users = await User.find({}, { orderBy: "id" });
335
+ const roles = await User.get_roles();
336
+ let roleMap = {};
337
+ roles.forEach((r) => {
338
+ roleMap[r.id] = r.role;
339
+ });
225
340
  return {
226
341
  above: [
227
342
  {
@@ -236,75 +351,37 @@ const welcome_page = async (req) => {
236
351
  {
237
352
  type: "card",
238
353
  //title: req.__("Install pack"),
239
- tabContents: {
240
- Packs: div(
241
- p(
242
- req.__(
243
- "Instead of building, get up and running in no time with packs"
244
- )
245
- ),
246
- p(
247
- { class: "font-italic" },
248
- req.__(
249
- "Packs are collections of tables, views and plugins that give you a full application which you can then edit to suit your needs."
250
- )
251
- ),
252
- mkTable(
253
- [
254
- { label: req.__("Name"), key: "name" },
255
- {
256
- label: req.__("Description"),
257
- key: "description",
258
- },
259
- ],
260
- packlist,
261
- { noHeader: true }
262
- ),
263
- a(
264
- { href: `/plugins?set=packs`, class: "btn btn-primary" },
265
- req.__("Go to pack store »")
266
- )
267
- ),
268
- Triggers: await actionsTab(req),
269
- Files: await filesTab(req),
270
- },
354
+ bodyClass: "py-0 pr-0",
355
+ class: "welcome-page-entity-list",
356
+
357
+ tabContents:
358
+ triggers.length > 0
359
+ ? {
360
+ Triggers: await actionsTab(req, triggers),
361
+ Files: await filesTab(req),
362
+ Packs: packTab(req, packlist),
363
+ }
364
+ : {
365
+ Packs: packTab(req, packlist),
366
+ Triggers: await actionsTab(req, triggers),
367
+ Files: await filesTab(req),
368
+ },
271
369
  },
272
370
  {
273
371
  type: "card",
274
372
  //title: req.__("Learn"),
275
- tabContents: {
276
- Help: div(
277
- p(req.__("Confused?")),
278
- p(
279
- req.__(
280
- "The Wiki contains the documentation and tutorials on installing and using Saltcorn"
281
- )
282
- ),
283
- a(
284
- {
285
- href: `https://wiki.saltcorn.com/`,
286
- class: "btn btn-primary",
287
- },
288
- req.__("Go to Wiki »")
289
- ),
290
- p(req.__("The YouTube channel has some video tutorials")),
291
- a(
292
- {
293
- href: `https://www.youtube.com/channel/UCBOpAcH8ep7ESbuocxcq0KQ`,
294
- class: "btn btn-secondary",
373
+ bodyClass: "py-0 pr-0",
374
+ class: "welcome-page-entity-list",
375
+ tabContents:
376
+ users.length > 4
377
+ ? {
378
+ Users: await usersTab(req, users, roleMap),
379
+ Help: helpCard(req),
380
+ }
381
+ : {
382
+ Help: helpCard(req),
383
+ Users: await usersTab(req, users, roleMap),
295
384
  },
296
- req.__("Go to YouTube »")
297
- ),
298
- div(
299
- { class: "mt-3" },
300
- a(
301
- { href: `https://blog.saltcorn.com/` },
302
- req.__("What's new? Read the blog »")
303
- )
304
- )
305
- ),
306
- Users: await usersTab(req),
307
- },
308
385
  },
309
386
  ],
310
387
  },
@@ -312,6 +389,11 @@ const welcome_page = async (req) => {
312
389
  };
313
390
  };
314
391
 
392
+ /**
393
+ * @param {object} req
394
+ * @param {object} res
395
+ * @returns {Promise<void>}
396
+ */
315
397
  const no_views_logged_in = async (req, res) => {
316
398
  const role = req.isAuthenticated() ? req.user.role_id : 10;
317
399
  if (role > 1 || req.user.tenant !== db.getTenantSchema())
@@ -337,6 +419,12 @@ const no_views_logged_in = async (req, res) => {
337
419
  }
338
420
  };
339
421
 
422
+ /**
423
+ * @param {number} role_id
424
+ * @param {object} res
425
+ * @param {object} req
426
+ * @returns {Promise<boolean>}
427
+ */
340
428
  const get_config_response = async (role_id, res, req) => {
341
429
  const modernCfg = getState().getConfig("home_page_by_role", false);
342
430
  const legacy_role = { 10: "public", 8: "user", 4: "staff", 1: "admin" }[
@@ -360,6 +448,13 @@ const get_config_response = async (role_id, res, req) => {
360
448
  return true;
361
449
  }
362
450
  };
451
+
452
+ /**
453
+ * Function assigned to 'module.exports'.
454
+ * @param {object} req
455
+ * @param {object} res
456
+ * @returns {Promise<void>}
457
+ */
363
458
  module.exports = async (req, res) => {
364
459
  const isAuth = req.isAuthenticated();
365
460
  const role_id = req.user ? req.user.role_id : 10;
package/routes/index.js CHANGED
@@ -1,6 +1,8 @@
1
1
  /**
2
2
  * Index is Main Router of App
3
- * @type {module:express-promise-router}
3
+ * @category server
4
+ * @module routes/index
5
+ * @subcategory routes
4
6
  */
5
7
  const table = require("./tables");
6
8
  const field = require("./fields");
@@ -32,6 +34,10 @@ const useradmin = require("../auth/admin");
32
34
  const roleadmin = require("../auth/roleadmin");
33
35
  const scapi = require("./scapi");
34
36
 
37
+ /**
38
+ * Function assigned to 'module.exports'
39
+ * @returns {void}
40
+ */
35
41
  module.exports = (app) => {
36
42
  app.use("/table", table);
37
43
  app.use("/field", field);