@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.
@@ -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();
@@ -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)
@@ -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
- ? [{ link: "/auth/signup", label: req.__("Sign up") }]
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
- ? [{ link: "/auth/login", label: req.__("Login") }]
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,