@saltcorn/server 0.8.0-beta.0 → 0.8.0-beta.2
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 +197 -46
- package/auth/roleadmin.js +5 -23
- package/locales/de.json +1049 -273
- package/locales/en.json +15 -3
- package/locales/it.json +6 -1
- package/locales/ru.json +14 -4
- package/markup/admin.js +6 -4
- package/package.json +8 -8
- package/public/blockly.js +19 -31
- package/routes/actions.js +1 -13
- package/routes/delete.js +6 -5
- package/routes/edit.js +5 -10
- package/routes/fields.js +60 -29
- package/routes/list.js +8 -9
- package/routes/tables.js +5 -9
- package/routes/tenant.js +67 -65
- package/routes/view.js +3 -3
- package/routes/viewedit.js +46 -57
- package/tests/admin.test.js +4 -2
- package/tests/fields.test.js +1 -0
- package/tests/tenant.test.js +8 -0
- package/tests/viewedit.test.js +15 -1
package/locales/en.json
CHANGED
|
@@ -960,7 +960,7 @@
|
|
|
960
960
|
"Remove From Tag": "Remove From Tag",
|
|
961
961
|
"Add tables": "Add tables",
|
|
962
962
|
"Add views": "Add views",
|
|
963
|
-
"Add
|
|
963
|
+
"Add tags": "Add tags",
|
|
964
964
|
"Trigger": "Trigger",
|
|
965
965
|
"Add %s to tag": "Add %s to tag",
|
|
966
966
|
"Tag %s deleted": "Tag %s deleted",
|
|
@@ -1035,5 +1035,17 @@
|
|
|
1035
1035
|
"Provide your own create warning text if need": "Provide your own create warning text if need",
|
|
1036
1036
|
"Specify some description for tenant if need": "Specify some description for tenant if need",
|
|
1037
1037
|
"Created": "Created",
|
|
1038
|
-
"First user E-mail": "First user E-mail"
|
|
1039
|
-
|
|
1038
|
+
"First user E-mail": "First user E-mail",
|
|
1039
|
+
"HTTP settings": "HTTP settings",
|
|
1040
|
+
"HTTP": "HTTP",
|
|
1041
|
+
"Login and Signup": "Login and Signup",
|
|
1042
|
+
"Rights": "Rights",
|
|
1043
|
+
"Rights settings": "Rights settings",
|
|
1044
|
+
"Database name": "Database name",
|
|
1045
|
+
"Database schema": "Database schema",
|
|
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
|
+
"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
|
+
"On delete": "On delete",
|
|
1049
|
+
"Database name": "Database name",
|
|
1050
|
+
"Database schema": "Database schema"
|
|
1051
|
+
}
|
package/locales/it.json
CHANGED
|
@@ -479,5 +479,10 @@
|
|
|
479
479
|
"Two-factor authentication": "Two-factor authentication",
|
|
480
480
|
"Two-factor authentication is disabled": "Two-factor authentication is disabled",
|
|
481
481
|
"Enable TWA": "Enable TWA",
|
|
482
|
-
"Modules": "Modules"
|
|
482
|
+
"Modules": "Modules",
|
|
483
|
+
"Login and Signup": "Login and Signup",
|
|
484
|
+
"Table access": "Table access",
|
|
485
|
+
"HTTP": "HTTP",
|
|
486
|
+
"Rights": "Rights",
|
|
487
|
+
"Table access": "Table access"
|
|
483
488
|
}
|
package/locales/ru.json
CHANGED
|
@@ -676,7 +676,7 @@
|
|
|
676
676
|
"No triggers": "Нет триггеров",
|
|
677
677
|
"No files": "Нет файлов",
|
|
678
678
|
"Home Timezone": "Домашняя Timezone",
|
|
679
|
-
"2FA policy": "2FA
|
|
679
|
+
"2FA policy": "Политика 2FA",
|
|
680
680
|
"Role to generate API keys": "Роль для API keys",
|
|
681
681
|
"User should have this role or higher to generate API keys in their user settings": "Минимальная роль для генерации API key",
|
|
682
682
|
"Cookie duration (hours)": "Срок действия Cookie (в часах)",
|
|
@@ -835,7 +835,7 @@
|
|
|
835
835
|
"Add tables": "Добавить таблицы",
|
|
836
836
|
"Add views": "Добавить представления",
|
|
837
837
|
"Remove From Tag": "Удалить из тега",
|
|
838
|
-
"Add
|
|
838
|
+
"Add tags": "Добавить теги",
|
|
839
839
|
"Trigger": "Триггер",
|
|
840
840
|
"Tag": "Тег",
|
|
841
841
|
"Download snapshots": "Скачать снепшоты",
|
|
@@ -898,7 +898,7 @@
|
|
|
898
898
|
"Discover tables that are already in the Database, but not known to Saltcorn": "Обнаружить таблицы, уже созданные в Базе Данных, но пока не подключенные к Saltcorn",
|
|
899
899
|
"Users already present": "Пользователи уже созданы",
|
|
900
900
|
"Database type": "Тип БД",
|
|
901
|
-
"Database name": "
|
|
901
|
+
"Database name": "Название БД",
|
|
902
902
|
"Database host": "Хост БД",
|
|
903
903
|
"Database port": "Порт БД",
|
|
904
904
|
"Database schema": "Схема БД",
|
|
@@ -909,5 +909,15 @@
|
|
|
909
909
|
"Development settings": "Настройки для разработчиков",
|
|
910
910
|
"Creator email": "Email создателя",
|
|
911
911
|
"Created": "Создано",
|
|
912
|
-
"Views display data from tables. A view is a view pattern applied to a table, with configuration.": "Представления отображают данные из таблиц. Представление - это конфигурируемый визуальный паттерн, применяемый к таблице."
|
|
912
|
+
"Views display data from tables. A view is a view pattern applied to a table, with configuration.": "Представления отображают данные из таблиц. Представление - это конфигурируемый визуальный паттерн, применяемый к таблице.",
|
|
913
|
+
"HTTP settings": "Настройки HTTP",
|
|
914
|
+
"HTTP": "HTTP",
|
|
915
|
+
"Rights settings": "Настройки прав",
|
|
916
|
+
"Login and Signup": "Авторизация и Регистрация",
|
|
917
|
+
"Rights": "Права",
|
|
918
|
+
"<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>Найдены представления с ролью доступа ниже уровня роли для чтения из соответствующей таблицы, без указания владельца таблицы. В следующих версиях Saltcorn это может привести к запрету на доступ. Пользователи должны будут иметь права на чтение, чтобы данные были отображены. </p> \n Потенциально затронутые представления: %s</p>",
|
|
919
|
+
"File not found": "Файл не найден",
|
|
920
|
+
"Permissions settings": "Настройки разрешений",
|
|
921
|
+
"Permissions": "Разрешения",
|
|
922
|
+
"Permissions settings updated": "Настройки разрешений обновлены"
|
|
913
923
|
}
|
package/markup/admin.js
CHANGED
|
@@ -223,9 +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
227
|
{ text: "Table access", href: "/useradmin/table-access" },
|
|
228
228
|
...(isRoot ? [{ text: "SSL", href: "/useradmin/ssl" }] : []),
|
|
229
|
+
{ text: "HTTP", href: "/useradmin/http" },
|
|
230
|
+
{ text: "Permissions", href: "/useradmin/permissions" },
|
|
229
231
|
],
|
|
230
232
|
...args,
|
|
231
233
|
});
|
|
@@ -282,7 +284,7 @@ const send_events_page = (args) => {
|
|
|
282
284
|
* @returns {void}
|
|
283
285
|
*/
|
|
284
286
|
const send_admin_page = (args) => {
|
|
285
|
-
const isRoot = db.getTenantSchema() === db.connectObj.default_schema;
|
|
287
|
+
//const isRoot = db.getTenantSchema() === db.connectObj.default_schema;
|
|
286
288
|
return send_settings_page({
|
|
287
289
|
main_section: "About application",
|
|
288
290
|
main_section_href: "/admin",
|
|
@@ -436,7 +438,7 @@ const save_config_from_form = async (form) => {
|
|
|
436
438
|
|
|
437
439
|
/**
|
|
438
440
|
* Get Base Domain
|
|
439
|
-
* @returns {string} base domain
|
|
441
|
+
* @returns {string|null} base domain
|
|
440
442
|
*/
|
|
441
443
|
const getBaseDomain = () => {
|
|
442
444
|
const base_url = getState().getConfig("base_url");
|
|
@@ -457,7 +459,7 @@ const hostname_matches_baseurl = (req, domain) => domain === req.hostname;
|
|
|
457
459
|
|
|
458
460
|
/**
|
|
459
461
|
* @param {string} domain
|
|
460
|
-
* @returns {string[]}
|
|
462
|
+
* @returns {string[]|boolean}
|
|
461
463
|
*/
|
|
462
464
|
const is_hsts_tld = (domain) => {
|
|
463
465
|
if (!domain) return false;
|
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.2",
|
|
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.
|
|
14
|
-
"@saltcorn/markup": "0.8.0-beta.
|
|
15
|
-
"@saltcorn/sbadmin2": "0.8.0-beta.
|
|
9
|
+
"@saltcorn/base-plugin": "0.8.0-beta.2",
|
|
10
|
+
"@saltcorn/builder": "0.8.0-beta.2",
|
|
11
|
+
"@saltcorn/data": "0.8.0-beta.2",
|
|
12
|
+
"@saltcorn/admin-models": "0.8.0-beta.2",
|
|
13
|
+
"@saltcorn/filemanager": "0.8.0-beta.2",
|
|
14
|
+
"@saltcorn/markup": "0.8.0-beta.2",
|
|
15
|
+
"@saltcorn/sbadmin2": "0.8.0-beta.2",
|
|
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/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);
|
package/routes/actions.js
CHANGED
|
@@ -8,7 +8,6 @@ const Router = require("express-promise-router");
|
|
|
8
8
|
const {
|
|
9
9
|
isAdmin,
|
|
10
10
|
error_catcher,
|
|
11
|
-
get_base_url,
|
|
12
11
|
addOnDoneRedirect,
|
|
13
12
|
} = require("./utils.js");
|
|
14
13
|
const { getState } = require("@saltcorn/data/db/state");
|
|
@@ -25,17 +24,9 @@ const { getTriggerList } = require("./common_lists");
|
|
|
25
24
|
const router = new Router();
|
|
26
25
|
module.exports = router;
|
|
27
26
|
const {
|
|
28
|
-
mkTable,
|
|
29
27
|
renderForm,
|
|
30
28
|
link,
|
|
31
|
-
// post_btn,
|
|
32
|
-
// settingsDropdown,
|
|
33
|
-
// post_dropdown_item,
|
|
34
|
-
post_delete_btn,
|
|
35
|
-
localeDateTime,
|
|
36
|
-
// localeDateTime,
|
|
37
29
|
} = require("@saltcorn/markup");
|
|
38
|
-
const actions = require("@saltcorn/data/base-plugin/actions");
|
|
39
30
|
const Form = require("@saltcorn/data/models/form");
|
|
40
31
|
const {
|
|
41
32
|
div,
|
|
@@ -52,14 +43,11 @@ const {
|
|
|
52
43
|
h6,
|
|
53
44
|
pre,
|
|
54
45
|
text,
|
|
55
|
-
hr,
|
|
56
46
|
} = require("@saltcorn/markup/tags");
|
|
57
47
|
const Table = require("@saltcorn/data/models/table");
|
|
58
48
|
const { getActionConfigFields } = require("@saltcorn/data/plugin-helper");
|
|
59
49
|
const { send_events_page } = require("../markup/admin.js");
|
|
60
|
-
const EventLog = require("@saltcorn/data/models/eventlog");
|
|
61
50
|
const User = require("@saltcorn/data/models/user");
|
|
62
|
-
const form = require("@saltcorn/markup/form");
|
|
63
51
|
const {
|
|
64
52
|
blocklyImportScripts,
|
|
65
53
|
blocklyToolbox,
|
|
@@ -587,7 +575,7 @@ router.get(
|
|
|
587
575
|
};
|
|
588
576
|
let table, row;
|
|
589
577
|
if (trigger.table_id) {
|
|
590
|
-
table = await Table.findOne(trigger.table_id);
|
|
578
|
+
table = await Table.findOne( { id: trigger.table_id } );
|
|
591
579
|
row = await table.getRow({});
|
|
592
580
|
}
|
|
593
581
|
try {
|
package/routes/delete.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
const Router = require("express-promise-router");
|
|
8
8
|
|
|
9
|
-
const {
|
|
9
|
+
const { error_catcher } = require("./utils.js");
|
|
10
10
|
const Table = require("@saltcorn/data/models/table");
|
|
11
11
|
|
|
12
12
|
/**
|
|
@@ -28,17 +28,18 @@ module.exports = router;
|
|
|
28
28
|
* @function
|
|
29
29
|
*/
|
|
30
30
|
router.post(
|
|
31
|
-
"/:
|
|
31
|
+
"/:tableName/:id",
|
|
32
32
|
error_catcher(async (req, res) => {
|
|
33
|
-
const {
|
|
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
37
|
const role = req.user && req.user.id ? req.user.role_id : 10;
|
|
37
38
|
try {
|
|
38
39
|
if (role <= table.min_role_write) await table.deleteRows({ id });
|
|
39
40
|
else if (table.ownership_field_id && req.user) {
|
|
40
41
|
const row = await table.getRow({ id });
|
|
41
|
-
if (row && (
|
|
42
|
+
if (row && (table.is_owner(req.user, row)))
|
|
42
43
|
await table.deleteRows({ id });
|
|
43
44
|
else req.flash("error", req.__("Not authorized"));
|
|
44
45
|
} else
|
package/routes/edit.js
CHANGED
|
@@ -6,14 +6,8 @@
|
|
|
6
6
|
|
|
7
7
|
const Router = require("express-promise-router");
|
|
8
8
|
|
|
9
|
-
const
|
|
10
|
-
const File = require("@saltcorn/data/models/file");
|
|
11
|
-
const Form = require("@saltcorn/data/models/form");
|
|
12
|
-
const { loggedIn, error_catcher } = require("./utils.js");
|
|
9
|
+
const { error_catcher } = require("./utils.js");
|
|
13
10
|
const Table = require("@saltcorn/data/models/table");
|
|
14
|
-
const pluralize = require("pluralize");
|
|
15
|
-
|
|
16
|
-
const { renderForm } = require("@saltcorn/markup");
|
|
17
11
|
|
|
18
12
|
/**
|
|
19
13
|
* @type {object}
|
|
@@ -32,11 +26,12 @@ module.exports = router;
|
|
|
32
26
|
* @function
|
|
33
27
|
*/
|
|
34
28
|
router.post(
|
|
35
|
-
"/toggle/:
|
|
29
|
+
"/toggle/:tableName/:id/:field_name",
|
|
36
30
|
error_catcher(async (req, res) => {
|
|
37
|
-
const {
|
|
31
|
+
const { tableName, id, field_name } = req.params;
|
|
38
32
|
const { redirect } = req.query;
|
|
39
|
-
|
|
33
|
+
// todo check that works after where change
|
|
34
|
+
const table = await Table.findOne({ name : tableName });
|
|
40
35
|
const role = req.user && req.user.id ? req.user.role_id : 10;
|
|
41
36
|
if (role <= table.min_role_write) await table.toggleBool(+id, field_name);
|
|
42
37
|
else
|
package/routes/fields.js
CHANGED
|
@@ -25,7 +25,10 @@ const db = require("@saltcorn/data/db");
|
|
|
25
25
|
|
|
26
26
|
const { isAdmin, error_catcher } = require("./utils.js");
|
|
27
27
|
const expressionBlurb = require("../markup/expression_blurb");
|
|
28
|
-
const {
|
|
28
|
+
const {
|
|
29
|
+
readState,
|
|
30
|
+
add_free_variables_to_joinfields,
|
|
31
|
+
} = require("@saltcorn/data/plugin-helper");
|
|
29
32
|
const { wizardCardTitle } = require("../markup/forms.js");
|
|
30
33
|
const FieldRepeat = require("@saltcorn/data/models/fieldrepeat");
|
|
31
34
|
const { applyAsync } = require("@saltcorn/data/utils");
|
|
@@ -185,6 +188,7 @@ const fieldFlow = (req) =>
|
|
|
185
188
|
attributes.summary_field = context.summary_field;
|
|
186
189
|
attributes.include_fts = context.include_fts;
|
|
187
190
|
attributes.on_delete_cascade = context.on_delete_cascade;
|
|
191
|
+
attributes.on_delete = context.on_delete;
|
|
188
192
|
const {
|
|
189
193
|
table_id,
|
|
190
194
|
name,
|
|
@@ -350,12 +354,13 @@ const fieldFlow = (req) =>
|
|
|
350
354
|
// todo sublabel
|
|
351
355
|
input_type: "custom_html",
|
|
352
356
|
attributes: {
|
|
353
|
-
html: `<button type="button" id="test_formula_btn" onclick="test_formula('${
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
357
|
+
html: `<button type="button" id="test_formula_btn" onclick="test_formula('${
|
|
358
|
+
table.name
|
|
359
|
+
}', ${JSON.stringify(
|
|
360
|
+
context.stored
|
|
361
|
+
)})" class="btn btn-outline-secondary">${req.__(
|
|
362
|
+
"Test"
|
|
363
|
+
)}</button>
|
|
359
364
|
<div id="test_formula_output"></div>`,
|
|
360
365
|
},
|
|
361
366
|
}),
|
|
@@ -400,13 +405,32 @@ const fieldFlow = (req) =>
|
|
|
400
405
|
type: "Bool",
|
|
401
406
|
showIf: { summary_field: textfields },
|
|
402
407
|
}),
|
|
403
|
-
new Field({
|
|
408
|
+
/*new Field({
|
|
404
409
|
name: "on_delete_cascade",
|
|
405
410
|
label: req.__("On delete cascade"),
|
|
406
411
|
type: "Bool",
|
|
407
412
|
sublabel: req.__(
|
|
408
413
|
"If the parent row is deleted, automatically delete the child rows."
|
|
409
414
|
),
|
|
415
|
+
}),*/
|
|
416
|
+
new Field({
|
|
417
|
+
name: "on_delete",
|
|
418
|
+
label: req.__("On delete"),
|
|
419
|
+
input_type: "select",
|
|
420
|
+
options: ["Fail", "Cascade", "Set null"],
|
|
421
|
+
required: true,
|
|
422
|
+
attributes: {
|
|
423
|
+
explainers: {
|
|
424
|
+
Fail: "Prevent any deletion of parent rows",
|
|
425
|
+
Cascade:
|
|
426
|
+
"If the parent row is deleted, automatically delete the child rows.",
|
|
427
|
+
"Set null":
|
|
428
|
+
"If the parent row is deleted, set key fields on child rows to null",
|
|
429
|
+
},
|
|
430
|
+
},
|
|
431
|
+
sublabel: req.__(
|
|
432
|
+
"If the parent row is deleted, do this to the child rows."
|
|
433
|
+
),
|
|
410
434
|
}),
|
|
411
435
|
],
|
|
412
436
|
});
|
|
@@ -622,14 +646,17 @@ router.post(
|
|
|
622
646
|
const { formula, tablename, stored } = req.body;
|
|
623
647
|
const table = await Table.findOne({ name: tablename });
|
|
624
648
|
const fields = await table.getFields();
|
|
625
|
-
const freeVars = freeVariables(formula)
|
|
626
|
-
const joinFields = {}
|
|
627
|
-
if (stored)
|
|
628
|
-
|
|
629
|
-
|
|
649
|
+
const freeVars = freeVariables(formula);
|
|
650
|
+
const joinFields = {};
|
|
651
|
+
if (stored) add_free_variables_to_joinfields(freeVars, joinFields, fields);
|
|
652
|
+
const rows = await table.getJoinedRows({
|
|
653
|
+
joinFields,
|
|
654
|
+
orderBy: "RANDOM()",
|
|
655
|
+
limit: 1,
|
|
656
|
+
});
|
|
630
657
|
if (rows.length < 1) {
|
|
631
658
|
res.send("No rows in table");
|
|
632
|
-
return
|
|
659
|
+
return;
|
|
633
660
|
}
|
|
634
661
|
let result;
|
|
635
662
|
try {
|
|
@@ -641,7 +668,8 @@ router.post(
|
|
|
641
668
|
result = f(rows[0]);
|
|
642
669
|
}
|
|
643
670
|
res.send(
|
|
644
|
-
`Result of running on row with id=${
|
|
671
|
+
`Result of running on row with id=${
|
|
672
|
+
rows[0].id
|
|
645
673
|
} is: <pre>${JSON.stringify(result)}</pre>`
|
|
646
674
|
);
|
|
647
675
|
} catch (e) {
|
|
@@ -671,10 +699,9 @@ router.post(
|
|
|
671
699
|
const fields = await table.getFields();
|
|
672
700
|
let row = { ...req.body };
|
|
673
701
|
if (!row || Object.keys(row).length === 0) {
|
|
674
|
-
const { id } = req.query
|
|
675
|
-
if (id) row = await table.getRow({ id })
|
|
676
|
-
} else
|
|
677
|
-
readState(row, fields);
|
|
702
|
+
const { id } = req.query;
|
|
703
|
+
if (id) row = await table.getRow({ id });
|
|
704
|
+
} else readState(row, fields);
|
|
678
705
|
|
|
679
706
|
if (fieldName.includes(".")) {
|
|
680
707
|
//join field
|
|
@@ -694,12 +721,18 @@ router.post(
|
|
|
694
721
|
const refRow = await reftable.getRow(q);
|
|
695
722
|
let fv;
|
|
696
723
|
if (targetField.type === "Key") {
|
|
697
|
-
fv = getState().keyFieldviews[fieldview]
|
|
724
|
+
fv = getState().keyFieldviews[fieldview];
|
|
698
725
|
if (!fv) {
|
|
699
|
-
const reftable2 = Table.findOne({
|
|
700
|
-
|
|
726
|
+
const reftable2 = Table.findOne({
|
|
727
|
+
name: targetField.reftable_name,
|
|
728
|
+
});
|
|
729
|
+
const refRow2 = await reftable2.getRow({
|
|
730
|
+
[reftable2.pk_name]: refRow[kpath[1]],
|
|
731
|
+
});
|
|
701
732
|
if (refRow2) {
|
|
702
|
-
res.send(
|
|
733
|
+
res.send(
|
|
734
|
+
text(`${refRow2[targetField.attributes.summary_field]}`)
|
|
735
|
+
);
|
|
703
736
|
} else {
|
|
704
737
|
res.send("");
|
|
705
738
|
}
|
|
@@ -711,7 +744,6 @@ router.post(
|
|
|
711
744
|
fv =
|
|
712
745
|
targetField.type.fieldviews.show ||
|
|
713
746
|
targetField.type.fieldviews.as_text;
|
|
714
|
-
|
|
715
747
|
}
|
|
716
748
|
|
|
717
749
|
const configuration = req.query;
|
|
@@ -756,7 +788,7 @@ router.post(
|
|
|
756
788
|
let result;
|
|
757
789
|
try {
|
|
758
790
|
if (!field.calculated) {
|
|
759
|
-
result = row[field.name]
|
|
791
|
+
result = row[field.name];
|
|
760
792
|
} else if (field.stored) {
|
|
761
793
|
const f = get_async_expression_function(formula, fields);
|
|
762
794
|
result = await f(row);
|
|
@@ -765,8 +797,7 @@ router.post(
|
|
|
765
797
|
result = f(row);
|
|
766
798
|
}
|
|
767
799
|
const fv = field.type.fieldviews[fieldview];
|
|
768
|
-
if (!fv)
|
|
769
|
-
res.send(text(result));
|
|
800
|
+
if (!fv) res.send(text(result));
|
|
770
801
|
else res.send(fv.run(result));
|
|
771
802
|
} catch (e) {
|
|
772
803
|
return res.status(400).send(`Error: ${e.message}`);
|
|
@@ -819,8 +850,8 @@ router.post(
|
|
|
819
850
|
field.type === "Key"
|
|
820
851
|
? getState().keyFieldviews
|
|
821
852
|
: field.type === "File"
|
|
822
|
-
|
|
823
|
-
|
|
853
|
+
? getState().fileviews
|
|
854
|
+
: field.type.fieldviews;
|
|
824
855
|
if (!field.type || !fieldviews) {
|
|
825
856
|
res.send("");
|
|
826
857
|
return;
|