@saltcorn/server 0.8.0-beta.2 → 0.8.0-beta.4
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/admin.js +3 -19
- package/locales/en.json +10 -2
- package/locales/it.json +1 -1
- package/locales/ru.json +25 -1
- package/markup/admin.js +70 -52
- package/markup/forms.js +27 -23
- package/package.json +8 -8
- package/public/saltcorn.js +2 -2
- package/routes/admin.js +136 -142
- package/routes/fields.js +15 -4
- package/routes/files.js +83 -22
- package/routes/homepage.js +70 -64
- package/routes/infoarch.js +10 -7
- package/routes/menu.js +22 -12
- package/routes/page.js +6 -1
- package/routes/plugins.js +112 -106
- package/routes/tables.js +173 -164
- package/routes/utils.js +3 -2
- package/routes/view.js +9 -2
- package/s3storage.js +24 -11
package/auth/admin.js
CHANGED
|
@@ -7,20 +7,12 @@
|
|
|
7
7
|
// todo refactor to few modules + rename to be in sync with router url
|
|
8
8
|
const Router = require("express-promise-router");
|
|
9
9
|
const { contract, is } = require("contractis");
|
|
10
|
-
|
|
11
10
|
const db = require("@saltcorn/data/db");
|
|
12
11
|
const User = require("@saltcorn/data/models/user");
|
|
13
12
|
const View = require("@saltcorn/data/models/view");
|
|
14
13
|
const Field = require("@saltcorn/data/models/field");
|
|
15
14
|
const Form = require("@saltcorn/data/models/form");
|
|
16
|
-
const {
|
|
17
|
-
mkTable,
|
|
18
|
-
renderForm,
|
|
19
|
-
link,
|
|
20
|
-
post_btn,
|
|
21
|
-
settingsDropdown,
|
|
22
|
-
post_dropdown_item,
|
|
23
|
-
} = require("@saltcorn/markup");
|
|
15
|
+
const { mkTable, renderForm, link, post_btn, settingsDropdown, post_dropdown_item } = require("@saltcorn/markup");
|
|
24
16
|
const { isAdmin, error_catcher } = require("../routes/utils");
|
|
25
17
|
const { send_reset_email } = require("./resetpw");
|
|
26
18
|
const { getState } = require("@saltcorn/data/db/state");
|
|
@@ -35,16 +27,7 @@ const {
|
|
|
35
27
|
is_hsts_tld,
|
|
36
28
|
} = require("../markup/admin");
|
|
37
29
|
const { send_verification_email } = require("@saltcorn/data/models/email");
|
|
38
|
-
const {
|
|
39
|
-
expressionValidator,
|
|
40
|
-
} = require("@saltcorn/data/models/expression");
|
|
41
|
-
/**
|
|
42
|
-
* @type {object}
|
|
43
|
-
* @const
|
|
44
|
-
* @namespace auth/adminRouter
|
|
45
|
-
* @category server
|
|
46
|
-
* @subcategory auth
|
|
47
|
-
*/
|
|
30
|
+
const { expressionValidator } = require("@saltcorn/data/models/expression");
|
|
48
31
|
const router = new Router();
|
|
49
32
|
module.exports = router;
|
|
50
33
|
|
|
@@ -357,6 +340,7 @@ const permissions_settings_form = async (req) =>
|
|
|
357
340
|
field_names: [
|
|
358
341
|
"min_role_upload",
|
|
359
342
|
"min_role_apikeygen",
|
|
343
|
+
//hidden "exttables_min_role_read",
|
|
360
344
|
],
|
|
361
345
|
action: "/useradmin/permissions",
|
|
362
346
|
submitLabel: req.__("Save"),
|
package/locales/en.json
CHANGED
|
@@ -1046,6 +1046,14 @@
|
|
|
1046
1046
|
"<p>You have views with a role to access lower than the table role to read, \n with no table ownership. In the next version of Saltcorn, this may cause a\n denial of access. Users will need to have table read access to any data displayed.</p> \n Views potentially affected: %s": "<p>You have views with a role to access lower than the table role to read, \n with no table ownership. In the next version of Saltcorn, this may cause a\n denial of access. Users will need to have table read access to any data displayed.</p> \n Views potentially affected: %s",
|
|
1047
1047
|
"If the parent row is deleted, do this to the child rows.": "If the parent row is deleted, do this to the child rows.",
|
|
1048
1048
|
"On delete": "On delete",
|
|
1049
|
-
"
|
|
1050
|
-
"
|
|
1049
|
+
"Permissions": "Permissions",
|
|
1050
|
+
"Permissions settings": "Permissions settings",
|
|
1051
|
+
"Files accept filter ": "Files accept filter ",
|
|
1052
|
+
"Specifies a filter for what file types the user can pick from the file input dialog box. Example is `.doc,audio/*,video/*,image/*`": "Specifies a filter for what file types the user can pick from the file input dialog box. Example is `.doc,audio/*,video/*,image/*`",
|
|
1053
|
+
"Permissions settings updated": "Permissions settings updated",
|
|
1054
|
+
"Upload file(s)": "Upload file(s)",
|
|
1055
|
+
"Specifies a filter for what file types the user can pick from the file input dialog box. Example is `text/csv,audio/*,video/*,image/*`": "Specifies a filter for what file types the user can pick from the file input dialog box. Example is `text/csv,audio/*,video/*,image/*`",
|
|
1056
|
+
"Default Files accept filter": "Default Files accept filter",
|
|
1057
|
+
"Specifies a default filter for what file types the user can pick from the file input dialog box. Example is `.doc, text/csv,audio/*,video/*,image/*`": "Specifies a default filter for what file types the user can pick from the file input dialog box. Example is `.doc, text/csv,audio/*,video/*,image/*`",
|
|
1058
|
+
"Destination page": "Destination page"
|
|
1051
1059
|
}
|
package/locales/it.json
CHANGED
package/locales/ru.json
CHANGED
|
@@ -919,5 +919,29 @@
|
|
|
919
919
|
"File not found": "Файл не найден",
|
|
920
920
|
"Permissions settings": "Настройки разрешений",
|
|
921
921
|
"Permissions": "Разрешения",
|
|
922
|
-
"Permissions settings updated": "Настройки разрешений обновлены"
|
|
922
|
+
"Permissions settings updated": "Настройки разрешений обновлены",
|
|
923
|
+
"Upload file(s)": "Upload file(s)",
|
|
924
|
+
"Split paste": "Split paste",
|
|
925
|
+
"Separate paste content into separate inputs": "Separate paste content into separate inputs",
|
|
926
|
+
"Preview": "Preview",
|
|
927
|
+
"Create new row": "Create new row",
|
|
928
|
+
"Descending?": "Descending?",
|
|
929
|
+
"Only include rows where this formula is true. ": "Only include rows where this formula is true. ",
|
|
930
|
+
"Use %s to access current user ID": "Use %s to access current user ID",
|
|
931
|
+
"Formula value": "Formula value",
|
|
932
|
+
"Units": "Units",
|
|
933
|
+
"%s view - %s on %s": "%s view - %s on %s",
|
|
934
|
+
"Password Repeat": "Password Repeat",
|
|
935
|
+
"Remember me": "Remember me",
|
|
936
|
+
"Files accept filter ": "Files accept filter ",
|
|
937
|
+
"Specifies a filter for what file types the user can pick from the file input dialog box. Example is `text/csv,audio/*,video/*,image/*`": "Specifies a filter for what file types the user can pick from the file input dialog box. Example is `text/csv,audio/*,video/*,image/*`",
|
|
938
|
+
"Home Page by Role": "Home Page by Role",
|
|
939
|
+
"Files accept filter": "Files accept filter",
|
|
940
|
+
"Specify how to create a new row": "Specify how to create a new row",
|
|
941
|
+
"Cascade delete to file": "Cascade delete to file",
|
|
942
|
+
"Deleting a row will also delete the file referenced by this field": "Deleting a row will also delete the file referenced by this field",
|
|
943
|
+
"Specifies a filter for what file types the user can pick from the file input dialog box. Example is `.doc,audio/*,video/*,image/*`": "Specifies a filter for what file types the user can pick from the file input dialog box. Example is `.doc,audio/*,video/*,image/*`",
|
|
944
|
+
"Default Files accept filter": "Default Files accept filter",
|
|
945
|
+
"Specifies a default filter for what file types the user can pick from the file input dialog box. Example is `.doc, text/csv,audio/*,video/*,image/*`": "Specifies a default filter for what file types the user can pick from the file input dialog box. Example is `.doc, text/csv,audio/*,video/*,image/*`",
|
|
946
|
+
"No file found": "No file found"
|
|
923
947
|
}
|
package/markup/admin.js
CHANGED
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
|
|
8
8
|
const {
|
|
9
9
|
div,
|
|
10
|
-
//hr,
|
|
11
10
|
form,
|
|
12
11
|
input,
|
|
13
12
|
label,
|
|
@@ -18,16 +17,8 @@ const {
|
|
|
18
17
|
li,
|
|
19
18
|
} = require("@saltcorn/markup/tags");
|
|
20
19
|
const db = require("@saltcorn/data/db");
|
|
21
|
-
const {
|
|
22
|
-
//getConfig,
|
|
23
|
-
//setConfig,
|
|
24
|
-
//getAllConfigOrDefaults,
|
|
25
|
-
//deleteConfig,
|
|
26
|
-
configTypes,
|
|
27
|
-
isFixedConfig,
|
|
28
|
-
} = require("@saltcorn/data/models/config");
|
|
20
|
+
const { configTypes, isFixedConfig } = require("@saltcorn/data/models/config");
|
|
29
21
|
const { getState } = require("@saltcorn/data/db/state");
|
|
30
|
-
|
|
31
22
|
const Form = require("@saltcorn/data/models/form");
|
|
32
23
|
const Table = require("@saltcorn/data/models/table");
|
|
33
24
|
const View = require("@saltcorn/data/models/view");
|
|
@@ -77,14 +68,40 @@ const restore_backup = (csrf, inner, action = `/admin/restore`) =>
|
|
|
77
68
|
* @param {*} opts.req
|
|
78
69
|
* @returns {object}
|
|
79
70
|
*/
|
|
80
|
-
const add_edit_bar = ({
|
|
71
|
+
const add_edit_bar = ({
|
|
72
|
+
role,
|
|
73
|
+
title,
|
|
74
|
+
contents,
|
|
75
|
+
what,
|
|
76
|
+
url,
|
|
77
|
+
req,
|
|
78
|
+
viewtemplate,
|
|
79
|
+
table,
|
|
80
|
+
cfgUrl,
|
|
81
|
+
}) => {
|
|
81
82
|
if (role > 1 && req && req.xhr) return { above: [contents] }; //make sure not put in card
|
|
82
83
|
if (role > 1) return contents;
|
|
84
|
+
let viewSpec = "";
|
|
85
|
+
if (viewtemplate) viewSpec = viewtemplate;
|
|
86
|
+
if (table) {
|
|
87
|
+
const tbl = Table.findOne(table);
|
|
88
|
+
if (tbl)
|
|
89
|
+
viewSpec = `${viewSpec} on <a href="/table/${table}">${tbl.name}</a>`;
|
|
90
|
+
}
|
|
91
|
+
|
|
83
92
|
const bar = div(
|
|
84
93
|
{ class: "alert alert-light d-print-none admin-edit-bar" },
|
|
85
94
|
title,
|
|
86
|
-
what && span({ class: "ms-1 badge bg-primary" }, what),
|
|
87
|
-
|
|
95
|
+
what && span({ class: "ms-1 me-2 badge bg-primary" }, what),
|
|
96
|
+
viewSpec,
|
|
97
|
+
a({ class: "ms-2", href: url }, "Edit ", i({ class: "fas fa-edit" })),
|
|
98
|
+
cfgUrl
|
|
99
|
+
? a(
|
|
100
|
+
{ class: "ms-1", href: cfgUrl },
|
|
101
|
+
"Configure ",
|
|
102
|
+
i({ class: "fas fa-cog" })
|
|
103
|
+
)
|
|
104
|
+
: ""
|
|
88
105
|
);
|
|
89
106
|
|
|
90
107
|
if (contents.above) {
|
|
@@ -122,35 +139,35 @@ const send_settings_page = ({
|
|
|
122
139
|
const pillCard = no_nav_pills
|
|
123
140
|
? []
|
|
124
141
|
: [
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
142
|
+
{
|
|
143
|
+
type: "card",
|
|
144
|
+
class: "mt-0",
|
|
145
|
+
contents: div(
|
|
146
|
+
{ class: "d-flex" },
|
|
147
|
+
ul(
|
|
148
|
+
{ class: "nav nav-pills plugin-section" },
|
|
149
|
+
sub_sections.map(({ text, href }) =>
|
|
150
|
+
li(
|
|
151
|
+
{ class: "nav-item" },
|
|
152
|
+
a(
|
|
153
|
+
{
|
|
154
|
+
href,
|
|
155
|
+
class: ["nav-link", active_sub === text && "active"],
|
|
156
|
+
},
|
|
157
|
+
req.__(text)
|
|
158
|
+
)
|
|
141
159
|
)
|
|
142
160
|
)
|
|
143
161
|
)
|
|
144
|
-
)
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
];
|
|
162
|
+
),
|
|
163
|
+
},
|
|
164
|
+
];
|
|
148
165
|
// headers
|
|
149
166
|
const title = headers
|
|
150
167
|
? {
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
168
|
+
title: req.__(active_sub),
|
|
169
|
+
headers,
|
|
170
|
+
}
|
|
154
171
|
: req.__(active_sub);
|
|
155
172
|
res.sendWrap(title, {
|
|
156
173
|
above: [
|
|
@@ -167,10 +184,10 @@ const send_settings_page = ({
|
|
|
167
184
|
},
|
|
168
185
|
...(sub2_page
|
|
169
186
|
? [
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
187
|
+
{
|
|
188
|
+
text: sub2_page,
|
|
189
|
+
},
|
|
190
|
+
]
|
|
174
191
|
: []),
|
|
175
192
|
],
|
|
176
193
|
},
|
|
@@ -199,9 +216,9 @@ const send_infoarch_page = (args) => {
|
|
|
199
216
|
{ text: "Languages", href: "/site-structure/localizer" },
|
|
200
217
|
...(tenant_list
|
|
201
218
|
? [
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
219
|
+
{ text: "Tenants", href: "/tenant/list" },
|
|
220
|
+
{ text: "Multitenancy", href: "/tenant/settings" },
|
|
221
|
+
]
|
|
205
222
|
: []),
|
|
206
223
|
{ text: "Tags", href: "/tag" },
|
|
207
224
|
{ text: "Diagram", href: "/diagram" },
|
|
@@ -245,6 +262,7 @@ const send_files_page = (args) => {
|
|
|
245
262
|
sub_sections: [
|
|
246
263
|
{ text: "Files", href: "/files" },
|
|
247
264
|
{ text: "Storage", href: "/files/storage" },
|
|
265
|
+
{ text: "Settings", href: "/files/settings" },
|
|
248
266
|
],
|
|
249
267
|
...args,
|
|
250
268
|
});
|
|
@@ -343,8 +361,8 @@ const flash_restart = (req) => {
|
|
|
343
361
|
req.flash(
|
|
344
362
|
"warning",
|
|
345
363
|
req.__(`Restart required for changes to take effect.`) +
|
|
346
|
-
|
|
347
|
-
|
|
364
|
+
" " +
|
|
365
|
+
a({ href: "/admin/system" }, req.__("Restart here"))
|
|
348
366
|
);
|
|
349
367
|
};
|
|
350
368
|
|
|
@@ -369,7 +387,7 @@ const config_fields_form = async ({
|
|
|
369
387
|
|
|
370
388
|
for (const name of field_names) {
|
|
371
389
|
values[name] = state.getConfig(name);
|
|
372
|
-
//console.log(`config field name: %s`,name);
|
|
390
|
+
// console.log(`config field name: %s`,name);
|
|
373
391
|
if (configTypes[name].root_only && tenant !== db.connectObj.default_schema)
|
|
374
392
|
continue;
|
|
375
393
|
const isView = (configTypes[name].type || "").startsWith("View ");
|
|
@@ -397,16 +415,16 @@ const config_fields_form = async ({
|
|
|
397
415
|
isView || isRole || isTenant
|
|
398
416
|
? "String"
|
|
399
417
|
: configTypes[name].input_type
|
|
400
|
-
|
|
401
|
-
|
|
418
|
+
? undefined
|
|
419
|
+
: configTypes[name].type,
|
|
402
420
|
input_type: configTypes[name].input_type,
|
|
403
421
|
attributes: isView
|
|
404
422
|
? await viewAttributes(name)
|
|
405
423
|
: isRole
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
424
|
+
? roleAttribs
|
|
425
|
+
: isTenant
|
|
426
|
+
? await getTenants()
|
|
427
|
+
: configTypes[name].attributes,
|
|
410
428
|
});
|
|
411
429
|
}
|
|
412
430
|
const form = new Form({
|
package/markup/forms.js
CHANGED
|
@@ -11,13 +11,11 @@ const {
|
|
|
11
11
|
text,
|
|
12
12
|
label,
|
|
13
13
|
input,
|
|
14
|
-
div,
|
|
15
|
-
i,
|
|
16
|
-
h5,
|
|
17
14
|
} = require("@saltcorn/markup/tags");
|
|
18
15
|
const { csrfField } = require("../routes/utils");
|
|
19
16
|
|
|
20
17
|
/**
|
|
18
|
+
* Edit Role form (for admin)
|
|
21
19
|
* @param {object} opts
|
|
22
20
|
* @param {string} opts.url
|
|
23
21
|
* @param {Role} opts.current_role
|
|
@@ -47,30 +45,36 @@ const editRoleForm = ({ url, current_role, roles, req }) =>
|
|
|
47
45
|
);
|
|
48
46
|
|
|
49
47
|
/**
|
|
50
|
-
*
|
|
48
|
+
* File upload form (for admin)
|
|
49
|
+
* @param {object} req
|
|
50
|
+
* @param folder
|
|
51
51
|
* @returns {Form}
|
|
52
52
|
*/
|
|
53
|
-
const fileUploadForm = (req, folder
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
53
|
+
const fileUploadForm = (req, folder
|
|
54
|
+
) => {
|
|
55
|
+
const frm = form(
|
|
56
|
+
{
|
|
57
|
+
action: "/files/upload",
|
|
58
|
+
method: "post",
|
|
59
|
+
enctype: "multipart/form-data",
|
|
60
|
+
},
|
|
61
|
+
csrfField(req),
|
|
62
|
+
label(req.__("Upload file(s)")),
|
|
63
|
+
input({
|
|
64
|
+
name: "file",
|
|
65
|
+
class: "form-control ms-1 w-unset d-inline",
|
|
66
|
+
type: "file",
|
|
67
|
+
onchange: "form.submit()",
|
|
68
|
+
multiple: true,
|
|
69
|
+
}),
|
|
70
|
+
folder && input({type: "hidden", name: "folder", value: folder})
|
|
71
|
+
);
|
|
72
|
+
return frm;
|
|
73
|
+
};
|
|
71
74
|
|
|
72
75
|
/**
|
|
73
|
-
*
|
|
76
|
+
* Get Wizard Card Title
|
|
77
|
+
* @param {string} wizardTitle
|
|
74
78
|
* @param {*} wf
|
|
75
79
|
* @param {object} wfres
|
|
76
80
|
* @returns {string}
|
package/package.json
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@saltcorn/server",
|
|
3
|
-
"version": "0.8.0-beta.
|
|
3
|
+
"version": "0.8.0-beta.4",
|
|
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.8.0-beta.
|
|
10
|
-
"@saltcorn/builder": "0.8.0-beta.
|
|
11
|
-
"@saltcorn/data": "0.8.0-beta.
|
|
12
|
-
"@saltcorn/admin-models": "0.8.0-beta.
|
|
13
|
-
"@saltcorn/filemanager": "0.8.0-beta.
|
|
14
|
-
"@saltcorn/markup": "0.8.0-beta.
|
|
15
|
-
"@saltcorn/sbadmin2": "0.8.0-beta.
|
|
9
|
+
"@saltcorn/base-plugin": "0.8.0-beta.4",
|
|
10
|
+
"@saltcorn/builder": "0.8.0-beta.4",
|
|
11
|
+
"@saltcorn/data": "0.8.0-beta.4",
|
|
12
|
+
"@saltcorn/admin-models": "0.8.0-beta.4",
|
|
13
|
+
"@saltcorn/filemanager": "0.8.0-beta.4",
|
|
14
|
+
"@saltcorn/markup": "0.8.0-beta.4",
|
|
15
|
+
"@saltcorn/sbadmin2": "0.8.0-beta.4",
|
|
16
16
|
"@socket.io/cluster-adapter": "^0.1.0",
|
|
17
17
|
"@socket.io/sticky": "^1.0.1",
|
|
18
18
|
"aws-sdk": "^2.1037.0",
|
package/public/saltcorn.js
CHANGED
|
@@ -201,12 +201,12 @@ function view_post(viewname, route, data, onDone) {
|
|
|
201
201
|
notifyAlert({ type: "danger", text: res.responseText });
|
|
202
202
|
});
|
|
203
203
|
}
|
|
204
|
-
|
|
204
|
+
let logged_errors = [];
|
|
205
205
|
function globalErrorCatcher(message, source, lineno, colno, error) {
|
|
206
206
|
if (error && error.preventDefault) error.preventDefault();
|
|
207
207
|
if (logged_errors.includes(message)) return;
|
|
208
208
|
logged_errors.push(message);
|
|
209
|
-
|
|
209
|
+
const data = { message, stack: (error && error.stack) || "" };
|
|
210
210
|
$.ajax("/crashlog/", {
|
|
211
211
|
dataType: "json",
|
|
212
212
|
type: "POST",
|