diff --git a/libs/angular/src/services/jslib-services.module.ts b/libs/angular/src/services/jslib-services.module.ts index 9cb39a35856..541260c6fc3 100644 --- a/libs/angular/src/services/jslib-services.module.ts +++ b/libs/angular/src/services/jslib-services.module.ts @@ -1478,7 +1478,7 @@ const safeProviders: SafeProvider[] = [ safeProvider({ provide: EndUserNotificationService, useClass: DefaultEndUserNotificationService, - deps: [StateProvider, ApiServiceAbstraction], + deps: [StateProvider, ApiServiceAbstraction, NotificationsService], }), safeProvider({ provide: DeviceTrustToastServiceAbstraction, diff --git a/libs/common/src/enums/notification-type.enum.ts b/libs/common/src/enums/notification-type.enum.ts index db59fcafa69..c366af1eb61 100644 --- a/libs/common/src/enums/notification-type.enum.ts +++ b/libs/common/src/enums/notification-type.enum.ts @@ -24,4 +24,6 @@ export enum NotificationType { SyncOrganizations = 17, SyncOrganizationStatusChanged = 18, SyncOrganizationCollectionSettingChanged = 19, + Notification = 20, + NotificationStatus = 21, } diff --git a/libs/common/src/platform/notifications/internal/noop-notifications.service.ts b/libs/common/src/platform/notifications/internal/noop-notifications.service.ts index f79cabfca8a..9c2435fb1a7 100644 --- a/libs/common/src/platform/notifications/internal/noop-notifications.service.ts +++ b/libs/common/src/platform/notifications/internal/noop-notifications.service.ts @@ -1,9 +1,14 @@ -import { Subscription } from "rxjs"; +import { Observable, Subject, Subscription } from "rxjs"; + +import { NotificationResponse } from "@bitwarden/common/models/response/notification.response"; +import { UserId } from "@bitwarden/common/types/guid"; import { LogService } from "../../abstractions/log.service"; import { NotificationsService } from "../notifications.service"; export class NoopNotificationsService implements NotificationsService { + notifications$: Observable = new Subject(); + constructor(private logService: LogService) {} startListening(): Subscription { diff --git a/libs/common/src/platform/notifications/notifications.service.ts b/libs/common/src/platform/notifications/notifications.service.ts index aa4ff2a57a6..2adc66e361f 100644 --- a/libs/common/src/platform/notifications/notifications.service.ts +++ b/libs/common/src/platform/notifications/notifications.service.ts @@ -1,9 +1,13 @@ -import { Subscription } from "rxjs"; +import { Observable, Subscription } from "rxjs"; + +import { NotificationResponse } from "@bitwarden/common/models/response/notification.response"; +import { UserId } from "@bitwarden/common/types/guid"; /** * A service offering abilities to interact with push notifications from the server. */ export abstract class NotificationsService { + abstract notifications$: Observable; /** * Starts automatic listening and processing of notifications, should only be called once per application, * or you will risk notifications being processed multiple times. diff --git a/libs/vault/src/notifications/abstractions/end-user-notification.service.ts b/libs/vault/src/notifications/abstractions/end-user-notification.service.ts index 2ed7e1de631..fe2852994f7 100644 --- a/libs/vault/src/notifications/abstractions/end-user-notification.service.ts +++ b/libs/vault/src/notifications/abstractions/end-user-notification.service.ts @@ -34,13 +34,6 @@ export abstract class EndUserNotificationService { */ abstract markAsDeleted(notificationId: any, userId: UserId): Promise; - /** - * Create/update a notification in the state for the user specified within the notification. - * @remarks This method should only be called when a notification payload is received from the web socket. - * @param notification - */ - abstract upsert(notification: Notification): Promise; - /** * Clear all notifications from state for the given user. * @param userId diff --git a/libs/vault/src/notifications/services/default-end-user-notification.service.spec.ts b/libs/vault/src/notifications/services/default-end-user-notification.service.spec.ts index ac4304998bc..1d7b2e5aa19 100644 --- a/libs/vault/src/notifications/services/default-end-user-notification.service.spec.ts +++ b/libs/vault/src/notifications/services/default-end-user-notification.service.spec.ts @@ -1,7 +1,8 @@ import { TestBed } from "@angular/core/testing"; -import { firstValueFrom } from "rxjs"; +import { firstValueFrom, of } from "rxjs"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; +import { NotificationsService } from "@bitwarden/common/platform/notifications"; import { StateProvider } from "@bitwarden/common/platform/state"; import { NotificationId, UserId } from "@bitwarden/common/types/guid"; import { DefaultEndUserNotificationService } from "@bitwarden/vault"; @@ -36,6 +37,12 @@ describe("End User Notification Center Service", () => { send: mockApiSend, }, }, + { + provide: NotificationsService, + useValue: { + notifications$: of(null), + }, + }, ], }); }); diff --git a/libs/vault/src/notifications/services/default-end-user-notification.service.ts b/libs/vault/src/notifications/services/default-end-user-notification.service.ts index 517a968f8af..404cb7c75c7 100644 --- a/libs/vault/src/notifications/services/default-end-user-notification.service.ts +++ b/libs/vault/src/notifications/services/default-end-user-notification.service.ts @@ -1,8 +1,10 @@ import { Injectable } from "@angular/core"; -import { map, Observable, switchMap } from "rxjs"; +import { concatMap, filter, map, Observable, switchMap } from "rxjs"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; +import { NotificationType } from "@bitwarden/common/enums"; import { ListResponse } from "@bitwarden/common/models/response/list.response"; +import { NotificationsService } from "@bitwarden/common/platform/notifications"; import { StateProvider } from "@bitwarden/common/platform/state"; import { UserId } from "@bitwarden/common/types/guid"; @@ -14,12 +16,30 @@ import { NOTIFICATIONS } from "../state/end-user-notification.state"; /** * A service for retrieving and managing notifications for end users. */ -@Injectable() +@Injectable({ + providedIn: "root", +}) export class DefaultEndUserNotificationService implements EndUserNotificationService { constructor( private stateProvider: StateProvider, private apiService: ApiService, - ) {} + private defaultNotifications: NotificationsService, + ) { + this.defaultNotifications.notifications$ + .pipe( + filter( + ([notification]) => + notification.type === NotificationType.Notification || + notification.type === NotificationType.NotificationStatus, + ), + concatMap(([notification, userId]) => + this.updateNotificationState(userId, [ + new NotificationViewData(notification.payload as NotificationViewResponse), + ]), + ), + ) + .subscribe(); + } notifications$ = perUserCache$((userId: UserId): Observable => { return this.notificationState(userId).state$.pipe( @@ -58,8 +78,6 @@ export class DefaultEndUserNotificationService implements EndUserNotificationSer await this.getNotifications(userId); } - upsert(notification: Notification): any {} - async clearState(userId: UserId): Promise { await this.updateNotificationState(userId, []); }