@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
@@ -8,9 +8,7 @@ const {
8
8
  settingsDropdown,
9
9
  post_dropdown_item,
10
10
  } = require("@saltcorn/markup");
11
- const {
12
- get_base_url,
13
- } = require("./utils.js");
11
+ const { get_base_url } = require("./utils.js");
14
12
  const { h4, p, div, a, input, text } = require("@saltcorn/markup/tags");
15
13
 
16
14
  /**
@@ -48,52 +46,52 @@ const tablesList = async (tables, req, { tagId, domId, showList } = {}) => {
48
46
  const getRole = (rid) => roles.find((r) => r.id === rid).role;
49
47
  return tables.length > 0
50
48
  ? mkTable(
51
- [
52
- {
53
- label: req.__("Name"),
54
- key: (r) => link(`/table/${r.id || r.name}`, text(r.name)),
55
- },
56
- {
57
- label: "",
58
- key: (r) => tableBadges(r, req),
59
- },
60
- {
61
- label: req.__("Access Read/Write"),
62
- key: (t) =>
63
- t.external
64
- ? `${getRole(t.min_role_read)} (read only)`
65
- : `${getRole(t.min_role_read)}/${getRole(t.min_role_write)}`,
66
- },
67
- !tagId
68
- ? {
69
- label: req.__("Delete"),
70
- key: (r) =>
71
- r.name === "users" || r.external
72
- ? ""
73
- : post_delete_btn(`/table/delete/${r.id}`, req, r.name),
74
- }
75
- : {
76
- label: req.__("Remove From Tag"),
77
- key: (r) =>
78
- post_delete_btn(
79
- `/tag-entries/remove/tables/${r.id}/${tagId}`,
80
- req,
81
- `${r.name} from this tag`
82
- ),
49
+ [
50
+ {
51
+ label: req.__("Name"),
52
+ key: (r) => link(`/table/${r.id || r.name}`, text(r.name)),
83
53
  },
84
- ],
85
- tables,
86
- {
87
- hover: true,
88
- tableClass: listClass(tagId, showList),
89
- tableId: domId,
90
- }
91
- )
54
+ {
55
+ label: "",
56
+ key: (r) => tableBadges(r, req),
57
+ },
58
+ {
59
+ label: req.__("Access Read/Write"),
60
+ key: (t) =>
61
+ t.external
62
+ ? `${getRole(t.min_role_read)} (read only)`
63
+ : `${getRole(t.min_role_read)}/${getRole(t.min_role_write)}`,
64
+ },
65
+ !tagId
66
+ ? {
67
+ label: req.__("Delete"),
68
+ key: (r) =>
69
+ r.name === "users" || r.external
70
+ ? ""
71
+ : post_delete_btn(`/table/delete/${r.id}`, req, r.name),
72
+ }
73
+ : {
74
+ label: req.__("Remove From Tag"),
75
+ key: (r) =>
76
+ post_delete_btn(
77
+ `/tag-entries/remove/tables/${r.id}/${tagId}`,
78
+ req,
79
+ `${r.name} from this tag`
80
+ ),
81
+ },
82
+ ],
83
+ tables,
84
+ {
85
+ hover: true,
86
+ tableClass: listClass(tagId, showList),
87
+ tableId: domId,
88
+ }
89
+ )
92
90
  : div(
93
- { class: listClass(tagId, showList), id: domId },
94
- h4(req.__("No tables defined")),
95
- p(req.__("Tables hold collections of similar data"))
96
- );
91
+ { class: listClass(tagId, showList), id: domId },
92
+ h4(req.__("No tables defined")),
93
+ p(req.__("Tables hold collections of similar data"))
94
+ );
97
95
  };
98
96
 
99
97
  /**
@@ -175,17 +173,17 @@ const viewsList = async (views, req, { tagId, domId, showList } = {}) => {
175
173
 
176
174
  return views.length > 0
177
175
  ? mkTable(
178
- [
179
- {
180
- label: req.__("Name"),
181
- key: (r) => link(`/view/${encodeURIComponent(r.name)}`, r.name),
182
- sortlink: !tagId
183
- ? `javascript:set_state_field('_sortby', 'name')`
184
- : undefined,
185
- },
186
- // description - currently I dont want to show description in view list
187
- // because description can be long
188
- /*
176
+ [
177
+ {
178
+ label: req.__("Name"),
179
+ key: (r) => link(`/view/${encodeURIComponent(r.name)}`, r.name),
180
+ sortlink: !tagId
181
+ ? `javascript:set_state_field('_sortby', 'name')`
182
+ : undefined,
183
+ },
184
+ // description - currently I dont want to show description in view list
185
+ // because description can be long
186
+ /*
189
187
  {
190
188
  label: req.__("Description"),
191
189
  key: "description",
@@ -193,60 +191,60 @@ const viewsList = async (views, req, { tagId, domId, showList } = {}) => {
193
191
  sortlink: `javascript:set_state_field('_sortby', 'description')`,
194
192
  },
195
193
  */
196
- // template
197
- {
198
- label: req.__("Pattern"),
199
- key: "viewtemplate",
200
- sortlink: !tagId
201
- ? `javascript:set_state_field('_sortby', 'viewtemplate')`
202
- : undefined,
203
- },
204
- {
205
- label: req.__("Table"),
206
- key: (r) => link(`/table/${r.table}`, r.table),
207
- sortlink: !tagId
208
- ? `javascript:set_state_field('_sortby', 'table')`
209
- : undefined,
210
- },
211
- {
212
- label: req.__("Role to access"),
213
- key: (row) => editViewRoleForm(row, roles, req),
214
- },
215
- {
216
- label: "",
217
- key: (r) =>
218
- link(
219
- `/viewedit/config/${encodeURIComponent(r.name)}`,
220
- req.__("Configure")
221
- ),
222
- },
223
- !tagId
224
- ? {
194
+ // template
195
+ {
196
+ label: req.__("Pattern"),
197
+ key: "viewtemplate",
198
+ sortlink: !tagId
199
+ ? `javascript:set_state_field('_sortby', 'viewtemplate')`
200
+ : undefined,
201
+ },
202
+ {
203
+ label: req.__("Table"),
204
+ key: (r) => link(`/table/${r.table}`, r.table),
205
+ sortlink: !tagId
206
+ ? `javascript:set_state_field('_sortby', 'table')`
207
+ : undefined,
208
+ },
209
+ {
210
+ label: req.__("Role to access"),
211
+ key: (row) => editViewRoleForm(row, roles, req),
212
+ },
213
+ {
225
214
  label: "",
226
- key: (r) => view_dropdown(r, req),
227
- }
228
- : {
229
- label: req.__("Remove From Tag"),
230
215
  key: (r) =>
231
- post_delete_btn(
232
- `/tag-entries/remove/views/${r.id}/${tagId}`,
233
- req,
234
- `${r.name} from this tag`
216
+ link(
217
+ `/viewedit/config/${encodeURIComponent(r.name)}`,
218
+ req.__("Configure")
235
219
  ),
236
220
  },
237
- ],
238
- views,
239
- {
240
- hover: true,
241
- tableClass: listClass(tagId, showList),
242
- tableId: domId,
243
- }
244
- )
221
+ !tagId
222
+ ? {
223
+ label: "",
224
+ key: (r) => view_dropdown(r, req),
225
+ }
226
+ : {
227
+ label: req.__("Remove From Tag"),
228
+ key: (r) =>
229
+ post_delete_btn(
230
+ `/tag-entries/remove/views/${r.id}/${tagId}`,
231
+ req,
232
+ `${r.name} from this tag`
233
+ ),
234
+ },
235
+ ],
236
+ views,
237
+ {
238
+ hover: true,
239
+ tableClass: listClass(tagId, showList),
240
+ tableId: domId,
241
+ }
242
+ )
245
243
  : div(
246
- { class: listClass(tagId, showList), id: domId },
247
- h4(req.__("No views defined")),
248
- p(req.__("Views define how table rows are displayed to the user"))
249
- );
244
+ { class: listClass(tagId, showList), id: domId },
245
+ h4(req.__("No views defined")),
246
+ p(req.__("Views define how table rows are displayed to the user"))
247
+ );
250
248
  };
251
249
 
252
250
  /**
@@ -334,19 +332,18 @@ const getPageList = (rows, roles, req, { tagId, domId, showList } = {}) => {
334
332
  },
335
333
  !tagId
336
334
  ? {
337
- label: "",
338
- key: (r) => page_dropdown(r, req),
339
- }
335
+ label: "",
336
+ key: (r) => page_dropdown(r, req),
337
+ }
340
338
  : {
341
- label: req.__("Remove From Tag"),
342
- key: (r) =>
343
- post_delete_btn(
344
- `/tag-entries/remove/pages/${r.id}/${tagId}`,
345
- req,
346
- `${r.name} from this tag`
347
- ),
348
- },
349
- ,
339
+ label: req.__("Remove From Tag"),
340
+ key: (r) =>
341
+ post_delete_btn(
342
+ `/tag-entries/remove/pages/${r.id}/${tagId}`,
343
+ req,
344
+ `${r.name} from this tag`
345
+ ),
346
+ },
350
347
  ],
351
348
  rows,
352
349
  {
@@ -391,18 +388,18 @@ const getTriggerList = (triggers, req, { tagId, domId, showList } = {}) => {
391
388
  },
392
389
  !tagId
393
390
  ? {
394
- label: req.__("Delete"),
395
- key: (r) => post_delete_btn(`/actions/delete/${r.id}`, req),
396
- }
391
+ label: req.__("Delete"),
392
+ key: (r) => post_delete_btn(`/actions/delete/${r.id}`, req),
393
+ }
397
394
  : {
398
- label: req.__("Remove From Tag"),
399
- key: (r) =>
400
- post_delete_btn(
401
- `/tag-entries/remove/trigger/${r.id}/${tagId}`,
402
- req,
403
- `${r.name} from this tag`
404
- ),
405
- },
395
+ label: req.__("Remove From Tag"),
396
+ key: (r) =>
397
+ post_delete_btn(
398
+ `/tag-entries/remove/trigger/${r.id}/${tagId}`,
399
+ req,
400
+ `${r.name} from this tag`
401
+ ),
402
+ },
406
403
  ],
407
404
  triggers,
408
405
  {
package/routes/delete.js CHANGED
@@ -33,13 +33,13 @@ router.post(
33
33
  const { tableName, id } = req.params;
34
34
  const { redirect } = req.query;
35
35
  // todo check that works after where change
36
- const table = await Table.findOne({ name : tableName });
36
+ const table = await Table.findOne({ name: tableName });
37
37
  const role = req.user && req.user.id ? req.user.role_id : 10;
38
38
  try {
39
39
  if (role <= table.min_role_write) await table.deleteRows({ id });
40
40
  else if (table.ownership_field_id && req.user) {
41
41
  const row = await table.getRow({ id });
42
- if (row && (table.is_owner(req.user, row)))
42
+ if (row && table.is_owner(req.user, row))
43
43
  await table.deleteRows({ id });
44
44
  else req.flash("error", req.__("Not authorized"));
45
45
  } else
package/routes/edit.js CHANGED
@@ -31,7 +31,7 @@ router.post(
31
31
  const { tableName, id, field_name } = req.params;
32
32
  const { redirect } = req.query;
33
33
  // todo check that works after where change
34
- const table = await Table.findOne({ name : tableName });
34
+ const table = await Table.findOne({ name: tableName });
35
35
  const role = req.user && req.user.id ? req.user.role_id : 10;
36
36
  if (role <= table.min_role_write) await table.toggleBool(+id, field_name);
37
37
  else
package/routes/fields.js CHANGED
@@ -28,11 +28,13 @@ const expressionBlurb = require("../markup/expression_blurb");
28
28
  const {
29
29
  readState,
30
30
  add_free_variables_to_joinfields,
31
+ calcfldViewConfig,
31
32
  } = require("@saltcorn/data/plugin-helper");
32
33
  const { wizardCardTitle } = require("../markup/forms.js");
33
34
  const FieldRepeat = require("@saltcorn/data/models/fieldrepeat");
34
35
  const { applyAsync } = require("@saltcorn/data/utils");
35
36
  const { text } = require("@saltcorn/markup/tags");
37
+ const { mkFormContentNoLayout } = require("@saltcorn/markup/form");
36
38
 
37
39
  /**
38
40
  * @type {object}
@@ -291,7 +293,9 @@ const fieldFlow = (req) =>
291
293
  form: async (context) => {
292
294
  if (context.type === "File") {
293
295
  const roles = await User.get_roles();
294
- const default_file_accept_filter = await getState().getConfig("files_accept_filter_default");
296
+ const default_file_accept_filter = await getState().getConfig(
297
+ "files_accept_filter_default"
298
+ );
295
299
  //console.log("default_file_accept_filter",default_file_accept_filter);
296
300
  return new Form({
297
301
  fields: [
@@ -317,7 +321,7 @@ const fieldFlow = (req) =>
317
321
  type: "String",
318
322
  label: req.__("Files accept filter"),
319
323
  sublabel: req.__(
320
- "Specifies a filter for what file types the user can pick from the file input dialog box. Example is `.doc,audio/*,video/*,image/*`"
324
+ "Specifies a filter for what file types the user can pick from the file input dialog box. Example is `.doc,audio/*,video/*,image/*`"
321
325
  ),
322
326
  default: default_file_accept_filter,
323
327
  },
@@ -901,3 +905,45 @@ router.post(
901
905
  res.send("");
902
906
  })
903
907
  );
908
+
909
+ router.post(
910
+ "/fieldviewcfgform/:tableName",
911
+ isAdmin,
912
+ error_catcher(async (req, res) => {
913
+ const { tableName } = req.params;
914
+ const {
915
+ field_name,
916
+ fieldview,
917
+ type,
918
+ join_field,
919
+ join_fieldview,
920
+ _columndef,
921
+ } = req.body;
922
+ const table = await Table.findOne({ name: tableName });
923
+ const fieldName = type == "Field" ? field_name : join_field;
924
+ const fv_name = type == "Field" ? fieldview : join_fieldview;
925
+ if (!fieldName) {
926
+ res.send("");
927
+ return;
928
+ }
929
+
930
+ const field = await table.getField(fieldName);
931
+
932
+ const fieldViewConfigForms = await calcfldViewConfig([field], false, 0);
933
+ const formFields = fieldViewConfigForms[field.name][fv_name];
934
+ if (!formFields) {
935
+ res.send("");
936
+ return;
937
+ }
938
+ formFields.forEach((ff) => {
939
+ ff.class = ff.class ? `${ff.class} item-menu` : "item-menu";
940
+ });
941
+
942
+ const form = new Form({
943
+ formStyle: "vert",
944
+ fields: formFields,
945
+ });
946
+ if (_columndef) form.values = JSON.parse(_columndef);
947
+ res.send(mkFormContentNoLayout(form));
948
+ })
949
+ );