@saltcorn/server 0.7.4 → 0.8.0-beta.1
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 +18 -11
- package/auth/admin.js +370 -120
- package/auth/roleadmin.js +5 -23
- package/auth/routes.js +40 -15
- package/locales/de.json +1049 -273
- package/locales/en.json +58 -3
- package/locales/es.json +134 -134
- package/locales/it.json +6 -1
- package/locales/ru.json +44 -7
- package/markup/admin.js +46 -42
- package/markup/forms.js +4 -3
- package/package.json +8 -7
- package/public/blockly.js +19 -31
- package/public/diagram_utils.js +530 -0
- package/public/gridedit.js +4 -1
- package/public/jquery-menu-editor.min.js +112 -112
- package/public/saltcorn-common.js +31 -8
- package/public/saltcorn.css +11 -0
- package/public/saltcorn.js +211 -70
- package/restart_watcher.js +1 -0
- package/routes/actions.js +6 -14
- package/routes/admin.js +229 -79
- package/routes/api.js +19 -2
- package/routes/common_lists.js +137 -134
- package/routes/delete.js +6 -5
- package/routes/diagram.js +43 -117
- package/routes/edit.js +5 -10
- package/routes/fields.js +63 -29
- package/routes/files.js +137 -101
- package/routes/homepage.js +2 -2
- package/routes/infoarch.js +2 -2
- package/routes/list.js +12 -13
- package/routes/page.js +16 -3
- package/routes/pageedit.js +13 -8
- package/routes/scapi.js +1 -1
- package/routes/search.js +1 -1
- package/routes/tables.js +9 -14
- package/routes/tag_entries.js +31 -10
- package/routes/tags.js +10 -10
- package/routes/tenant.js +114 -50
- package/routes/utils.js +12 -0
- package/routes/view.js +3 -4
- package/routes/viewedit.js +57 -55
- package/serve.js +5 -0
- package/tests/admin.test.js +6 -2
- package/tests/auth.test.js +20 -0
- package/tests/fields.test.js +1 -0
- package/tests/files.test.js +11 -20
- package/tests/tenant.test.js +12 -2
- package/tests/viewedit.test.js +15 -1
package/markup/admin.js
CHANGED
|
@@ -122,35 +122,35 @@ const send_settings_page = ({
|
|
|
122
122
|
const pillCard = no_nav_pills
|
|
123
123
|
? []
|
|
124
124
|
: [
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
)
|
|
125
|
+
{
|
|
126
|
+
type: "card",
|
|
127
|
+
class: "mt-0",
|
|
128
|
+
contents: div(
|
|
129
|
+
{ class: "d-flex" },
|
|
130
|
+
ul(
|
|
131
|
+
{ class: "nav nav-pills plugin-section" },
|
|
132
|
+
sub_sections.map(({ text, href }) =>
|
|
133
|
+
li(
|
|
134
|
+
{ class: "nav-item" },
|
|
135
|
+
a(
|
|
136
|
+
{
|
|
137
|
+
href,
|
|
138
|
+
class: ["nav-link", active_sub === text && "active"],
|
|
139
|
+
},
|
|
140
|
+
req.__(text)
|
|
142
141
|
)
|
|
143
142
|
)
|
|
144
143
|
)
|
|
145
|
-
)
|
|
146
|
-
|
|
147
|
-
|
|
144
|
+
)
|
|
145
|
+
),
|
|
146
|
+
},
|
|
147
|
+
];
|
|
148
148
|
// headers
|
|
149
149
|
const title = headers
|
|
150
150
|
? {
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
151
|
+
title: req.__(active_sub),
|
|
152
|
+
headers,
|
|
153
|
+
}
|
|
154
154
|
: req.__(active_sub);
|
|
155
155
|
res.sendWrap(title, {
|
|
156
156
|
above: [
|
|
@@ -167,10 +167,10 @@ const send_settings_page = ({
|
|
|
167
167
|
},
|
|
168
168
|
...(sub2_page
|
|
169
169
|
? [
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
170
|
+
{
|
|
171
|
+
text: sub2_page,
|
|
172
|
+
},
|
|
173
|
+
]
|
|
174
174
|
: []),
|
|
175
175
|
],
|
|
176
176
|
},
|
|
@@ -199,9 +199,9 @@ const send_infoarch_page = (args) => {
|
|
|
199
199
|
{ text: "Languages", href: "/site-structure/localizer" },
|
|
200
200
|
...(tenant_list
|
|
201
201
|
? [
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
202
|
+
{ text: "Tenants", href: "/tenant/list" },
|
|
203
|
+
{ text: "Multitenancy", href: "/tenant/settings" },
|
|
204
|
+
]
|
|
205
205
|
: []),
|
|
206
206
|
{ text: "Tags", href: "/tag" },
|
|
207
207
|
{ text: "Diagram", href: "/diagram" },
|
|
@@ -223,8 +223,11 @@ const send_users_page = (args) => {
|
|
|
223
223
|
sub_sections: [
|
|
224
224
|
{ text: "Users", href: "/useradmin" },
|
|
225
225
|
{ text: "Roles", href: "/roleadmin" },
|
|
226
|
-
{ text: "
|
|
226
|
+
{ text: "Login and Signup", href: "/useradmin/settings" },
|
|
227
|
+
{ text: "Table access", href: "/useradmin/table-access" },
|
|
227
228
|
...(isRoot ? [{ text: "SSL", href: "/useradmin/ssl" }] : []),
|
|
229
|
+
{ text: "HTTP", href: "/useradmin/http" },
|
|
230
|
+
{ text: "Permissions", href: "/useradmin/permissions" },
|
|
228
231
|
],
|
|
229
232
|
...args,
|
|
230
233
|
});
|
|
@@ -281,7 +284,7 @@ const send_events_page = (args) => {
|
|
|
281
284
|
* @returns {void}
|
|
282
285
|
*/
|
|
283
286
|
const send_admin_page = (args) => {
|
|
284
|
-
const isRoot = db.getTenantSchema() === db.connectObj.default_schema;
|
|
287
|
+
//const isRoot = db.getTenantSchema() === db.connectObj.default_schema;
|
|
285
288
|
return send_settings_page({
|
|
286
289
|
main_section: "About application",
|
|
287
290
|
main_section_href: "/admin",
|
|
@@ -291,6 +294,7 @@ const send_admin_page = (args) => {
|
|
|
291
294
|
{ text: "Email", href: "/admin/email" },
|
|
292
295
|
{ text: "System", href: "/admin/system" },
|
|
293
296
|
{ text: "Mobile app", href: "/admin/build-mobile-app" },
|
|
297
|
+
{ text: "Development", href: "/admin/dev" },
|
|
294
298
|
],
|
|
295
299
|
...args,
|
|
296
300
|
});
|
|
@@ -339,8 +343,8 @@ const flash_restart = (req) => {
|
|
|
339
343
|
req.flash(
|
|
340
344
|
"warning",
|
|
341
345
|
req.__(`Restart required for changes to take effect.`) +
|
|
342
|
-
|
|
343
|
-
|
|
346
|
+
" " +
|
|
347
|
+
a({ href: "/admin/system" }, req.__("Restart here"))
|
|
344
348
|
);
|
|
345
349
|
};
|
|
346
350
|
|
|
@@ -393,16 +397,16 @@ const config_fields_form = async ({
|
|
|
393
397
|
isView || isRole || isTenant
|
|
394
398
|
? "String"
|
|
395
399
|
: configTypes[name].input_type
|
|
396
|
-
|
|
397
|
-
|
|
400
|
+
? undefined
|
|
401
|
+
: configTypes[name].type,
|
|
398
402
|
input_type: configTypes[name].input_type,
|
|
399
403
|
attributes: isView
|
|
400
404
|
? await viewAttributes(name)
|
|
401
405
|
: isRole
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
+
? roleAttribs
|
|
407
|
+
: isTenant
|
|
408
|
+
? await getTenants()
|
|
409
|
+
: configTypes[name].attributes,
|
|
406
410
|
});
|
|
407
411
|
}
|
|
408
412
|
const form = new Form({
|
|
@@ -434,7 +438,7 @@ const save_config_from_form = async (form) => {
|
|
|
434
438
|
|
|
435
439
|
/**
|
|
436
440
|
* Get Base Domain
|
|
437
|
-
* @returns {string} base domain
|
|
441
|
+
* @returns {string|null} base domain
|
|
438
442
|
*/
|
|
439
443
|
const getBaseDomain = () => {
|
|
440
444
|
const base_url = getState().getConfig("base_url");
|
|
@@ -455,7 +459,7 @@ const hostname_matches_baseurl = (req, domain) => domain === req.hostname;
|
|
|
455
459
|
|
|
456
460
|
/**
|
|
457
461
|
* @param {string} domain
|
|
458
|
-
* @returns {string[]}
|
|
462
|
+
* @returns {string[]|boolean}
|
|
459
463
|
*/
|
|
460
464
|
const is_hsts_tld = (domain) => {
|
|
461
465
|
if (!domain) return false;
|
package/markup/forms.js
CHANGED
|
@@ -50,7 +50,7 @@ const editRoleForm = ({ url, current_role, roles, req }) =>
|
|
|
50
50
|
* @param {object} req
|
|
51
51
|
* @returns {Form}
|
|
52
52
|
*/
|
|
53
|
-
const fileUploadForm = (req) =>
|
|
53
|
+
const fileUploadForm = (req, folder) =>
|
|
54
54
|
form(
|
|
55
55
|
{
|
|
56
56
|
action: "/files/upload",
|
|
@@ -61,11 +61,12 @@ const fileUploadForm = (req) =>
|
|
|
61
61
|
label(req.__("Upload file ")),
|
|
62
62
|
input({
|
|
63
63
|
name: "file",
|
|
64
|
-
class: "form-control-
|
|
64
|
+
class: "form-control ms-1 w-unset d-inline",
|
|
65
65
|
type: "file",
|
|
66
66
|
onchange: "form.submit()",
|
|
67
67
|
multiple: true,
|
|
68
|
-
})
|
|
68
|
+
}),
|
|
69
|
+
folder && input({ type: "hidden", name: "folder", value: folder })
|
|
69
70
|
);
|
|
70
71
|
|
|
71
72
|
/**
|
package/package.json
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@saltcorn/server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0-beta.1",
|
|
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.
|
|
10
|
-
"@saltcorn/builder": "0.
|
|
11
|
-
"@saltcorn/data": "0.
|
|
12
|
-
"@saltcorn/admin-models": "0.
|
|
13
|
-
"@saltcorn/
|
|
14
|
-
"@saltcorn/
|
|
9
|
+
"@saltcorn/base-plugin": "0.8.0-beta.1",
|
|
10
|
+
"@saltcorn/builder": "0.8.0-beta.1",
|
|
11
|
+
"@saltcorn/data": "0.8.0-beta.1",
|
|
12
|
+
"@saltcorn/admin-models": "0.8.0-beta.1",
|
|
13
|
+
"@saltcorn/filemanager": "0.8.0-beta.1",
|
|
14
|
+
"@saltcorn/markup": "0.8.0-beta.1",
|
|
15
|
+
"@saltcorn/sbadmin2": "0.8.0-beta.1",
|
|
15
16
|
"@socket.io/cluster-adapter": "^0.1.0",
|
|
16
17
|
"@socket.io/sticky": "^1.0.1",
|
|
17
18
|
"aws-sdk": "^2.1037.0",
|
package/public/blockly.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// todo replace var with let / const
|
|
1
2
|
function activate_blockly({ events, actions, tables }) {
|
|
2
3
|
// https://blockly-demo.appspot.com/static/demos/blockfactory/index.html#arpfmx
|
|
3
4
|
|
|
@@ -21,8 +22,7 @@ function activate_blockly({ events, actions, tables }) {
|
|
|
21
22
|
Blockly.JavaScript.ORDER_ATOMIC
|
|
22
23
|
);
|
|
23
24
|
// TODO: Assemble JavaScript into code variable.
|
|
24
|
-
|
|
25
|
-
return code;
|
|
25
|
+
return `console.log(${value_string});\n`;
|
|
26
26
|
};
|
|
27
27
|
|
|
28
28
|
Blockly.Blocks["emit_event"] = {
|
|
@@ -58,9 +58,7 @@ function activate_blockly({ events, actions, tables }) {
|
|
|
58
58
|
Blockly.JavaScript.ORDER_ATOMIC
|
|
59
59
|
);
|
|
60
60
|
// TODO: Assemble JavaScript into code variable.
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
return code;
|
|
61
|
+
return `emitEvent("${dropdown_event}", ${value_channel}, ${value_payload});\n`;
|
|
64
62
|
};
|
|
65
63
|
|
|
66
64
|
Blockly.Blocks["row"] = {
|
|
@@ -75,7 +73,7 @@ function activate_blockly({ events, actions, tables }) {
|
|
|
75
73
|
|
|
76
74
|
Blockly.JavaScript["row"] = function (block) {
|
|
77
75
|
// TODO: Assemble JavaScript into code variable.
|
|
78
|
-
|
|
76
|
+
const code = "row";
|
|
79
77
|
// TODO: Change ORDER_NONE to the correct strength.
|
|
80
78
|
return [code, Blockly.JavaScript.ORDER_NONE];
|
|
81
79
|
};
|
|
@@ -91,7 +89,7 @@ function activate_blockly({ events, actions, tables }) {
|
|
|
91
89
|
};
|
|
92
90
|
Blockly.JavaScript["current_channel"] = function (block) {
|
|
93
91
|
// TODO: Assemble JavaScript into code variable.
|
|
94
|
-
|
|
92
|
+
const code = "channel";
|
|
95
93
|
// TODO: Change ORDER_NONE to the correct strength.
|
|
96
94
|
return [code, Blockly.JavaScript.ORDER_NONE];
|
|
97
95
|
};
|
|
@@ -106,7 +104,7 @@ function activate_blockly({ events, actions, tables }) {
|
|
|
106
104
|
};
|
|
107
105
|
Blockly.JavaScript["empty"] = function (block) {
|
|
108
106
|
// TODO: Assemble JavaScript into code variable.
|
|
109
|
-
|
|
107
|
+
const code = "{}";
|
|
110
108
|
// TODO: Change ORDER_NONE to the correct strength.
|
|
111
109
|
return [code, Blockly.JavaScript.ORDER_NONE];
|
|
112
110
|
};
|
|
@@ -170,8 +168,7 @@ function activate_blockly({ events, actions, tables }) {
|
|
|
170
168
|
Blockly.JavaScript.ORDER_ATOMIC
|
|
171
169
|
);
|
|
172
170
|
// TODO: Assemble JavaScript into code variable.
|
|
173
|
-
|
|
174
|
-
return code;
|
|
171
|
+
return `${value_row}.${text_key}=${value_value};\n`;
|
|
175
172
|
};
|
|
176
173
|
Blockly.Blocks["insert_table"] = {
|
|
177
174
|
init: function () {
|
|
@@ -196,8 +193,7 @@ function activate_blockly({ events, actions, tables }) {
|
|
|
196
193
|
Blockly.JavaScript.ORDER_ATOMIC
|
|
197
194
|
);
|
|
198
195
|
// TODO: Assemble JavaScript into code variable.
|
|
199
|
-
|
|
200
|
-
return code;
|
|
196
|
+
return `await Table.findOne({name: '${dropdown_table}'})\n .tryInsertRow(${value_row});\n`;
|
|
201
197
|
};
|
|
202
198
|
Blockly.Blocks["query_table"] = {
|
|
203
199
|
init: function () {
|
|
@@ -281,8 +277,7 @@ function activate_blockly({ events, actions, tables }) {
|
|
|
281
277
|
Blockly.JavaScript.ORDER_ATOMIC
|
|
282
278
|
);
|
|
283
279
|
// TODO: Assemble JavaScript into code variable.
|
|
284
|
-
|
|
285
|
-
return code;
|
|
280
|
+
return `await Table.findOne({name: '${dropdown_table}'})\n .deleteRows({id: ${value_id}});\n`;
|
|
286
281
|
};
|
|
287
282
|
|
|
288
283
|
Blockly.Blocks["delete_table_where"] = {
|
|
@@ -309,9 +304,7 @@ function activate_blockly({ events, actions, tables }) {
|
|
|
309
304
|
Blockly.JavaScript.ORDER_ATOMIC
|
|
310
305
|
);
|
|
311
306
|
// TODO: Assemble JavaScript into code variable.
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
return code;
|
|
307
|
+
return `await Table.findOne({name: '${dropdown_table}'})\n .deleteRows(${value_where});\n`;
|
|
315
308
|
};
|
|
316
309
|
Blockly.Blocks["update_table"] = {
|
|
317
310
|
init: function () {
|
|
@@ -342,8 +335,7 @@ function activate_blockly({ events, actions, tables }) {
|
|
|
342
335
|
Blockly.JavaScript.ORDER_ATOMIC
|
|
343
336
|
);
|
|
344
337
|
// TODO: Assemble JavaScript into code variable.
|
|
345
|
-
|
|
346
|
-
return code;
|
|
338
|
+
return `await Table.findOne({name: '${dropdown_table}'})\n .tryUpdateRow(${value_row}, ${value_id});\n`;
|
|
347
339
|
};
|
|
348
340
|
|
|
349
341
|
Blockly.Blocks["sleep"] = {
|
|
@@ -363,10 +355,9 @@ function activate_blockly({ events, actions, tables }) {
|
|
|
363
355
|
},
|
|
364
356
|
};
|
|
365
357
|
Blockly.JavaScript["sleep"] = function (block) {
|
|
366
|
-
|
|
358
|
+
const number_sleep_ms = block.getFieldValue("SLEEP_MS");
|
|
367
359
|
// TODO: Assemble JavaScript into code variable.
|
|
368
|
-
|
|
369
|
-
return code;
|
|
360
|
+
return `await sleep(${number_sleep_ms});\n`;
|
|
370
361
|
};
|
|
371
362
|
|
|
372
363
|
Blockly.Blocks["http_request"] = {
|
|
@@ -439,7 +430,7 @@ function activate_blockly({ events, actions, tables }) {
|
|
|
439
430
|
"POPUP",
|
|
440
431
|
Blockly.JavaScript.ORDER_ATOMIC
|
|
441
432
|
);
|
|
442
|
-
var checkbox_reload = block.getFieldValue("RELOAD")
|
|
433
|
+
var checkbox_reload = block.getFieldValue("RELOAD") === "TRUE";
|
|
443
434
|
var value_notify = Blockly.JavaScript.valueToCode(
|
|
444
435
|
block,
|
|
445
436
|
"NOTIFY",
|
|
@@ -451,8 +442,7 @@ function activate_blockly({ events, actions, tables }) {
|
|
|
451
442
|
if (value_popup) s += `popup: ${value_popup},`;
|
|
452
443
|
if (value_notify) s += `notify: ${value_notify},`;
|
|
453
444
|
if (checkbox_reload) s += `reload_page: true,`;
|
|
454
|
-
|
|
455
|
-
return code;
|
|
445
|
+
return `return {${s}};\n`;
|
|
456
446
|
};
|
|
457
447
|
Blockly.Blocks["push_to_list"] = {
|
|
458
448
|
init: function () {
|
|
@@ -480,8 +470,7 @@ function activate_blockly({ events, actions, tables }) {
|
|
|
480
470
|
Blockly.JavaScript.ORDER_ATOMIC
|
|
481
471
|
);
|
|
482
472
|
// TODO: Assemble JavaScript into code variable.
|
|
483
|
-
|
|
484
|
-
return code;
|
|
473
|
+
return `${value_list}.push(${value_name});\n`;
|
|
485
474
|
};
|
|
486
475
|
if (actions.length > 0) {
|
|
487
476
|
Blockly.Blocks["action"] = {
|
|
@@ -501,12 +490,11 @@ function activate_blockly({ events, actions, tables }) {
|
|
|
501
490
|
};
|
|
502
491
|
|
|
503
492
|
Blockly.JavaScript["action"] = function (block) {
|
|
504
|
-
|
|
493
|
+
const dropdown_name = block.getFieldValue("NAME");
|
|
505
494
|
// TODO: Assemble JavaScript into code variable.
|
|
506
|
-
|
|
495
|
+
return dropdown_name.includes(" ")
|
|
507
496
|
? `Actions['${dropdown_name}']();\n`
|
|
508
497
|
: `Actions.${dropdown_name}();\n`;
|
|
509
|
-
return code;
|
|
510
498
|
};
|
|
511
499
|
}
|
|
512
500
|
Blockly.Blocks["unit_row"] = {
|
|
@@ -577,7 +565,7 @@ function activate_blockly({ events, actions, tables }) {
|
|
|
577
565
|
$("#blocklyForm").submit();
|
|
578
566
|
});
|
|
579
567
|
function myUpdateFunction(event) {
|
|
580
|
-
|
|
568
|
+
const code = Blockly.JavaScript.workspaceToCode(workspace);
|
|
581
569
|
$("#blockly_js_output").html(code);
|
|
582
570
|
}
|
|
583
571
|
workspace.addChangeListener(myUpdateFunction);
|