refactor: removed unnecessary code when sending web push notification
This commit is contained in:
@@ -5,4 +5,4 @@ config/
|
||||
|
||||
# assets
|
||||
src/assets/
|
||||
# public/
|
||||
public/
|
||||
|
||||
78
public/sw.js
78
public/sw.js
@@ -4,30 +4,30 @@
|
||||
// This variable is intentionally declared and unused.
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const OFFLINE_VERSION = 3;
|
||||
const CACHE_NAME = 'offline';
|
||||
const CACHE_NAME = "offline";
|
||||
// Customize this with a different URL if needed.
|
||||
const OFFLINE_URL = '/offline.html';
|
||||
const OFFLINE_URL = "/offline.html";
|
||||
|
||||
self.addEventListener('install', (event) => {
|
||||
self.addEventListener("install", (event) => {
|
||||
event.waitUntil(
|
||||
(async () => {
|
||||
const cache = await caches.open(CACHE_NAME);
|
||||
// Setting {cache: 'reload'} in the new request will ensure that the
|
||||
// response isn't fulfilled from the HTTP cache; i.e., it will be from
|
||||
// the network.
|
||||
await cache.add(new Request(OFFLINE_URL, { cache: 'reload' }));
|
||||
await cache.add(new Request(OFFLINE_URL, { cache: "reload" }));
|
||||
})()
|
||||
);
|
||||
// Force the waiting service worker to become the active service worker.
|
||||
self.skipWaiting();
|
||||
});
|
||||
|
||||
self.addEventListener('activate', (event) => {
|
||||
self.addEventListener("activate", (event) => {
|
||||
event.waitUntil(
|
||||
(async () => {
|
||||
// Enable navigation preload if it's supported.
|
||||
// See https://developers.google.com/web/updates/2017/02/navigation-preload
|
||||
if ('navigationPreload' in self.registration) {
|
||||
if ("navigationPreload" in self.registration) {
|
||||
await self.registration.navigationPreload.enable();
|
||||
}
|
||||
})()
|
||||
@@ -37,10 +37,10 @@ self.addEventListener('activate', (event) => {
|
||||
clients.claim();
|
||||
});
|
||||
|
||||
self.addEventListener('fetch', (event) => {
|
||||
self.addEventListener("fetch", (event) => {
|
||||
// We only want to call event.respondWith() if this is a navigation request
|
||||
// for an HTML page.
|
||||
if (event.request.mode === 'navigate') {
|
||||
if (event.request.mode === "navigate") {
|
||||
event.respondWith(
|
||||
(async () => {
|
||||
try {
|
||||
@@ -59,7 +59,7 @@ self.addEventListener('fetch', (event) => {
|
||||
// If fetch() returns a valid HTTP response with a response code in
|
||||
// the 4xx or 5xx range, the catch() will NOT be called.
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('Fetch failed; returning offline page instead.', error);
|
||||
console.log("Fetch failed; returning offline page instead.", error);
|
||||
|
||||
const cache = await caches.open(CACHE_NAME);
|
||||
const cachedResponse = await cache.match(OFFLINE_URL);
|
||||
@@ -70,7 +70,7 @@ self.addEventListener('fetch', (event) => {
|
||||
}
|
||||
});
|
||||
|
||||
self.addEventListener('push', async (event) => {
|
||||
self.addEventListener('push', (event) => {
|
||||
const payload = event.data ? event.data.json() : {};
|
||||
|
||||
const options = {
|
||||
@@ -85,13 +85,15 @@ self.addEventListener('push', async (event) => {
|
||||
requestId: payload.requestId,
|
||||
},
|
||||
actions: [],
|
||||
};
|
||||
}
|
||||
|
||||
if (payload.actionUrl) {
|
||||
options.actions.push({
|
||||
action: 'view',
|
||||
title: payload.actionUrlTitle ?? 'View',
|
||||
});
|
||||
if (payload.actionUrl){
|
||||
options.actions.push(
|
||||
{
|
||||
action: 'view',
|
||||
title: payload.actionUrlTitle ?? 'View',
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
if (payload.notificationType === 'MEDIA_PENDING') {
|
||||
@@ -107,10 +109,12 @@ self.addEventListener('push', async (event) => {
|
||||
);
|
||||
}
|
||||
|
||||
//Set the badge with the amount of pending requests
|
||||
//Only update the badge if the payload confirms they are the admin
|
||||
if (
|
||||
(payload.notificationType === 'MEDIA_APPROVED' ||
|
||||
payload.notificationType === 'MEDIA_DECLINED') &&
|
||||
payload.isAdmin === true
|
||||
payload.isAdmin
|
||||
) {
|
||||
if ('setAppBadge' in navigator) {
|
||||
navigator.setAppBadge(payload.pendingRequestsCount);
|
||||
@@ -124,29 +128,27 @@ self.addEventListener('push', async (event) => {
|
||||
}
|
||||
}
|
||||
|
||||
event.waitUntil(self.registration.showNotification(payload.subject, options));
|
||||
event.waitUntil(
|
||||
self.registration.showNotification(payload.subject, options)
|
||||
);
|
||||
});
|
||||
|
||||
self.addEventListener(
|
||||
'notificationclick',
|
||||
async (event) => {
|
||||
const notificationData = event.notification.data;
|
||||
self.addEventListener('notificationclick', (event) => {
|
||||
const notificationData = event.notification.data;
|
||||
|
||||
event.notification.close();
|
||||
event.notification.close();
|
||||
|
||||
if (event.action === 'approve') {
|
||||
fetch(`/api/v1/request/${notificationData.requestId}/approve`, {
|
||||
method: 'POST',
|
||||
});
|
||||
} else if (event.action === 'decline') {
|
||||
fetch(`/api/v1/request/${notificationData.requestId}/decline`, {
|
||||
method: 'POST',
|
||||
});
|
||||
}
|
||||
if (event.action === 'approve') {
|
||||
fetch(`/api/v1/request/${notificationData.requestId}/approve`, {
|
||||
method: 'POST',
|
||||
});
|
||||
} else if (event.action === 'decline') {
|
||||
fetch(`/api/v1/request/${notificationData.requestId}/decline`, {
|
||||
method: 'POST',
|
||||
});
|
||||
}
|
||||
|
||||
if (notificationData.actionUrl) {
|
||||
clients.openWindow(notificationData.actionUrl);
|
||||
}
|
||||
},
|
||||
false
|
||||
);
|
||||
if (notificationData.actionUrl) {
|
||||
clients.openWindow(notificationData.actionUrl);
|
||||
}
|
||||
}, false);
|
||||
|
||||
@@ -1178,11 +1178,9 @@ export class MediaRequest {
|
||||
switch (type) {
|
||||
case Notification.MEDIA_APPROVED:
|
||||
event = `${this.is4k ? '4K ' : ''}${mediaType} Request Approved`;
|
||||
notifyAdmin = false;
|
||||
break;
|
||||
case Notification.MEDIA_DECLINED:
|
||||
event = `${this.is4k ? '4K ' : ''}${mediaType} Request Declined`;
|
||||
notifyAdmin = false;
|
||||
break;
|
||||
case Notification.MEDIA_PENDING:
|
||||
event = `New ${this.is4k ? '4K ' : ''}${mediaType} Request`;
|
||||
@@ -1211,7 +1209,9 @@ export class MediaRequest {
|
||||
request: this,
|
||||
notifyAdmin,
|
||||
notifySystem,
|
||||
notifyUser: notifyAdmin ? undefined : this.requestedBy,
|
||||
notifyUser: Notification.MEDIA_AUTO_REQUESTED
|
||||
? this.requestedBy
|
||||
: undefined,
|
||||
event,
|
||||
subject: `${movie.title}${
|
||||
movie.release_date ? ` (${movie.release_date.slice(0, 4)})` : ''
|
||||
|
||||
@@ -156,6 +156,45 @@ class WebPushAgent
|
||||
|
||||
const mainUser = await userRepository.findOne({ where: { id: 1 } });
|
||||
|
||||
const webPushNotification = async (
|
||||
pushSub: UserPushSubscription,
|
||||
notificationPayload: Buffer
|
||||
) => {
|
||||
logger.debug('Sending web push notification', {
|
||||
label: 'Notifications',
|
||||
recipient: pushSub.user.displayName,
|
||||
type: Notification[type],
|
||||
subject: payload.subject,
|
||||
});
|
||||
|
||||
try {
|
||||
await webpush.sendNotification(
|
||||
{
|
||||
endpoint: pushSub.endpoint,
|
||||
keys: {
|
||||
auth: pushSub.auth,
|
||||
p256dh: pushSub.p256dh,
|
||||
},
|
||||
},
|
||||
notificationPayload
|
||||
);
|
||||
} catch (e) {
|
||||
logger.error(
|
||||
'Error sending web push notification; removing subscription',
|
||||
{
|
||||
label: 'Notifications',
|
||||
recipient: pushSub.user.displayName,
|
||||
type: Notification[type],
|
||||
subject: payload.subject,
|
||||
errorMessage: e.message,
|
||||
}
|
||||
);
|
||||
|
||||
// Failed to send notification so we need to remove the subscription
|
||||
userPushSubRepository.remove(pushSub);
|
||||
}
|
||||
};
|
||||
|
||||
if (
|
||||
payload.notifyUser &&
|
||||
// Check if user has webpush notifications enabled and fallback to true if undefined
|
||||
@@ -196,97 +235,38 @@ class WebPushAgent
|
||||
})
|
||||
.getMany();
|
||||
|
||||
pushSubs.push(...allSubs);
|
||||
}
|
||||
if (
|
||||
type === Notification.MEDIA_APPROVED ||
|
||||
type === Notification.MEDIA_DECLINED
|
||||
) {
|
||||
if (mainUser && allSubs.length > 0) {
|
||||
webpush.setVapidDetails(
|
||||
`mailto:${mainUser.email}`,
|
||||
settings.vapidPublic,
|
||||
settings.vapidPrivate
|
||||
);
|
||||
|
||||
if (
|
||||
type === Notification.MEDIA_APPROVED ||
|
||||
type === Notification.MEDIA_DECLINED
|
||||
) {
|
||||
const users = await userRepository.find();
|
||||
const pushSubsForBadge: UserPushSubscription[] = [];
|
||||
const notificationBadgePayload = Buffer.from(
|
||||
JSON.stringify(
|
||||
this.getNotificationPayload(type, {
|
||||
subject: payload.subject,
|
||||
notifySystem: false,
|
||||
notifyAdmin: true,
|
||||
isAdmin: true,
|
||||
pendingRequestsCount: payload.pendingRequestsCount,
|
||||
})
|
||||
),
|
||||
'utf-8'
|
||||
);
|
||||
|
||||
const manageUsers = users.filter(
|
||||
(user) =>
|
||||
// Check if user has webpush notifications enabled and fallback to true if undefined
|
||||
// since web push should default to true
|
||||
(user.settings?.hasNotificationType(
|
||||
NotificationAgentKey.WEBPUSH,
|
||||
type
|
||||
) ??
|
||||
true) &&
|
||||
shouldSendAdminNotification(type, user, payload)
|
||||
);
|
||||
|
||||
const allSubs = await userPushSubRepository
|
||||
.createQueryBuilder('pushSub')
|
||||
.leftJoinAndSelect('pushSub.user', 'user')
|
||||
.where('pushSub.userId IN (:users)', {
|
||||
users: manageUsers
|
||||
.filter((user) => user.id === 1)
|
||||
.map((user) => user.id),
|
||||
})
|
||||
.getMany();
|
||||
|
||||
pushSubsForBadge.push(...allSubs);
|
||||
|
||||
if (mainUser && pushSubsForBadge.length > 0) {
|
||||
webpush.setVapidDetails(
|
||||
`mailto:${mainUser.email}`,
|
||||
settings.vapidPublic,
|
||||
settings.vapidPrivate
|
||||
);
|
||||
|
||||
const notificationPayload = Buffer.from(
|
||||
JSON.stringify(
|
||||
this.getNotificationPayload(type, {
|
||||
subject: 'Set PWA badge',
|
||||
notifySystem: false,
|
||||
notifyAdmin: true,
|
||||
isAdmin: true,
|
||||
pendingRequestsCount: payload.pendingRequestsCount,
|
||||
await Promise.all(
|
||||
allSubs.map(async (sub) => {
|
||||
webPushNotification(sub, notificationBadgePayload);
|
||||
})
|
||||
),
|
||||
'utf-8'
|
||||
);
|
||||
|
||||
await Promise.all(
|
||||
pushSubsForBadge.map(async (sub) => {
|
||||
logger.debug('Sending web push notification for badge update', {
|
||||
label: 'Notifications',
|
||||
recipient: sub.user.displayName,
|
||||
type: Notification[type],
|
||||
subject: payload.subject,
|
||||
});
|
||||
|
||||
try {
|
||||
await webpush.sendNotification(
|
||||
{
|
||||
endpoint: sub.endpoint,
|
||||
keys: {
|
||||
auth: sub.auth,
|
||||
p256dh: sub.p256dh,
|
||||
},
|
||||
},
|
||||
notificationPayload
|
||||
);
|
||||
} catch (e) {
|
||||
logger.error(
|
||||
'Error sending web push notification to update badge; removing subscription',
|
||||
{
|
||||
label: 'Notifications',
|
||||
recipient: sub.user.displayName,
|
||||
type: Notification[type],
|
||||
subject: payload.subject,
|
||||
errorMessage: e.message,
|
||||
}
|
||||
);
|
||||
|
||||
// Failed to send notification so we need to remove the subscription
|
||||
userPushSubRepository.remove(sub);
|
||||
}
|
||||
})
|
||||
);
|
||||
);
|
||||
}
|
||||
} else {
|
||||
pushSubs.push(...allSubs);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -304,39 +284,7 @@ class WebPushAgent
|
||||
|
||||
await Promise.all(
|
||||
pushSubs.map(async (sub) => {
|
||||
logger.debug('Sending web push notification', {
|
||||
label: 'Notifications',
|
||||
recipient: sub.user.displayName,
|
||||
type: Notification[type],
|
||||
subject: payload.subject,
|
||||
});
|
||||
|
||||
try {
|
||||
await webpush.sendNotification(
|
||||
{
|
||||
endpoint: sub.endpoint,
|
||||
keys: {
|
||||
auth: sub.auth,
|
||||
p256dh: sub.p256dh,
|
||||
},
|
||||
},
|
||||
notificationPayload
|
||||
);
|
||||
} catch (e) {
|
||||
logger.error(
|
||||
'Error sending web push notification; removing subscription',
|
||||
{
|
||||
label: 'Notifications',
|
||||
recipient: sub.user.displayName,
|
||||
type: Notification[type],
|
||||
subject: payload.subject,
|
||||
errorMessage: e.message,
|
||||
}
|
||||
);
|
||||
|
||||
// Failed to send notification so we need to remove the subscription
|
||||
userPushSubRepository.remove(sub);
|
||||
}
|
||||
webPushNotification(sub, notificationPayload);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
@@ -114,30 +114,27 @@ const CoreApp: Omit<NextAppComponentType, 'origGetInitialProps'> = ({
|
||||
loadLocaleData(currentLocale).then(setMessages);
|
||||
}, [currentLocale]);
|
||||
|
||||
const requestsCount = async () => {
|
||||
const response = await axios.get('/api/v1/request/count');
|
||||
|
||||
return response.data;
|
||||
};
|
||||
|
||||
const { hasPermission } = useUser();
|
||||
|
||||
useEffect(() => {
|
||||
//Set navigator to new variable with any type to prevent setAppBadge unknown error
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
let newNavigator: any;
|
||||
const requestsCount = async () => {
|
||||
const response = await axios.get('/api/v1/request/count');
|
||||
return response.data;
|
||||
};
|
||||
|
||||
//Set navigator to new variable with any type to prevent setAppBadge unknown error since it does actually exist on navigator
|
||||
//eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const newNavigator: any = navigator;
|
||||
|
||||
if ('setAppBadge' in navigator) {
|
||||
newNavigator = navigator;
|
||||
}
|
||||
|
||||
if (
|
||||
!router.pathname.match(/(login|setup|resetpassword)/) &&
|
||||
hasPermission(Permission.ADMIN)
|
||||
) {
|
||||
requestsCount().then((data) => newNavigator.setAppBadge(data.pending));
|
||||
} else {
|
||||
newNavigator.clearAppBadge();
|
||||
if (
|
||||
!router.pathname.match(/(login|setup|resetpassword)/) &&
|
||||
hasPermission(Permission.ADMIN)
|
||||
) {
|
||||
requestsCount().then((data) => newNavigator.setAppBadge(data.pending));
|
||||
} else {
|
||||
newNavigator.clearAppBadge();
|
||||
}
|
||||
}
|
||||
}, [hasPermission, router.pathname]);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user