@saltcorn/server 0.9.6-beta.9 → 0.9.7-rc.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 (47) hide show
  1. package/app.js +9 -2
  2. package/auth/admin.js +51 -52
  3. package/auth/roleadmin.js +6 -2
  4. package/auth/routes.js +28 -10
  5. package/auth/testhelp.js +86 -0
  6. package/help/Field label.tmd +11 -0
  7. package/help/Field types.tmd +39 -0
  8. package/help/Inclusion Formula.tmd +38 -0
  9. package/help/Ownership field.tmd +76 -0
  10. package/help/Ownership formula.tmd +75 -0
  11. package/help/Table roles.tmd +20 -0
  12. package/help/User groups.tmd +35 -0
  13. package/help/User roles.tmd +30 -0
  14. package/load_plugins.js +28 -4
  15. package/locales/en.json +28 -1
  16. package/locales/it.json +3 -2
  17. package/markup/forms.js +5 -1
  18. package/package.json +9 -9
  19. package/public/log_viewer_utils.js +32 -0
  20. package/public/mermaid.min.js +705 -306
  21. package/public/saltcorn-builder.css +23 -0
  22. package/public/saltcorn-common.js +195 -71
  23. package/public/saltcorn.css +72 -0
  24. package/public/saltcorn.js +78 -0
  25. package/restart_watcher.js +1 -0
  26. package/routes/actions.js +27 -0
  27. package/routes/admin.js +180 -66
  28. package/routes/api.js +6 -0
  29. package/routes/common_lists.js +42 -32
  30. package/routes/fields.js +9 -1
  31. package/routes/homepage.js +2 -0
  32. package/routes/menu.js +69 -4
  33. package/routes/notifications.js +90 -10
  34. package/routes/pageedit.js +18 -13
  35. package/routes/plugins.js +5 -1
  36. package/routes/search.js +10 -4
  37. package/routes/tables.js +47 -27
  38. package/routes/tenant.js +4 -15
  39. package/routes/utils.js +20 -6
  40. package/routes/viewedit.js +11 -7
  41. package/serve.js +27 -5
  42. package/tests/edit.test.js +426 -0
  43. package/tests/fields.test.js +21 -0
  44. package/tests/filter.test.js +68 -0
  45. package/tests/page.test.js +2 -2
  46. package/tests/sync.test.js +59 -0
  47. package/wrapper.js +4 -1
@@ -0,0 +1,30 @@
1
+ Each user in Saltcorn has a role and the roles have a strictly hierachical ordering,
2
+ which you [can edit](/roleadmin). The ordering means that users in a role can access
3
+ everything the users in the role "below" then can acceess, but the users in the role
4
+ "above" have further access.
5
+
6
+ Assigning access by role is a quick way to give users more or less access based on how
7
+ much you trust them. Use the role to Determine access to views, pages (by setting the
8
+ minimum role to run on each entity) and tables (by setting the minimum role to read or write.)
9
+ In addition many components of views, such as actionsm containers or columns in lists have a
10
+ setting for the minimum role to show or run.
11
+
12
+ Sometimes you need more refined access control than that afforded by a simple hierarchical
13
+ role system. For these purposes you can use table ownership (see the help topics in the table
14
+ properties).
15
+
16
+ When there is no logged in user, The permissions will treat the session as if it is a user
17
+ with the role public (role id = 100). You can use this to give access to resources to non-logged-in
18
+ visitors.
19
+
20
+ For each role, you can set the theme (out of the themes installed in the module store) and the
21
+ two-factor authentication (2FA) policy, where you can allow users to set up 2FA (Optional),
22
+ disallow 2FA (Disabled), or force users to set up 2FA (Mandatory)
23
+
24
+ In the role editor you can also create new roles. When you do so, you set the role name and the
25
+ role ID. The role ID determines the how high the new role is in the role hierarchy, with a lower
26
+ role ID indicating a more powerful role. The lowest role ID is the admin user role, with ID = 1,
27
+ who have access to all resource and in addition can edit views, pages etc. The least powerful role is
28
+ the public (not logged in) users, with role ID = 100. Normally newly created users have role 80
29
+ (role ID = 80), but you can set the role of signed up users in the
30
+ [Login and signup settings](useradmin/settings).
package/load_plugins.js CHANGED
@@ -8,6 +8,8 @@
8
8
  const db = require("@saltcorn/data/db");
9
9
  const { getState, getRootState } = require("@saltcorn/data/db/state");
10
10
  const Plugin = require("@saltcorn/data/models/plugin");
11
+ const { isRoot } = require("@saltcorn/data/utils");
12
+ const { eachTenant } = require("@saltcorn/admin-models/models/tenant");
11
13
 
12
14
  const PluginInstaller = require("@saltcorn/plugins-loader/plugin_installer");
13
15
 
@@ -60,9 +62,23 @@ const loadPlugin = async (plugin, force) => {
60
62
  console.error(error); // todo i think that situation is not resolved
61
63
  }
62
64
  }
65
+
66
+ if (isRoot() && res.plugin_module.authentication)
67
+ await eachTenant(reloadAuthFromRoot);
63
68
  return res;
64
69
  };
65
70
 
71
+ const reloadAuthFromRoot = () => {
72
+ if (isRoot()) return;
73
+ const rootState = getRootState();
74
+ const tenantState = getState();
75
+ if (!rootState || !tenantState || rootState === tenantState) return;
76
+ tenantState.auth_methods = {};
77
+ for (const [k, v] of Object.entries(rootState.auth_methods)) {
78
+ if (v.shareWithTenants) tenantState.auth_methods[k] = v;
79
+ }
80
+ };
81
+
66
82
  /**
67
83
  * Install plugin
68
84
  * @param plugin - plugin name
@@ -90,6 +106,7 @@ const loadAllPlugins = async (force) => {
90
106
  }
91
107
  await getState().refreshUserLayouts();
92
108
  await getState().refresh(true);
109
+ if (!isRoot()) reloadAuthFromRoot();
93
110
  };
94
111
 
95
112
  /**
@@ -104,14 +121,14 @@ const loadAndSaveNewPlugin = async (
104
121
  plugin,
105
122
  force,
106
123
  noSignalOrDB,
107
- __ = (str) => str
124
+ __ = (str) => str,
125
+ allowUnsafeOnTenantsWithoutConfigSetting
108
126
  ) => {
109
127
  const tenants_unsafe_plugins = getRootState().getConfig(
110
128
  "tenants_unsafe_plugins",
111
129
  false
112
130
  );
113
- const isRoot = db.getTenantSchema() === db.connectObj.default_schema;
114
- if (!isRoot && !tenants_unsafe_plugins) {
131
+ if (!isRoot() && !tenants_unsafe_plugins) {
115
132
  if (plugin.source !== "npm") {
116
133
  console.error("\nWARNING: Skipping unsafe plugin ", plugin.name);
117
134
  return;
@@ -126,7 +143,10 @@ const loadAndSaveNewPlugin = async (
126
143
 
127
144
  const instore = getRootState().getConfig("available_plugins", []);
128
145
  const safes = instore.filter((p) => !p.unsafe).map((p) => p.location);
129
- if (!safes.includes(plugin.location)) {
146
+ if (
147
+ !safes.includes(plugin.location) &&
148
+ !allowUnsafeOnTenantsWithoutConfigSetting
149
+ ) {
130
150
  console.error("\nWARNING: Skipping unsafe plugin ", plugin.name);
131
151
  return;
132
152
  }
@@ -196,6 +216,10 @@ const loadAndSaveNewPlugin = async (
196
216
  }
197
217
  }
198
218
  if (version) plugin.version = version;
219
+
220
+ if (isRoot() && plugin_module.authentication)
221
+ await eachTenant(reloadAuthFromRoot);
222
+
199
223
  if (!noSignalOrDB) {
200
224
  await plugin.upsert();
201
225
  getState().processSend({
package/locales/en.json CHANGED
@@ -1426,5 +1426,32 @@
1426
1426
  "Keystore Password": "Keystore Password",
1427
1427
  "xcodebuild": "xcodebuild",
1428
1428
  "Provisioning Profile": "Provisioning Profile",
1429
- "Registry editor": "Registry editor"
1429
+ "Registry editor": "Registry editor",
1430
+ "Mobile HTML": "Mobile HTML",
1431
+ "HTML for the item in the bottom navigation bar. Currently, only supported by the metronic theme.": "HTML for the item in the bottom navigation bar. Currently, only supported by the metronic theme.",
1432
+ "A short name that will be in the page URL": "A short name that will be in the page URL",
1433
+ "A longer description that is not visible but appears in the page header and is indexed by search engines": "A longer description that is not visible but appears in the page header and is indexed by search engines",
1434
+ "User role required to access page": "User role required to access page",
1435
+ "Example: <code>`/view/TheOtherView?id=${id}`</code>": "Example: <code>`/view/TheOtherView?id=${id}`</code>",
1436
+ "Older": "Older",
1437
+ "Newest": "Newest",
1438
+ "Delete all read": "Delete all read",
1439
+ "Trigger %s duplicated as %s": "Trigger %s duplicated as %s",
1440
+ "Tooltip": "Tooltip",
1441
+ "Tooltip formula": "Tooltip formula",
1442
+ "Install a different version": "Install a different version",
1443
+ "Page group": "Page group",
1444
+ "Starting upgrade, please wait...\n": "Starting upgrade, please wait...\n",
1445
+ "Upgrade done (if it was available) with code 0.\n\nPress the BACK button in your browser, then RELOAD the page.": "Upgrade done (if it was available) with code 0.\n\nPress the BACK button in your browser, then RELOAD the page.",
1446
+ "Installing %s, please wait...\n": "Installing %s, please wait...\n",
1447
+ "Install done with code 0.\n\nPress the BACK button in your browser, then RELOAD the page.": "Install done with code 0.\n\nPress the BACK button in your browser, then RELOAD the page.",
1448
+ "Pulling the cordova-builder docker image...": "Pulling the cordova-builder docker image...",
1449
+ "Check updates": "Check updates",
1450
+ "Choose version": "Choose version",
1451
+ "Unknown authentication method %s": "Unknown authentication method %s",
1452
+ "Card rows": "Card rows",
1453
+ "Each row in a card. Not supported by all themes": "Each row in a card. Not supported by all themes",
1454
+ "Prune session interval (seconds)": "Prune session interval (seconds)",
1455
+ "Interval in seconds to check for expred sessions in the postgres db. 0, empty or a negative number to disable": "Interval in seconds to check for expred sessions in the postgres db. 0, empty or a negative number to disable",
1456
+ "Progressive Web Application is not enabled": "Progressive Web Application is not enabled"
1430
1457
  }
package/locales/it.json CHANGED
@@ -518,5 +518,6 @@
518
518
  "Save before going back": "Save before going back",
519
519
  "Reload after going back": "Reload after going back",
520
520
  "Steps to go back": "Steps to go back",
521
- "%s configuration": "%s configuration"
522
- }
521
+ "%s configuration": "%s configuration",
522
+ "The current theme has no user specific settings": "The current theme has no user specific settings"
523
+ }
package/markup/forms.js CHANGED
@@ -28,10 +28,14 @@ const editRoleForm = ({ url, current_role, roles, req }) =>
28
28
  {
29
29
  action: url,
30
30
  method: "post",
31
+ onchange: "saveAndContinue(this)",
31
32
  },
32
33
  csrfField(req),
33
34
  select(
34
- { name: "role", onchange: "form.submit()" },
35
+ {
36
+ name: "role",
37
+ class: "w-unset form-select form-select-sm",
38
+ },
35
39
  roles.map((role) =>
36
40
  option(
37
41
  {
package/package.json CHANGED
@@ -1,20 +1,20 @@
1
1
  {
2
2
  "name": "@saltcorn/server",
3
- "version": "0.9.6-beta.9",
3
+ "version": "0.9.7-rc.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
9
  "@aws-sdk/client-s3": "^3.451.0",
10
- "@saltcorn/base-plugin": "0.9.6-beta.9",
11
- "@saltcorn/builder": "0.9.6-beta.9",
12
- "@saltcorn/data": "0.9.6-beta.9",
13
- "@saltcorn/admin-models": "0.9.6-beta.9",
14
- "@saltcorn/filemanager": "0.9.6-beta.9",
15
- "@saltcorn/markup": "0.9.6-beta.9",
16
- "@saltcorn/plugins-loader": "0.9.6-beta.9",
17
- "@saltcorn/sbadmin2": "0.9.6-beta.9",
10
+ "@saltcorn/base-plugin": "0.9.7-rc.0",
11
+ "@saltcorn/builder": "0.9.7-rc.0",
12
+ "@saltcorn/data": "0.9.7-rc.0",
13
+ "@saltcorn/admin-models": "0.9.7-rc.0",
14
+ "@saltcorn/filemanager": "0.9.7-rc.0",
15
+ "@saltcorn/markup": "0.9.7-rc.0",
16
+ "@saltcorn/plugins-loader": "0.9.7-rc.0",
17
+ "@saltcorn/sbadmin2": "0.9.7-rc.0",
18
18
  "@socket.io/cluster-adapter": "^0.2.1",
19
19
  "@socket.io/sticky": "^1.0.1",
20
20
  "adm-zip": "0.5.10",
@@ -10,6 +10,9 @@ var logViewerHelpers = (() => {
10
10
  second: "2-digit",
11
11
  };
12
12
  let lostConnection = false;
13
+ let waitingForTestMessage = false;
14
+ let startedWaitingAt = null;
15
+ let waitTimeout = false;
13
16
 
14
17
  const logLevelColor = (level) => {
15
18
  switch (parseInt(level)) {
@@ -94,6 +97,17 @@ var logViewerHelpers = (() => {
94
97
  });
95
98
  };
96
99
 
100
+ const testMsgWaiter = (waiterStartedAt) => () => {
101
+ if (waitingForTestMessage && waiterStartedAt === startedWaitingAt) {
102
+ emptyAlerts();
103
+ waitTimeout = true;
104
+ notifyAlert({
105
+ type: "danger",
106
+ text: "You are connected but not receiving any messages",
107
+ });
108
+ }
109
+ };
110
+
97
111
  const handleConnect = (socket) => {
98
112
  socket.emit("join_log_room", (ack) => {
99
113
  if (ack) {
@@ -109,6 +123,10 @@ var logViewerHelpers = (() => {
109
123
  text: "You are connected again",
110
124
  });
111
125
  }
126
+ waitingForTestMessage = true;
127
+ waitTimeout = false;
128
+ startedWaitingAt = new Date().valueOf();
129
+ setTimeout(testMsgWaiter(startedWaitingAt), 5000);
112
130
  } else if (ack.status === "error" && ack.msg) {
113
131
  notifyAlert({
114
132
  type: "danger",
@@ -129,6 +147,19 @@ var logViewerHelpers = (() => {
129
147
  });
130
148
  };
131
149
 
150
+ const handleTestConnMsg = () => {
151
+ waitingForTestMessage = false;
152
+ startedWaitingAt = null;
153
+ if (waitTimeout) {
154
+ emptyAlerts();
155
+ notifyAlert({
156
+ type: "success",
157
+ text: "You are connected and receiving messages",
158
+ });
159
+ waitTimeout = false;
160
+ }
161
+ };
162
+
132
163
  return {
133
164
  init_log_socket: () => {
134
165
  let socket = null;
@@ -152,6 +183,7 @@ var logViewerHelpers = (() => {
152
183
  socket.on("connect", () => handleConnect(socket));
153
184
  socket.on("disconnect", handleDisconnect);
154
185
  socket.on("log_msg", handleLogMsg);
186
+ socket.on("test_conn_msg", handleTestConnMsg);
155
187
  },
156
188
  goToLogsPage: (n) => {
157
189
  currentPage = n;