From f0af3ca61d19b25767e21e8c94b1bcbc679d1060 Mon Sep 17 00:00:00 2001 From: Brandon Cohen Date: Thu, 27 Feb 2025 22:14:48 -0600 Subject: [PATCH] Revert "fix: improved web push management (#3421)" (#4058) --- overseerr-api.yml | 84 ----- package.json | 2 - server/1684249347630-datasource.ts | 51 --- server/entity/UserPushSubscription.ts | 16 +- server/routes/user/index.ts | 78 +--- src/components/ServiceWorkerSetup/index.tsx | 27 +- .../UserNotificationsWebPush.tsx | 123 +++++++ .../UserNotificationsWebPush/DeviceItem.tsx | 107 ------ .../UserNotificationsWebPush/index.tsx | 338 ------------------ src/i18n/locale/en.json | 22 +- yarn.lock | 10 - 11 files changed, 153 insertions(+), 705 deletions(-) delete mode 100644 server/1684249347630-datasource.ts create mode 100644 src/components/UserProfile/UserSettings/UserNotificationSettings/UserNotificationsWebPush.tsx delete mode 100644 src/components/UserProfile/UserSettings/UserNotificationSettings/UserNotificationsWebPush/DeviceItem.tsx delete mode 100644 src/components/UserProfile/UserSettings/UserNotificationSettings/UserNotificationsWebPush/index.tsx diff --git a/overseerr-api.yml b/overseerr-api.yml index 7cbf6affc..e23b97c36 100644 --- a/overseerr-api.yml +++ b/overseerr-api.yml @@ -3579,8 +3579,6 @@ paths: type: string p256dh: type: string - userAgent: - type: string required: - endpoint - auth @@ -3588,88 +3586,6 @@ paths: responses: '204': description: Successfully registered push subscription - /user/{userId}/pushSubscriptions: - get: - summary: Get all web push notification settings for a user - description: | - Returns all web push notification settings for a user in a JSON object. - tags: - - users - parameters: - - in: path - name: userId - required: true - schema: - type: number - responses: - '200': - description: User web push notification settings in JSON - content: - application/json: - schema: - type: object - properties: - endpoint: - type: string - p256dh: - type: string - auth: - type: string - userAgent: - type: string - /user/{userId}/pushSubscription/{key}: - get: - summary: Get web push notification settings for a user - description: | - Returns web push notification settings for a user in a JSON object. - tags: - - users - parameters: - - in: path - name: userId - required: true - schema: - type: number - - in: path - name: key - required: true - schema: - type: string - responses: - '200': - description: User web push notification settings in JSON - content: - application/json: - schema: - type: object - properties: - endpoint: - type: string - p256dh: - type: string - auth: - type: string - userAgent: - type: string - delete: - summary: Delete user push subscription by key - description: Deletes the user push subscription with the provided key. - tags: - - users - parameters: - - in: path - name: userId - required: true - schema: - type: number - - in: path - name: key - required: true - schema: - type: string - responses: - '204': - description: Successfully removed user push subscription /user/{userId}: get: summary: Get user by ID diff --git a/package.json b/package.json index e2186ccb2..8b82e45d4 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,6 @@ "@supercharge/request-ip": "1.2.0", "@svgr/webpack": "6.5.1", "@tanem/react-nprogress": "5.0.30", - "@types/ua-parser-js": "^0.7.36", "ace-builds": "1.15.2", "axios": "1.3.4", "axios-rate-limit": "1.3.0", @@ -91,7 +90,6 @@ "swagger-ui-express": "4.6.2", "swr": "2.0.4", "typeorm": "0.3.12", - "ua-parser-js": "^1.0.35", "web-push": "3.5.0", "winston": "3.8.2", "winston-daily-rotate-file": "4.7.1", diff --git a/server/1684249347630-datasource.ts b/server/1684249347630-datasource.ts deleted file mode 100644 index 4b7356f4a..000000000 --- a/server/1684249347630-datasource.ts +++ /dev/null @@ -1,51 +0,0 @@ -import type { MigrationInterface, QueryRunner } from 'typeorm'; - -export class datasource1684249347630 implements MigrationInterface { - name = 'datasource1684249347630'; - - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `CREATE TABLE "temporary_user_push_subscription" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "endpoint" varchar NOT NULL, "p256dh" varchar NOT NULL, "auth" varchar NOT NULL, "userId" integer, "userAgent" varchar, "createdAt" datetime DEFAULT (datetime('now')), CONSTRAINT "UQ_95f313437ec4a8f8148d74a0ed8" UNIQUE ("auth"), CONSTRAINT "FK_03f7958328e311761b0de675fbe" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)` - ); - await queryRunner.query( - `INSERT INTO "temporary_user_push_subscription"("id", "endpoint", "p256dh", "auth", "userId", "userAgent", "createdAt") SELECT "id", "endpoint", "p256dh", "auth", "userId", "userAgent", "createdAt" FROM "user_push_subscription"` - ); - await queryRunner.query(`DROP TABLE "user_push_subscription"`); - await queryRunner.query( - `ALTER TABLE "temporary_user_push_subscription" RENAME TO "user_push_subscription"` - ); - await queryRunner.query( - `CREATE TABLE "temporary_user_push_subscription" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "endpoint" varchar NOT NULL, "p256dh" varchar NOT NULL, "auth" varchar NOT NULL, "userId" integer, "userAgent" varchar, "createdAt" datetime DEFAULT (datetime('now')), CONSTRAINT "UQ_95f313437ec4a8f8148d74a0ed8" UNIQUE ("auth"), CONSTRAINT "FK_03f7958328e311761b0de675fbe" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)` - ); - await queryRunner.query( - `INSERT INTO "temporary_user_push_subscription"("id", "endpoint", "p256dh", "auth", "userId", "userAgent", "createdAt") SELECT "id", "endpoint", "p256dh", "auth", "userId", "userAgent", "createdAt" FROM "user_push_subscription"` - ); - await queryRunner.query(`DROP TABLE "user_push_subscription"`); - await queryRunner.query( - `ALTER TABLE "temporary_user_push_subscription" RENAME TO "user_push_subscription"` - ); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query( - `ALTER TABLE "user_push_subscription" RENAME TO "temporary_user_push_subscription"` - ); - await queryRunner.query( - `CREATE TABLE "user_push_subscription" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "endpoint" varchar NOT NULL, "p256dh" varchar NOT NULL, "auth" varchar NOT NULL, "userId" integer, "userAgent" varchar, "createdAt" datetime DEFAULT (datetime('now')), CONSTRAINT "UQ_95f313437ec4a8f8148d74a0ed8" UNIQUE ("auth"), CONSTRAINT "FK_03f7958328e311761b0de675fbe" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)` - ); - await queryRunner.query( - `INSERT INTO "user_push_subscription"("id", "endpoint", "p256dh", "auth", "userId", "userAgent", "createdAt") SELECT "id", "endpoint", "p256dh", "auth", "userId", "userAgent", "createdAt" FROM "temporary_user_push_subscription"` - ); - await queryRunner.query(`DROP TABLE "temporary_user_push_subscription"`); - await queryRunner.query( - `ALTER TABLE "user_push_subscription" RENAME TO "temporary_user_push_subscription"` - ); - await queryRunner.query( - `CREATE TABLE "user_push_subscription" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "endpoint" varchar NOT NULL, "p256dh" varchar NOT NULL, "auth" varchar NOT NULL, "userId" integer, "userAgent" varchar, "createdAt" datetime DEFAULT (datetime('now')), CONSTRAINT "UQ_95f313437ec4a8f8148d74a0ed8" UNIQUE ("auth"), CONSTRAINT "FK_03f7958328e311761b0de675fbe" FOREIGN KEY ("userId") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)` - ); - await queryRunner.query( - `INSERT INTO "user_push_subscription"("id", "endpoint", "p256dh", "auth", "userId", "userAgent", "createdAt") SELECT "id", "endpoint", "p256dh", "auth", "userId", "userAgent", "createdAt" FROM "temporary_user_push_subscription"` - ); - await queryRunner.query(`DROP TABLE "temporary_user_push_subscription"`); - } -} diff --git a/server/entity/UserPushSubscription.ts b/server/entity/UserPushSubscription.ts index f05dd0f2b..6389ea0b8 100644 --- a/server/entity/UserPushSubscription.ts +++ b/server/entity/UserPushSubscription.ts @@ -1,10 +1,4 @@ -import { - Column, - CreateDateColumn, - Entity, - ManyToOne, - PrimaryGeneratedColumn, -} from 'typeorm'; +import { Column, Entity, ManyToOne, PrimaryGeneratedColumn } from 'typeorm'; import { User } from './User'; @Entity() @@ -24,15 +18,9 @@ export class UserPushSubscription { @Column() public p256dh: string; - @Column() + @Column({ unique: true }) public auth: string; - @Column({ nullable: true }) - public userAgent: string; - - @CreateDateColumn({ nullable: true }) - public createdAt: Date; - constructor(init?: Partial) { Object.assign(this, init); } diff --git a/server/routes/user/index.ts b/server/routes/user/index.ts index afca9bd78..94784df51 100644 --- a/server/routes/user/index.ts +++ b/server/routes/user/index.ts @@ -145,15 +145,13 @@ router.post< endpoint: string; p256dh: string; auth: string; - userAgent: string; } >('/registerPushSubscription', async (req, res, next) => { try { const userPushSubRepository = getRepository(UserPushSubscription); const existingSubs = await userPushSubRepository.find({ - relations: { user: true }, - where: { auth: req.body.auth, user: { id: req.user?.id } }, + where: { auth: req.body.auth }, }); if (existingSubs.length > 0) { @@ -168,7 +166,6 @@ router.post< auth: req.body.auth, endpoint: req.body.endpoint, p256dh: req.body.p256dh, - userAgent: req.body.userAgent, user: req.user, }); @@ -183,79 +180,6 @@ router.post< } }); -router.get<{ userId: number }>( - '/:userId/pushSubscriptions', - async (req, res, next) => { - try { - const userPushSubRepository = getRepository(UserPushSubscription); - - const userPushSubs = await userPushSubRepository.find({ - relations: { user: true }, - where: { user: { id: req.params.userId } }, - }); - - return res.status(200).json(userPushSubs); - } catch (e) { - next({ status: 404, message: 'User subscriptions not found.' }); - } - } -); - -router.get<{ userId: number; key: string }>( - '/:userId/pushSubscription/:key', - async (req, res, next) => { - try { - const userPushSubRepository = getRepository(UserPushSubscription); - - const userPushSub = await userPushSubRepository.findOneOrFail({ - relations: { - user: true, - }, - where: { - user: { id: req.params.userId }, - p256dh: req.params.key, - }, - }); - - return res.status(200).json(userPushSub); - } catch (e) { - next({ status: 404, message: 'User subscription not found.' }); - } - } -); - -router.delete<{ userId: number; key: string }>( - '/:userId/pushSubscription/:key', - async (req, res, next) => { - try { - const userPushSubRepository = getRepository(UserPushSubscription); - - const userPushSub = await userPushSubRepository.findOneOrFail({ - relations: { - user: true, - }, - where: { - user: { id: req.params.userId }, - p256dh: req.params.key, - }, - }); - - await userPushSubRepository.remove(userPushSub); - return res.status(204).send(); - } catch (e) { - logger.error('Something went wrong deleting the user push subcription', { - label: 'API', - key: req.params.key, - errorMessage: e.message, - }); - return next({ - status: 500, - message: 'User push subcription not found', - }); - } - } -); - router.get<{ id: string }>('/:id', async (req, res, next) => { try { const userRepository = getRepository(User); diff --git a/src/components/ServiceWorkerSetup/index.tsx b/src/components/ServiceWorkerSetup/index.tsx index 2e0313f4d..f30a26d16 100644 --- a/src/components/ServiceWorkerSetup/index.tsx +++ b/src/components/ServiceWorkerSetup/index.tsx @@ -1,9 +1,11 @@ /* eslint-disable no-console */ - +import useSettings from '@app/hooks/useSettings'; import { useUser } from '@app/hooks/useUser'; +import axios from 'axios'; import { useEffect } from 'react'; const ServiceWorkerSetup = () => { + const { currentSettings } = useSettings(); const { user } = useUser(); useEffect(() => { if ('serviceWorker' in navigator && user?.id) { @@ -14,12 +16,33 @@ const ServiceWorkerSetup = () => { '[SW] Registration successful, scope is:', registration.scope ); + + if (currentSettings.enablePushRegistration) { + const sub = await registration.pushManager.subscribe({ + userVisibleOnly: true, + applicationServerKey: currentSettings.vapidPublic, + }); + + const parsedSub = JSON.parse(JSON.stringify(sub)); + + if (parsedSub.keys.p256dh && parsedSub.keys.auth) { + await axios.post('/api/v1/user/registerPushSubscription', { + endpoint: parsedSub.endpoint, + p256dh: parsedSub.keys.p256dh, + auth: parsedSub.keys.auth, + }); + } + } }) .catch(function (error) { console.log('[SW] Service worker registration failed, error:', error); }); } - }, [user]); + }, [ + user, + currentSettings.vapidPublic, + currentSettings.enablePushRegistration, + ]); return null; }; diff --git a/src/components/UserProfile/UserSettings/UserNotificationSettings/UserNotificationsWebPush.tsx b/src/components/UserProfile/UserSettings/UserNotificationSettings/UserNotificationsWebPush.tsx new file mode 100644 index 000000000..2c940d292 --- /dev/null +++ b/src/components/UserProfile/UserSettings/UserNotificationSettings/UserNotificationsWebPush.tsx @@ -0,0 +1,123 @@ +import Button from '@app/components/Common/Button'; +import LoadingSpinner from '@app/components/Common/LoadingSpinner'; +import NotificationTypeSelector, { + ALL_NOTIFICATIONS, +} from '@app/components/NotificationTypeSelector'; +import { useUser } from '@app/hooks/useUser'; +import globalMessages from '@app/i18n/globalMessages'; +import { ArrowDownOnSquareIcon } from '@heroicons/react/24/outline'; +import type { UserSettingsNotificationsResponse } from '@server/interfaces/api/userSettingsInterfaces'; +import axios from 'axios'; +import { Form, Formik } from 'formik'; +import { useRouter } from 'next/router'; +import { defineMessages, useIntl } from 'react-intl'; +import { useToasts } from 'react-toast-notifications'; +import useSWR, { mutate } from 'swr'; + +const messages = defineMessages({ + webpushsettingssaved: 'Web push notification settings saved successfully!', + webpushsettingsfailed: 'Web push notification settings failed to save.', +}); + +const UserWebPushSettings = () => { + const intl = useIntl(); + const { addToast } = useToasts(); + const router = useRouter(); + const { user } = useUser({ id: Number(router.query.userId) }); + const { + data, + error, + mutate: revalidate, + } = useSWR( + user ? `/api/v1/user/${user?.id}/settings/notifications` : null + ); + + if (!data && !error) { + return ; + } + + return ( + { + try { + await axios.post(`/api/v1/user/${user?.id}/settings/notifications`, { + pgpKey: data?.pgpKey, + discordId: data?.discordId, + pushbulletAccessToken: data?.pushbulletAccessToken, + pushoverApplicationToken: data?.pushoverApplicationToken, + pushoverUserKey: data?.pushoverUserKey, + telegramChatId: data?.telegramChatId, + telegramSendSilently: data?.telegramSendSilently, + notificationTypes: { + webpush: values.types, + }, + }); + mutate('/api/v1/settings/public'); + addToast(intl.formatMessage(messages.webpushsettingssaved), { + appearance: 'success', + autoDismiss: true, + }); + } catch (e) { + addToast(intl.formatMessage(messages.webpushsettingsfailed), { + appearance: 'error', + autoDismiss: true, + }); + } finally { + revalidate(); + } + }} + > + {({ + errors, + touched, + isSubmitting, + isValid, + values, + setFieldValue, + setFieldTouched, + }) => { + return ( +
+ { + setFieldValue('types', newTypes); + setFieldTouched('types'); + }} + error={ + errors.types && touched.types + ? (errors.types as string) + : undefined + } + /> +
+
+ + + +
+
+ + ); + }} +
+ ); +}; + +export default UserWebPushSettings; diff --git a/src/components/UserProfile/UserSettings/UserNotificationSettings/UserNotificationsWebPush/DeviceItem.tsx b/src/components/UserProfile/UserSettings/UserNotificationSettings/UserNotificationsWebPush/DeviceItem.tsx deleted file mode 100644 index 64ad47b4e..000000000 --- a/src/components/UserProfile/UserSettings/UserNotificationSettings/UserNotificationsWebPush/DeviceItem.tsx +++ /dev/null @@ -1,107 +0,0 @@ -import ConfirmButton from '@app/components/Common/ConfirmButton'; -import globalMessages from '@app/i18n/globalMessages'; -import { - ComputerDesktopIcon, - DevicePhoneMobileIcon, - TrashIcon, -} from '@heroicons/react/24/solid'; -import { defineMessages, useIntl } from 'react-intl'; -import { UAParser } from 'ua-parser-js'; - -interface DeviceItemProps { - disablePushNotifications: (p256dh: string) => void; - device: { - endpoint: string; - p256dh: string; - auth: string; - userAgent: string; - createdAt: Date; - }; -} - -const messages = defineMessages({ - operatingsystem: 'Operating System', - browser: 'Browser', - engine: 'Engine', - deletesubscription: 'Delete Subscription', -}); - -const DeviceItem = ({ disablePushNotifications, device }: DeviceItemProps) => { - const intl = useIntl(); - - return ( -
-
-
-
- {UAParser(device.userAgent).device.type === 'mobile' ? ( - - ) : ( - - )} -
-
-
- {device.createdAt - ? intl.formatDate(device.createdAt, { - year: 'numeric', - month: 'long', - day: 'numeric', - }) - : 'Unknown'} -
-
- {device.userAgent - ? UAParser(device.userAgent).device.model - : 'Unknown'} -
-
-
-
-
- - {intl.formatMessage(messages.operatingsystem)} - - - {device.userAgent - ? UAParser(device.userAgent).os.name - : 'Unknown'} - -
-
- - {intl.formatMessage(messages.browser)} - - - {device.userAgent - ? UAParser(device.userAgent).browser.name - : 'Unknown'} - -
-
- - {intl.formatMessage(messages.engine)} - - - {device.userAgent - ? UAParser(device.userAgent).engine.name - : 'Unknown'} - -
-
-
-
- disablePushNotifications(device.p256dh)} - confirmText={intl.formatMessage(globalMessages.areyousure)} - className="w-full" - > - - {intl.formatMessage(messages.deletesubscription)} - -
-
- ); -}; - -export default DeviceItem; diff --git a/src/components/UserProfile/UserSettings/UserNotificationSettings/UserNotificationsWebPush/index.tsx b/src/components/UserProfile/UserSettings/UserNotificationSettings/UserNotificationsWebPush/index.tsx deleted file mode 100644 index c4667460f..000000000 --- a/src/components/UserProfile/UserSettings/UserNotificationSettings/UserNotificationsWebPush/index.tsx +++ /dev/null @@ -1,338 +0,0 @@ -import Alert from '@app/components/Common/Alert'; -import Button from '@app/components/Common/Button'; -import LoadingSpinner from '@app/components/Common/LoadingSpinner'; -import NotificationTypeSelector, { - ALL_NOTIFICATIONS, -} from '@app/components/NotificationTypeSelector'; -import DeviceItem from '@app/components/UserProfile/UserSettings/UserNotificationSettings/UserNotificationsWebPush/DeviceItem'; -import useSettings from '@app/hooks/useSettings'; -import { useUser } from '@app/hooks/useUser'; -import globalMessages from '@app/i18n/globalMessages'; -import { ArrowDownOnSquareIcon } from '@heroicons/react/24/outline'; -import { - CloudArrowDownIcon, - CloudArrowUpIcon, -} from '@heroicons/react/24/solid'; -import type { UserPushSubscription } from '@server/entity/UserPushSubscription'; -import type { UserSettingsNotificationsResponse } from '@server/interfaces/api/userSettingsInterfaces'; -import axios from 'axios'; -import { Form, Formik } from 'formik'; -import { useRouter } from 'next/router'; -import { useEffect, useState } from 'react'; -import { defineMessages, useIntl } from 'react-intl'; -import { useToasts } from 'react-toast-notifications'; -import useSWR, { mutate } from 'swr'; - -const messages = defineMessages({ - webpushsettingssaved: 'Web push notification settings saved successfully!', - webpushsettingsfailed: 'Web push notification settings failed to save.', - enablewebpush: 'Enable web push', - disablewebpush: 'Disable web push', - managedevices: 'Manage Devices', - type: 'type', - created: 'Created', - device: 'Device', - subscriptiondeleted: 'Subscription deleted.', - subscriptiondeleteerror: - 'Something went wrong while deleting the user subscription.', - nodevicestoshow: 'You have no web push subscriptions to show.', - webpushhasbeenenabled: 'Web push has been enabled.', - webpushhasbeendisabled: 'Web push has been disabled.', - enablingwebpusherror: 'Something went wrong while enabling web push.', - disablingwebpusherror: 'Something went wrong while disabling web push.', -}); - -const UserWebPushSettings = () => { - const intl = useIntl(); - const { addToast } = useToasts(); - const router = useRouter(); - const { user } = useUser({ id: Number(router.query.userId) }); - const { currentSettings } = useSettings(); - const [webPushEnabled, setWebPushEnabled] = useState(false); - const { - data, - error, - mutate: revalidate, - } = useSWR( - user ? `/api/v1/user/${user?.id}/settings/notifications` : null - ); - const { data: dataDevices, mutate: revalidateDevices } = useSWR< - { - endpoint: string; - p256dh: string; - auth: string; - userAgent: string; - createdAt: Date; - }[] - >(`/api/v1/user/${user?.id}/pushSubscriptions`, { revalidateOnMount: true }); - - // Subscribes to the push manager - // Will only add to the database if subscribing for the first time - const enablePushNotifications = () => { - if ('serviceWorker' in navigator && user?.id) { - navigator.serviceWorker - .getRegistration('/sw.js') - .then(async (registration) => { - if (currentSettings.enablePushRegistration) { - const sub = await registration?.pushManager.subscribe({ - userVisibleOnly: true, - applicationServerKey: currentSettings.vapidPublic, - }); - const parsedSub = JSON.parse(JSON.stringify(sub)); - - if (parsedSub.keys.p256dh && parsedSub.keys.auth) { - await axios.post('/api/v1/user/registerPushSubscription', { - endpoint: parsedSub.endpoint, - p256dh: parsedSub.keys.p256dh, - auth: parsedSub.keys.auth, - userAgent: navigator.userAgent, - }); - setWebPushEnabled(true); - addToast(intl.formatMessage(messages.webpushhasbeenenabled), { - appearance: 'success', - autoDismiss: true, - }); - } - } - }) - .catch(function () { - addToast(intl.formatMessage(messages.enablingwebpusherror), { - autoDismiss: true, - appearance: 'error', - }); - }) - .finally(function () { - revalidateDevices(); - }); - } - }; - - // Unsubscribes from the push manager - // Deletes/disables corresponding push subscription from database - const disablePushNotifications = async (p256dh?: string) => { - if ('serviceWorker' in navigator && user?.id) { - navigator.serviceWorker.getRegistration('/sw.js').then((registration) => { - registration?.pushManager - .getSubscription() - .then(async (subscription) => { - const parsedSub = JSON.parse(JSON.stringify(subscription)); - - await axios.delete( - `/api/v1/user/${user?.id}/pushSubscription/${ - p256dh ? p256dh : parsedSub.keys.p256dh - }` - ); - if (subscription && (p256dh === parsedSub.keys.p256dh || !p256dh)) { - subscription.unsubscribe(); - setWebPushEnabled(false); - } - addToast( - intl.formatMessage( - p256dh - ? messages.subscriptiondeleted - : messages.webpushhasbeendisabled - ), - { - autoDismiss: true, - appearance: 'success', - } - ); - }) - .catch(function () { - addToast( - intl.formatMessage( - p256dh - ? messages.subscriptiondeleteerror - : messages.disablingwebpusherror - ), - { - autoDismiss: true, - appearance: 'error', - } - ); - }) - .finally(function () { - revalidateDevices(); - }); - }); - } - }; - - // Checks our current subscription on page load - // Will set the web push state to true if subscribed - useEffect(() => { - if ('serviceWorker' in navigator && user?.id) { - navigator.serviceWorker - .getRegistration('/sw.js') - .then(async (registration) => { - await registration?.pushManager - .getSubscription() - .then(async (subscription) => { - if (subscription) { - const parsedKey = JSON.parse(JSON.stringify(subscription)); - const currentUserPushSub = - await axios.get( - `/api/v1/user/${user.id}/pushSubscription/${parsedKey.keys.p256dh}` - ); - - if (currentUserPushSub.data.p256dh !== parsedKey.keys.p256dh) { - return; - } - setWebPushEnabled(true); - } else { - setWebPushEnabled(false); - } - }); - }) - .catch(function (error) { - setWebPushEnabled(false); - // eslint-disable-next-line no-console - console.log( - '[SW] Failure retrieving push manager subscription, error:', - error - ); - }); - } - }, [user?.id]); - - if (!data && !error) { - return ; - } - - return ( - <> - { - try { - await axios.post( - `/api/v1/user/${user?.id}/settings/notifications`, - { - pgpKey: data?.pgpKey, - discordId: data?.discordId, - pushbulletAccessToken: data?.pushbulletAccessToken, - pushoverApplicationToken: data?.pushoverApplicationToken, - pushoverUserKey: data?.pushoverUserKey, - telegramChatId: data?.telegramChatId, - telegramSendSilently: data?.telegramSendSilently, - notificationTypes: { - webpush: values.types, - }, - } - ); - mutate('/api/v1/settings/public'); - addToast(intl.formatMessage(messages.webpushsettingssaved), { - appearance: 'success', - autoDismiss: true, - }); - } catch (e) { - addToast(intl.formatMessage(messages.webpushsettingsfailed), { - appearance: 'error', - autoDismiss: true, - }); - } finally { - revalidate(); - } - }} - > - {({ - errors, - touched, - isSubmitting, - isValid, - values, - setFieldValue, - setFieldTouched, - }) => { - return ( -
- { - setFieldValue('types', newTypes); - setFieldTouched('types'); - }} - error={ - errors.types && touched.types - ? (errors.types as string) - : undefined - } - /> -
-
- - - - - - -
-
- - ); - }} -
-
-

- {intl.formatMessage(messages.managedevices)} -

-
- {dataDevices?.length ? ( - dataDevices?.map((device, index) => ( -
- -
- )) - ) : ( - <> - - - )} -
-
- - ); -}; - -export default UserWebPushSettings; diff --git a/src/i18n/locale/en.json b/src/i18n/locale/en.json index 37c82c00d..568895313 100644 --- a/src/i18n/locale/en.json +++ b/src/i18n/locale/en.json @@ -1106,25 +1106,6 @@ "components.UserProfile.UserSettings.UserGeneralSettings.toastSettingsSuccess": "Settings saved successfully!", "components.UserProfile.UserSettings.UserGeneralSettings.user": "User", "components.UserProfile.UserSettings.UserGeneralSettings.validationDiscordId": "You must provide a valid Discord user ID", - "components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.browser": "Browser", - "components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.created": "Created", - "components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.deletesubscription": "Delete Subscription", - "components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.device": "Device", - "components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablewebpush": "Disable web push", - "components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.disablingwebpusherror": "Something went wrong while disabling web push.", - "components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablewebpush": "Enable web push", - "components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.enablingwebpusherror": "Something went wrong while enabling web push.", - "components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.engine": "Engine", - "components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.managedevices": "Manage Devices", - "components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.nodevicestoshow": "You have no web push subscriptions to show.", - "components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.operatingsystem": "Operating System", - "components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleted": "Subscription deleted.", - "components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.subscriptiondeleteerror": "Something went wrong while deleting the user subscription.", - "components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.type": "type", - "components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeendisabled": "Web push has been disabled.", - "components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushhasbeenenabled": "Web push has been enabled.", - "components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingsfailed": "Web push notification settings failed to save.", - "components.UserProfile.UserSettings.UserNotificationSettings.UserNotificationsWebPush.webpushsettingssaved": "Web push notification settings saved successfully!", "components.UserProfile.UserSettings.UserNotificationSettings.deviceDefault": "Device Default", "components.UserProfile.UserSettings.UserNotificationSettings.discordId": "User ID", "components.UserProfile.UserSettings.UserNotificationSettings.discordIdTip": "The multi-digit ID number associated with your user account", @@ -1161,6 +1142,8 @@ "components.UserProfile.UserSettings.UserNotificationSettings.validationPushoverUserKey": "You must provide a valid user or group key", "components.UserProfile.UserSettings.UserNotificationSettings.validationTelegramChatId": "You must provide a valid chat ID", "components.UserProfile.UserSettings.UserNotificationSettings.webpush": "Web Push", + "components.UserProfile.UserSettings.UserNotificationSettings.webpushsettingsfailed": "Web push notification settings failed to save.", + "components.UserProfile.UserSettings.UserNotificationSettings.webpushsettingssaved": "Web push notification settings saved successfully!", "components.UserProfile.UserSettings.UserPasswordChange.confirmpassword": "Confirm Password", "components.UserProfile.UserSettings.UserPasswordChange.currentpassword": "Current Password", "components.UserProfile.UserSettings.UserPasswordChange.newpassword": "New Password", @@ -1241,7 +1224,6 @@ "i18n.saving": "Saving…", "i18n.settings": "Settings", "i18n.showingresults": "Showing {from} to {to} of {total} results", - "i18n.specials": "Specials", "i18n.status": "Status", "i18n.test": "Test", "i18n.testing": "Testing…", diff --git a/yarn.lock b/yarn.lock index 5555ad10e..886aee53e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4040,11 +4040,6 @@ "@types/express" "*" "@types/serve-static" "*" -"@types/ua-parser-js@^0.7.36": - version "0.7.36" - resolved "https://registry.yarnpkg.com/@types/ua-parser-js/-/ua-parser-js-0.7.36.tgz#9bd0b47f26b5a3151be21ba4ce9f5fa457c5f190" - integrity sha512-N1rW+njavs70y2cApeIw1vLMYXRwfBy+7trgavGuuTfOd7j1Yh7QTRc/yqsPl6ncokt72ZXuxEU0PiCp9bSwNQ== - "@types/unist@*", "@types/unist@^2.0.0": version "2.0.6" resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.6.tgz#250a7b16c3b91f672a24552ec64678eeb1d3a08d" @@ -13337,11 +13332,6 @@ typescript@^4.0, typescript@^4.6.4, typescript@^4.7: resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.4.tgz#a2a3d2756c079abda241d75f149df9d561091e78" integrity sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg== -ua-parser-js@^1.0.35: - version "1.0.35" - resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-1.0.35.tgz#c4ef44343bc3db0a3cbefdf21822f1b1fc1ab011" - integrity sha512-fKnGuqmTBnIE+/KXSzCn4db8RTigUzw1AN0DmdU6hJovUTbYJKyqj+8Mt1c4VfRDnOVJnENmfYkIPZ946UrSAA== - uc.micro@^1.0.1: version "1.0.6" resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.6.tgz#9c411a802a409a91fc6cf74081baba34b24499ac"