From b6a11a4a8ed1aa47f355ff41f1724770393cba42 Mon Sep 17 00:00:00 2001 From: Prithpal Sooriya Date: Fri, 27 Sep 2024 16:08:07 +0100 Subject: [PATCH] feat: add reset notifications flow (#4738) ## Explanation This adds the ability for users or developers to reset their remote notification state. For example recovering from a corrupted state, or to just clear existing notifications. ## References https://consensyssoftware.atlassian.net/browse/NOTIFY-1168 ## Changelog ### `@metamask/notification-services-controller` - **ADDED**: `resetNotifications` option during the notification creation flow ## Checklist - [x] I've updated the test suite for new or updated code as appropriate - [x] I've updated documentation (JSDoc, Markdown, etc.) for new or updated code as appropriate - [x] I've highlighted breaking changes using the "BREAKING" category above as appropriate - [x] I've prepared draft pull requests for clients and consumer packages to resolve any breaking changes --- .../NotificationServicesController.test.ts | 23 +++++++++++++++++++ .../NotificationServicesController.ts | 15 ++++++++++-- 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/packages/notification-services-controller/src/NotificationServicesController/NotificationServicesController.test.ts b/packages/notification-services-controller/src/NotificationServicesController/NotificationServicesController.test.ts index 87154aa8c0..38ed6a2176 100644 --- a/packages/notification-services-controller/src/NotificationServicesController/NotificationServicesController.test.ts +++ b/packages/notification-services-controller/src/NotificationServicesController/NotificationServicesController.test.ts @@ -306,6 +306,29 @@ describe('metamask-notifications - createOnChainTriggers()', () => { ); } }); + + it('creates new triggers if a user has chosen to reset notifications', async () => { + const { + messenger, + mockInitializeUserStorage, + mockEnablePushNotifications, + mockCreateOnChainTriggers, + mockPerformGetStorage, + } = arrangeMocks(); + const controller = new NotificationServicesController({ + messenger, + env: { featureAnnouncements: featureAnnouncementsEnv }, + }); + + const result = await controller.createOnChainTriggers({ + resetNotifications: true, + }); + expect(result).toBeDefined(); + expect(mockPerformGetStorage).not.toHaveBeenCalled(); // not called as we are resetting notifications + expect(mockInitializeUserStorage).toHaveBeenCalled(); // called since no user storage (this is an existing user) + expect(mockCreateOnChainTriggers).toHaveBeenCalled(); + expect(mockEnablePushNotifications).toHaveBeenCalled(); + }); }); describe('metamask-notifications - deleteOnChainTriggersByAccount', () => { diff --git a/packages/notification-services-controller/src/NotificationServicesController/NotificationServicesController.ts b/packages/notification-services-controller/src/NotificationServicesController/NotificationServicesController.ts index 0888cf9f32..2ffc48d63c 100644 --- a/packages/notification-services-controller/src/NotificationServicesController/NotificationServicesController.ts +++ b/packages/notification-services-controller/src/NotificationServicesController/NotificationServicesController.ts @@ -786,10 +786,15 @@ export default class NotificationServicesController extends BaseController< * * **Action** - Used during Sign In / Enabling of notifications. * + * @param opts - optional options to mutate this functionality + * @param opts.resetNotifications - this will not use the users stored preferences, and instead re-create notification triggers + * It will help in case uses get into a corrupted state or wants to wipe their notifications. * @returns The updated or newly created user storage. * @throws {Error} Throws an error if unauthenticated or from other operations. */ - public async createOnChainTriggers(): Promise { + public async createOnChainTriggers(opts?: { + resetNotifications?: boolean; + }): Promise { try { this.#setIsUpdatingMetamaskNotifications(true); @@ -800,7 +805,13 @@ export default class NotificationServicesController extends BaseController< const { accounts } = await this.#accounts.listAccounts(); - let userStorage = await this.#getUserStorage(); + // Attempt Get User Storage + // Will be null if entry does not exist, or a user is resetting their notifications + // Will be defined if entry exists + // Will throw if fails to get the user storage entry + let userStorage = opts?.resetNotifications + ? null + : await this.#getUserStorage(); // If userStorage does not exist, create a new one // All the triggers created are set as: "disabled"