@saltcorn/server 0.8.5-beta.3 → 0.8.5-beta.5
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 +23 -2
- package/auth/testhelp.js +15 -0
- package/locales/da.json +3 -1
- package/locales/en.json +26 -1
- package/locales/pl.json +17 -1
- package/markup/admin.js +15 -6
- package/package.json +8 -8
- package/public/saltcorn-common.js +30 -1
- package/public/saltcorn.css +27 -0
- package/public/saltcorn.js +3 -0
- package/public/serviceworker.js +1 -0
- package/public/vis-network.min.js +49 -0
- package/routes/admin.js +110 -219
- package/routes/api.js +66 -10
- package/routes/common_lists.js +1 -0
- package/routes/fields.js +11 -1
- package/routes/index.js +2 -0
- package/routes/list.js +8 -5
- package/routes/notifications.js +136 -0
- package/routes/plugins.js +47 -16
- package/routes/tables.js +160 -23
- package/routes/tenant.js +4 -0
- package/routes/utils.js +64 -1
- package/tests/api.test.js +2 -2
- package/tests/crud.test.js +53 -0
- package/tests/plugins.test.js +1 -1
- package/tests/table.test.js +17 -0
- package/wrapper.js +40 -3
package/tests/crud.test.js
CHANGED
|
@@ -13,6 +13,7 @@ const {
|
|
|
13
13
|
const db = require("@saltcorn/data/db");
|
|
14
14
|
const Table = require("@saltcorn/data/models/table");
|
|
15
15
|
const View = require("@saltcorn/data/models/view");
|
|
16
|
+
const Notification = require("@saltcorn/data/models/notification");
|
|
16
17
|
const User = require("@saltcorn/data/models/user");
|
|
17
18
|
const reset = require("@saltcorn/data/db/reset_schema");
|
|
18
19
|
|
|
@@ -42,6 +43,58 @@ describe("standard edit form", () => {
|
|
|
42
43
|
});
|
|
43
44
|
});
|
|
44
45
|
|
|
46
|
+
describe("notifications", () => {
|
|
47
|
+
it("show empty notifications", async () => {
|
|
48
|
+
const loginCookie = await getStaffLoginCookie();
|
|
49
|
+
const app = await getApp({ disableCsrf: true });
|
|
50
|
+
await request(app)
|
|
51
|
+
.get("/notifications")
|
|
52
|
+
.set("Cookie", loginCookie)
|
|
53
|
+
.expect(toInclude("No notifications"));
|
|
54
|
+
});
|
|
55
|
+
it("no unread notifications", async () => {
|
|
56
|
+
const loginCookie = await getStaffLoginCookie();
|
|
57
|
+
const app = await getApp({ disableCsrf: true });
|
|
58
|
+
await request(app)
|
|
59
|
+
.get("/notifications/count-unread")
|
|
60
|
+
.set("Cookie", loginCookie)
|
|
61
|
+
.expect(succeedJsonWith((n) => n === 0));
|
|
62
|
+
});
|
|
63
|
+
it("add notification", async () => {
|
|
64
|
+
const user = await User.findOne({ role_id: 4 });
|
|
65
|
+
await Notification.create({
|
|
66
|
+
user_id: user.id,
|
|
67
|
+
title: "This is a staff announcement",
|
|
68
|
+
body: "Will a member of staff please proceed to the checkout area",
|
|
69
|
+
link: "https://www.sainsburys.co.uk/",
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
it("one unread notifications", async () => {
|
|
73
|
+
const loginCookie = await getStaffLoginCookie();
|
|
74
|
+
const app = await getApp({ disableCsrf: true });
|
|
75
|
+
await request(app)
|
|
76
|
+
.get("/notifications/count-unread")
|
|
77
|
+
.set("Cookie", loginCookie)
|
|
78
|
+
.expect(succeedJsonWith((n) => n === 1));
|
|
79
|
+
});
|
|
80
|
+
it("show new notifications", async () => {
|
|
81
|
+
const loginCookie = await getStaffLoginCookie();
|
|
82
|
+
const app = await getApp({ disableCsrf: true });
|
|
83
|
+
await request(app)
|
|
84
|
+
.get("/notifications")
|
|
85
|
+
.set("Cookie", loginCookie)
|
|
86
|
+
.expect(toInclude("This is a staff announcement"))
|
|
87
|
+
.expect(toInclude("unread-notify"));
|
|
88
|
+
});
|
|
89
|
+
it("no unread notifications", async () => {
|
|
90
|
+
const loginCookie = await getStaffLoginCookie();
|
|
91
|
+
const app = await getApp({ disableCsrf: true });
|
|
92
|
+
await request(app)
|
|
93
|
+
.get("/notifications/count-unread")
|
|
94
|
+
.set("Cookie", loginCookie)
|
|
95
|
+
.expect(succeedJsonWith((n) => n === 0));
|
|
96
|
+
});
|
|
97
|
+
});
|
|
45
98
|
describe("homepage", () => {
|
|
46
99
|
it("shows to admin", async () => {
|
|
47
100
|
const loginCookie = await getAdminLoginCookie();
|
package/tests/plugins.test.js
CHANGED
|
@@ -318,7 +318,7 @@ describe("config endpoints", () => {
|
|
|
318
318
|
.send("site_name=FooSiteName")
|
|
319
319
|
.send("multitenancy_enabled=on")
|
|
320
320
|
.set("Cookie", loginCookie)
|
|
321
|
-
.expect(toRedirect("/admin"));
|
|
321
|
+
.expect(toRedirect("/admin/"));
|
|
322
322
|
await request(app)
|
|
323
323
|
.get("/admin")
|
|
324
324
|
.set("Cookie", loginCookie)
|
package/tests/table.test.js
CHANGED
|
@@ -5,11 +5,13 @@ const Field = require("@saltcorn/data/models/field");
|
|
|
5
5
|
const {
|
|
6
6
|
getStaffLoginCookie,
|
|
7
7
|
getAdminLoginCookie,
|
|
8
|
+
getUserLoginCookie,
|
|
8
9
|
itShouldRedirectUnauthToLogin,
|
|
9
10
|
toInclude,
|
|
10
11
|
toNotInclude,
|
|
11
12
|
toRedirect,
|
|
12
13
|
resetToFixtures,
|
|
14
|
+
succeedJsonWith,
|
|
13
15
|
} = require("../auth/testhelp");
|
|
14
16
|
const db = require("@saltcorn/data/db");
|
|
15
17
|
const User = require("@saltcorn/data/models/user");
|
|
@@ -262,7 +264,22 @@ describe("deletion to table with row ownership", () => {
|
|
|
262
264
|
const row = await persons.insertRow({ name: "something", owner: user.id });
|
|
263
265
|
expect(await persons.countRows()).toBe(1);
|
|
264
266
|
const loginCookie = await getStaffLoginCookie();
|
|
267
|
+
const uloginCookie = await getUserLoginCookie();
|
|
265
268
|
const app = await getApp({ disableCsrf: true });
|
|
269
|
+
await request(app).get("/api/owned").expect(401);
|
|
270
|
+
await request(app)
|
|
271
|
+
.get("/api/owned")
|
|
272
|
+
.set("Cookie", loginCookie)
|
|
273
|
+
.expect(
|
|
274
|
+
succeedJsonWith(
|
|
275
|
+
(rows) => rows.length == 1 && rows[0].name === "something"
|
|
276
|
+
)
|
|
277
|
+
);
|
|
278
|
+
await request(app)
|
|
279
|
+
.get("/api/owned")
|
|
280
|
+
.set("Cookie", uloginCookie)
|
|
281
|
+
.expect(succeedJsonWith((rows) => rows.length == 0));
|
|
282
|
+
|
|
266
283
|
await request(app)
|
|
267
284
|
.post("/delete/owned/" + row)
|
|
268
285
|
.expect(toRedirect("/list/owned"));
|
package/wrapper.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
const { getState } = require("@saltcorn/data/db/state");
|
|
6
6
|
const { get_extra_menu } = require("@saltcorn/data/web-mobile-commons");
|
|
7
7
|
//const db = require("@saltcorn/data/db");
|
|
8
|
-
const { h3, div, small } = require("@saltcorn/markup/tags");
|
|
8
|
+
const { h3, div, small, domReady } = require("@saltcorn/markup/tags");
|
|
9
9
|
const { renderForm, link } = require("@saltcorn/markup");
|
|
10
10
|
const renderLayout = require("@saltcorn/markup/layout");
|
|
11
11
|
/**
|
|
@@ -30,6 +30,7 @@ const get_menu = (req) => {
|
|
|
30
30
|
const role = (req.user || {}).role_id || 10;
|
|
31
31
|
|
|
32
32
|
const allow_signup = state.getConfig("allow_signup");
|
|
33
|
+
const notification_in_menu = state.getConfig("notification_in_menu");
|
|
33
34
|
const login_menu = state.getConfig("login_menu");
|
|
34
35
|
const locale = req.getLocale();
|
|
35
36
|
const __ = (s) => state.i18n.__({ phrase: s, locale }) || s;
|
|
@@ -42,6 +43,16 @@ const get_menu = (req) => {
|
|
|
42
43
|
isUser: true,
|
|
43
44
|
subitems: [
|
|
44
45
|
{ label: small((req.user.email || "").split("@")[0]) },
|
|
46
|
+
...(notification_in_menu
|
|
47
|
+
? [
|
|
48
|
+
{
|
|
49
|
+
label: req.__("Notifications"),
|
|
50
|
+
icon: "far fa-bell",
|
|
51
|
+
class: "notify-menu-item",
|
|
52
|
+
link: "/notifications",
|
|
53
|
+
},
|
|
54
|
+
]
|
|
55
|
+
: []),
|
|
45
56
|
{
|
|
46
57
|
label: req.__("User Settings"),
|
|
47
58
|
icon: "fas fa-user-cog",
|
|
@@ -58,10 +69,22 @@ const get_menu = (req) => {
|
|
|
58
69
|
]
|
|
59
70
|
: [
|
|
60
71
|
...(allow_signup
|
|
61
|
-
? [
|
|
72
|
+
? [
|
|
73
|
+
{
|
|
74
|
+
link: "/auth/signup",
|
|
75
|
+
icon: "fas fa-user-plus",
|
|
76
|
+
label: req.__("Sign up"),
|
|
77
|
+
},
|
|
78
|
+
]
|
|
62
79
|
: []),
|
|
63
80
|
...(login_menu
|
|
64
|
-
? [
|
|
81
|
+
? [
|
|
82
|
+
{
|
|
83
|
+
link: "/auth/login",
|
|
84
|
+
icon: "fas fa-sign-in-alt",
|
|
85
|
+
label: req.__("Login"),
|
|
86
|
+
},
|
|
87
|
+
]
|
|
65
88
|
: []),
|
|
66
89
|
];
|
|
67
90
|
// const schema = db.getTenantSchema();
|
|
@@ -141,6 +164,8 @@ const get_menu = (req) => {
|
|
|
141
164
|
const get_headers = (req, version_tag, description, extras = []) => {
|
|
142
165
|
const state = getState();
|
|
143
166
|
const favicon = state.getConfig("favicon_id", null);
|
|
167
|
+
const notification_in_menu = state.getConfig("notification_in_menu");
|
|
168
|
+
const pwa_enabled = state.getConfig("pwa_enabled");
|
|
144
169
|
|
|
145
170
|
const iconHeader = favicon
|
|
146
171
|
? [
|
|
@@ -175,6 +200,18 @@ const get_headers = (req, version_tag, description, extras = []) => {
|
|
|
175
200
|
for (const hs of Object.values(state.headers)) {
|
|
176
201
|
state_headers.push(...hs);
|
|
177
202
|
}
|
|
203
|
+
if (notification_in_menu)
|
|
204
|
+
from_cfg.push({ scriptBody: domReady(`check_saltcorn_notifications()`) });
|
|
205
|
+
if (pwa_enabled) {
|
|
206
|
+
from_cfg.push({
|
|
207
|
+
headerTag: `<link rel="manifest" href="/notifications/manifest.json">`,
|
|
208
|
+
});
|
|
209
|
+
from_cfg.push({
|
|
210
|
+
scriptBody: `if('serviceWorker' in navigator) {
|
|
211
|
+
navigator.serviceWorker.register('/serviceworker.js', { scope: '/' });
|
|
212
|
+
}`,
|
|
213
|
+
});
|
|
214
|
+
}
|
|
178
215
|
return [
|
|
179
216
|
...stdHeaders,
|
|
180
217
|
...iconHeader,
|