@saltcorn/server 1.1.1-rc.4 → 1.1.2-beta.0
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/locales/pl.json +31 -1
- package/package.json +37 -37
- package/public/saltcorn-common.js +5 -1
- package/routes/actions.js +18 -94
- 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 +21 -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/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(
|
|
@@ -712,6 +712,7 @@ const attribBadges = (f) => {
|
|
|
712
712
|
if (
|
|
713
713
|
[
|
|
714
714
|
"summary_field",
|
|
715
|
+
"importance",
|
|
715
716
|
"on_delete_cascade",
|
|
716
717
|
"on_delete",
|
|
717
718
|
"unique_error_msg",
|
|
@@ -1168,7 +1169,7 @@ router.post(
|
|
|
1168
1169
|
"/",
|
|
1169
1170
|
isAdminOrHasConfigMinRole("min_role_edit_tables"),
|
|
1170
1171
|
error_catcher(async (req, res) => {
|
|
1171
|
-
const v = req.body;
|
|
1172
|
+
const v = req.body || {};
|
|
1172
1173
|
if (typeof v.id === "undefined" && typeof v.external === "undefined") {
|
|
1173
1174
|
// insert
|
|
1174
1175
|
v.name = v.name.trim();
|
|
@@ -1633,21 +1634,14 @@ const constraintForm = (req, table, fields, type) => {
|
|
|
1633
1634
|
case "Index":
|
|
1634
1635
|
const fieldopts = fields.map((f) => ({ label: f.label, name: f.name }));
|
|
1635
1636
|
const hasIncludeFts = fields.filter((f) => f.attributes?.include_fts);
|
|
1636
|
-
if (!db.isSQLite
|
|
1637
|
+
if (!db.isSQLite)
|
|
1637
1638
|
fieldopts.push({ label: "Full-text search", name: "_fts" });
|
|
1638
1639
|
return new Form({
|
|
1639
1640
|
action: `/table/add-constraint/${table.id}/${type}`,
|
|
1640
|
-
blurb:
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
" " +
|
|
1645
|
-
(hasIncludeFts.length
|
|
1646
|
-
? req.__(
|
|
1647
|
-
`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`,
|
|
1648
|
-
hasIncludeFts.map((f) => f.name).join(",")
|
|
1649
|
-
)
|
|
1650
|
-
: ""),
|
|
1641
|
+
blurb: req.__(
|
|
1642
|
+
"Choose the field to be indexed. This make searching the table faster."
|
|
1643
|
+
),
|
|
1644
|
+
|
|
1651
1645
|
fields: [
|
|
1652
1646
|
{
|
|
1653
1647
|
type: "String",
|
|
@@ -1656,6 +1650,11 @@ const constraintForm = (req, table, fields, type) => {
|
|
|
1656
1650
|
required: true,
|
|
1657
1651
|
attributes: {
|
|
1658
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
|
+
: {},
|
|
1659
1658
|
},
|
|
1660
1659
|
},
|
|
1661
1660
|
],
|
|
@@ -1728,7 +1727,7 @@ router.post(
|
|
|
1728
1727
|
}
|
|
1729
1728
|
const fields = table.getFields();
|
|
1730
1729
|
const form = constraintForm(req, table, fields, type);
|
|
1731
|
-
form.validate(req.body);
|
|
1730
|
+
form.validate(req.body || {});
|
|
1732
1731
|
if (form.hasErrors) req.flash("error", req.__("An error occurred"));
|
|
1733
1732
|
else {
|
|
1734
1733
|
let configuration = {};
|
|
@@ -1819,7 +1818,7 @@ router.post(
|
|
|
1819
1818
|
const table = Table.findOne({ id });
|
|
1820
1819
|
const form = renameForm(table.id, req);
|
|
1821
1820
|
|
|
1822
|
-
form.validate(req.body);
|
|
1821
|
+
form.validate(req.body || {});
|
|
1823
1822
|
if (form.hasErrors) req.flash("error", req.__("An error occurred"));
|
|
1824
1823
|
else {
|
|
1825
1824
|
await table.rename(form.values.name);
|
|
@@ -2187,7 +2186,7 @@ router.post(
|
|
|
2187
2186
|
return;
|
|
2188
2187
|
}
|
|
2189
2188
|
const workflow = get_provider_workflow(table, req);
|
|
2190
|
-
const wfres = await workflow.run(req.body, req);
|
|
2189
|
+
const wfres = await workflow.run(req.body || {}, req);
|
|
2191
2190
|
respondWorkflow(table, workflow, wfres, req, res);
|
|
2192
2191
|
})
|
|
2193
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 () => {
|