@saltcorn/server 0.7.1 → 0.7.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/locales/en.json +2 -1
- package/package.json +9 -7
- package/public/jquery-menu-editor.min.js +5 -0
- package/public/saltcorn.css +9 -0
- package/public/saltcorn.js +42 -1
- package/routes/files.js +51 -0
- package/routes/viewedit.js +45 -0
- package/tests/plugins.test.js +2 -2
package/locales/en.json
CHANGED
|
@@ -888,5 +888,6 @@
|
|
|
888
888
|
"Cannot install unsafe plugins on subdomain tenants": "Cannot install unsafe plugins on subdomain tenants",
|
|
889
889
|
"Default order descending?": "Default order descending?",
|
|
890
890
|
"This is the view to which the user will be sent when the form is submitted. The view you specify here can be ignored depending on the context of the form, for instance if it appears in a pop-up the redirect will not take place.": "This is the view to which the user will be sent when the form is submitted. The view you specify here can be ignored depending on the context of the form, for instance if it appears in a pop-up the redirect will not take place.",
|
|
891
|
-
"Destination view": "Destination view"
|
|
891
|
+
"Destination view": "Destination view",
|
|
892
|
+
"Finish": "Finish"
|
|
892
893
|
}
|
package/package.json
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@saltcorn/server",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.2-beta.0",
|
|
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.7.
|
|
10
|
-
"@saltcorn/builder": "0.7.
|
|
11
|
-
"@saltcorn/data": "0.7.
|
|
12
|
-
"@saltcorn/admin-models": "0.7.
|
|
13
|
-
"@saltcorn/markup": "0.7.
|
|
14
|
-
"@saltcorn/sbadmin2": "0.7.
|
|
9
|
+
"@saltcorn/base-plugin": "0.7.2-beta.0",
|
|
10
|
+
"@saltcorn/builder": "0.7.2-beta.0",
|
|
11
|
+
"@saltcorn/data": "0.7.2-beta.0",
|
|
12
|
+
"@saltcorn/admin-models": "0.7.2-beta.0",
|
|
13
|
+
"@saltcorn/markup": "0.7.2-beta.0",
|
|
14
|
+
"@saltcorn/sbadmin2": "0.7.2-beta.0",
|
|
15
15
|
"@socket.io/cluster-adapter": "^0.1.0",
|
|
16
16
|
"@socket.io/sticky": "^1.0.1",
|
|
17
17
|
"aws-sdk": "^2.1037.0",
|
|
@@ -46,6 +46,7 @@
|
|
|
46
46
|
"pg": "^8.2.1",
|
|
47
47
|
"pluralize": "^8.0.0",
|
|
48
48
|
"qrcode": "1.5.0",
|
|
49
|
+
"sharp": "0.30.3",
|
|
49
50
|
"socket.io": "4.2.0",
|
|
50
51
|
"thirty-two": "1.0.2",
|
|
51
52
|
"tmp-promise": "^3.0.2",
|
|
@@ -58,6 +59,7 @@
|
|
|
58
59
|
"repository": "github:saltcorn/saltcorn",
|
|
59
60
|
"devDependencies": {
|
|
60
61
|
"jest": "26.6.3",
|
|
62
|
+
"jest-environment-jsdom": "^26.6.2",
|
|
61
63
|
"supertest": "^4.0.2"
|
|
62
64
|
},
|
|
63
65
|
"scripts": {
|
|
@@ -117,6 +117,7 @@ function MenuEditor(e, t) {
|
|
|
117
117
|
(n.prev("div").children(".sortableListsOpener").first().remove(),
|
|
118
118
|
n.remove()),
|
|
119
119
|
MenuEditor.updateButtons(s);
|
|
120
|
+
l.onUpdate();
|
|
120
121
|
}
|
|
121
122
|
}),
|
|
122
123
|
$(document).on("click", ".btnEdit", function (e) {
|
|
@@ -145,11 +146,13 @@ function MenuEditor(e, t) {
|
|
|
145
146
|
e.preventDefault();
|
|
146
147
|
var t = $(this).closest("li");
|
|
147
148
|
t.prev("li").before(t), MenuEditor.updateButtons(s);
|
|
149
|
+
l.onUpdate();
|
|
148
150
|
}),
|
|
149
151
|
s.on("click", ".btnDown", function (e) {
|
|
150
152
|
e.preventDefault();
|
|
151
153
|
var t = $(this).closest("li");
|
|
152
154
|
t.next("li").after(t), MenuEditor.updateButtons(s);
|
|
155
|
+
l.onUpdate();
|
|
153
156
|
}),
|
|
154
157
|
s.on("click", ".btnOut", function (e) {
|
|
155
158
|
e.preventDefault();
|
|
@@ -161,6 +164,7 @@ function MenuEditor(e, t) {
|
|
|
161
164
|
t.remove()),
|
|
162
165
|
MenuEditor.updateButtons(s),
|
|
163
166
|
s.updateLevels();
|
|
167
|
+
l.onUpdate();
|
|
164
168
|
}),
|
|
165
169
|
s.on("click", ".btnIn", function (e) {
|
|
166
170
|
e.preventDefault();
|
|
@@ -174,6 +178,7 @@ function MenuEditor(e, t) {
|
|
|
174
178
|
l.append(n), n.append(t), l.addClass("sortableListsOpen"), f(l);
|
|
175
179
|
}
|
|
176
180
|
MenuEditor.updateButtons(s), s.updateLevels();
|
|
181
|
+
l.onUpdate();
|
|
177
182
|
}),
|
|
178
183
|
(this.setForm = function (e) {
|
|
179
184
|
i = e;
|
package/public/saltcorn.css
CHANGED
package/public/saltcorn.js
CHANGED
|
@@ -618,6 +618,47 @@ function saveAndContinue(e, k) {
|
|
|
618
618
|
return false;
|
|
619
619
|
}
|
|
620
620
|
|
|
621
|
+
function applyViewConfig(e, url) {
|
|
622
|
+
var form = $(e).closest("form");
|
|
623
|
+
var form_data = form.serializeArray();
|
|
624
|
+
const cfg = {};
|
|
625
|
+
form_data.forEach((item) => {
|
|
626
|
+
cfg[item.name] = item.value;
|
|
627
|
+
});
|
|
628
|
+
$.ajax(url, {
|
|
629
|
+
type: "POST",
|
|
630
|
+
dataType: "json",
|
|
631
|
+
contentType: "application/json",
|
|
632
|
+
headers: {
|
|
633
|
+
"CSRF-Token": _sc_globalCsrf,
|
|
634
|
+
},
|
|
635
|
+
data: JSON.stringify(cfg),
|
|
636
|
+
error: function (request) {},
|
|
637
|
+
});
|
|
638
|
+
|
|
639
|
+
return false;
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
const repeaterCopyValuesToForm = (form, editor) => {
|
|
643
|
+
const vs = JSON.parse(editor.getString());
|
|
644
|
+
//console.log(vs)
|
|
645
|
+
const setVal = (k, ix, v) => {
|
|
646
|
+
const $e = form.find(`input[name="${k}_${ix}"]`);
|
|
647
|
+
if ($e.length) $e.val(v);
|
|
648
|
+
else
|
|
649
|
+
form.append(
|
|
650
|
+
`<input type="hidden" name="${k}_${ix}" value="${v}"></input>`
|
|
651
|
+
);
|
|
652
|
+
};
|
|
653
|
+
vs.forEach((v, ix) => {
|
|
654
|
+
Object.entries(v).forEach(([k, v]) => {
|
|
655
|
+
//console.log(ix, k, typeof v, v)
|
|
656
|
+
if (typeof v === "boolean") setVal(k, ix, v ? "on" : "");
|
|
657
|
+
else setVal(k, ix, v);
|
|
658
|
+
});
|
|
659
|
+
});
|
|
660
|
+
};
|
|
661
|
+
|
|
621
662
|
function ajaxSubmitForm(e) {
|
|
622
663
|
var form = $(e).closest("form");
|
|
623
664
|
var url = form.attr("action");
|
|
@@ -834,7 +875,7 @@ const columnSummary = (col) => {
|
|
|
834
875
|
if (!col) return "Unknown";
|
|
835
876
|
switch (col.type) {
|
|
836
877
|
case "Field":
|
|
837
|
-
return `Field ${col.field_name} ${col.fieldview}`;
|
|
878
|
+
return `Field ${col.field_name} ${col.fieldview || ""}`;
|
|
838
879
|
case "Link":
|
|
839
880
|
return `Link ${col.link_text}`;
|
|
840
881
|
case "JoinField":
|
package/routes/files.js
CHANGED
|
@@ -9,6 +9,7 @@ const File = require("@saltcorn/data/models/file");
|
|
|
9
9
|
const User = require("@saltcorn/data/models/user");
|
|
10
10
|
const { getState } = require("@saltcorn/data/db/state");
|
|
11
11
|
const s3storage = require("../s3storage");
|
|
12
|
+
const sharp = require("sharp");
|
|
12
13
|
|
|
13
14
|
const {
|
|
14
15
|
mkTable,
|
|
@@ -43,6 +44,8 @@ const {
|
|
|
43
44
|
config_fields_form,
|
|
44
45
|
save_config_from_form,
|
|
45
46
|
} = require("../markup/admin");
|
|
47
|
+
const fsp = require("fs").promises;
|
|
48
|
+
const fs = require("fs");
|
|
46
49
|
|
|
47
50
|
/**
|
|
48
51
|
* @type {object}
|
|
@@ -187,6 +190,54 @@ router.get(
|
|
|
187
190
|
})
|
|
188
191
|
);
|
|
189
192
|
|
|
193
|
+
/**
|
|
194
|
+
* @name get/resize/:id
|
|
195
|
+
* @function
|
|
196
|
+
* @memberof module:routes/files~filesRouter
|
|
197
|
+
* @function
|
|
198
|
+
*/
|
|
199
|
+
router.get(
|
|
200
|
+
"/resize/:id/:width_str",
|
|
201
|
+
error_catcher(async (req, res) => {
|
|
202
|
+
const role = req.user && req.user.id ? req.user.role_id : 10;
|
|
203
|
+
const user_id = req.user && req.user.id;
|
|
204
|
+
const { id, width_str } = req.params;
|
|
205
|
+
let file;
|
|
206
|
+
if (typeof strictParseInt(id) !== "undefined")
|
|
207
|
+
file = await File.findOne({ id });
|
|
208
|
+
else file = await File.findOne({ filename: id });
|
|
209
|
+
|
|
210
|
+
if (!file) {
|
|
211
|
+
res
|
|
212
|
+
.status(404)
|
|
213
|
+
.sendWrap(req.__("Not found"), h1(req.__("File not found")));
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
if (role <= file.min_role_read || (user_id && user_id === file.user_id)) {
|
|
217
|
+
res.type(file.mimetype);
|
|
218
|
+
const cacheability = file.min_role_read === 10 ? "public" : "private";
|
|
219
|
+
res.set("Cache-Control", `${cacheability}, max-age=86400`);
|
|
220
|
+
//TODO s3
|
|
221
|
+
if (file.s3_store) s3storage.serveObject(file, res, false);
|
|
222
|
+
else {
|
|
223
|
+
const width = strictParseInt(width_str);
|
|
224
|
+
if (!width) {
|
|
225
|
+
res.sendFile(file.location);
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
const fnm = `${file.location}_w${width}`;
|
|
229
|
+
if (!fs.existsSync(fnm)) {
|
|
230
|
+
await sharp(file.location).resize({ width }).toFile(fnm);
|
|
231
|
+
}
|
|
232
|
+
res.sendFile(fnm);
|
|
233
|
+
}
|
|
234
|
+
} else {
|
|
235
|
+
req.flash("warning", req.__("Not authorized"));
|
|
236
|
+
res.redirect("/");
|
|
237
|
+
}
|
|
238
|
+
})
|
|
239
|
+
);
|
|
240
|
+
|
|
190
241
|
/**
|
|
191
242
|
* @name post/setrole/:id
|
|
192
243
|
* @function
|
package/routes/viewedit.js
CHANGED
|
@@ -582,8 +582,11 @@ router.get(
|
|
|
582
582
|
return;
|
|
583
583
|
}
|
|
584
584
|
const configFlow = await view.get_config_flow(req);
|
|
585
|
+
const hasConfig =
|
|
586
|
+
view.configuration && Object.keys(view.configuration).length > 0;
|
|
585
587
|
const wfres = await configFlow.run(
|
|
586
588
|
{
|
|
589
|
+
id: hasConfig ? view.id : undefined,
|
|
587
590
|
table_id: view.table_id,
|
|
588
591
|
exttable_name: view.exttable_name,
|
|
589
592
|
viewname: name,
|
|
@@ -704,6 +707,48 @@ router.post(
|
|
|
704
707
|
})
|
|
705
708
|
);
|
|
706
709
|
|
|
710
|
+
/**
|
|
711
|
+
* @name post/saveconfig/:id
|
|
712
|
+
* @function
|
|
713
|
+
* @memberof module:routes/viewedit~vieweditRouter
|
|
714
|
+
* @function
|
|
715
|
+
*/
|
|
716
|
+
router.post(
|
|
717
|
+
"/saveconfig/:viewname",
|
|
718
|
+
isAdmin,
|
|
719
|
+
error_catcher(async (req, res) => {
|
|
720
|
+
const { viewname } = req.params;
|
|
721
|
+
|
|
722
|
+
if (viewname && req.body) {
|
|
723
|
+
const view = await View.findOne({ name: viewname });
|
|
724
|
+
const configFlow = await view.get_config_flow(req);
|
|
725
|
+
const step = await configFlow.singleStepForm(req.body, req);
|
|
726
|
+
if (step?.renderForm) {
|
|
727
|
+
if (!step.renderForm.hasErrors) {
|
|
728
|
+
let newcfg;
|
|
729
|
+
if (step.contextField)
|
|
730
|
+
newcfg = {
|
|
731
|
+
...view.configuration,
|
|
732
|
+
[step.contextField]: {
|
|
733
|
+
...view.configuration?.[step.contextField],
|
|
734
|
+
...step.renderForm.values,
|
|
735
|
+
},
|
|
736
|
+
};
|
|
737
|
+
else newcfg = { ...view.configuration, ...step.renderForm.values };
|
|
738
|
+
await View.update({ configuration: newcfg }, view.id);
|
|
739
|
+
res.json({ success: "ok" });
|
|
740
|
+
} else {
|
|
741
|
+
res.json({ error: step.renderForm.errorSummary });
|
|
742
|
+
}
|
|
743
|
+
} else {
|
|
744
|
+
res.json({ error: "no form" });
|
|
745
|
+
}
|
|
746
|
+
} else {
|
|
747
|
+
res.json({ error: "no view" });
|
|
748
|
+
}
|
|
749
|
+
})
|
|
750
|
+
);
|
|
751
|
+
|
|
707
752
|
/**
|
|
708
753
|
* @name post/setrole/:id
|
|
709
754
|
* @function
|
package/tests/plugins.test.js
CHANGED
|
@@ -90,7 +90,7 @@ describe("Plugin Endpoints", () => {
|
|
|
90
90
|
.expect(toInclude("testfilecontents"));
|
|
91
91
|
await request(app)
|
|
92
92
|
.get(
|
|
93
|
-
"/plugins/pubdeps/sbadmin2/startbootstrap-sb-admin-2-bs5/4.1.5-beta.
|
|
93
|
+
"/plugins/pubdeps/sbadmin2/startbootstrap-sb-admin-2-bs5/4.1.5-beta.4/css/sb-admin-2.min.css"
|
|
94
94
|
)
|
|
95
95
|
.expect(toInclude("Start Bootstrap"));
|
|
96
96
|
|
|
@@ -100,7 +100,7 @@ describe("Plugin Endpoints", () => {
|
|
|
100
100
|
.expect(toRedirect("/plugins"));
|
|
101
101
|
await request(app)
|
|
102
102
|
.get(
|
|
103
|
-
"/plugins/pubdeps/sbadmin2/startbootstrap-sb-admin-2-bs5/4.1.5-beta.
|
|
103
|
+
"/plugins/pubdeps/sbadmin2/startbootstrap-sb-admin-2-bs5/4.1.5-beta.4/css/sb-admin-2.min.css"
|
|
104
104
|
)
|
|
105
105
|
.expect(toInclude("Start Bootstrap"));
|
|
106
106
|
});
|