nodebb-plugin-web-push 0.1.0 → 0.3.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/lib/controllers.js +11 -3
- package/lib/subscriptions.js +15 -1
- package/library.js +12 -0
- package/package.json +4 -4
- package/plugin.json +0 -3
- package/public/languages/en-GB/web-push.json +5 -1
- package/public/lib/main.js +2 -0
- package/public/lib/settings.js +13 -7
- package/templates/account/web-push.tpl +4 -1
- package/templates/admin/plugins/web-push.tpl +26 -17
package/lib/controllers.js
CHANGED
|
@@ -17,7 +17,6 @@ Controllers.renderSettings = async function (req, res) {
|
|
|
17
17
|
user.getUserFields(res.locals.uid, ['username', 'userslug']),
|
|
18
18
|
subscriptions.count(req.uid),
|
|
19
19
|
]);
|
|
20
|
-
console.log(count);
|
|
21
20
|
|
|
22
21
|
const payload = {
|
|
23
22
|
...res.locals.userData,
|
|
@@ -29,8 +28,17 @@ Controllers.renderSettings = async function (req, res) {
|
|
|
29
28
|
res.render('account/web-push', payload);
|
|
30
29
|
};
|
|
31
30
|
|
|
32
|
-
Controllers.renderAdminPage =
|
|
31
|
+
Controllers.renderAdminPage = async (req, res/* , next */) => {
|
|
32
|
+
const countsByUser = await subscriptions.getUsers();
|
|
33
|
+
const uids = Array.from(countsByUser.keys());
|
|
34
|
+
let users = await user.getUsersFields(uids, ['uid', 'username', 'picture']);
|
|
35
|
+
users = users.map((user) => {
|
|
36
|
+
user.deviceCount = countsByUser.get(user.uid);
|
|
37
|
+
return user;
|
|
38
|
+
});
|
|
39
|
+
|
|
33
40
|
res.render('admin/plugins/web-push', {
|
|
34
|
-
title: '
|
|
41
|
+
title: 'Push Notifications',
|
|
42
|
+
users,
|
|
35
43
|
});
|
|
36
44
|
};
|
package/lib/subscriptions.js
CHANGED
|
@@ -6,6 +6,13 @@ const Subscriptions = module.exports;
|
|
|
6
6
|
|
|
7
7
|
Subscriptions.count = async uid => await db.sortedSetCard(`uid:${uid}:web-push:subscriptions`);
|
|
8
8
|
|
|
9
|
+
Subscriptions.getUsers = async () => {
|
|
10
|
+
const uids = await db.getSetMembers('web-push:uids');
|
|
11
|
+
const counts = await db.sortedSetsCard(uids.map(uid => `uid:${uid}:web-push:subscriptions`));
|
|
12
|
+
|
|
13
|
+
return new Map(uids.map((uid, idx) => [parseInt(uid, 10), counts[idx]]));
|
|
14
|
+
};
|
|
15
|
+
|
|
9
16
|
Subscriptions.list = async (uids) => {
|
|
10
17
|
const subscriptions = await db.getSortedSetsMembers(uids.map(uid => `uid:${uid}:web-push:subscriptions`));
|
|
11
18
|
const response = new Map();
|
|
@@ -17,9 +24,16 @@ Subscriptions.list = async (uids) => {
|
|
|
17
24
|
};
|
|
18
25
|
|
|
19
26
|
Subscriptions.add = async (uid, subscription) => {
|
|
20
|
-
await
|
|
27
|
+
await Promise.all([
|
|
28
|
+
db.sortedSetAdd(`uid:${uid}:web-push:subscriptions`, Date.now(), JSON.stringify(subscription)),
|
|
29
|
+
db.setAdd('web-push:uids', uid),
|
|
30
|
+
]);
|
|
21
31
|
};
|
|
22
32
|
|
|
23
33
|
Subscriptions.remove = async (uid, subscription) => {
|
|
24
34
|
await db.sortedSetRemove(`uid:${uid}:web-push:subscriptions`, JSON.stringify(subscription));
|
|
35
|
+
const count = await Subscriptions.count(uid);
|
|
36
|
+
if (count < 1) {
|
|
37
|
+
db.setRemove('web-push:uids', uid);
|
|
38
|
+
}
|
|
25
39
|
};
|
package/library.js
CHANGED
|
@@ -85,6 +85,18 @@ plugin.addRoutes = async ({ router, middleware, helpers }) => {
|
|
|
85
85
|
await subscriptions.remove(req.uid, subscription);
|
|
86
86
|
helpers.formatApiResponse(200, res);
|
|
87
87
|
});
|
|
88
|
+
|
|
89
|
+
routeHelpers.setupApiRoute(router, 'post', '/web-push/test', middlewares, async (req, res) => {
|
|
90
|
+
if (!req.uid) {
|
|
91
|
+
return helpers.notAllowed(req, res);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const { subscription } = req.body;
|
|
95
|
+
await webPush.sendNotification(subscription, JSON.stringify({
|
|
96
|
+
title: 'Test notification',
|
|
97
|
+
body: 'This is a test message sent from NodeBB',
|
|
98
|
+
}));
|
|
99
|
+
});
|
|
88
100
|
};
|
|
89
101
|
|
|
90
102
|
plugin.addAdminNavigation = (header) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nodebb-plugin-web-push",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "A starter kit for quickly creating NodeBB plugins",
|
|
5
5
|
"main": "library.js",
|
|
6
6
|
"repository": {
|
|
@@ -34,12 +34,12 @@
|
|
|
34
34
|
"compatibility": "^4.0.0"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
|
-
"@commitlint/cli": "19.
|
|
38
|
-
"@commitlint/config-angular": "19.
|
|
37
|
+
"@commitlint/cli": "19.5.0",
|
|
38
|
+
"@commitlint/config-angular": "19.5.0",
|
|
39
39
|
"eslint": "8.x",
|
|
40
40
|
"eslint-config-nodebb": "0.2.1",
|
|
41
41
|
"eslint-plugin-import": "2.x",
|
|
42
|
-
"husky": "9.1.
|
|
42
|
+
"husky": "9.1.6",
|
|
43
43
|
"lint-staged": "15.2.10"
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
package/plugin.json
CHANGED
|
@@ -11,9 +11,6 @@
|
|
|
11
11
|
{ "hook": "filter:user.profileMenu", "method": "addProfileItem" }
|
|
12
12
|
],
|
|
13
13
|
"languages": "public/languages",
|
|
14
|
-
"scripts": [
|
|
15
|
-
"public/lib/main.js"
|
|
16
|
-
],
|
|
17
14
|
"modules": {
|
|
18
15
|
"../client/account/web-push.js": "./public/lib/settings.js",
|
|
19
16
|
"../admin/plugins/web-push.js": "./public/lib/admin.js"
|
|
@@ -3,5 +3,9 @@
|
|
|
3
3
|
"profile.introduction": "In addition to in-application and email notifications, you may opt-in to receive push notifications as well. This will allow you to be notified even if the app is not open on your device.",
|
|
4
4
|
"profile.option": "Enable push notifications on this device",
|
|
5
5
|
"profile.devices": "Currently notifying <strong>%1</strong> device(s).",
|
|
6
|
-
"profile.permissionBlocked": "Your device is currently disallowing notifications from this site. Please grant the notification permission to continue."
|
|
6
|
+
"profile.permissionBlocked": "Your device is currently disallowing notifications from this site. Please grant the notification permission to continue.",
|
|
7
|
+
"profile.send-test": "Send Test Notification",
|
|
8
|
+
|
|
9
|
+
"toast.test_success": "Test notification sent.",
|
|
10
|
+
"toast.test_unavailable": "Cannot send test notification as push notifications are not enabled on this device."
|
|
7
11
|
}
|
package/public/lib/main.js
CHANGED
package/public/lib/settings.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
/* eslint-disable import/no-unresolved */
|
|
2
|
+
|
|
1
3
|
'use strict';
|
|
2
4
|
|
|
3
5
|
import { post, del } from 'api';
|
|
4
|
-
import { success } from 'alerts';
|
|
6
|
+
import { success, warning } from 'alerts';
|
|
5
7
|
|
|
6
8
|
// eslint-disable-next-line import/prefer-default-export
|
|
7
9
|
export async function init() {
|
|
@@ -16,11 +18,15 @@ export async function init() {
|
|
|
16
18
|
const action = e.target.getAttribute('data-action');
|
|
17
19
|
|
|
18
20
|
switch (action) {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
case 'test': {
|
|
22
|
+
if (subscription) {
|
|
23
|
+
await post('/plugins/web-push/test', { subscription });
|
|
24
|
+
success('[[web-push:toast.test_success]]');
|
|
25
|
+
} else {
|
|
26
|
+
warning('[[web-push:toast.test_unavailable]]');
|
|
27
|
+
}
|
|
28
|
+
break;
|
|
29
|
+
}
|
|
24
30
|
|
|
25
31
|
case 'toggle': {
|
|
26
32
|
const countEl = document.querySelector('#deviceCount strong');
|
|
@@ -77,7 +83,7 @@ export async function init() {
|
|
|
77
83
|
function urlBase64ToUint8Array(base64String) {
|
|
78
84
|
var padding = '='.repeat((4 - (base64String.length % 4)) % 4);
|
|
79
85
|
var base64 = (base64String + padding)
|
|
80
|
-
.replace(
|
|
86
|
+
.replace(/-/g, '+')
|
|
81
87
|
.replace(/_/g, '/');
|
|
82
88
|
|
|
83
89
|
var rawData = window.atob(base64);
|
|
@@ -7,11 +7,14 @@
|
|
|
7
7
|
<div class="alert alert-warning d-none" id="permission-warning">[[web-push:profile.permissionBlocked]]</div>
|
|
8
8
|
|
|
9
9
|
<form role="form">
|
|
10
|
-
<div class="form-check form-switch">
|
|
10
|
+
<div class="form-check form-switch mb-3">
|
|
11
11
|
<input type="checkbox" class="form-check-input" id="enabled" name="enabled" autocomplete="off" data-action="toggle">
|
|
12
12
|
<label for="enabled" class="form-check-label">[[web-push:profile.option]]</label>
|
|
13
13
|
<p class="form-text" id="deviceCount">[[web-push:profile.devices, {count}]]</p>
|
|
14
14
|
</div>
|
|
15
|
+
<div class="mb-3">
|
|
16
|
+
<button type="button" class="btn btn-primary" data-action="test">[[web-push:profile.send-test]]</button>
|
|
17
|
+
</div>
|
|
15
18
|
</form>
|
|
16
19
|
|
|
17
20
|
<!-- IMPORT partials/account/footer.tpl -->
|
|
@@ -5,27 +5,36 @@
|
|
|
5
5
|
<div id="spy-container" class="col-12 col-md-8 px-0 mb-4" tabindex="0">
|
|
6
6
|
<form role="form" class="web-push-settings">
|
|
7
7
|
<div class="mb-4">
|
|
8
|
-
<h5 class="fw-bold tracking-tight settings-header">
|
|
8
|
+
<h5 class="fw-bold tracking-tight settings-header">Settings</h5>
|
|
9
9
|
|
|
10
|
-
<p class="
|
|
11
|
-
|
|
12
|
-
<br/><code>await meta.settings.get('web-push');</code>
|
|
10
|
+
<p class="fst-italic">
|
|
11
|
+
There are no settings to adjust for this plugin — at this time.
|
|
13
12
|
</p>
|
|
14
|
-
<div class="mb-3">
|
|
15
|
-
<label class="form-label" for="setting-1">Setting 1</label>
|
|
16
|
-
<input type="text" id="setting-1" name="setting-1" title="Setting 1" class="form-control" placeholder="Setting 1">
|
|
17
|
-
</div>
|
|
18
|
-
<div class="mb-3">
|
|
19
|
-
<label class="form-label" for="setting-2">Setting 2</label>
|
|
20
|
-
<input type="text" id="setting-2" name="setting-2" title="Setting 2" class="form-control" placeholder="Setting 2">
|
|
21
|
-
</div>
|
|
22
|
-
|
|
23
|
-
<div class="form-check form-switch">
|
|
24
|
-
<input type="checkbox" class="form-check-input" id="setting-3" name="setting-3">
|
|
25
|
-
<label for="setting-3" class="form-check-label">Setting 3</label>
|
|
26
|
-
</div>
|
|
27
13
|
</div>
|
|
28
14
|
</form>
|
|
15
|
+
|
|
16
|
+
<div class="mb-4">
|
|
17
|
+
<h5 class="fw-bold tracking-tight settings-header">Users</h5>
|
|
18
|
+
<table class="table">
|
|
19
|
+
<thead>
|
|
20
|
+
<tr>
|
|
21
|
+
<th>User</th>
|
|
22
|
+
<th>Devices</th>
|
|
23
|
+
</tr>
|
|
24
|
+
</thead>
|
|
25
|
+
<tbody>
|
|
26
|
+
{{{ each users }}}
|
|
27
|
+
<tr>
|
|
28
|
+
<td>
|
|
29
|
+
{buildAvatar(users, "24px", false)}
|
|
30
|
+
{./username}
|
|
31
|
+
</td>
|
|
32
|
+
<td>{./deviceCount}</td>
|
|
33
|
+
</tr>
|
|
34
|
+
{{{ end }}}
|
|
35
|
+
</tbody>
|
|
36
|
+
</table>
|
|
37
|
+
</div>
|
|
29
38
|
</div>
|
|
30
39
|
|
|
31
40
|
<!-- IMPORT admin/partials/settings/toc.tpl -->
|