@saltcorn/server 0.7.1 → 0.7.2-beta.3
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 +64 -9
- package/auth/routes.js +37 -13
- package/load_plugins.js +29 -24
- package/locales/da.json +1 -1
- package/locales/de.json +155 -155
- package/locales/en.json +9 -5
- package/locales/it.json +1 -1
- package/locales/ru.json +52 -18
- package/locales/zh.json +3 -3
- package/package.json +13 -8
- package/public/jquery-menu-editor.min.js +5 -0
- package/public/saltcorn-common.js +105 -0
- package/public/saltcorn.css +70 -0
- package/public/saltcorn.js +96 -83
- package/routes/admin.js +1 -1
- package/routes/api.js +36 -1
- package/routes/edit.js +2 -1
- package/routes/fields.js +12 -0
- package/routes/files.js +51 -0
- package/routes/viewedit.js +54 -0
- package/tests/admin.test.js +72 -1
- package/tests/clientjs.test.js +1 -0
- package/tests/plugins.test.js +2 -2
- package/tests/viewedit.test.js +94 -0
- package/wrapper.js +1 -0
package/routes/admin.js
CHANGED
|
@@ -787,7 +787,7 @@ router.get(
|
|
|
787
787
|
? div(
|
|
788
788
|
{ class: "alert alert-success", role: "alert" },
|
|
789
789
|
i({ class: "fas fa-check-circle fa-lg me-2" }),
|
|
790
|
-
h5({ class: "d-inline" }, "No errors detected")
|
|
790
|
+
h5({ class: "d-inline" }, req.__("No errors detected during configuration check"))
|
|
791
791
|
)
|
|
792
792
|
: errors.map(mkError)
|
|
793
793
|
),
|
package/routes/api.js
CHANGED
|
@@ -20,6 +20,7 @@ const { error_catcher } = require("./utils.js");
|
|
|
20
20
|
//const { mkTable, renderForm, link, post_btn } = require("@saltcorn/markup");
|
|
21
21
|
const { getState } = require("@saltcorn/data/db/state");
|
|
22
22
|
const Table = require("@saltcorn/data/models/table");
|
|
23
|
+
const View = require("@saltcorn/data/models/view");
|
|
23
24
|
//const Field = require("@saltcorn/data/models/field");
|
|
24
25
|
const Trigger = require("@saltcorn/data/models/trigger");
|
|
25
26
|
//const load_plugins = require("../load_plugins");
|
|
@@ -111,6 +112,40 @@ function accessAllowed(req, user, trigger) {
|
|
|
111
112
|
return role <= trigger.min_role;
|
|
112
113
|
}
|
|
113
114
|
|
|
115
|
+
router.post(
|
|
116
|
+
"/viewQuery/:viewName/:queryName",
|
|
117
|
+
error_catcher(async (req, res, next) => {
|
|
118
|
+
let { viewName, queryName } = req.params;
|
|
119
|
+
const view = await View.findOne({ name: viewName });
|
|
120
|
+
if (!view) {
|
|
121
|
+
res.status(404).json({ error: req.__("Not found") });
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
await passport.authenticate(
|
|
125
|
+
"jwt",
|
|
126
|
+
{ session: false },
|
|
127
|
+
async function (err, user, info) {
|
|
128
|
+
const role = user && user.id ? user.role_id : 10;
|
|
129
|
+
if (
|
|
130
|
+
role <= view.min_role ||
|
|
131
|
+
(await view.authorise_get({ req, ...view })) // TODO set query to state
|
|
132
|
+
) {
|
|
133
|
+
const queries = view.queries(false, req);
|
|
134
|
+
if (queries[queryName]) {
|
|
135
|
+
const { args } = req.body;
|
|
136
|
+
const resp = await queries[queryName](...args, true);
|
|
137
|
+
res.json({ success: resp });
|
|
138
|
+
} else {
|
|
139
|
+
res.status(404).json({ error: req.__("Not found") });
|
|
140
|
+
}
|
|
141
|
+
} else {
|
|
142
|
+
res.status(401).json({ error: req.__("Not authorized") });
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
)(req, res, next);
|
|
146
|
+
})
|
|
147
|
+
);
|
|
148
|
+
|
|
114
149
|
router.get(
|
|
115
150
|
"/:tableName/distinct/:fieldName",
|
|
116
151
|
//passport.authenticate("api-bearer", { session: false }),
|
|
@@ -180,7 +215,7 @@ router.get(
|
|
|
180
215
|
}
|
|
181
216
|
|
|
182
217
|
await passport.authenticate(
|
|
183
|
-
"api-bearer",
|
|
218
|
+
["api-bearer", "jwt"],
|
|
184
219
|
{ session: false },
|
|
185
220
|
async function (err, user, info) {
|
|
186
221
|
if (accessAllowedRead(req, user, table)) {
|
package/routes/edit.js
CHANGED
|
@@ -44,7 +44,8 @@ router.post(
|
|
|
44
44
|
"error",
|
|
45
45
|
req.__("Not allowed to write to table %s", table.name)
|
|
46
46
|
);
|
|
47
|
-
if (req.
|
|
47
|
+
if (req.xhr) res.send("OK");
|
|
48
|
+
else if (req.get("referer")) res.redirect(req.get("referer"));
|
|
48
49
|
else res.redirect(redirect || `/list/${table.name}`);
|
|
49
50
|
})
|
|
50
51
|
);
|
package/routes/fields.js
CHANGED
|
@@ -181,6 +181,7 @@ const fieldFlow = (req) =>
|
|
|
181
181
|
var attributes = context.attributes || {};
|
|
182
182
|
attributes.default = context.default;
|
|
183
183
|
attributes.summary_field = context.summary_field;
|
|
184
|
+
attributes.include_fts = context.include_fts;
|
|
184
185
|
attributes.on_delete_cascade = context.on_delete_cascade;
|
|
185
186
|
const {
|
|
186
187
|
table_id,
|
|
@@ -370,6 +371,11 @@ const fieldFlow = (req) =>
|
|
|
370
371
|
value: f.name,
|
|
371
372
|
label: f.label,
|
|
372
373
|
}));
|
|
374
|
+
const textfields = orderedFields
|
|
375
|
+
.filter(
|
|
376
|
+
(f) => (!f.calculated || f.stored) && f.type?.sql_name === "text"
|
|
377
|
+
)
|
|
378
|
+
.map((f) => f.name);
|
|
373
379
|
return new Form({
|
|
374
380
|
fields: [
|
|
375
381
|
new Field({
|
|
@@ -378,6 +384,12 @@ const fieldFlow = (req) =>
|
|
|
378
384
|
input_type: "select",
|
|
379
385
|
options: keyfields,
|
|
380
386
|
}),
|
|
387
|
+
new Field({
|
|
388
|
+
name: "include_fts",
|
|
389
|
+
label: req.__("Include in full-text search"),
|
|
390
|
+
type: "Bool",
|
|
391
|
+
showIf: { summary_field: textfields },
|
|
392
|
+
}),
|
|
381
393
|
new Field({
|
|
382
394
|
name: "on_delete_cascade",
|
|
383
395
|
label: req.__("On delete cascade"),
|
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
|
|
@@ -730,3 +775,12 @@ router.post(
|
|
|
730
775
|
res.redirect("/viewedit");
|
|
731
776
|
})
|
|
732
777
|
);
|
|
778
|
+
|
|
779
|
+
router.post(
|
|
780
|
+
"/test/inserter",
|
|
781
|
+
isAdmin,
|
|
782
|
+
error_catcher(async (req, res) => {
|
|
783
|
+
const view = await View.create(req.body);
|
|
784
|
+
res.json({ view });
|
|
785
|
+
})
|
|
786
|
+
);
|
package/tests/admin.test.js
CHANGED
|
@@ -12,6 +12,7 @@ const {
|
|
|
12
12
|
respondJsonWith,
|
|
13
13
|
} = require("../auth/testhelp");
|
|
14
14
|
const db = require("@saltcorn/data/db");
|
|
15
|
+
const { sleep } = require("@saltcorn/data/tests/mocks");
|
|
15
16
|
const fs = require("fs").promises;
|
|
16
17
|
const File = require("@saltcorn/data/models/file");
|
|
17
18
|
const User = require("@saltcorn/data/models/user");
|
|
@@ -30,7 +31,12 @@ beforeAll(async () => {
|
|
|
30
31
|
4
|
|
31
32
|
);
|
|
32
33
|
});
|
|
33
|
-
|
|
34
|
+
|
|
35
|
+
afterAll(async () => {
|
|
36
|
+
await sleep(200);
|
|
37
|
+
db.close();
|
|
38
|
+
});
|
|
39
|
+
|
|
34
40
|
const adminPageContains = (specs) =>
|
|
35
41
|
it("adminPageContains " + specs.map((s) => s[1]).join(","), async () => {
|
|
36
42
|
const app = await getApp({ disableCsrf: true });
|
|
@@ -456,6 +462,71 @@ describe("actions", () => {
|
|
|
456
462
|
.expect(toRedirect("/actions/"));
|
|
457
463
|
});
|
|
458
464
|
});
|
|
465
|
+
describe("localizer", () => {
|
|
466
|
+
itShouldRedirectUnauthToLogin("/site-structure/localizer");
|
|
467
|
+
itShouldRedirectUnauthToLogin("/site-structure/localizer/add-lang");
|
|
468
|
+
it("redirects site struct to menu", async () => {
|
|
469
|
+
const app = await getApp({ disableCsrf: true });
|
|
470
|
+
const loginCookie = await getAdminLoginCookie();
|
|
471
|
+
await request(app)
|
|
472
|
+
.get("/site-structure")
|
|
473
|
+
.set("Cookie", loginCookie)
|
|
474
|
+
.expect(toRedirect("/menu"));
|
|
475
|
+
});
|
|
476
|
+
it("shows languages", async () => {
|
|
477
|
+
const app = await getApp({ disableCsrf: true });
|
|
478
|
+
const loginCookie = await getAdminLoginCookie();
|
|
479
|
+
await request(app)
|
|
480
|
+
.get("/site-structure/localizer")
|
|
481
|
+
.set("Cookie", loginCookie)
|
|
482
|
+
.expect(toInclude("Languages"));
|
|
483
|
+
});
|
|
484
|
+
it("shows add language form", async () => {
|
|
485
|
+
const app = await getApp({ disableCsrf: true });
|
|
486
|
+
const loginCookie = await getAdminLoginCookie();
|
|
487
|
+
await request(app)
|
|
488
|
+
.get("/site-structure/localizer/add-lang")
|
|
489
|
+
.set("Cookie", loginCookie)
|
|
490
|
+
.expect(toInclude("Locale identifier short code"));
|
|
491
|
+
});
|
|
492
|
+
it("add language", async () => {
|
|
493
|
+
const app = await getApp({ disableCsrf: true });
|
|
494
|
+
const loginCookie = await getAdminLoginCookie();
|
|
495
|
+
await request(app)
|
|
496
|
+
.post("/site-structure/localizer/save-lang")
|
|
497
|
+
.set("Cookie", loginCookie)
|
|
498
|
+
.send("name=dansk")
|
|
499
|
+
.send("locale=da")
|
|
500
|
+
.expect(toRedirect("/site-structure/localizer/edit/da"));
|
|
501
|
+
});
|
|
502
|
+
it("shows new in languages", async () => {
|
|
503
|
+
const app = await getApp({ disableCsrf: true });
|
|
504
|
+
const loginCookie = await getAdminLoginCookie();
|
|
505
|
+
await request(app)
|
|
506
|
+
.get("/site-structure/localizer")
|
|
507
|
+
.set("Cookie", loginCookie)
|
|
508
|
+
.expect(toInclude("dansk"));
|
|
509
|
+
});
|
|
510
|
+
|
|
511
|
+
it("shows edit language form", async () => {
|
|
512
|
+
const app = await getApp({ disableCsrf: true });
|
|
513
|
+
const loginCookie = await getAdminLoginCookie();
|
|
514
|
+
await request(app)
|
|
515
|
+
.get("/site-structure/localizer/edit/da")
|
|
516
|
+
.set("Cookie", loginCookie)
|
|
517
|
+
.expect(toInclude("Hello world"));
|
|
518
|
+
});
|
|
519
|
+
it("set string language", async () => {
|
|
520
|
+
const app = await getApp({ disableCsrf: true });
|
|
521
|
+
const loginCookie = await getAdminLoginCookie();
|
|
522
|
+
await request(app)
|
|
523
|
+
.post("/site-structure/localizer/save-string/da/Hello%20world")
|
|
524
|
+
.set("Cookie", loginCookie)
|
|
525
|
+
.send("value=Hej+verden")
|
|
526
|
+
.expect(toRedirect("/site-structure/localizer/edit/da"));
|
|
527
|
+
});
|
|
528
|
+
});
|
|
529
|
+
|
|
459
530
|
/**
|
|
460
531
|
* Pages tests
|
|
461
532
|
*/
|
package/tests/clientjs.test.js
CHANGED
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
|
});
|
package/tests/viewedit.test.js
CHANGED
|
@@ -8,6 +8,7 @@ const {
|
|
|
8
8
|
toInclude,
|
|
9
9
|
toNotInclude,
|
|
10
10
|
resetToFixtures,
|
|
11
|
+
succeedJsonWith,
|
|
11
12
|
} = require("../auth/testhelp");
|
|
12
13
|
const db = require("@saltcorn/data/db");
|
|
13
14
|
const View = require("@saltcorn/data/models/view");
|
|
@@ -371,3 +372,96 @@ describe("viewedit new Show", () => {
|
|
|
371
372
|
.expect(toRedirect("/viewedit"));
|
|
372
373
|
});
|
|
373
374
|
});
|
|
375
|
+
describe("Library", () => {
|
|
376
|
+
it("should save new from builder", async () => {
|
|
377
|
+
const loginCookie = await getAdminLoginCookie();
|
|
378
|
+
const app = await getApp({ disableCsrf: true });
|
|
379
|
+
await request(app)
|
|
380
|
+
.post("/library/savefrombuilder/")
|
|
381
|
+
.set("Cookie", loginCookie)
|
|
382
|
+
.send({
|
|
383
|
+
layout: {
|
|
384
|
+
columns: [],
|
|
385
|
+
layout: {
|
|
386
|
+
type: "card",
|
|
387
|
+
contents: {
|
|
388
|
+
above: [
|
|
389
|
+
null,
|
|
390
|
+
{
|
|
391
|
+
besides: [
|
|
392
|
+
{
|
|
393
|
+
above: [
|
|
394
|
+
null,
|
|
395
|
+
{
|
|
396
|
+
type: "blank",
|
|
397
|
+
contents: "Hello world",
|
|
398
|
+
block: false,
|
|
399
|
+
inline: false,
|
|
400
|
+
textStyle: "",
|
|
401
|
+
isFormula: {},
|
|
402
|
+
labelFor: "",
|
|
403
|
+
style: {},
|
|
404
|
+
font: "",
|
|
405
|
+
},
|
|
406
|
+
],
|
|
407
|
+
},
|
|
408
|
+
{
|
|
409
|
+
above: [
|
|
410
|
+
null,
|
|
411
|
+
{
|
|
412
|
+
type: "blank",
|
|
413
|
+
contents: "Bye bye",
|
|
414
|
+
block: false,
|
|
415
|
+
inline: false,
|
|
416
|
+
textStyle: "",
|
|
417
|
+
isFormula: {},
|
|
418
|
+
labelFor: "",
|
|
419
|
+
style: {},
|
|
420
|
+
font: "",
|
|
421
|
+
},
|
|
422
|
+
],
|
|
423
|
+
},
|
|
424
|
+
],
|
|
425
|
+
breakpoints: ["", ""],
|
|
426
|
+
style: {},
|
|
427
|
+
widths: [6, 6],
|
|
428
|
+
},
|
|
429
|
+
],
|
|
430
|
+
},
|
|
431
|
+
title: "header",
|
|
432
|
+
style: {},
|
|
433
|
+
},
|
|
434
|
+
},
|
|
435
|
+
icon: "far fa-angry",
|
|
436
|
+
name: "ShinyCard",
|
|
437
|
+
})
|
|
438
|
+
.set("Content-Type", "application/json")
|
|
439
|
+
.set("Accept", "application/json")
|
|
440
|
+
.expect(succeedJsonWith(() => true));
|
|
441
|
+
});
|
|
442
|
+
it("shows library with item", async () => {
|
|
443
|
+
const app = await getApp({ disableCsrf: true });
|
|
444
|
+
const loginCookie = await getAdminLoginCookie();
|
|
445
|
+
await request(app)
|
|
446
|
+
.get("/library/list")
|
|
447
|
+
.set("Cookie", loginCookie)
|
|
448
|
+
.expect(toInclude("ShinyCard"));
|
|
449
|
+
});
|
|
450
|
+
it("deletes in library", async () => {
|
|
451
|
+
const app = await getApp({ disableCsrf: true });
|
|
452
|
+
const loginCookie = await getAdminLoginCookie();
|
|
453
|
+
await request(app)
|
|
454
|
+
.post("/library/delete/1")
|
|
455
|
+
.set("Cookie", loginCookie)
|
|
456
|
+
.expect(toRedirect("/library/list"));
|
|
457
|
+
});
|
|
458
|
+
it("shows empty library", async () => {
|
|
459
|
+
const app = await getApp({ disableCsrf: true });
|
|
460
|
+
const loginCookie = await getAdminLoginCookie();
|
|
461
|
+
await request(app)
|
|
462
|
+
.get("/library/list")
|
|
463
|
+
.set("Cookie", loginCookie)
|
|
464
|
+
.expect(toInclude("Library"))
|
|
465
|
+
.expect(toNotInclude("ShinyCard"))
|
|
466
|
+
});
|
|
467
|
+
});
|
package/wrapper.js
CHANGED
|
@@ -167,6 +167,7 @@ const get_headers = (req, version_tag, description, extras = []) => {
|
|
|
167
167
|
headerTag: `<script>var _sc_globalCsrf = "${req.csrfToken()}"; var _sc_version_tag = "${version_tag}";</script>`,
|
|
168
168
|
},
|
|
169
169
|
{ css: `/static_assets/${version_tag}/saltcorn.css` },
|
|
170
|
+
{ script: `/static_assets/${version_tag}/saltcorn-common.js` },
|
|
170
171
|
{ script: `/static_assets/${version_tag}/saltcorn.js` },
|
|
171
172
|
];
|
|
172
173
|
let from_cfg = [];
|