refactor: removed unnecessary code when sending web push notification

This commit is contained in:
Brandon
2023-04-06 00:52:49 -04:00
committed by Brandon Cohen
parent fa741a690d
commit e3478a18dd
5 changed files with 129 additions and 182 deletions

View File

@@ -5,4 +5,4 @@ config/
# assets
src/assets/
# public/
public/

View File

@@ -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);

View File

@@ -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)})` : ''

View File

@@ -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);
})
);
}

View File

@@ -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]);