@saltcorn/server 1.1.1 → 1.1.2-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/CHANGELOG.md +5 -1
- package/app.js +10 -5
- package/auth/admin.js +7 -7
- package/auth/roleadmin.js +3 -3
- package/auth/routes.js +27 -27
- package/package.json +38 -38
- package/public/saltcorn-common.js +5 -1
- package/routes/actions.js +7 -7
- package/routes/admin.js +17 -12
- package/routes/api.js +11 -10
- package/routes/config.js +7 -3
- package/routes/crashlog.js +2 -2
- package/routes/eventlog.js +3 -3
- package/routes/fields.js +5 -5
- package/routes/files.js +32 -31
- package/routes/infoarch.js +4 -3
- package/routes/library.js +1 -1
- package/routes/menu.js +1 -1
- package/routes/models.js +4 -4
- package/routes/notifications.js +7 -4
- package/routes/packs.js +4 -4
- package/routes/page_group.js +3 -3
- package/routes/page_groupedit.js +5 -5
- package/routes/pageedit.js +10 -10
- package/routes/plugins.js +12 -9
- package/routes/registry.js +1 -1
- package/routes/search.js +1 -1
- package/routes/sync.js +4 -4
- package/routes/tables.js +20 -22
- package/routes/tag_entries.js +2 -2
- package/routes/tags.js +1 -1
- package/routes/tenant.js +4 -4
- package/routes/utils.js +3 -3
- package/routes/view.js +7 -7
- package/routes/viewedit.js +11 -11
- package/s3storage.js +1 -1
- package/tests/files.test.js +10 -0
- package/tests/plugins.test.js +2 -6
package/routes/pageedit.js
CHANGED
|
@@ -477,9 +477,9 @@ router.post(
|
|
|
477
477
|
"/edit-properties",
|
|
478
478
|
isAdminOrHasConfigMinRole("min_role_edit_pages"),
|
|
479
479
|
error_catcher(async (req, res) => {
|
|
480
|
-
const form = await pagePropertiesForm(req, !req.body.id);
|
|
480
|
+
const form = await pagePropertiesForm(req, !(req.body || {}).id);
|
|
481
481
|
form.hidden("id");
|
|
482
|
-
form.validate(req.body);
|
|
482
|
+
form.validate(req.body || {});
|
|
483
483
|
if (form.hasErrors) {
|
|
484
484
|
res.sendWrap(
|
|
485
485
|
req.__(`Page attributes`),
|
|
@@ -688,9 +688,9 @@ router.post(
|
|
|
688
688
|
if (!page) {
|
|
689
689
|
req.flash("error", req.__(`Page %s not found`, pagename));
|
|
690
690
|
res.redirect(redirectTarget);
|
|
691
|
-
} else if (req.body.layout) {
|
|
691
|
+
} else if ((req.body || {}).layout) {
|
|
692
692
|
await Page.update(page.id, {
|
|
693
|
-
layout: decodeURIComponent(req.body.layout),
|
|
693
|
+
layout: decodeURIComponent((req.body || {}).layout),
|
|
694
694
|
});
|
|
695
695
|
Trigger.emitEvent("AppChange", `Page ${page.name}`, req.user, {
|
|
696
696
|
entity_type: "Page",
|
|
@@ -698,12 +698,12 @@ router.post(
|
|
|
698
698
|
});
|
|
699
699
|
req.flash("success", req.__(`Page %s saved`, pagename));
|
|
700
700
|
res.redirect(redirectTarget);
|
|
701
|
-
} else if (req.body.code) {
|
|
701
|
+
} else if ((req.body || {}).code) {
|
|
702
702
|
try {
|
|
703
703
|
if (!page.html_file) throw new Error(req.__("File not found"));
|
|
704
704
|
const file = await File.findOne(page.html_file);
|
|
705
705
|
if (!file) throw new Error(req.__("File not found"));
|
|
706
|
-
await fsp.writeFile(file.location, req.body.code);
|
|
706
|
+
await fsp.writeFile(file.location, (req.body || {}).code);
|
|
707
707
|
Trigger.emitEvent("AppChange", `Page ${page.name}`, req.user, {
|
|
708
708
|
entity_type: "Page",
|
|
709
709
|
entity_name: page.name,
|
|
@@ -722,7 +722,7 @@ router.post(
|
|
|
722
722
|
else res.json({ error: error.message });
|
|
723
723
|
}
|
|
724
724
|
} else {
|
|
725
|
-
getState().log(2, `POST /edit/${pagename}: '${req.body}'`);
|
|
725
|
+
getState().log(2, `POST /edit/${pagename}: '${req.body || {}}'`);
|
|
726
726
|
req.flash("error", req.__(`Error processing page`));
|
|
727
727
|
res.redirect(redirectTarget);
|
|
728
728
|
}
|
|
@@ -742,8 +742,8 @@ router.post(
|
|
|
742
742
|
error_catcher(async (req, res) => {
|
|
743
743
|
const { id } = req.params;
|
|
744
744
|
|
|
745
|
-
if (id && req.body.layout) {
|
|
746
|
-
await Page.update(+id, { layout: req.body.layout });
|
|
745
|
+
if (id && (req.body || {}).layout) {
|
|
746
|
+
await Page.update(+id, { layout: (req.body || {}).layout });
|
|
747
747
|
const page = await Page.findOne({ id });
|
|
748
748
|
Trigger.emitEvent("AppChange", `Page ${page.name}`, req.user, {
|
|
749
749
|
entity_type: "Page",
|
|
@@ -794,7 +794,7 @@ router.post(
|
|
|
794
794
|
const pageGroups = await PageGroup.find({}, { orderBy: "name" });
|
|
795
795
|
const roles = await User.get_roles();
|
|
796
796
|
const form = getRootPageForm(pages, pageGroups, roles, req);
|
|
797
|
-
const valres = form.validate(req.body);
|
|
797
|
+
const valres = form.validate(req.body || {});
|
|
798
798
|
if (valres.success) {
|
|
799
799
|
const home_page_by_role =
|
|
800
800
|
getState().getConfigCopy("home_page_by_role", {}) || {};
|
package/routes/plugins.js
CHANGED
|
@@ -839,7 +839,7 @@ router.post(
|
|
|
839
839
|
flow.action = `/plugins/configure/${encodeURIComponent(plugin.name)}`;
|
|
840
840
|
flow.autoSave = true;
|
|
841
841
|
flow.saveURL = `/plugins/saveconfig/${encodeURIComponent(plugin.name)}`;
|
|
842
|
-
const wfres = await flow.run(req.body);
|
|
842
|
+
const wfres = await flow.run(req.body || {});
|
|
843
843
|
if (wfres.renderForm) {
|
|
844
844
|
if (module.layout) {
|
|
845
845
|
wfres.renderForm.additionalButtons = [
|
|
@@ -893,7 +893,7 @@ router.post(
|
|
|
893
893
|
module = getState().plugins[getState().plugin_module_names[plugin.name]];
|
|
894
894
|
}
|
|
895
895
|
const flow = module.configuration_workflow();
|
|
896
|
-
const step = await flow.singleStepForm(req.body, req);
|
|
896
|
+
const step = await flow.singleStepForm(req.body || {}, req);
|
|
897
897
|
if (step?.renderForm) {
|
|
898
898
|
if (step.renderForm.hasErrors || step.savingErrors)
|
|
899
899
|
res.status(400).send(step.savingErrors || "Error");
|
|
@@ -1003,7 +1003,7 @@ router.post(
|
|
|
1003
1003
|
...(plugin.configuration || {}),
|
|
1004
1004
|
...(user._attributes?.layout?.config || {}),
|
|
1005
1005
|
});
|
|
1006
|
-
const valResult = form.validate(req.body);
|
|
1006
|
+
const valResult = form.validate(req.body || {});
|
|
1007
1007
|
if (form.hasErrors) {
|
|
1008
1008
|
req.flash("warning", req.__("An error occurred"));
|
|
1009
1009
|
return res.sendWrap(
|
|
@@ -1056,7 +1056,7 @@ router.post(
|
|
|
1056
1056
|
...(plugin.configuration || {}),
|
|
1057
1057
|
...(user._attributes?.layout?.config || {}),
|
|
1058
1058
|
});
|
|
1059
|
-
const valResult = form.validate(req.body);
|
|
1059
|
+
const valResult = form.validate(req.body || {});
|
|
1060
1060
|
if (form.hasErrors) {
|
|
1061
1061
|
return res.status(400).json({ error: req.__("An error occured") });
|
|
1062
1062
|
}
|
|
@@ -1154,10 +1154,10 @@ router.get(
|
|
|
1154
1154
|
* @function
|
|
1155
1155
|
*/
|
|
1156
1156
|
router.get(
|
|
1157
|
-
"/public/:plugin/*",
|
|
1157
|
+
"/public/:plugin/*filepath",
|
|
1158
1158
|
error_catcher(async (req, res) => {
|
|
1159
1159
|
const { plugin } = req.params;
|
|
1160
|
-
const filepath = req.params
|
|
1160
|
+
const filepath = path.join(...req.params.filepath);
|
|
1161
1161
|
const hasVersion = plugin.includes("@");
|
|
1162
1162
|
const location =
|
|
1163
1163
|
getState().plugin_locations[hasVersion ? plugin.split("@")[0] : plugin];
|
|
@@ -1167,7 +1167,10 @@ router.get(
|
|
|
1167
1167
|
.replace(/^(\.\.(\/|\\|$))+/, "");
|
|
1168
1168
|
const fullpath = path.join(location, "public", safeFile);
|
|
1169
1169
|
if (fs.existsSync(fullpath))
|
|
1170
|
-
res.sendFile(fullpath, {
|
|
1170
|
+
res.sendFile(fullpath, {
|
|
1171
|
+
maxAge: hasVersion ? "100d" : "1d",
|
|
1172
|
+
dotfiles: "allow",
|
|
1173
|
+
});
|
|
1171
1174
|
else {
|
|
1172
1175
|
getState().log(6, `Plugin serve public: file not found ${fullpath}`);
|
|
1173
1176
|
res.status(404).send(req.__("Not found"));
|
|
@@ -1428,7 +1431,7 @@ router.post(
|
|
|
1428
1431
|
"/",
|
|
1429
1432
|
isAdmin,
|
|
1430
1433
|
error_catcher(async (req, res) => {
|
|
1431
|
-
const plugin = new Plugin(req.body);
|
|
1434
|
+
const plugin = new Plugin(req.body || {});
|
|
1432
1435
|
const schema = db.getTenantSchema();
|
|
1433
1436
|
const tenants_install_git = getRootState().getConfig(
|
|
1434
1437
|
"tenants_install_git",
|
|
@@ -1505,7 +1508,7 @@ router.post(
|
|
|
1505
1508
|
isAdmin,
|
|
1506
1509
|
error_catcher(async (req, res) => {
|
|
1507
1510
|
const { name } = req.params;
|
|
1508
|
-
const { version } = req.body;
|
|
1511
|
+
const { version } = req.body || {};
|
|
1509
1512
|
const tenants_unsafe_plugins = getRootState().getConfig(
|
|
1510
1513
|
"tenants_unsafe_plugins",
|
|
1511
1514
|
false
|
package/routes/registry.js
CHANGED
|
@@ -340,7 +340,7 @@ router.post(
|
|
|
340
340
|
const { etype, ename, q } = req.query;
|
|
341
341
|
const qlink = q ? `&q=${encodeURIComponent(q)}` : "";
|
|
342
342
|
|
|
343
|
-
const entVal = JSON.parse(req.body.regval);
|
|
343
|
+
const entVal = JSON.parse((req.body || {}).regval);
|
|
344
344
|
let pack = {
|
|
345
345
|
plugins: [],
|
|
346
346
|
tables: [],
|
package/routes/search.js
CHANGED
|
@@ -136,7 +136,7 @@ router.post(
|
|
|
136
136
|
const views = await View.find({}, { orderBy: "name" });
|
|
137
137
|
const tables = await Table.find();
|
|
138
138
|
const form = searchConfigForm(tables, views, req);
|
|
139
|
-
const result = form.validate(req.body);
|
|
139
|
+
const result = form.validate(req.body || {});
|
|
140
140
|
|
|
141
141
|
if (result.success) {
|
|
142
142
|
const dbversion = await db.getVersion(true);
|
package/routes/sync.js
CHANGED
|
@@ -118,7 +118,7 @@ router.post(
|
|
|
118
118
|
"/load_changes",
|
|
119
119
|
error_catcher(async (req, res) => {
|
|
120
120
|
const result = {};
|
|
121
|
-
const { syncInfos, loadUntil } = req.body;
|
|
121
|
+
const { syncInfos, loadUntil } = req.body || {};
|
|
122
122
|
if (!loadUntil) {
|
|
123
123
|
getState().log(2, `POST /load_changes: loadUntil is missing`);
|
|
124
124
|
return res.status(400).json({ error: "loadUntil is missing" });
|
|
@@ -202,7 +202,7 @@ const getDelRows = async (tblName, syncFrom, syncUntil, client) => {
|
|
|
202
202
|
router.post(
|
|
203
203
|
"/deletes",
|
|
204
204
|
error_catcher(async (req, res) => {
|
|
205
|
-
const { syncInfos, syncTimestamp } = req.body;
|
|
205
|
+
const { syncInfos, syncTimestamp } = req.body || {};
|
|
206
206
|
const client = await db.getClient();
|
|
207
207
|
try {
|
|
208
208
|
await client.query(`BEGIN`);
|
|
@@ -238,7 +238,7 @@ router.post(
|
|
|
238
238
|
router.post(
|
|
239
239
|
"/offline_changes",
|
|
240
240
|
error_catcher(async (req, res) => {
|
|
241
|
-
const { changes, syncTimestamp } = req.body;
|
|
241
|
+
const { changes, syncTimestamp } = req.body || {};
|
|
242
242
|
const rootFolder = await File.rootFolder();
|
|
243
243
|
try {
|
|
244
244
|
const syncDirName = `${syncTimestamp}_${req.user?.email || "public"}`;
|
|
@@ -334,7 +334,7 @@ router.get(
|
|
|
334
334
|
router.post(
|
|
335
335
|
"/clean_sync_dir",
|
|
336
336
|
error_catcher(async (req, res) => {
|
|
337
|
-
const { dir_name } = req.body;
|
|
337
|
+
const { dir_name } = req.body || {};
|
|
338
338
|
try {
|
|
339
339
|
const rootFolder = await File.rootFolder();
|
|
340
340
|
const syncDir = File.normalise_in_base(
|
package/routes/tables.js
CHANGED
|
@@ -51,7 +51,7 @@ const {
|
|
|
51
51
|
pre,
|
|
52
52
|
button,
|
|
53
53
|
} = require("@saltcorn/markup/tags");
|
|
54
|
-
const stringify = require("csv-stringify");
|
|
54
|
+
const { stringify } = require("csv-stringify");
|
|
55
55
|
const TableConstraint = require("@saltcorn/data/models/table_constraints");
|
|
56
56
|
const fs = require("fs").promises;
|
|
57
57
|
const {
|
|
@@ -359,7 +359,7 @@ router.post(
|
|
|
359
359
|
error_catcher(async (req, res) => {
|
|
360
360
|
const tbls = await discoverable_tables();
|
|
361
361
|
const form = discoverForm(tbls, req);
|
|
362
|
-
form.validate(req.body);
|
|
362
|
+
form.validate(req.body || {});
|
|
363
363
|
const tableNames = tbls
|
|
364
364
|
.filter((t) => form.values[t.table_name])
|
|
365
365
|
.map((t) => t.table_name);
|
|
@@ -437,8 +437,8 @@ router.post(
|
|
|
437
437
|
setTenant,
|
|
438
438
|
isAdminOrHasConfigMinRole("min_role_edit_tables"),
|
|
439
439
|
error_catcher(async (req, res) => {
|
|
440
|
-
if (req.body.name && req.files && req.files.file) {
|
|
441
|
-
const name = req.body.name;
|
|
440
|
+
if ((req.body || {}).name && req.files && req.files.file) {
|
|
441
|
+
const name = (req.body || {}).name;
|
|
442
442
|
const alltables = await Table.find({});
|
|
443
443
|
const existing_tables = [
|
|
444
444
|
"users",
|
|
@@ -645,8 +645,8 @@ router.get(
|
|
|
645
645
|
div(
|
|
646
646
|
{
|
|
647
647
|
id: "erd-wrapper",
|
|
648
|
-
style:
|
|
649
|
-
|
|
648
|
+
style:
|
|
649
|
+
"height: calc(100vh - 250px); overflow: hidden !important;",
|
|
650
650
|
},
|
|
651
651
|
screenshotPanel(),
|
|
652
652
|
pre(
|
|
@@ -1169,7 +1169,7 @@ router.post(
|
|
|
1169
1169
|
"/",
|
|
1170
1170
|
isAdminOrHasConfigMinRole("min_role_edit_tables"),
|
|
1171
1171
|
error_catcher(async (req, res) => {
|
|
1172
|
-
const v = req.body;
|
|
1172
|
+
const v = req.body || {};
|
|
1173
1173
|
if (typeof v.id === "undefined" && typeof v.external === "undefined") {
|
|
1174
1174
|
// insert
|
|
1175
1175
|
v.name = v.name.trim();
|
|
@@ -1634,21 +1634,14 @@ const constraintForm = (req, table, fields, type) => {
|
|
|
1634
1634
|
case "Index":
|
|
1635
1635
|
const fieldopts = fields.map((f) => ({ label: f.label, name: f.name }));
|
|
1636
1636
|
const hasIncludeFts = fields.filter((f) => f.attributes?.include_fts);
|
|
1637
|
-
if (!db.isSQLite
|
|
1637
|
+
if (!db.isSQLite)
|
|
1638
1638
|
fieldopts.push({ label: "Full-text search", name: "_fts" });
|
|
1639
1639
|
return new Form({
|
|
1640
1640
|
action: `/table/add-constraint/${table.id}/${type}`,
|
|
1641
|
-
blurb:
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
" " +
|
|
1646
|
-
(hasIncludeFts.length
|
|
1647
|
-
? req.__(
|
|
1648
|
-
`Full-text search index is not available as the table contains Key fields (%s) with the "Include in full-text search" option enabled. Disable this before creating a Full-text search index`,
|
|
1649
|
-
hasIncludeFts.map((f) => f.name).join(",")
|
|
1650
|
-
)
|
|
1651
|
-
: ""),
|
|
1641
|
+
blurb: req.__(
|
|
1642
|
+
"Choose the field to be indexed. This make searching the table faster."
|
|
1643
|
+
),
|
|
1644
|
+
|
|
1652
1645
|
fields: [
|
|
1653
1646
|
{
|
|
1654
1647
|
type: "String",
|
|
@@ -1657,6 +1650,11 @@ const constraintForm = (req, table, fields, type) => {
|
|
|
1657
1650
|
required: true,
|
|
1658
1651
|
attributes: {
|
|
1659
1652
|
options: fieldopts,
|
|
1653
|
+
explainers: hasIncludeFts
|
|
1654
|
+
? {
|
|
1655
|
+
_fts: "Full text search index is not compatible with Key fields with the 'Include in Full text search' option. A new field will be created for your search context",
|
|
1656
|
+
}
|
|
1657
|
+
: {},
|
|
1660
1658
|
},
|
|
1661
1659
|
},
|
|
1662
1660
|
],
|
|
@@ -1729,7 +1727,7 @@ router.post(
|
|
|
1729
1727
|
}
|
|
1730
1728
|
const fields = table.getFields();
|
|
1731
1729
|
const form = constraintForm(req, table, fields, type);
|
|
1732
|
-
form.validate(req.body);
|
|
1730
|
+
form.validate(req.body || {});
|
|
1733
1731
|
if (form.hasErrors) req.flash("error", req.__("An error occurred"));
|
|
1734
1732
|
else {
|
|
1735
1733
|
let configuration = {};
|
|
@@ -1820,7 +1818,7 @@ router.post(
|
|
|
1820
1818
|
const table = Table.findOne({ id });
|
|
1821
1819
|
const form = renameForm(table.id, req);
|
|
1822
1820
|
|
|
1823
|
-
form.validate(req.body);
|
|
1821
|
+
form.validate(req.body || {});
|
|
1824
1822
|
if (form.hasErrors) req.flash("error", req.__("An error occurred"));
|
|
1825
1823
|
else {
|
|
1826
1824
|
await table.rename(form.values.name);
|
|
@@ -2188,7 +2186,7 @@ router.post(
|
|
|
2188
2186
|
return;
|
|
2189
2187
|
}
|
|
2190
2188
|
const workflow = get_provider_workflow(table, req);
|
|
2191
|
-
const wfres = await workflow.run(req.body, req);
|
|
2189
|
+
const wfres = await workflow.run(req.body || {}, req);
|
|
2192
2190
|
respondWorkflow(table, workflow, wfres, req, res);
|
|
2193
2191
|
})
|
|
2194
2192
|
);
|
package/routes/tag_entries.js
CHANGED
|
@@ -161,7 +161,7 @@ router.post(
|
|
|
161
161
|
isAdmin,
|
|
162
162
|
error_catcher(async (req, res) => {
|
|
163
163
|
const { entry_type, tag_id } = req.params;
|
|
164
|
-
const { ids } = req.body;
|
|
164
|
+
const { ids } = req.body || {};
|
|
165
165
|
if (!ids) {
|
|
166
166
|
req.flash("error", req.__("Please select at least one item"));
|
|
167
167
|
return res.redirect(`/tag-entries/add/${entry_type}/${tag_id}`);
|
|
@@ -218,7 +218,7 @@ router.post(
|
|
|
218
218
|
isAdmin,
|
|
219
219
|
error_catcher(async (req, res) => {
|
|
220
220
|
let { entry_type, object_id } = req.params;
|
|
221
|
-
let { tag_ids } = req.body;
|
|
221
|
+
let { tag_ids } = req.body || {};
|
|
222
222
|
object_id = parseInt(object_id);
|
|
223
223
|
tag_ids = tag_ids.map((id) => parseInt(id));
|
|
224
224
|
const tags = (await Tag.find()).filter((tag) => tag_ids.includes(tag.id));
|
package/routes/tags.js
CHANGED
|
@@ -315,7 +315,7 @@ router.post(
|
|
|
315
315
|
"/",
|
|
316
316
|
isAdmin,
|
|
317
317
|
error_catcher(async (req, res) => {
|
|
318
|
-
const { name } = req.body;
|
|
318
|
+
const { name } = req.body || {};
|
|
319
319
|
const tag = await Tag.create({ name });
|
|
320
320
|
req.flash("success", req.__(`Tag %s created`, name));
|
|
321
321
|
res.redirect(`/tag/${tag.id}?show_list=tables`);
|
package/routes/tenant.js
CHANGED
|
@@ -265,7 +265,7 @@ router.post(
|
|
|
265
265
|
const base_url = get_cfg_tenant_base_url(req);
|
|
266
266
|
const form = tenant_form(req, base_url);
|
|
267
267
|
// validate ui form
|
|
268
|
-
const valres = form.validate(req.body);
|
|
268
|
+
const valres = form.validate(req.body || {});
|
|
269
269
|
if (valres.errors)
|
|
270
270
|
res.sendWrap(
|
|
271
271
|
req.__("Create application"),
|
|
@@ -548,7 +548,7 @@ router.post(
|
|
|
548
548
|
isAdmin,
|
|
549
549
|
error_catcher(async (req, res) => {
|
|
550
550
|
const form = await tenant_settings_form(req);
|
|
551
|
-
form.validate(req.body);
|
|
551
|
+
form.validate(req.body || {});
|
|
552
552
|
if (form.hasErrors) {
|
|
553
553
|
send_infoarch_page({
|
|
554
554
|
res,
|
|
@@ -872,11 +872,11 @@ router.post(
|
|
|
872
872
|
return;
|
|
873
873
|
}
|
|
874
874
|
const { subdomain } = req.params;
|
|
875
|
-
const { base_url } = req.body;
|
|
875
|
+
const { base_url } = req.body || {};
|
|
876
876
|
const saneDomain = domain_sanitize(subdomain);
|
|
877
877
|
|
|
878
878
|
// save description
|
|
879
|
-
const { description } = req.body;
|
|
879
|
+
const { description } = req.body || {};
|
|
880
880
|
await Tenant.update(saneDomain, { description: description });
|
|
881
881
|
|
|
882
882
|
await db.runWithTenant(saneDomain, async () => {
|
package/routes/utils.js
CHANGED
|
@@ -446,7 +446,7 @@ const admin_config_route = ({
|
|
|
446
446
|
isAdmin,
|
|
447
447
|
error_catcher(async (req, res) => {
|
|
448
448
|
const form = await getTheForm(req);
|
|
449
|
-
form.validate(req.body);
|
|
449
|
+
form.validate(req.body || {});
|
|
450
450
|
if (form.hasErrors) {
|
|
451
451
|
response(form, req, res);
|
|
452
452
|
} else {
|
|
@@ -493,7 +493,7 @@ const sendHtmlFile = async (req, res, file) => {
|
|
|
493
493
|
path.dirname(fullPath)
|
|
494
494
|
);
|
|
495
495
|
if (scFile && role <= scFile.min_role_read) {
|
|
496
|
-
res.sendFile(fullPath);
|
|
496
|
+
res.sendFile(fullPath, { dotfiles: "allow" });
|
|
497
497
|
} else {
|
|
498
498
|
return res
|
|
499
499
|
.status(404)
|
|
@@ -517,7 +517,7 @@ const sendHtmlFile = async (req, res, file) => {
|
|
|
517
517
|
*/
|
|
518
518
|
const setRole = async (req, res, model) => {
|
|
519
519
|
const { id } = req.params;
|
|
520
|
-
const role = req.body.role;
|
|
520
|
+
const role = (req.body || {}).role;
|
|
521
521
|
await model.update(+id, { min_role: role });
|
|
522
522
|
const page = model.findOne({ id });
|
|
523
523
|
const roles = await User.get_roles();
|
package/routes/view.js
CHANGED
|
@@ -39,7 +39,7 @@ module.exports = router;
|
|
|
39
39
|
* @function
|
|
40
40
|
*/
|
|
41
41
|
router.get(
|
|
42
|
-
["/:viewname", "/:viewname/*"],
|
|
42
|
+
["/:viewname", "/:viewname/*slug"],
|
|
43
43
|
error_catcher(async (req, res) => {
|
|
44
44
|
const { viewname } = req.params;
|
|
45
45
|
const query = { ...req.query };
|
|
@@ -60,7 +60,7 @@ router.get(
|
|
|
60
60
|
}
|
|
61
61
|
const tic = new Date();
|
|
62
62
|
|
|
63
|
-
view.rewrite_query_from_slug(query, req.params);
|
|
63
|
+
view.rewrite_query_from_slug(query, req.params.slug);
|
|
64
64
|
if (
|
|
65
65
|
role > view.min_role &&
|
|
66
66
|
!(await view.authorise_get({ query, req, ...view }))
|
|
@@ -231,7 +231,7 @@ router.post(
|
|
|
231
231
|
|
|
232
232
|
res.redirect("/");
|
|
233
233
|
} else {
|
|
234
|
-
await view.runRoute(route, req.body, res, { res, req });
|
|
234
|
+
await view.runRoute(route, req.body || {}, res, { res, req });
|
|
235
235
|
}
|
|
236
236
|
})
|
|
237
237
|
);
|
|
@@ -243,7 +243,7 @@ router.post(
|
|
|
243
243
|
* @function
|
|
244
244
|
*/
|
|
245
245
|
router.post(
|
|
246
|
-
["/:viewname", "/:viewname/*"],
|
|
246
|
+
["/:viewname", "/:viewname/*slug"],
|
|
247
247
|
setTenant,
|
|
248
248
|
error_catcher(async (req, res) => {
|
|
249
249
|
const { viewname } = req.params;
|
|
@@ -263,11 +263,11 @@ router.post(
|
|
|
263
263
|
res.redirect("/");
|
|
264
264
|
return;
|
|
265
265
|
}
|
|
266
|
-
view.rewrite_query_from_slug(query, req.params);
|
|
266
|
+
view.rewrite_query_from_slug(query, req.params.slug);
|
|
267
267
|
|
|
268
268
|
if (
|
|
269
269
|
role > view.min_role &&
|
|
270
|
-
!(await view.authorise_post({ body: req.body, req, ...view }))
|
|
270
|
+
!(await view.authorise_post({ body: req.body || {}, req, ...view }))
|
|
271
271
|
) {
|
|
272
272
|
req.flash("danger", req.__("Not authorized"));
|
|
273
273
|
state.log(2, `View ${viewname} POST not authorized`);
|
|
@@ -280,7 +280,7 @@ router.post(
|
|
|
280
280
|
} does not supply a POST handler`
|
|
281
281
|
);
|
|
282
282
|
} else {
|
|
283
|
-
await view.runPost(query, req.body, { res, req });
|
|
283
|
+
await view.runPost(query, req.body || {}, { res, req });
|
|
284
284
|
}
|
|
285
285
|
})
|
|
286
286
|
);
|
package/routes/viewedit.js
CHANGED
|
@@ -492,7 +492,7 @@ router.post(
|
|
|
492
492
|
const roles = await User.get_roles();
|
|
493
493
|
const pages = await Page.find();
|
|
494
494
|
const form = await viewForm(req, tableOptions, roles, pages);
|
|
495
|
-
const result = form.validate(req.body);
|
|
495
|
+
const result = form.validate(req.body || {});
|
|
496
496
|
const sendForm = (form) => {
|
|
497
497
|
res.sendWrap(req.__(`Edit view`), {
|
|
498
498
|
above: [
|
|
@@ -521,7 +521,7 @@ router.post(
|
|
|
521
521
|
} else {
|
|
522
522
|
const existing_view = await View.findOne({ name: result.success.name });
|
|
523
523
|
if (existing_view)
|
|
524
|
-
if (+req.body.id !== existing_view.id) {
|
|
524
|
+
if (+(req.body || {}).id !== existing_view.id) {
|
|
525
525
|
// may be need !== but doesnt work
|
|
526
526
|
form.errors.name = req.__("A view with this name already exists");
|
|
527
527
|
form.hasErrors = true;
|
|
@@ -544,8 +544,8 @@ router.post(
|
|
|
544
544
|
}
|
|
545
545
|
//const table = Table.findOne({ name: v.table_name });
|
|
546
546
|
delete v.table_name;
|
|
547
|
-
if (req.body.id) {
|
|
548
|
-
await View.update(v, +req.body.id);
|
|
547
|
+
if ((req.body || {}).id) {
|
|
548
|
+
await View.update(v, +(req.body || {}).id);
|
|
549
549
|
} else {
|
|
550
550
|
const vt = getState().viewtemplates[v.viewtemplate];
|
|
551
551
|
if (vt.initial_config) v.configuration = await vt.initial_config(v);
|
|
@@ -744,7 +744,7 @@ router.post(
|
|
|
744
744
|
entity_name: view.name,
|
|
745
745
|
});
|
|
746
746
|
};
|
|
747
|
-
const wfres = await configFlow.run(req.body, req);
|
|
747
|
+
const wfres = await configFlow.run(req.body || {}, req);
|
|
748
748
|
|
|
749
749
|
let table;
|
|
750
750
|
if (view.table_id) table = Table.findOne({ id: view.table_id });
|
|
@@ -852,9 +852,9 @@ router.post(
|
|
|
852
852
|
error_catcher(async (req, res) => {
|
|
853
853
|
const { id } = req.params;
|
|
854
854
|
|
|
855
|
-
if (id && req.body) {
|
|
855
|
+
if (id && (req.body || {})) {
|
|
856
856
|
const exview = await View.findOne({ id });
|
|
857
|
-
let newcfg = { ...exview.configuration, ...req.body };
|
|
857
|
+
let newcfg = { ...exview.configuration, ...(req.body || {}) };
|
|
858
858
|
await View.update({ configuration: newcfg }, +id);
|
|
859
859
|
Trigger.emitEvent("AppChange", `View ${exview.name}`, req.user, {
|
|
860
860
|
entity_type: "View",
|
|
@@ -880,11 +880,11 @@ router.post(
|
|
|
880
880
|
error_catcher(async (req, res) => {
|
|
881
881
|
const { viewname } = req.params;
|
|
882
882
|
|
|
883
|
-
if (viewname && req.body) {
|
|
883
|
+
if (viewname && (req.body || {})) {
|
|
884
884
|
const view = await View.findOne({ name: viewname });
|
|
885
885
|
req.staticFieldViewConfig = true;
|
|
886
886
|
const configFlow = await view.get_config_flow(req);
|
|
887
|
-
const step = await configFlow.singleStepForm(req.body, req);
|
|
887
|
+
const step = await configFlow.singleStepForm(req.body || {}, req);
|
|
888
888
|
if (step?.renderForm) {
|
|
889
889
|
if (!step.renderForm.hasErrors) {
|
|
890
890
|
let newcfg;
|
|
@@ -926,7 +926,7 @@ router.post(
|
|
|
926
926
|
isAdminOrHasConfigMinRole("min_role_edit_views"),
|
|
927
927
|
error_catcher(async (req, res) => {
|
|
928
928
|
const { id } = req.params;
|
|
929
|
-
const role = req.body.role;
|
|
929
|
+
const role = (req.body || {}).role;
|
|
930
930
|
await View.update({ min_role: role }, +id);
|
|
931
931
|
const view = await View.findOne({ id });
|
|
932
932
|
Trigger.emitEvent("AppChange", `View ${view.name}`, req.user, {
|
|
@@ -955,7 +955,7 @@ router.post(
|
|
|
955
955
|
"/test/inserter",
|
|
956
956
|
isAdminOrHasConfigMinRole("min_role_edit_views"),
|
|
957
957
|
error_catcher(async (req, res) => {
|
|
958
|
-
const view = await View.create(req.body);
|
|
958
|
+
const view = await View.create(req.body || {});
|
|
959
959
|
res.json({ view });
|
|
960
960
|
})
|
|
961
961
|
);
|
package/s3storage.js
CHANGED
package/tests/files.test.js
CHANGED
|
@@ -358,9 +358,19 @@ describe("visible_entries test", () => {
|
|
|
358
358
|
.send(`role=${role}`)
|
|
359
359
|
.expect(toRedirect("/files?dir=_sc_test_subfolder_one"));
|
|
360
360
|
};
|
|
361
|
+
const setDirRole = async (role, entry) => {
|
|
362
|
+
const app = await getApp({ disableCsrf: true });
|
|
363
|
+
const adminCookie = await getAdminLoginCookie();
|
|
364
|
+
await request(app)
|
|
365
|
+
.post(`/files/setrole/${entry}`)
|
|
366
|
+
.set("Cookie", adminCookie)
|
|
367
|
+
.send(`role=${role}`)
|
|
368
|
+
.expect(toRedirect("/files?dir=."));
|
|
369
|
+
};
|
|
361
370
|
|
|
362
371
|
it("shows allowed files", async () => {
|
|
363
372
|
await setRole(100, path.join("_sc_test_subfolder_one", "foo_image.png"));
|
|
373
|
+
await setDirRole(100, "_sc_test_subfolder_one");
|
|
364
374
|
|
|
365
375
|
const app = await getApp({ disableCsrf: true });
|
|
366
376
|
const staffCookie = await getStaffLoginCookie();
|
package/tests/plugins.test.js
CHANGED
|
@@ -91,9 +91,7 @@ describe("Plugin Endpoints", () => {
|
|
|
91
91
|
.get("/plugins/public/any-bootstrap-theme/test.txt")
|
|
92
92
|
.expect(toInclude("testfilecontents"));
|
|
93
93
|
await request(app)
|
|
94
|
-
.get(
|
|
95
|
-
"/plugins/public/sbadmin2@9.9.9/sb-admin-2.min.css"
|
|
96
|
-
)
|
|
94
|
+
.get("/plugins/public/sbadmin2@9.9.9/sb-admin-2.min.css")
|
|
97
95
|
.expect(toInclude("Start Bootstrap"));
|
|
98
96
|
|
|
99
97
|
await request(app)
|
|
@@ -101,9 +99,7 @@ describe("Plugin Endpoints", () => {
|
|
|
101
99
|
.set("Cookie", loginCookie)
|
|
102
100
|
.expect(toRedirect("/plugins"));
|
|
103
101
|
await request(app)
|
|
104
|
-
.get(
|
|
105
|
-
"/plugins/public/sbadmin2@9.9.9/sb-admin-2.min.css"
|
|
106
|
-
)
|
|
102
|
+
.get("/plugins/public/sbadmin2@9.9.9/sb-admin-2.min.css")
|
|
107
103
|
.expect(toInclude("Start Bootstrap"));
|
|
108
104
|
});
|
|
109
105
|
it("should install named without config", async () => {
|