@saltcorn/server 0.6.1-beta.1 → 0.6.2-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.
package/auth/index.js CHANGED
@@ -2,6 +2,19 @@
2
2
  /**
3
3
  *
4
4
  * @category server
5
- * @module auth/inde
5
+ * @module auth/index
6
6
  * @subcategory auth
7
- */
7
+ */
8
+
9
+ /**
10
+ * All files in the auth module.
11
+ * @namespace auth_overview
12
+ * @property {module:auth/admin} admin
13
+ * @property {module:auth/resetpw} resetpw
14
+ * @property {module:auth/roleadmin} roleadmin
15
+ * @property {module:auth/routes} routes
16
+ * @property {module:auth/testhelp} testhelp
17
+ *
18
+ * @category server
19
+ * @subcategory auth
20
+ */
package/index.js CHANGED
@@ -3,4 +3,20 @@
3
3
  *
4
4
  * @category server
5
5
  * @module server/index
6
- */
6
+ */
7
+
8
+ /**
9
+ * All files and sub-modules in the saltcorn-markup package.
10
+ * @namespace server_overview
11
+ * @property {module:auth/index~auth_overview} auth
12
+ * @property {module:markup/index~markup_overview} markup
13
+ * @property {module:routes/index~routes_overview} routes
14
+ *
15
+ * @property {module:app} app
16
+ * @property {module:errors} errors
17
+ * @property {module:load_plugins} load_plugins
18
+ * @property {module:serve} serve
19
+ * @property {module:systemd} systemd
20
+ * @property {module:wrapper} wrapper
21
+ * @category server
22
+ */
package/locales/en.json CHANGED
@@ -808,5 +808,11 @@
808
808
  "Set to 0 for expration at the end of browser session": "Set to 0 for expration at the end of browser session",
809
809
  "Cookie duration (hours) when remember ticked": "Cookie duration (hours) when remember ticked",
810
810
  "Forget table": "Forget table",
811
- "Table %s forgotten. You can now discover it.": "Table %s forgotten. You can now discover it."
811
+ "Table %s forgotten. You can now discover it.": "Table %s forgotten. You can now discover it.",
812
+ "No triggers": "No triggers",
813
+ "List width": "List width",
814
+ "Number of columns (1-12) allocated to the list view": "Number of columns (1-12) allocated to the list view",
815
+ "New tenant template": "New tenant template",
816
+ "Copy site structure for new tenants from this tenant": "Copy site structure for new tenants from this tenant",
817
+ "Use this link: <a href=\"%s\">%s</a> to revisit your application at any time.": "Use this link: <a href=\"%s\">%s</a> to revisit your application at any time."
812
818
  }
package/markup/admin.js CHANGED
@@ -33,9 +33,9 @@ const View = require("@saltcorn/data/models/view");
33
33
  const User = require("@saltcorn/data/models/user");
34
34
 
35
35
  /**
36
- * @param {*} csrf
37
- * @param {*} inner
38
- * @param {string} action
36
+ * @param {*} csrf
37
+ * @param {*} inner
38
+ * @param {string} action
39
39
  * @returns {*}
40
40
  */
41
41
  const restore_backup = (csrf, inner, action = `/admin/restore`) =>
@@ -168,7 +168,7 @@ const send_settings_page = ({
168
168
  };
169
169
 
170
170
  /**
171
- * @param {object} args
171
+ * @param {object} args
172
172
  * @returns {void}
173
173
  */
174
174
  const send_infoarch_page = (args) => {
@@ -195,7 +195,7 @@ const send_infoarch_page = (args) => {
195
195
  };
196
196
 
197
197
  /**
198
- * @param {object} args
198
+ * @param {object} args
199
199
  * @returns {void}
200
200
  */
201
201
  const send_users_page = (args) => {
@@ -214,7 +214,7 @@ const send_users_page = (args) => {
214
214
  };
215
215
 
216
216
  /**
217
- * @param {object} args
217
+ * @param {object} args
218
218
  * @returns {void}
219
219
  */
220
220
  const send_events_page = (args) => {
@@ -234,7 +234,7 @@ const send_events_page = (args) => {
234
234
  };
235
235
 
236
236
  /**
237
- * @param {object} args
237
+ * @param {object} args
238
238
  * @returns {void}
239
239
  */
240
240
  const send_admin_page = (args) => {
@@ -252,8 +252,8 @@ const send_admin_page = (args) => {
252
252
  });
253
253
  };
254
254
 
255
- /**
256
- * @param {object} key
255
+ /**
256
+ * @param {object} key
257
257
  * @returns {Promise<object>}
258
258
  */
259
259
  const viewAttributes = async (key) => {
@@ -269,8 +269,8 @@ const viewAttributes = async (key) => {
269
269
  };
270
270
 
271
271
  /**
272
- * @param {*} cfgForm
273
- * @param {*} req
272
+ * @param {*} cfgForm
273
+ * @param {*} req
274
274
  * @returns {void}
275
275
  */
276
276
  const flash_restart_if_required = (cfgForm, req) => {
@@ -285,7 +285,7 @@ const flash_restart_if_required = (cfgForm, req) => {
285
285
  };
286
286
 
287
287
  /**
288
- * @param {object} req
288
+ * @param {object} req
289
289
  * @returns {void}
290
290
  */
291
291
  const flash_restart = (req) => {
@@ -316,6 +316,7 @@ const config_fields_form = async ({ field_names, req, ...formArgs }) => {
316
316
  continue;
317
317
  const isView = (configTypes[name].type || "").startsWith("View ");
318
318
  const isRole = configTypes[name].type === "Role";
319
+ const isTenant = configTypes[name].type === "Tenant";
319
320
  const label = configTypes[name].label || name;
320
321
  const sublabel = configTypes[name].sublabel || configTypes[name].blurb;
321
322
  const roleAttribs = {
@@ -324,6 +325,10 @@ const config_fields_form = async ({ field_names, req, ...formArgs }) => {
324
325
  name: `${r.id}`,
325
326
  })),
326
327
  };
328
+ const getTenants = async () => {
329
+ const tens = await db.select("_sc_tenants");
330
+ return { options: tens.map((t) => t.subdomain) };
331
+ };
327
332
  fields.push({
328
333
  name,
329
334
  ...configTypes[name],
@@ -331,7 +336,7 @@ const config_fields_form = async ({ field_names, req, ...formArgs }) => {
331
336
  sublabel: sublabel ? req.__(sublabel) : undefined,
332
337
  disabled: isFixedConfig(name),
333
338
  type:
334
- isView || isRole
339
+ isView || isRole || isTenant
335
340
  ? "String"
336
341
  : configTypes[name].input_type
337
342
  ? undefined
@@ -341,6 +346,8 @@ const config_fields_form = async ({ field_names, req, ...formArgs }) => {
341
346
  ? await viewAttributes(name)
342
347
  : isRole
343
348
  ? roleAttribs
349
+ : isTenant
350
+ ? await getTenants()
344
351
  : configTypes[name].attributes,
345
352
  });
346
353
  }
@@ -356,7 +363,7 @@ const config_fields_form = async ({ field_names, req, ...formArgs }) => {
356
363
  };
357
364
 
358
365
  /**
359
- * @param {*} form
366
+ * @param {*} form
360
367
  * @returns {Promise<void>}
361
368
  */
362
369
  const save_config_from_form = async (form) => {
@@ -384,14 +391,14 @@ const getBaseDomain = () => {
384
391
  };
385
392
 
386
393
  /**
387
- * @param {object} req
388
- * @param {string} domain
394
+ * @param {object} req
395
+ * @param {string} domain
389
396
  * @returns {boolean}
390
397
  */
391
398
  const hostname_matches_baseurl = (req, domain) => domain === req.hostname;
392
399
 
393
400
  /**
394
- * @param {string} domain
401
+ * @param {string} domain
395
402
  * @returns {string[]}
396
403
  */
397
404
  const is_hsts_tld = (domain) => {
package/markup/index.js CHANGED
@@ -4,4 +4,17 @@
4
4
  * @category server
5
5
  * @module markup/index
6
6
  * @subcategory markup
7
- */
7
+ */
8
+
9
+ /**
10
+ * All files in the auth module.
11
+ * @namespace markup_overview
12
+ * @property {module:markup/admin} admin
13
+ * @property {module:markup/blockly} blockly
14
+ * @property {module:markup/expression_blurb} expression_blurb
15
+ * @property {module:markup/forms} forms
16
+ * @property {module:markup/plugin-store} plugin-store
17
+ *
18
+ * @category server
19
+ * @subcategory markup
20
+ */
package/package.json CHANGED
@@ -1,17 +1,17 @@
1
1
  {
2
2
  "name": "@saltcorn/server",
3
- "version": "0.6.1-beta.1",
3
+ "version": "0.6.2-beta.0",
4
4
  "description": "Server app for Saltcorn, open-source no-code platform",
5
5
  "homepage": "https://saltcorn.com",
6
6
  "main": "index.js",
7
7
  "license": "MIT",
8
8
  "dependencies": {
9
- "@saltcorn/base-plugin": "0.6.1-beta.1",
10
- "@saltcorn/builder": "0.6.1-beta.1",
11
- "@saltcorn/data": "0.6.1-beta.1",
9
+ "@saltcorn/base-plugin": "0.6.2-beta.0",
10
+ "@saltcorn/builder": "0.6.2-beta.0",
11
+ "@saltcorn/data": "0.6.2-beta.0",
12
12
  "greenlock-express": "^4.0.3",
13
- "@saltcorn/markup": "0.6.1-beta.1",
14
- "@saltcorn/sbadmin2": "0.6.1-beta.1",
13
+ "@saltcorn/markup": "0.6.2-beta.0",
14
+ "@saltcorn/sbadmin2": "0.6.2-beta.0",
15
15
  "@socket.io/cluster-adapter": "^0.1.0",
16
16
  "@socket.io/sticky": "^1.0.1",
17
17
  "connect-flash": "^0.1.1",
@@ -33,6 +33,7 @@
33
33
  "live-plugin-manager": "^0.16.0",
34
34
  "moment": "^2.27.0",
35
35
  "node-fetch": "2.6.2",
36
+ "node-watch": "^0.7.2",
36
37
  "passport": "^0.4.1",
37
38
  "passport-custom": "^1.1.1",
38
39
  "passport-http-bearer": "^1.0.1",
@@ -51,7 +52,9 @@
51
52
  },
52
53
  "scripts": {
53
54
  "dev": "nodemon index.js",
54
- "test": "jest --runInBand"
55
+ "test": "jest --runInBand",
56
+ "tsc": "echo \"Error: no TypeScript support yet\"",
57
+ "clean": "echo \"Error: no TypeScript support yet\""
55
58
  },
56
59
  "jest": {
57
60
  "testEnvironment": "node",
@@ -62,7 +65,10 @@
62
65
  "coveragePathIgnorePatterns": [
63
66
  "/node_modules/",
64
67
  "/plugin_packages/"
65
- ]
68
+ ],
69
+ "moduleNameMapper": {
70
+ "@saltcorn/sqlite/(.*)": "@saltcorn/sqlite/dist/$1"
71
+ }
66
72
  },
67
73
  "publishConfig": {
68
74
  "access": "public"
@@ -306,6 +306,18 @@ function select_id(id) {
306
306
  function set_state_field(key, value) {
307
307
  pjax_to(updateQueryStringParameter(window.location.href, key, value));
308
308
  }
309
+
310
+ function check_state_field(that) {
311
+ const checked = that.checked;
312
+ const name = that.name;
313
+ const value = that.value;
314
+ var separator = window.location.href.indexOf("?") !== -1 ? "&" : "?";
315
+ let dest;
316
+ if (checked) dest = window.location.href + `${separator}${name}=${value}`;
317
+ else dest = window.location.href.replace(`${name}=${value}`, "");
318
+ pjax_to(dest.replace("&&", "&").replace("?&", "?"));
319
+ }
320
+
309
321
  function set_state_fields(kvs) {
310
322
  var newhref = window.location.href;
311
323
  Object.entries(kvs).forEach((kv) => {
@@ -341,7 +353,11 @@ function pjax_to(href) {
341
353
  setTimeout(() => {
342
354
  loadPage = true;
343
355
  }, 0);
344
-
356
+ if (res.includes("<!--SCPT:")) {
357
+ const start = res.indexOf("<!--SCPT:");
358
+ const end = res.indexOf("-->", start);
359
+ document.title = res.substring(start + 9, end);
360
+ }
345
361
  $("#page-inner-content").html(res);
346
362
  initialize_page();
347
363
  },
@@ -0,0 +1,146 @@
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
+
11
+ /**
12
+ * packages that should trigger a server re-start
13
+ */
14
+ const relevantPackages = [
15
+ "db-common",
16
+ "postgres",
17
+ "saltcorn-data",
18
+ "saltcorn-markup",
19
+ "server",
20
+ "sqlite",
21
+ ];
22
+
23
+ /**
24
+ * excluded directories or file name patterns
25
+ */
26
+ const excludePatterns = [
27
+ /\/node_modules/,
28
+ /\/public/,
29
+ /\.git/,
30
+ /\.docs/,
31
+ /\.docs/,
32
+ /\migrations/,
33
+ /.*test.js/,
34
+ ];
35
+
36
+ /**
37
+ * get the root directory of the saltcorn project
38
+ * @returns {string} project root path
39
+ */
40
+ const getProjectRoot = () => {
41
+ return path.normalize(`${__dirname}/../../`);
42
+ };
43
+
44
+ /**
45
+ * get the packages directory of the saltcorn project
46
+ * @returns {string} packages path
47
+ */
48
+ const getPackagesDirectory = () => {
49
+ return `${getProjectRoot()}/packages`;
50
+ };
51
+
52
+ /**
53
+ * get all package directories that should trigger a server re-start
54
+ * @returns {string[]} list of paths to relevant directories
55
+ */
56
+ const getRelevantPackages = () => {
57
+ const packagesDir = getPackagesDirectory();
58
+ return relevantPackages.map((packageName) => `${packagesDir}/${packageName}`);
59
+ };
60
+
61
+ /**
62
+ * get all plugin directories that should trigger a server re-start
63
+ * @returns {string[]} list of paths to relevant directories
64
+ */
65
+ const getPluginDirectories = async () => {
66
+ const local_plugins = await Plugin.find({ source: "local" });
67
+ return local_plugins.map((p) => p.location);
68
+ };
69
+
70
+ const projectRoot = getProjectRoot();
71
+
72
+ const watchCfg = {
73
+ recursive: true,
74
+ filter(file, skip) {
75
+ for (const excludePattern of excludePatterns) {
76
+ if (excludePattern.test(file)) return skip;
77
+ }
78
+ return /(\.js|\.ts)$/.test(file);
79
+ },
80
+ };
81
+
82
+ let activeWatchers = [];
83
+
84
+ /**
85
+ * close all open file watchers
86
+ */
87
+ const closeWatchers = () => {
88
+ for (const activeWatcher of activeWatchers) {
89
+ if (!activeWatcher.isClosed()) {
90
+ activeWatcher.close();
91
+ }
92
+ }
93
+ };
94
+
95
+ /**
96
+ * register many file change listener and do re-starts on changes
97
+ * The listener calls process.exit() and assumes
98
+ * that pm2 does the actual re-start.
99
+ * @param {string[]} projectDirs package paths that should trigger re-starts.
100
+ * @param {string[]} pluginDirs plugin paths that should trigger re-starts.
101
+ */
102
+ const listenForChanges = (projectDirs, pluginDirs) => {
103
+ // watch project dirs
104
+ for (const projectDir of projectDirs) {
105
+ activeWatchers.push(
106
+ watch(
107
+ projectDir,
108
+ watchCfg,
109
+ // event is either 'update' or 'remove'
110
+ (event, file) => {
111
+ console.log("'%s' changed \n re-starting now", file);
112
+ closeWatchers();
113
+ spawnSync("npm", ["run", "tsc"], {
114
+ stdio: "inherit",
115
+ cwd: projectRoot,
116
+ });
117
+ process.exit();
118
+ }
119
+ )
120
+ );
121
+ }
122
+ // watch plugin dirs
123
+ for (const pluginDir of pluginDirs) {
124
+ activeWatchers.push(
125
+ watch(
126
+ pluginDir,
127
+ watchCfg,
128
+ // event is either 'update' or 'remove'
129
+ (event, file) => {
130
+ console.log("'%s' changed \n re-starting now", file);
131
+ closeWatchers();
132
+ process.exit();
133
+ }
134
+ )
135
+ );
136
+ }
137
+ };
138
+
139
+ module.exports = {
140
+ listenForChanges,
141
+ getProjectRoot,
142
+ getPackagesDirectory,
143
+ getRelevantPackages,
144
+ getPluginDirectories,
145
+ closeWatchers,
146
+ };
package/routes/fields.js CHANGED
@@ -38,11 +38,11 @@ const router = new Router();
38
38
  module.exports = router;
39
39
 
40
40
  /**
41
- * @param {object} req
42
- * @param {*} fkey_opts
43
- * @param {*} existing_names
44
- * @param {*} id
45
- * @param {*} hasData
41
+ * @param {object} req
42
+ * @param {*} fkey_opts
43
+ * @param {*} existing_names
44
+ * @param {*} id
45
+ * @param {*} hasData
46
46
  * @returns {Promise<Form>}
47
47
  */
48
48
  const fieldForm = async (req, fkey_opts, existing_names, id, hasData) => {
@@ -137,7 +137,7 @@ const fieldForm = async (req, fkey_opts, existing_names, id, hasData) => {
137
137
  };
138
138
 
139
139
  /**
140
- * @param {string} ctxType
140
+ * @param {string} ctxType
141
141
  * @returns {object}
142
142
  */
143
143
  const calcFieldType = (ctxType) =>
@@ -146,8 +146,8 @@ const calcFieldType = (ctxType) =>
146
146
  : { type: ctxType };
147
147
 
148
148
  /**
149
- * @param {*} attrs
150
- * @param {object} req
149
+ * @param {*} attrs
150
+ * @param {object} req
151
151
  * @returns {*}
152
152
  */
153
153
  const translateAttributes = (attrs, req) =>
@@ -156,8 +156,8 @@ const translateAttributes = (attrs, req) =>
156
156
  : attrs;
157
157
 
158
158
  /**
159
- * @param {*} attr
160
- * @param {*} req
159
+ * @param {*} attr
160
+ * @param {*} req
161
161
  * @returns {object}
162
162
  */
163
163
  const translateAttribute = (attr, req) => {
@@ -167,7 +167,7 @@ const translateAttribute = (attr, req) => {
167
167
  };
168
168
 
169
169
  /**
170
- * @param {*} req
170
+ * @param {*} req
171
171
  * @returns {Workflow}
172
172
  */
173
173
  const fieldFlow = (req) =>
@@ -697,12 +697,12 @@ router.post(
697
697
  if (!fv && field.type === "Key" && fieldview === "select")
698
698
  res.send("<select disabled></select>");
699
699
  else if (!fv) res.send("");
700
- else if (fv.isEdit)
700
+ else if (fv.isEdit || fv.isFilter)
701
701
  res.send(
702
702
  fv.run(
703
703
  field.name,
704
704
  undefined,
705
- { disabled: true, ...configuration },
705
+ { disabled: true, ...configuration, ...(field.attributes || {}) },
706
706
  "",
707
707
  false,
708
708
  field