@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/routes/list.js
CHANGED
|
@@ -11,9 +11,8 @@
|
|
|
11
11
|
const Router = require("express-promise-router");
|
|
12
12
|
|
|
13
13
|
const db = require("@saltcorn/data/db");
|
|
14
|
-
const { mkTable,
|
|
14
|
+
const { mkTable, link, post_btn } = require("@saltcorn/markup");
|
|
15
15
|
const {
|
|
16
|
-
a,
|
|
17
16
|
script,
|
|
18
17
|
domReady,
|
|
19
18
|
div,
|
|
@@ -27,7 +26,6 @@ const {
|
|
|
27
26
|
const Table = require("@saltcorn/data/models/table");
|
|
28
27
|
const { isAdmin, error_catcher } = require("./utils");
|
|
29
28
|
const moment = require("moment");
|
|
30
|
-
const { readState } = require("@saltcorn/data/plugin-helper");
|
|
31
29
|
|
|
32
30
|
/**
|
|
33
31
|
* @type {object}
|
|
@@ -49,11 +47,11 @@ module.exports = router;
|
|
|
49
47
|
* @function
|
|
50
48
|
*/
|
|
51
49
|
router.get(
|
|
52
|
-
"/_versions/:
|
|
50
|
+
"/_versions/:tableName/:id",
|
|
53
51
|
isAdmin,
|
|
54
52
|
error_catcher(async (req, res) => {
|
|
55
|
-
const {
|
|
56
|
-
const table = await Table.findOne({ name });
|
|
53
|
+
const { tableName, id } = req.params;
|
|
54
|
+
const table = await Table.findOne({ name : tableName });
|
|
57
55
|
|
|
58
56
|
const fields = await table.getFields();
|
|
59
57
|
var tfields = fields.map((f) => ({ label: f.label, key: f.listKey }));
|
|
@@ -97,11 +95,11 @@ router.get(
|
|
|
97
95
|
* @function
|
|
98
96
|
*/
|
|
99
97
|
router.post(
|
|
100
|
-
"/_restore/:
|
|
98
|
+
"/_restore/:tableName/:id/:_version",
|
|
101
99
|
isAdmin,
|
|
102
100
|
error_catcher(async (req, res) => {
|
|
103
|
-
const {
|
|
104
|
-
const table = await Table.findOne({ name });
|
|
101
|
+
const { tableName, id, _version } = req.params;
|
|
102
|
+
const table = await Table.findOne({ name : tableName });
|
|
105
103
|
|
|
106
104
|
const fields = await table.getFields();
|
|
107
105
|
const row = await db.selectOne(`${db.sqlsanitize(table.name)}__history`, {
|
|
@@ -217,7 +215,8 @@ jsGrid.fields.versions = VersionsField;
|
|
|
217
215
|
const arrangeIdFirst = (flds) => {
|
|
218
216
|
const noId = flds.filter((f) => f.name !== "id");
|
|
219
217
|
const id = flds.find((f) => f.name === "id");
|
|
220
|
-
return [id, ...noId];
|
|
218
|
+
if (id) return [id, ...noId];
|
|
219
|
+
else return flds
|
|
221
220
|
};
|
|
222
221
|
|
|
223
222
|
/**
|
|
@@ -245,6 +244,7 @@ router.get(
|
|
|
245
244
|
}
|
|
246
245
|
|
|
247
246
|
//console.log(fields);
|
|
247
|
+
// todo remove keyfields - unused
|
|
248
248
|
const keyfields = fields
|
|
249
249
|
.filter((f) => f.type === "Key" || f.type === "File")
|
|
250
250
|
.map((f) => ({ name: f.name, type: f.reftype }));
|
|
@@ -369,9 +369,8 @@ router.get(
|
|
|
369
369
|
})
|
|
370
370
|
})
|
|
371
371
|
window.tabulator_table = new Tabulator("#jsGrid", {
|
|
372
|
-
ajaxURL:"/api/${table.name}${
|
|
373
|
-
|
|
374
|
-
}",
|
|
372
|
+
ajaxURL:"/api/${table.name}${table.versioned ? "?versioncount=on" : ""
|
|
373
|
+
}",
|
|
375
374
|
layout:"fitColumns",
|
|
376
375
|
columns,
|
|
377
376
|
height:"100%",
|
package/routes/page.js
CHANGED
|
@@ -7,10 +7,8 @@
|
|
|
7
7
|
const Router = require("express-promise-router");
|
|
8
8
|
|
|
9
9
|
const Page = require("@saltcorn/data/models/page");
|
|
10
|
-
const { div, a, i } = require("@saltcorn/markup/tags");
|
|
11
|
-
const { renderForm } = require("@saltcorn/markup");
|
|
12
10
|
const { getState } = require("@saltcorn/data/db/state");
|
|
13
|
-
const { error_catcher, scan_for_page_title } = require("../routes/utils.js");
|
|
11
|
+
const { error_catcher, scan_for_page_title, isAdmin } = require("../routes/utils.js");
|
|
14
12
|
const { add_edit_bar } = require("../markup/admin.js");
|
|
15
13
|
const { traverseSync } = require("@saltcorn/data/models/layout");
|
|
16
14
|
const { run_action_column } = require("@saltcorn/data/plugin-helper");
|
|
@@ -67,6 +65,21 @@ router.get(
|
|
|
67
65
|
})
|
|
68
66
|
);
|
|
69
67
|
|
|
68
|
+
router.post(
|
|
69
|
+
"/:pagename/preview",
|
|
70
|
+
isAdmin,
|
|
71
|
+
error_catcher(async (req, res) => {
|
|
72
|
+
const { pagename } = req.params;
|
|
73
|
+
const page = await Page.findOne({ name: pagename });
|
|
74
|
+
if (!page) {
|
|
75
|
+
res.send("");
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
const contents = await page.run(req.query, { res, req });
|
|
79
|
+
res.sendWrap({}, contents);
|
|
80
|
+
})
|
|
81
|
+
);
|
|
82
|
+
|
|
70
83
|
/**
|
|
71
84
|
* @name post/:pagename/action/:rndid
|
|
72
85
|
* @function
|
package/routes/pageedit.js
CHANGED
|
@@ -100,6 +100,7 @@ const pageBuilderData = async (req, context) => {
|
|
|
100
100
|
const views = await View.find();
|
|
101
101
|
const pages = await Page.find();
|
|
102
102
|
const images = await File.find({ mime_super: "image" });
|
|
103
|
+
images.forEach(im => im.location = im.path_to_serve)
|
|
103
104
|
const roles = await User.get_roles();
|
|
104
105
|
const stateActions = getState().actions;
|
|
105
106
|
const actions = [
|
|
@@ -130,6 +131,9 @@ const pageBuilderData = async (req, context) => {
|
|
|
130
131
|
const fs = await view.get_state_fields();
|
|
131
132
|
for (const frec of fs) {
|
|
132
133
|
const f = new Field(frec);
|
|
134
|
+
if (f.input_type === "hidden") continue;
|
|
135
|
+
if (f.name === "_fts") continue;
|
|
136
|
+
|
|
133
137
|
f.required = false;
|
|
134
138
|
if (f.type && f.type.name === "Bool") f.fieldview = "tristate";
|
|
135
139
|
|
|
@@ -156,6 +160,7 @@ const pageBuilderData = async (req, context) => {
|
|
|
156
160
|
}
|
|
157
161
|
}
|
|
158
162
|
}
|
|
163
|
+
//console.log(fixed_state_fields.ListTasks);
|
|
159
164
|
return {
|
|
160
165
|
views,
|
|
161
166
|
images,
|
|
@@ -569,13 +574,13 @@ router.post(
|
|
|
569
574
|
const page = await Page.findOne({ id });
|
|
570
575
|
const roles = await User.get_roles();
|
|
571
576
|
const roleRow = roles.find((r) => r.id === +role);
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
req.__(`Minimum role
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
res.
|
|
577
|
+
const message =
|
|
578
|
+
roleRow && page
|
|
579
|
+
? req.__(`Minimum role for %s updated to %s`, page.name, roleRow.role)
|
|
580
|
+
: req.__(`Minimum role updated`);
|
|
581
|
+
if (!req.xhr) {
|
|
582
|
+
req.flash("success", message);
|
|
583
|
+
res.redirect("/pageedit");
|
|
584
|
+
} else res.json({ okay: true, responseText: message });
|
|
580
585
|
})
|
|
581
586
|
);
|
package/routes/scapi.js
CHANGED
|
@@ -185,7 +185,7 @@ router.get(
|
|
|
185
185
|
{ session: false },
|
|
186
186
|
async function (err, user, info) {
|
|
187
187
|
if (accessAllowedRead(req, user)) {
|
|
188
|
-
const triggers =
|
|
188
|
+
const triggers = Trigger.find({});
|
|
189
189
|
|
|
190
190
|
res.json({ success: triggers });
|
|
191
191
|
} else {
|
package/routes/search.js
CHANGED
|
@@ -188,7 +188,7 @@ const runSearch = async ({ q, _page, table }, req, res) => {
|
|
|
188
188
|
pages: current_page + (vresps.length === 20 ? 1 : 0),
|
|
189
189
|
trailing_ellipsis: vresps.length === 20,
|
|
190
190
|
get_page_link: (n) =>
|
|
191
|
-
`javascript:gopage(${n}, 20, {table:'${tableName}'})`,
|
|
191
|
+
`javascript:gopage(${n}, 20, undefined, {table:'${tableName}'})`,
|
|
192
192
|
});
|
|
193
193
|
}
|
|
194
194
|
|
package/routes/tables.js
CHANGED
|
@@ -8,7 +8,6 @@ const Router = require("express-promise-router");
|
|
|
8
8
|
|
|
9
9
|
const db = require("@saltcorn/data/db");
|
|
10
10
|
const Table = require("@saltcorn/data/models/table");
|
|
11
|
-
const Field = require("@saltcorn/data/models/field");
|
|
12
11
|
const File = require("@saltcorn/data/models/file");
|
|
13
12
|
const View = require("@saltcorn/data/models/view");
|
|
14
13
|
const User = require("@saltcorn/data/models/user");
|
|
@@ -16,7 +15,6 @@ const {
|
|
|
16
15
|
mkTable,
|
|
17
16
|
renderForm,
|
|
18
17
|
link,
|
|
19
|
-
post_btn,
|
|
20
18
|
settingsDropdown,
|
|
21
19
|
post_delete_btn,
|
|
22
20
|
post_dropdown_item,
|
|
@@ -29,10 +27,7 @@ const { isAdmin, error_catcher, setTenant } = require("./utils.js");
|
|
|
29
27
|
const Form = require("@saltcorn/data/models/form");
|
|
30
28
|
const {
|
|
31
29
|
span,
|
|
32
|
-
h5,
|
|
33
30
|
h4,
|
|
34
|
-
h3,
|
|
35
|
-
nbsp,
|
|
36
31
|
p,
|
|
37
32
|
a,
|
|
38
33
|
div,
|
|
@@ -41,7 +36,6 @@ const {
|
|
|
41
36
|
label,
|
|
42
37
|
input,
|
|
43
38
|
text,
|
|
44
|
-
tr,
|
|
45
39
|
script,
|
|
46
40
|
domReady,
|
|
47
41
|
code,
|
|
@@ -135,6 +129,7 @@ const tableForm = async (table, req) => {
|
|
|
135
129
|
name: "min_role_read",
|
|
136
130
|
input_type: "select",
|
|
137
131
|
options: roleOptions,
|
|
132
|
+
attributes: { asideNext: !table.external }
|
|
138
133
|
},
|
|
139
134
|
...(table.external
|
|
140
135
|
? []
|
|
@@ -551,14 +546,13 @@ router.get(
|
|
|
551
546
|
res.redirect(`/table`);
|
|
552
547
|
return;
|
|
553
548
|
}
|
|
554
|
-
id = table.id;
|
|
555
549
|
const nrows = await table.countRows();
|
|
556
550
|
const fields = await table.getFields();
|
|
557
551
|
const { child_relations } = await table.get_child_relations();
|
|
558
552
|
const inbound_refs = [
|
|
559
553
|
...new Set(child_relations.map(({ table }) => table.name)),
|
|
560
554
|
];
|
|
561
|
-
|
|
555
|
+
let fieldCard;
|
|
562
556
|
if (fields.length === 0) {
|
|
563
557
|
fieldCard = [
|
|
564
558
|
h4(req.__(`No fields defined in %s table`, table.name)),
|
|
@@ -865,8 +859,10 @@ router.post(
|
|
|
865
859
|
res.redirect(`/table/${table.id}`);
|
|
866
860
|
}
|
|
867
861
|
} else if (v.external) {
|
|
862
|
+
// todo check that works after where change
|
|
863
|
+
// todo findOne can be have parameter for external table here
|
|
868
864
|
//we can only save min role
|
|
869
|
-
const table = await Table.findOne(v.name);
|
|
865
|
+
const table = await Table.findOne( { name : v.name });
|
|
870
866
|
if (table) {
|
|
871
867
|
const exttables_min_role_read = getState().getConfigCopy(
|
|
872
868
|
"exttables_min_role_read",
|
|
@@ -885,15 +881,13 @@ router.post(
|
|
|
885
881
|
const table = await Table.findOne({ id: parseInt(id) });
|
|
886
882
|
const old_versioned = table.versioned;
|
|
887
883
|
let hasError = false;
|
|
884
|
+
let notify = ""
|
|
888
885
|
if (!rest.versioned) rest.versioned = false;
|
|
889
886
|
if (rest.ownership_field_id === "_formula") {
|
|
890
887
|
rest.ownership_field_id = null;
|
|
891
888
|
const fmlValidRes = expressionValidator(rest.ownership_formula);
|
|
892
889
|
if (typeof fmlValidRes === "string") {
|
|
893
|
-
req.
|
|
894
|
-
"error",
|
|
895
|
-
req.__(`Invalid ownership formula: %s`, fmlValidRes)
|
|
896
|
-
);
|
|
890
|
+
notify = req.__(`Invalid ownership formula: %s`, fmlValidRes)
|
|
897
891
|
hasError = true;
|
|
898
892
|
}
|
|
899
893
|
} else rest.ownership_formula = null;
|
|
@@ -911,7 +905,7 @@ router.post(
|
|
|
911
905
|
else if (!hasError) req.flash("success", req.__("Table saved"));
|
|
912
906
|
|
|
913
907
|
if (!req.xhr) res.redirect(`/table/${id}`);
|
|
914
|
-
else res.json({ success: "ok" });
|
|
908
|
+
else res.json({ success: "ok", notify });
|
|
915
909
|
}
|
|
916
910
|
})
|
|
917
911
|
);
|
|
@@ -1149,6 +1143,7 @@ router.get(
|
|
|
1149
1143
|
/**
|
|
1150
1144
|
* Constraint Fields Edition Form
|
|
1151
1145
|
* Choosing fields for adding to contrain
|
|
1146
|
+
* @param req
|
|
1152
1147
|
* @param {string} table_id
|
|
1153
1148
|
* @param {object[]} fields
|
|
1154
1149
|
* @returns {Form}
|
package/routes/tag_entries.js
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
const {
|
|
2
|
-
a,
|
|
3
2
|
div,
|
|
4
|
-
text,
|
|
5
3
|
button,
|
|
6
|
-
i,
|
|
7
4
|
form,
|
|
8
5
|
select,
|
|
9
6
|
option,
|
|
@@ -81,10 +78,10 @@ const formOptions = async (type, tag_id) => {
|
|
|
81
78
|
),
|
|
82
79
|
};
|
|
83
80
|
}
|
|
84
|
-
case "
|
|
81
|
+
case "triggers": {
|
|
85
82
|
const ids = await tag.getTriggerIds();
|
|
86
83
|
return {
|
|
87
|
-
|
|
84
|
+
triggers: (Trigger.find()).filter(
|
|
88
85
|
(value) => ids.indexOf(value.id) === -1
|
|
89
86
|
),
|
|
90
87
|
};
|
|
@@ -101,7 +98,7 @@ router.get(
|
|
|
101
98
|
above: [
|
|
102
99
|
{
|
|
103
100
|
type: "breadcrumbs",
|
|
104
|
-
crumbs: [{ text: `Tag entry` }],
|
|
101
|
+
crumbs: [{ text: req.__(`Tag entry`) }],
|
|
105
102
|
},
|
|
106
103
|
{
|
|
107
104
|
type: "card",
|
|
@@ -120,15 +117,19 @@ router.get(
|
|
|
120
117
|
|
|
121
118
|
const idField = (entryType) => {
|
|
122
119
|
switch (entryType) {
|
|
123
|
-
case "tables":
|
|
120
|
+
case "tables":
|
|
121
|
+
case "table": {
|
|
124
122
|
return "table_id";
|
|
125
123
|
}
|
|
126
|
-
case "views":
|
|
124
|
+
case "views":
|
|
125
|
+
case "view": {
|
|
127
126
|
return "view_id";
|
|
128
127
|
}
|
|
129
|
-
case "pages":
|
|
128
|
+
case "pages":
|
|
129
|
+
case "page": {
|
|
130
130
|
return "page_id";
|
|
131
131
|
}
|
|
132
|
+
case "triggers":
|
|
132
133
|
case "trigger": {
|
|
133
134
|
return "trigger_id";
|
|
134
135
|
}
|
|
@@ -136,6 +137,7 @@ const idField = (entryType) => {
|
|
|
136
137
|
return null;
|
|
137
138
|
};
|
|
138
139
|
|
|
140
|
+
// add multiple objects to one tag
|
|
139
141
|
router.post(
|
|
140
142
|
"/add/:entry_type/:tag_id",
|
|
141
143
|
isAdmin,
|
|
@@ -155,6 +157,24 @@ router.post(
|
|
|
155
157
|
})
|
|
156
158
|
);
|
|
157
159
|
|
|
160
|
+
// add one object to multiple tags
|
|
161
|
+
router.post(
|
|
162
|
+
"/add/multiple_tags/:entry_type/:object_id",
|
|
163
|
+
isAdmin,
|
|
164
|
+
error_catcher(async (req, res) => {
|
|
165
|
+
let { entry_type, object_id } = req.params;
|
|
166
|
+
let { tag_ids } = req.body;
|
|
167
|
+
object_id = parseInt(object_id);
|
|
168
|
+
tag_ids = tag_ids.map((id) => parseInt(id));
|
|
169
|
+
const tags = (await Tag.find()).filter((tag) => tag_ids.includes(tag.id));
|
|
170
|
+
const fieldName = idField(entry_type);
|
|
171
|
+
for (const tag of tags) {
|
|
172
|
+
await tag.addEntry({ [fieldName]: object_id });
|
|
173
|
+
}
|
|
174
|
+
res.json({ tags });
|
|
175
|
+
})
|
|
176
|
+
);
|
|
177
|
+
|
|
158
178
|
router.post(
|
|
159
179
|
"/remove/:entry_type/:entry_id/:tag_id",
|
|
160
180
|
isAdmin,
|
|
@@ -168,6 +188,7 @@ router.post(
|
|
|
168
188
|
} else {
|
|
169
189
|
await TagEntry.update(entry.id, { [fieldName]: null });
|
|
170
190
|
}
|
|
171
|
-
res.redirect(`/tag/${tag_id}?show_list=${entry_type}`);
|
|
191
|
+
if (!req.xhr) res.redirect(`/tag/${tag_id}?show_list=${entry_type}`);
|
|
192
|
+
else res.json({ okay: true });
|
|
172
193
|
})
|
|
173
194
|
);
|
package/routes/tags.js
CHANGED
|
@@ -128,18 +128,18 @@ router.get(
|
|
|
128
128
|
const views = await tag.getViews();
|
|
129
129
|
await setTableRefs(views);
|
|
130
130
|
const pages = await tag.getPages();
|
|
131
|
-
const
|
|
131
|
+
const triggers = await tag.getTriggers();
|
|
132
132
|
const roles = await User.get_roles();
|
|
133
133
|
|
|
134
134
|
const tablesDomId = "tablesListId";
|
|
135
135
|
const viewsDomId = "viewsListId";
|
|
136
136
|
const pagesDomId = "pagesDomId";
|
|
137
|
-
const
|
|
137
|
+
const triggersDomId = "triggerDomId";
|
|
138
138
|
res.sendWrap(req.__("%s Tag", tag.name), {
|
|
139
139
|
above: [
|
|
140
140
|
{
|
|
141
141
|
type: "breadcrumbs",
|
|
142
|
-
crumbs: [{ text: `Tag:
|
|
142
|
+
crumbs: [{ text: req.__(`Tag: %s`, tag.name) }],
|
|
143
143
|
},
|
|
144
144
|
{
|
|
145
145
|
type: "card",
|
|
@@ -211,19 +211,19 @@ router.get(
|
|
|
211
211
|
type: "card",
|
|
212
212
|
bodyId: "collapseTriggerCard",
|
|
213
213
|
title: headerWithCollapser(
|
|
214
|
-
req.__("
|
|
215
|
-
|
|
216
|
-
isShowList(show_list, "
|
|
214
|
+
req.__("Triggers"),
|
|
215
|
+
triggersDomId,
|
|
216
|
+
isShowList(show_list, "triggers")
|
|
217
217
|
),
|
|
218
218
|
contents: [
|
|
219
|
-
getTriggerList(
|
|
219
|
+
getTriggerList(triggers, req, {
|
|
220
220
|
tagId: tag.id,
|
|
221
|
-
domId:
|
|
222
|
-
showList: isShowList(show_list, "
|
|
221
|
+
domId: triggersDomId,
|
|
222
|
+
showList: isShowList(show_list, "triggers"),
|
|
223
223
|
}),
|
|
224
224
|
a(
|
|
225
225
|
{
|
|
226
|
-
href: `/tag-entries/add/
|
|
226
|
+
href: `/tag-entries/add/triggers/${tag.id}`,
|
|
227
227
|
class: "btn btn-primary",
|
|
228
228
|
},
|
|
229
229
|
req.__("Add triggers")
|