@saltcorn/server 0.8.0-beta.4 → 0.8.1-beta.0

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 (46) hide show
  1. package/app.js +7 -6
  2. package/auth/admin.js +260 -217
  3. package/auth/index.js +20 -20
  4. package/auth/roleadmin.js +2 -9
  5. package/auth/routes.js +193 -139
  6. package/auth/testhelp.js +62 -55
  7. package/fixture_persons.js +1 -1
  8. package/index.js +22 -22
  9. package/locales/en.json +13 -1
  10. package/locales/fr.json +14 -2
  11. package/locales/ru.json +25 -19
  12. package/markup/admin.js +22 -15
  13. package/markup/blockly.js +1 -1
  14. package/markup/expression_blurb.js +15 -15
  15. package/markup/forms.js +21 -22
  16. package/markup/index.js +20 -20
  17. package/markup/plugin-store.js +4 -4
  18. package/package.json +8 -8
  19. package/public/diagram_utils.js +22 -9
  20. package/public/saltcorn-common.js +128 -68
  21. package/public/saltcorn.css +6 -0
  22. package/public/saltcorn.js +68 -20
  23. package/restart_watcher.js +157 -157
  24. package/routes/actions.js +4 -11
  25. package/routes/admin.js +14 -6
  26. package/routes/api.js +11 -18
  27. package/routes/common_lists.js +127 -130
  28. package/routes/delete.js +2 -2
  29. package/routes/edit.js +1 -1
  30. package/routes/fields.js +48 -2
  31. package/routes/files.js +112 -94
  32. package/routes/homepage.js +1 -1
  33. package/routes/infoarch.js +1 -1
  34. package/routes/list.js +6 -5
  35. package/routes/packs.js +1 -2
  36. package/routes/pageedit.js +1 -1
  37. package/routes/tag_entries.js +1 -1
  38. package/routes/tenant.js +2 -1
  39. package/routes/utils.js +3 -1
  40. package/routes/view.js +14 -2
  41. package/routes/viewedit.js +35 -0
  42. package/s3storage.js +13 -11
  43. package/serve.js +35 -31
  44. package/systemd.js +23 -21
  45. package/tests/fields.test.js +23 -0
  46. package/wrapper.js +46 -45
@@ -1,157 +1,157 @@
1
- /**
2
- * @category server
3
- * @module restart_watcher
4
- */
5
-
6
- const path = require("path");
7
- const { spawnSync } = require("child_process");
8
- const watch = require("node-watch");
9
- const Plugin = require("@saltcorn/data/models/plugin");
10
- const db = require("@saltcorn/data/db");
11
- const { eachTenant } = require("@saltcorn/admin-models/models/tenant");
12
-
13
- /**
14
- * packages that should trigger a server re-start
15
- */
16
- const relevantPackages = [
17
- "db-common",
18
- "postgres",
19
- "saltcorn-data",
20
- "saltcorn-builder",
21
- "saltcorn-admin-models",
22
- "saltcorn-markup",
23
- "saltcorn-sbadmin2",
24
- "server",
25
- "sqlite",
26
- "filemanager"
27
- ];
28
-
29
- /**
30
- * excluded directories or file name patterns
31
- */
32
- const excludePatterns = [
33
- /\/node_modules/,
34
- /\.git/,
35
- /\.docs/,
36
- /\.docs/,
37
- /\migrations/,
38
- /.*test.js/,
39
- ];
40
-
41
- /**
42
- * get the root directory of the saltcorn project
43
- * @returns {string} project root path
44
- */
45
- const getProjectRoot = () => {
46
- return path.normalize(`${__dirname}/../../`);
47
- };
48
-
49
- /**
50
- * get the packages directory of the saltcorn project
51
- * @returns {string} packages path
52
- */
53
- const getPackagesDirectory = () => {
54
- return `${getProjectRoot()}/packages`;
55
- };
56
-
57
- /**
58
- * get all package directories that should trigger a server re-start
59
- * @returns {string[]} list of paths to relevant directories
60
- */
61
- const getRelevantPackages = () => {
62
- const packagesDir = getPackagesDirectory();
63
- return relevantPackages.map((packageName) => `${packagesDir}/${packageName}`);
64
- };
65
-
66
- /**
67
- * get all plugin directories that should trigger a server re-start
68
- * @returns {string[]} list of paths to relevant directories
69
- */
70
- const getPluginDirectories = async () => {
71
- const getDirs = async () => {
72
- const local_plugins = await Plugin.find({ source: "local" });
73
- return local_plugins.map((p) => p.location);
74
- };
75
- const listOfDirs = [];
76
- await eachTenant(async () => {
77
- listOfDirs.push(await getDirs());
78
- });
79
- return [...new Set(listOfDirs.flat(1))];
80
- };
81
-
82
- const projectRoot = getProjectRoot();
83
-
84
- const watchCfg = {
85
- recursive: true,
86
- filter(file, skip) {
87
- for (const excludePattern of excludePatterns) {
88
- if (excludePattern.test(file)) return skip;
89
- }
90
- return /(\.js|\.ts)$/.test(file);
91
- },
92
- };
93
-
94
- let activeWatchers = [];
95
-
96
- /**
97
- * close all open file watchers
98
- */
99
- const closeWatchers = () => {
100
- for (const activeWatcher of activeWatchers) {
101
- if (!activeWatcher.isClosed()) {
102
- activeWatcher.close();
103
- }
104
- }
105
- };
106
-
107
- /**
108
- * register many file change listener and do re-starts on changes
109
- * The listener calls process.exit() and assumes
110
- * that pm2 does the actual re-start.
111
- * @param {string[]} projectDirs package paths that should trigger re-starts.
112
- * @param {string[]} pluginDirs plugin paths that should trigger re-starts.
113
- */
114
- const listenForChanges = (projectDirs, pluginDirs) => {
115
- // watch project dirs
116
- for (const projectDir of projectDirs) {
117
- activeWatchers.push(
118
- watch(
119
- projectDir,
120
- watchCfg,
121
- // event is either 'update' or 'remove'
122
- (event, file) => {
123
- console.log("'%s' changed \n re-starting now", file);
124
- closeWatchers();
125
- spawnSync("npm", ["run", "tsc"], {
126
- stdio: "inherit",
127
- });
128
- process.exit();
129
- }
130
- )
131
- );
132
- }
133
- // watch plugin dirs
134
- for (const pluginDir of pluginDirs) {
135
- activeWatchers.push(
136
- watch(
137
- pluginDir,
138
- watchCfg,
139
- // event is either 'update' or 'remove'
140
- (event, file) => {
141
- console.log("'%s' changed \n re-starting now", file);
142
- closeWatchers();
143
- process.exit();
144
- }
145
- )
146
- );
147
- }
148
- };
149
-
150
- module.exports = {
151
- listenForChanges,
152
- getProjectRoot,
153
- getPackagesDirectory,
154
- getRelevantPackages,
155
- getPluginDirectories,
156
- closeWatchers,
157
- };
1
+ /**
2
+ * @category server
3
+ * @module restart_watcher
4
+ */
5
+
6
+ const path = require("path");
7
+ const { spawnSync } = require("child_process");
8
+ const watch = require("node-watch");
9
+ const Plugin = require("@saltcorn/data/models/plugin");
10
+ const db = require("@saltcorn/data/db");
11
+ const { eachTenant } = require("@saltcorn/admin-models/models/tenant");
12
+
13
+ /**
14
+ * packages that should trigger a server re-start
15
+ */
16
+ const relevantPackages = [
17
+ "db-common",
18
+ "postgres",
19
+ "saltcorn-data",
20
+ "saltcorn-builder",
21
+ "saltcorn-admin-models",
22
+ "saltcorn-markup",
23
+ "saltcorn-sbadmin2",
24
+ "server",
25
+ "sqlite",
26
+ "filemanager",
27
+ ];
28
+
29
+ /**
30
+ * excluded directories or file name patterns
31
+ */
32
+ const excludePatterns = [
33
+ /\/node_modules/,
34
+ /\.git/,
35
+ /\.docs/,
36
+ /\.docs/,
37
+ /migrations/,
38
+ /.*test.js/,
39
+ ];
40
+
41
+ /**
42
+ * get the root directory of the saltcorn project
43
+ * @returns {string} project root path
44
+ */
45
+ const getProjectRoot = () => {
46
+ return path.normalize(`${__dirname}/../../`);
47
+ };
48
+
49
+ /**
50
+ * get the packages directory of the saltcorn project
51
+ * @returns {string} packages path
52
+ */
53
+ const getPackagesDirectory = () => {
54
+ return `${getProjectRoot()}/packages`;
55
+ };
56
+
57
+ /**
58
+ * get all package directories that should trigger a server re-start
59
+ * @returns {string[]} list of paths to relevant directories
60
+ */
61
+ const getRelevantPackages = () => {
62
+ const packagesDir = getPackagesDirectory();
63
+ return relevantPackages.map((packageName) => `${packagesDir}/${packageName}`);
64
+ };
65
+
66
+ /**
67
+ * get all plugin directories that should trigger a server re-start
68
+ * @returns {string[]} list of paths to relevant directories
69
+ */
70
+ const getPluginDirectories = async () => {
71
+ const getDirs = async () => {
72
+ const local_plugins = await Plugin.find({ source: "local" });
73
+ return local_plugins.map((p) => p.location);
74
+ };
75
+ const listOfDirs = [];
76
+ await eachTenant(async () => {
77
+ listOfDirs.push(await getDirs());
78
+ });
79
+ return [...new Set(listOfDirs.flat(1))];
80
+ };
81
+
82
+ const projectRoot = getProjectRoot();
83
+
84
+ const watchCfg = {
85
+ recursive: true,
86
+ filter(file, skip) {
87
+ for (const excludePattern of excludePatterns) {
88
+ if (excludePattern.test(file)) return skip;
89
+ }
90
+ return /(\.js|\.ts)$/.test(file);
91
+ },
92
+ };
93
+
94
+ let activeWatchers = [];
95
+
96
+ /**
97
+ * close all open file watchers
98
+ */
99
+ const closeWatchers = () => {
100
+ for (const activeWatcher of activeWatchers) {
101
+ if (!activeWatcher.isClosed()) {
102
+ activeWatcher.close();
103
+ }
104
+ }
105
+ };
106
+
107
+ /**
108
+ * register many file change listener and do re-starts on changes
109
+ * The listener calls process.exit() and assumes
110
+ * that pm2 does the actual re-start.
111
+ * @param {string[]} projectDirs package paths that should trigger re-starts.
112
+ * @param {string[]} pluginDirs plugin paths that should trigger re-starts.
113
+ */
114
+ const listenForChanges = (projectDirs, pluginDirs) => {
115
+ // watch project dirs
116
+ for (const projectDir of projectDirs) {
117
+ activeWatchers.push(
118
+ watch(
119
+ projectDir,
120
+ watchCfg,
121
+ // event is either 'update' or 'remove'
122
+ (event, file) => {
123
+ console.log("'%s' changed \n re-starting now", file);
124
+ closeWatchers();
125
+ spawnSync("npm", ["run", "tsc"], {
126
+ stdio: "inherit",
127
+ });
128
+ process.exit();
129
+ }
130
+ )
131
+ );
132
+ }
133
+ // watch plugin dirs
134
+ for (const pluginDir of pluginDirs) {
135
+ activeWatchers.push(
136
+ watch(
137
+ pluginDir,
138
+ watchCfg,
139
+ // event is either 'update' or 'remove'
140
+ (event, file) => {
141
+ console.log("'%s' changed \n re-starting now", file);
142
+ closeWatchers();
143
+ process.exit();
144
+ }
145
+ )
146
+ );
147
+ }
148
+ };
149
+
150
+ module.exports = {
151
+ listenForChanges,
152
+ getProjectRoot,
153
+ getPackagesDirectory,
154
+ getRelevantPackages,
155
+ getPluginDirectories,
156
+ closeWatchers,
157
+ };
package/routes/actions.js CHANGED
@@ -5,11 +5,7 @@
5
5
  * @subcategory routes
6
6
  */
7
7
  const Router = require("express-promise-router");
8
- const {
9
- isAdmin,
10
- error_catcher,
11
- addOnDoneRedirect,
12
- } = require("./utils.js");
8
+ const { isAdmin, error_catcher, addOnDoneRedirect } = require("./utils.js");
13
9
  const { getState } = require("@saltcorn/data/db/state");
14
10
  const Trigger = require("@saltcorn/data/models/trigger");
15
11
  const { getTriggerList } = require("./common_lists");
@@ -23,10 +19,7 @@ const { getTriggerList } = require("./common_lists");
23
19
  */
24
20
  const router = new Router();
25
21
  module.exports = router;
26
- const {
27
- renderForm,
28
- link,
29
- } = require("@saltcorn/markup");
22
+ const { renderForm, link } = require("@saltcorn/markup");
30
23
  const Form = require("@saltcorn/data/models/form");
31
24
  const {
32
25
  div,
@@ -378,7 +371,7 @@ router.get(
378
371
  if (!trigger) {
379
372
  req.flash("warning", req.__("Action not found"));
380
373
  res.redirect(`/actions/`);
381
- return
374
+ return;
382
375
  }
383
376
  const action = getState().actions[trigger.action];
384
377
  if (!action) {
@@ -575,7 +568,7 @@ router.get(
575
568
  };
576
569
  let table, row;
577
570
  if (trigger.table_id) {
578
- table = await Table.findOne( { id: trigger.table_id } );
571
+ table = await Table.findOne({ id: trigger.table_id });
579
572
  row = await table.getRow({});
580
573
  }
581
574
  try {
package/routes/admin.js CHANGED
@@ -111,14 +111,17 @@ const site_id_form = (req) =>
111
111
  field_names: [
112
112
  "site_name",
113
113
  "timezone",
114
+ "base_url",
115
+ ...(getConfigFile() ? ["multitenancy_enabled"] : []),
116
+ { section_header: "Logo image" },
114
117
  "site_logo_id",
115
118
  "favicon_id",
116
- "base_url",
119
+ { section_header: "Custom code" },
117
120
  "page_custom_css",
118
121
  "page_custom_html",
122
+ { section_header: "Extension store" },
119
123
  "plugins_store_endpoint",
120
124
  "packs_store_endpoint",
121
- ...(getConfigFile() ? ["multitenancy_enabled"] : []),
122
125
  ],
123
126
  action: "/admin",
124
127
  submitLabel: req.__("Save"),
@@ -1654,11 +1657,11 @@ router.post(
1654
1657
  const childOutputs = [];
1655
1658
  child.stdout.on("data", (data) => {
1656
1659
  // console.log(data.toString());
1657
- childOutputs.push(data.toString());
1660
+ if (data) childOutputs.push(data.toString());
1658
1661
  });
1659
1662
  child.stderr.on("data", (data) => {
1660
1663
  // console.log(data.toString());
1661
- childOutputs.push(data.toString());
1664
+ childOutputs.push(data ? data.toString() : req.__("An error occurred"));
1662
1665
  });
1663
1666
  child.on("exit", async function (exitCode, signal) {
1664
1667
  const logFile = exitCode === 0 ? "logs.txt" : "error_logs.txt";
@@ -1681,7 +1684,7 @@ router.post(
1681
1684
  [message, stack].join("\n"),
1682
1685
  (error) => {
1683
1686
  if (error) {
1684
- console.log(`unable to write '${logFile}' to '${buildDir}'`);
1687
+ console.log(`unable to write logFile to '${buildDir}'`);
1685
1688
  console.log(error);
1686
1689
  }
1687
1690
  }
@@ -1819,7 +1822,12 @@ router.post(
1819
1822
  const dev_form = async (req) => {
1820
1823
  return await config_fields_form({
1821
1824
  req,
1822
- field_names: ["development_mode", "log_sql", "log_level"],
1825
+ field_names: [
1826
+ "development_mode",
1827
+ "log_sql",
1828
+ "log_client_errors",
1829
+ "log_level",
1830
+ ],
1823
1831
  action: "/admin/dev",
1824
1832
  });
1825
1833
  };
package/routes/api.js CHANGED
@@ -71,8 +71,8 @@ function accessAllowedRead(req, user, table) {
71
71
  req.user && req.user.id
72
72
  ? req.user.role_id
73
73
  : user && user.role_id
74
- ? user.role_id
75
- : 10;
74
+ ? user.role_id
75
+ : 10;
76
76
 
77
77
  return role <= table.min_role_read;
78
78
  }
@@ -89,8 +89,8 @@ function accessAllowedWrite(req, user, table) {
89
89
  req.user && req.user.id
90
90
  ? req.user.role_id
91
91
  : user && user.role_id
92
- ? user.role_id
93
- : 10;
92
+ ? user.role_id
93
+ : 10;
94
94
 
95
95
  return role <= table.min_role_write;
96
96
  }
@@ -106,8 +106,8 @@ function accessAllowed(req, user, trigger) {
106
106
  req.user && req.user.id
107
107
  ? req.user.role_id
108
108
  : user && user.role_id
109
- ? user.role_id
110
- : 10;
109
+ ? user.role_id
110
+ : 10;
111
111
 
112
112
  return role <= trigger.min_role;
113
113
  }
@@ -126,7 +126,7 @@ router.post(
126
126
  const view = await View.findOne({ name: viewName });
127
127
  const db = require("@saltcorn/data/db");
128
128
  if (!view) {
129
- res.status(404).json({
129
+ res.status(404).json({
130
130
  error: req.__("View %s not found", viewName),
131
131
  view: viewName,
132
132
  queryName: queryName,
@@ -152,7 +152,7 @@ router.post(
152
152
  const resp = await queries[queryName](...args, true);
153
153
  res.json({ success: resp, alerts: getFlashes(req) });
154
154
  } else {
155
- res.status(404).json({
155
+ res.status(404).json({
156
156
  error: req.__("Query %s not found", queryName),
157
157
  view: viewName,
158
158
  queryName: queryName,
@@ -264,7 +264,7 @@ router.get(
264
264
  fields: tbl_fields,
265
265
  approximate: !!approximate,
266
266
  state: req_query,
267
- table
267
+ table,
268
268
  });
269
269
  rows = await table.getRows(qstate);
270
270
  } else {
@@ -381,10 +381,7 @@ router.post(
381
381
  res.status(400).json({ error: errors.join(", ") });
382
382
  return;
383
383
  }
384
- const ins_res = await table.tryInsertRow(
385
- row,
386
- req.user ? +req.user.id : undefined
387
- );
384
+ const ins_res = await table.tryInsertRow(row, req.user);
388
385
  if (ins_res.error) res.status(400).json(ins_res);
389
386
  else res.json(ins_res);
390
387
  } else {
@@ -439,11 +436,7 @@ router.post(
439
436
  res.status(400).json({ error: errors.join(", ") });
440
437
  return;
441
438
  }
442
- const ins_res = await table.tryUpdateRow(
443
- row,
444
- id,
445
- req.user ? +req.user.id : undefined
446
- );
439
+ const ins_res = await table.tryUpdateRow(row, id, req.user);
447
440
 
448
441
  if (ins_res.error) res.status(400).json(ins_res);
449
442
  else res.json(ins_res);