fix: better handling for active webpush subscription (#4146)

fix: remove yarn from package manager

fix: update openapi yml
This commit is contained in:
Brandon Cohen
2025-06-12 19:07:53 -04:00
committed by GitHub
parent 07dc8d755a
commit 21b188b0b2
4 changed files with 36 additions and 30 deletions

View File

@@ -3617,7 +3617,7 @@ paths:
type: string
userAgent:
type: string
/user/{userId}/pushSubscription/{key}:
/user/{userId}/pushSubscription/{endpoint}:
get:
summary: Get web push notification settings for a user
description: |
@@ -3631,7 +3631,7 @@ paths:
schema:
type: number
- in: path
name: key
name: endpoint
required: true
schema:
type: string
@@ -3663,7 +3663,7 @@ paths:
schema:
type: number
- in: path
name: key
name: endpoint
required: true
schema:
type: string

View File

@@ -201,8 +201,8 @@ router.get<{ userId: number }>(
}
);
router.get<{ userId: number; key: string }>(
'/:userId/pushSubscription/:key',
router.get<{ userId: number; endpoint: string }>(
'/:userId/pushSubscription/:endpoint',
async (req, res, next) => {
try {
const userPushSubRepository = getRepository(UserPushSubscription);
@@ -213,7 +213,7 @@ router.get<{ userId: number; key: string }>(
},
where: {
user: { id: req.params.userId },
p256dh: req.params.key,
endpoint: req.params.endpoint,
},
});
@@ -224,8 +224,8 @@ router.get<{ userId: number; key: string }>(
}
);
router.delete<{ userId: number; key: string }>(
'/:userId/pushSubscription/:key',
router.delete<{ userId: number; endpoint: string }>(
'/:userId/pushSubscription/:endpoint',
async (req, res, next) => {
try {
const userPushSubRepository = getRepository(UserPushSubscription);
@@ -236,7 +236,7 @@ router.delete<{ userId: number; key: string }>(
},
where: {
user: { id: req.params.userId },
p256dh: req.params.key,
endpoint: req.params.endpoint,
},
});
@@ -245,7 +245,7 @@ router.delete<{ userId: number; key: string }>(
} catch (e) {
logger.error('Something went wrong deleting the user push subcription', {
label: 'API',
key: req.params.key,
endpoint: req.params.endpoint,
errorMessage: e.message,
});
return next({

View File

@@ -29,13 +29,14 @@ const messages = defineMessages({
const DeviceItem = ({ disablePushNotifications, device }: DeviceItemProps) => {
const intl = useIntl();
const parsedUserAgent = UAParser(device.userAgent);
return (
<div className="relative flex w-full flex-col justify-between overflow-hidden rounded-xl bg-gray-800 py-4 text-gray-400 shadow-md ring-1 ring-gray-700 xl:h-28 xl:flex-row">
<div className="relative flex w-full flex-col justify-between overflow-hidden sm:flex-row">
<div className="relative z-10 flex w-full items-center overflow-hidden pl-4 pr-4 sm:pr-0 xl:w-7/12 2xl:w-2/3">
<div className="relative h-auto w-12 flex-shrink-0 scale-100 transform-gpu overflow-hidden rounded-md transition duration-300 hover:scale-105">
{UAParser(device.userAgent).device.type === 'mobile' ? (
{parsedUserAgent.device.type === 'mobile' ? (
<DevicePhoneMobileIcon />
) : (
<ComputerDesktopIcon />
@@ -52,8 +53,8 @@ const DeviceItem = ({ disablePushNotifications, device }: DeviceItemProps) => {
: 'N/A'}
</div>
<div className="mr-2 min-w-0 truncate text-lg font-bold text-white hover:underline xl:text-xl">
{device.userAgent
? UAParser(device.userAgent).device.model
{device.userAgent && parsedUserAgent.device.model
? parsedUserAgent.device.model
: intl.formatMessage(messages.unknown)}
</div>
</div>
@@ -64,7 +65,7 @@ const DeviceItem = ({ disablePushNotifications, device }: DeviceItemProps) => {
{intl.formatMessage(messages.operatingsystem)}
</span>
<span className="flex truncate text-sm text-gray-300">
{device.userAgent ? UAParser(device.userAgent).os.name : 'N/A'}
{device.userAgent ? parsedUserAgent.os.name : 'N/A'}
</span>
</div>
<div className="card-field">
@@ -72,9 +73,7 @@ const DeviceItem = ({ disablePushNotifications, device }: DeviceItemProps) => {
{intl.formatMessage(messages.browser)}
</span>
<span className="flex truncate text-sm text-gray-300">
{device.userAgent
? UAParser(device.userAgent).browser.name
: 'N/A'}
{device.userAgent ? parsedUserAgent.browser.name : 'N/A'}
</span>
</div>
<div className="card-field">
@@ -82,16 +81,14 @@ const DeviceItem = ({ disablePushNotifications, device }: DeviceItemProps) => {
{intl.formatMessage(messages.engine)}
</span>
<span className="flex truncate text-sm text-gray-300">
{device.userAgent
? UAParser(device.userAgent).engine.name
: 'N/A'}
{device.userAgent ? parsedUserAgent.engine.name : 'N/A'}
</span>
</div>
</div>
</div>
<div className="z-10 mt-4 flex w-full flex-col justify-center space-y-2 pl-4 pr-4 xl:mt-0 xl:w-96 xl:items-end xl:pl-0">
<ConfirmButton
onClick={() => disablePushNotifications(device.p256dh)}
onClick={() => disablePushNotifications(device.endpoint)}
confirmText={intl.formatMessage(globalMessages.areyousure)}
className="w-full"
>

View File

@@ -109,7 +109,7 @@ const UserWebPushSettings = () => {
// Unsubscribes from the push manager
// Deletes/disables corresponding push subscription from database
const disablePushNotifications = async (p256dh?: string) => {
const disablePushNotifications = async (endpoint?: string) => {
if ('serviceWorker' in navigator && user?.id) {
navigator.serviceWorker.getRegistration('/sw.js').then((registration) => {
registration?.pushManager
@@ -118,17 +118,21 @@ const UserWebPushSettings = () => {
const parsedSub = JSON.parse(JSON.stringify(subscription));
await axios.delete(
`/api/v1/user/${user?.id}/pushSubscription/${
p256dh ? p256dh : parsedSub.keys.p256dh
}`
`/api/v1/user/${user.id}/pushSubscription/${encodeURIComponent(
endpoint ?? parsedSub.endpoint
)}`
);
if (subscription && (p256dh === parsedSub.keys.p256dh || !p256dh)) {
if (
subscription &&
(endpoint === parsedSub.endpoint || !endpoint)
) {
subscription.unsubscribe();
setWebPushEnabled(false);
}
addToast(
intl.formatMessage(
p256dh
endpoint
? messages.subscriptiondeleted
: messages.webpushhasbeendisabled
),
@@ -141,7 +145,7 @@ const UserWebPushSettings = () => {
.catch(function () {
addToast(
intl.formatMessage(
p256dh
endpoint
? messages.subscriptiondeleteerror
: messages.disablingwebpusherror
),
@@ -172,12 +176,17 @@ const UserWebPushSettings = () => {
const parsedKey = JSON.parse(JSON.stringify(subscription));
const currentUserPushSub =
await axios.get<UserPushSubscription>(
`/api/v1/user/${user.id}/pushSubscription/${parsedKey.keys.p256dh}`
`/api/v1/user/${
user.id
}/pushSubscription/${encodeURIComponent(
parsedKey.endpoint
)}`
);
if (currentUserPushSub.data.p256dh !== parsedKey.keys.p256dh) {
if (currentUserPushSub.data.endpoint !== parsedKey.endpoint) {
return;
}
setWebPushEnabled(true);
} else {
setWebPushEnabled(false);