@saltcorn/server 0.9.1-beta.0 → 0.9.1-beta.10
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/auth/admin.js +1 -1
- package/auth/routes.js +4 -6
- package/help/API actions.tmd +20 -1
- package/help/Event types.tmd +78 -0
- package/help/Extra state formula.tmd +12 -0
- package/help/JavaScript action code.tmd +1 -14
- package/locales/en.json +11 -1
- package/package.json +13 -13
- package/public/saltcorn-common.js +135 -54
- package/public/saltcorn.css +1 -0
- package/public/saltcorn.js +2 -11
- package/routes/actions.js +2 -1
- package/routes/api.js +10 -2
- package/routes/fields.js +28 -1
- package/routes/homepage.js +86 -12
- package/routes/page.js +27 -21
- package/routes/pageedit.js +185 -26
- package/routes/utils.js +36 -0
- package/routes/view.js +8 -7
- package/s3storage.js +6 -5
- package/tests/fields.test.js +37 -1
- package/tests/page.test.js +123 -1
- package/tests/table.test.js +5 -1
- package/tests/view.test.js +97 -0
- package/wrapper.js +8 -1
package/tests/fields.test.js
CHANGED
|
@@ -364,7 +364,43 @@ describe("Field Endpoints", () => {
|
|
|
364
364
|
await request(app)
|
|
365
365
|
.post("/field/show-calculated/books/pagesp1/show")
|
|
366
366
|
.set("Cookie", loginCookie)
|
|
367
|
-
.expect((r) => +r.body >
|
|
367
|
+
.expect((r) => +r.body > 2);
|
|
368
|
+
});
|
|
369
|
+
it("should show calculated with single joinfield", async () => {
|
|
370
|
+
const loginCookie = await getAdminLoginCookie();
|
|
371
|
+
const table = Table.findOne({ name: "patients" });
|
|
372
|
+
await Field.create({
|
|
373
|
+
table,
|
|
374
|
+
label: "pagesp1",
|
|
375
|
+
type: "Integer",
|
|
376
|
+
calculated: true,
|
|
377
|
+
stored: true,
|
|
378
|
+
expression: "favbook.pages+1",
|
|
379
|
+
});
|
|
380
|
+
const app = await getApp({ disableCsrf: true });
|
|
381
|
+
|
|
382
|
+
await request(app)
|
|
383
|
+
.post("/field/show-calculated/patients/pagesp1/show")
|
|
384
|
+
.set("Cookie", loginCookie)
|
|
385
|
+
.expect((r) => +r.body > 2);
|
|
386
|
+
});
|
|
387
|
+
it("should show calculated with double joinfield", async () => {
|
|
388
|
+
const loginCookie = await getAdminLoginCookie();
|
|
389
|
+
const table = Table.findOne({ name: "readings" });
|
|
390
|
+
await Field.create({
|
|
391
|
+
table,
|
|
392
|
+
label: "pagesp1",
|
|
393
|
+
type: "Integer",
|
|
394
|
+
calculated: true,
|
|
395
|
+
stored: true,
|
|
396
|
+
expression: "patient_id.favbook.pages+1",
|
|
397
|
+
});
|
|
398
|
+
const app = await getApp({ disableCsrf: true });
|
|
399
|
+
|
|
400
|
+
await request(app)
|
|
401
|
+
.post("/field/show-calculated/readings/pagesp1/show")
|
|
402
|
+
.set("Cookie", loginCookie)
|
|
403
|
+
.expect((r) => +r.body > 2);
|
|
368
404
|
});
|
|
369
405
|
});
|
|
370
406
|
|
package/tests/page.test.js
CHANGED
|
@@ -13,9 +13,39 @@ const {
|
|
|
13
13
|
} = require("../auth/testhelp");
|
|
14
14
|
const db = require("@saltcorn/data/db");
|
|
15
15
|
const Page = require("@saltcorn/data/models/page");
|
|
16
|
+
const File = require("@saltcorn/data/models/file");
|
|
17
|
+
const { existsSync } = require("fs");
|
|
18
|
+
const { join } = require("path");
|
|
19
|
+
const fs = require("fs");
|
|
20
|
+
|
|
21
|
+
let htmlFile = null;
|
|
22
|
+
|
|
23
|
+
const prepHtmlFiles = async () => {
|
|
24
|
+
const createFile = async (folder, name, content) => {
|
|
25
|
+
const scFolder = join(
|
|
26
|
+
db.connectObj.file_store,
|
|
27
|
+
db.getTenantSchema(),
|
|
28
|
+
folder
|
|
29
|
+
);
|
|
30
|
+
const html = `<html><head><title>Landing page</title></head><body><h1>${content}</h1></body></html>`;
|
|
31
|
+
if (!existsSync(scFolder)) await File.new_folder(folder);
|
|
32
|
+
if (!existsSync(join(scFolder, name))) {
|
|
33
|
+
return await File.from_contents(name, "text/html", html, 1, 1, folder);
|
|
34
|
+
} else {
|
|
35
|
+
const file = await File.from_file_on_disk(name, scFolder);
|
|
36
|
+
fs.writeFileSync(file.location, html);
|
|
37
|
+
file.location = File.absPathToServePath(file.location);
|
|
38
|
+
return file;
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
htmlFile = await createFile("/", "fixed_page.html", "Land here");
|
|
42
|
+
await createFile("/subfolder", "fixed_page2.html", "Or Land here");
|
|
43
|
+
await createFile("/", "test.html", "page with fixed html");
|
|
44
|
+
};
|
|
16
45
|
|
|
17
46
|
beforeAll(async () => {
|
|
18
47
|
await resetToFixtures();
|
|
48
|
+
await prepHtmlFiles();
|
|
19
49
|
});
|
|
20
50
|
afterAll(db.close);
|
|
21
51
|
|
|
@@ -36,9 +66,18 @@ describe("page create", () => {
|
|
|
36
66
|
await request(app)
|
|
37
67
|
.get("/pageedit/new")
|
|
38
68
|
.set("Cookie", loginCookie)
|
|
39
|
-
|
|
40
69
|
.expect(toInclude("A short name that will be in your URL"));
|
|
41
70
|
});
|
|
71
|
+
it("shows new with html file selector", async () => {
|
|
72
|
+
const app = await getApp({ disableCsrf: true });
|
|
73
|
+
const loginCookie = await getAdminLoginCookie();
|
|
74
|
+
await request(app)
|
|
75
|
+
.get("/pageedit/new")
|
|
76
|
+
.set("Cookie", loginCookie)
|
|
77
|
+
.expect(toInclude("HTML file"))
|
|
78
|
+
.expect(toInclude("fixed_page.html"))
|
|
79
|
+
.expect(toInclude(join("subfolder", "fixed_page2.html")));
|
|
80
|
+
});
|
|
42
81
|
it("fills basic details", async () => {
|
|
43
82
|
const app = await getApp({ disableCsrf: true });
|
|
44
83
|
const loginCookie = await getAdminLoginCookie();
|
|
@@ -48,6 +87,19 @@ describe("page create", () => {
|
|
|
48
87
|
.set("Cookie", loginCookie)
|
|
49
88
|
.expect(toRedirect("/pageedit/edit/whales"));
|
|
50
89
|
});
|
|
90
|
+
it("fills details with html-file", async () => {
|
|
91
|
+
const app = await getApp({ disableCsrf: true });
|
|
92
|
+
const loginCookie = await getAdminLoginCookie();
|
|
93
|
+
await request(app)
|
|
94
|
+
.post("/pageedit/edit-properties")
|
|
95
|
+
.send(
|
|
96
|
+
`name=new_page_with_html_file&title=foo&description=bar&min_role=100&html_file=${encodeURIComponent(
|
|
97
|
+
htmlFile.location
|
|
98
|
+
)}`
|
|
99
|
+
)
|
|
100
|
+
.set("Cookie", loginCookie)
|
|
101
|
+
.expect(toRedirect("/pageedit/"));
|
|
102
|
+
});
|
|
51
103
|
it("fills layout", async () => {
|
|
52
104
|
const app = await getApp({ disableCsrf: true });
|
|
53
105
|
const loginCookie = await getAdminLoginCookie();
|
|
@@ -68,6 +120,49 @@ describe("page create", () => {
|
|
|
68
120
|
.set("Cookie", loginCookie)
|
|
69
121
|
.expect(toInclude("Herman"));
|
|
70
122
|
});
|
|
123
|
+
|
|
124
|
+
it("shows page with html file", async () => {
|
|
125
|
+
const app = await getApp({ disableCsrf: true });
|
|
126
|
+
const loginCookie = await getAdminLoginCookie();
|
|
127
|
+
await request(app)
|
|
128
|
+
.get("/page/new_page_with_html_file")
|
|
129
|
+
.set("Cookie", loginCookie)
|
|
130
|
+
.expect(toInclude("Land here"));
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it("does not find the html file for staff or public", async () => {
|
|
134
|
+
const app = await getApp({ disableCsrf: true });
|
|
135
|
+
await request(app)
|
|
136
|
+
.post(`/files/setrole/fixed_page.html`)
|
|
137
|
+
.set("Cookie", await getAdminLoginCookie())
|
|
138
|
+
.send("role=1")
|
|
139
|
+
.expect(toRedirect("/files?dir=."));
|
|
140
|
+
const loginCookie = await getStaffLoginCookie();
|
|
141
|
+
await request(app)
|
|
142
|
+
.get("/page/new_page_with_html_file")
|
|
143
|
+
.set("Cookie", loginCookie)
|
|
144
|
+
.expect(toInclude("not found", 404));
|
|
145
|
+
await request(app)
|
|
146
|
+
.get("/page/new_page_with_html_file")
|
|
147
|
+
.expect(toInclude("not found", 404));
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it("finds the html file for staff (after update)", async () => {
|
|
151
|
+
const app = await getApp({ disableCsrf: true });
|
|
152
|
+
await request(app)
|
|
153
|
+
.post("/files/setrole/fixed_page.html")
|
|
154
|
+
.set("Cookie", await getAdminLoginCookie())
|
|
155
|
+
.send("role=40")
|
|
156
|
+
.expect(toRedirect("/files?dir=."));
|
|
157
|
+
const loginCookie = await getStaffLoginCookie();
|
|
158
|
+
await request(app)
|
|
159
|
+
.get("/page/new_page_with_html_file")
|
|
160
|
+
.set("Cookie", loginCookie)
|
|
161
|
+
.expect(toInclude("Land here"));
|
|
162
|
+
await request(app)
|
|
163
|
+
.get("/page/new_page_with_html_file")
|
|
164
|
+
.expect(toInclude("not found", 404));
|
|
165
|
+
});
|
|
71
166
|
});
|
|
72
167
|
|
|
73
168
|
describe("page action", () => {
|
|
@@ -154,6 +249,33 @@ describe("pageedit", () => {
|
|
|
154
249
|
.set("Cookie", loginCookie)
|
|
155
250
|
.expect(toInclude("<script>builder.renderBuilder"));
|
|
156
251
|
});
|
|
252
|
+
it("show editor with html file", async () => {
|
|
253
|
+
const app = await getApp({ disableCsrf: true });
|
|
254
|
+
const loginCookie = await getAdminLoginCookie();
|
|
255
|
+
await request(app)
|
|
256
|
+
.get("/pageedit/edit/page_with_html_file")
|
|
257
|
+
.set("Cookie", loginCookie)
|
|
258
|
+
.expect(toInclude(`<textarea mode="text/html"`));
|
|
259
|
+
});
|
|
260
|
+
it("edit editor with html file", async () => {
|
|
261
|
+
const app = await getApp({ disableCsrf: true });
|
|
262
|
+
const loginCookie = await getAdminLoginCookie();
|
|
263
|
+
const newHtml =
|
|
264
|
+
"<html><head><title>title</title></head><body><h1>new html</h1></body</html>";
|
|
265
|
+
await request(app)
|
|
266
|
+
.get("/page/page_with_html_file")
|
|
267
|
+
.set("Cookie", loginCookie)
|
|
268
|
+
.expect(toInclude("page with fixed html"));
|
|
269
|
+
await request(app)
|
|
270
|
+
.post("/pageedit/edit/page_with_html_file")
|
|
271
|
+
.set("Cookie", loginCookie)
|
|
272
|
+
.send("code=" + encodeURIComponent(newHtml))
|
|
273
|
+
.expect(toRedirect("/pageedit"));
|
|
274
|
+
await request(app)
|
|
275
|
+
.get("/page/page_with_html_file")
|
|
276
|
+
.set("Cookie", loginCookie)
|
|
277
|
+
.expect(toInclude("new html"));
|
|
278
|
+
});
|
|
157
279
|
|
|
158
280
|
it("sets root page", async () => {
|
|
159
281
|
const app = await getApp({ disableCsrf: true });
|
package/tests/table.test.js
CHANGED
|
@@ -17,8 +17,12 @@ const db = require("@saltcorn/data/db");
|
|
|
17
17
|
const User = require("@saltcorn/data/models/user");
|
|
18
18
|
const { plugin_with_routes } = require("@saltcorn/data/tests/mocks");
|
|
19
19
|
const { getState } = require("@saltcorn/data/db/state");
|
|
20
|
+
const { sleep } = require("@saltcorn/data/utils");
|
|
20
21
|
|
|
21
|
-
afterAll(
|
|
22
|
+
afterAll(async () => {
|
|
23
|
+
await sleep(200);
|
|
24
|
+
await db.close();
|
|
25
|
+
});
|
|
22
26
|
beforeAll(async () => {
|
|
23
27
|
await resetToFixtures();
|
|
24
28
|
});
|
package/tests/view.test.js
CHANGED
|
@@ -17,6 +17,9 @@ const View = require("@saltcorn/data/models/view");
|
|
|
17
17
|
const Table = require("@saltcorn/data/models/table");
|
|
18
18
|
|
|
19
19
|
const { plugin_with_routes } = require("@saltcorn/data/tests/mocks");
|
|
20
|
+
const {
|
|
21
|
+
prepareArtistsAlbumRelation,
|
|
22
|
+
} = require("@saltcorn/data/tests/common_helpers");
|
|
20
23
|
|
|
21
24
|
afterAll(db.close);
|
|
22
25
|
beforeAll(async () => {
|
|
@@ -586,3 +589,97 @@ describe("inbound relations", () => {
|
|
|
586
589
|
.expect(toNotInclude("Content of post CPost C"));
|
|
587
590
|
});
|
|
588
591
|
});
|
|
592
|
+
|
|
593
|
+
describe("many to many relations", () => {
|
|
594
|
+
beforeAll(async () => {
|
|
595
|
+
await prepareArtistsAlbumRelation();
|
|
596
|
+
});
|
|
597
|
+
|
|
598
|
+
it("artist_plays_on_album", async () => {
|
|
599
|
+
const app = await getApp({ disableCsrf: true });
|
|
600
|
+
const loginCookie = await getAdminLoginCookie();
|
|
601
|
+
await request(app)
|
|
602
|
+
.get("/view/show_artist?id=1")
|
|
603
|
+
.set("Cookie", loginCookie)
|
|
604
|
+
.expect(toInclude("album A"))
|
|
605
|
+
.expect(toInclude("album B"));
|
|
606
|
+
|
|
607
|
+
await request(app)
|
|
608
|
+
.get("/view/show_artist?id=2")
|
|
609
|
+
.set("Cookie", loginCookie)
|
|
610
|
+
.expect(toInclude("album A"))
|
|
611
|
+
.expect(toNotInclude("album B"));
|
|
612
|
+
});
|
|
613
|
+
|
|
614
|
+
it("albums feed with query", async () => {
|
|
615
|
+
const app = await getApp({ disableCsrf: true });
|
|
616
|
+
const loginCookie = await getAdminLoginCookie();
|
|
617
|
+
|
|
618
|
+
const queryObj_1 = {
|
|
619
|
+
relation: ".artists.artist_plays_on_album$artist.album",
|
|
620
|
+
srcId: 1,
|
|
621
|
+
};
|
|
622
|
+
await request(app)
|
|
623
|
+
.get(
|
|
624
|
+
`/view/albums_feed?_inbound_relation_path_=${encodeURIComponent(
|
|
625
|
+
JSON.stringify(queryObj_1)
|
|
626
|
+
)}`
|
|
627
|
+
)
|
|
628
|
+
.set("Cookie", loginCookie)
|
|
629
|
+
.expect(toInclude("album A"))
|
|
630
|
+
.expect(toInclude("album B"));
|
|
631
|
+
|
|
632
|
+
const queryObj_2 = {
|
|
633
|
+
relation: ".artists.artist_plays_on_album$artist.album",
|
|
634
|
+
srcId: 2,
|
|
635
|
+
};
|
|
636
|
+
await request(app)
|
|
637
|
+
.get(
|
|
638
|
+
`/view/albums_feed?_inbound_relation_path_=${encodeURIComponent(
|
|
639
|
+
JSON.stringify(queryObj_2)
|
|
640
|
+
)}`
|
|
641
|
+
)
|
|
642
|
+
.set("Cookie", loginCookie)
|
|
643
|
+
.expect(toInclude("album A"))
|
|
644
|
+
.expect(toNotInclude("album B"));
|
|
645
|
+
});
|
|
646
|
+
|
|
647
|
+
it("fan_club feed with query", async () => {
|
|
648
|
+
const app = await getApp({ disableCsrf: true });
|
|
649
|
+
const loginCookie = await getAdminLoginCookie();
|
|
650
|
+
|
|
651
|
+
const queryObj_1 = {
|
|
652
|
+
relation:
|
|
653
|
+
".pressing_job.album.artist_plays_on_album$album.artist.fan_club$artist",
|
|
654
|
+
srcId: 1,
|
|
655
|
+
};
|
|
656
|
+
await request(app)
|
|
657
|
+
.get(
|
|
658
|
+
`/view/fan_club_feed?_inbound_relation_path_=${encodeURIComponent(
|
|
659
|
+
JSON.stringify(queryObj_1)
|
|
660
|
+
)}`
|
|
661
|
+
)
|
|
662
|
+
.set("Cookie", loginCookie)
|
|
663
|
+
.expect(toInclude("crazy fan club"))
|
|
664
|
+
.expect(toInclude("another club"))
|
|
665
|
+
.expect(toInclude("fan club"))
|
|
666
|
+
.expect(toInclude("fan club official"));
|
|
667
|
+
|
|
668
|
+
const queryObj_2 = {
|
|
669
|
+
relation:
|
|
670
|
+
".pressing_job.album.artist_plays_on_album$album.artist.fan_club$artist",
|
|
671
|
+
srcId: 2,
|
|
672
|
+
};
|
|
673
|
+
await request(app)
|
|
674
|
+
.get(
|
|
675
|
+
`/view/fan_club_feed?_inbound_relation_path_=${encodeURIComponent(
|
|
676
|
+
JSON.stringify(queryObj_2)
|
|
677
|
+
)}`
|
|
678
|
+
)
|
|
679
|
+
.set("Cookie", loginCookie)
|
|
680
|
+
.expect(toInclude("crazy fan club"))
|
|
681
|
+
.expect(toNotInclude("another club"))
|
|
682
|
+
.expect(toInclude("fan club"))
|
|
683
|
+
.expect(toInclude("fan club official"));
|
|
684
|
+
});
|
|
685
|
+
});
|
package/wrapper.js
CHANGED
|
@@ -316,7 +316,14 @@ module.exports = (version_tag) =>
|
|
|
316
316
|
if (req.xhr) {
|
|
317
317
|
const renderToHtml = layout.renderBody
|
|
318
318
|
? (h, role, req) =>
|
|
319
|
-
layout.renderBody({
|
|
319
|
+
layout.renderBody({
|
|
320
|
+
title,
|
|
321
|
+
body: h,
|
|
322
|
+
role,
|
|
323
|
+
alerts,
|
|
324
|
+
req,
|
|
325
|
+
hints: layout.hints,
|
|
326
|
+
})
|
|
320
327
|
: defaultRenderToHtml;
|
|
321
328
|
res.header(
|
|
322
329
|
"Cache-Control",
|