@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.
- package/app.js +7 -6
- package/auth/admin.js +260 -217
- package/auth/index.js +20 -20
- package/auth/roleadmin.js +2 -9
- package/auth/routes.js +193 -139
- package/auth/testhelp.js +62 -55
- package/fixture_persons.js +1 -1
- package/index.js +22 -22
- package/locales/en.json +13 -1
- package/locales/fr.json +14 -2
- package/locales/ru.json +25 -19
- package/markup/admin.js +22 -15
- package/markup/blockly.js +1 -1
- package/markup/expression_blurb.js +15 -15
- package/markup/forms.js +21 -22
- package/markup/index.js +20 -20
- package/markup/plugin-store.js +4 -4
- package/package.json +8 -8
- package/public/diagram_utils.js +22 -9
- package/public/saltcorn-common.js +128 -68
- package/public/saltcorn.css +6 -0
- package/public/saltcorn.js +68 -20
- package/restart_watcher.js +157 -157
- package/routes/actions.js +4 -11
- package/routes/admin.js +14 -6
- package/routes/api.js +11 -18
- package/routes/common_lists.js +127 -130
- package/routes/delete.js +2 -2
- package/routes/edit.js +1 -1
- package/routes/fields.js +48 -2
- package/routes/files.js +112 -94
- package/routes/homepage.js +1 -1
- package/routes/infoarch.js +1 -1
- package/routes/list.js +6 -5
- package/routes/packs.js +1 -2
- package/routes/pageedit.js +1 -1
- package/routes/tag_entries.js +1 -1
- package/routes/tenant.js +2 -1
- package/routes/utils.js +3 -1
- package/routes/view.js +14 -2
- package/routes/viewedit.js +35 -0
- package/s3storage.js +13 -11
- package/serve.js +35 -31
- package/systemd.js +23 -21
- package/tests/fields.test.js +23 -0
- package/wrapper.js +46 -45
package/routes/common_lists.js
CHANGED
|
@@ -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
|
-
|
|
54
|
-
|
|
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
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
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
|
-
|
|
94
|
-
|
|
95
|
-
|
|
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
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
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
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
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
|
-
|
|
232
|
-
`/
|
|
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
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
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
|
-
|
|
247
|
-
|
|
248
|
-
|
|
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
|
-
|
|
338
|
-
|
|
339
|
-
|
|
335
|
+
label: "",
|
|
336
|
+
key: (r) => page_dropdown(r, req),
|
|
337
|
+
}
|
|
340
338
|
: {
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
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
|
-
|
|
395
|
-
|
|
396
|
-
|
|
391
|
+
label: req.__("Delete"),
|
|
392
|
+
key: (r) => post_delete_btn(`/actions/delete/${r.id}`, req),
|
|
393
|
+
}
|
|
397
394
|
: {
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
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
|
|
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 &&
|
|
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
|
|
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(
|
|
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
|
-
|
|
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
|
+
);
|