diff --git a/apps/web/src/app/core/event.service.spec.ts b/apps/web/src/app/core/event.service.spec.ts index d178260211e..42120d607b9 100644 --- a/apps/web/src/app/core/event.service.spec.ts +++ b/apps/web/src/app/core/event.service.spec.ts @@ -1,6 +1,8 @@ import { mock } from "jest-mock-extended"; import { + CollectionService, + CollectionView, OrganizationUserApiService, OrganizationUserUserMiniResponse, } from "@bitwarden/admin-console/common"; @@ -24,9 +26,11 @@ describe("EventService", () => { let mockAccountService: AccountService; let mockCipherService = mock(); let mockOrgUserApiService = mock(); + let mockCollectionService = mock(); const userId = Utils.newGuid() as UserId; const orgId = Utils.newGuid() as OrganizationId; + const collectionId = Utils.newGuid() as string; const orgUserMiniResponse: ListResponse = { continuationToken: null, @@ -39,12 +43,20 @@ describe("EventService", () => { ], } as ListResponse; + const collectionViews = [ + { + id: collectionId, + name: "Test Collection", + } as CollectionView, + ]; + const baseEvent = { type: EventType.Cipher_Created, cipherId: "abcdef1234567890", organizationId: "orgid1234567890" as OrganizationId, organizationUserId: userId, userId: userId, + collectionId: collectionId, deviceType: 0, // Android } as any; @@ -54,14 +66,19 @@ describe("EventService", () => { mockAccountService = mockAccountServiceWith(userId); mockCipherService = mock(); mockOrgUserApiService = mock(); + mockCollectionService = mock(); eventService = new EventService( mocki18nService, mockPolicyService, mockAccountService, mockCipherService, mockOrgUserApiService, + mockCollectionService, ); + // reset mocks + jest.clearAllMocks(); + // Default mock for i18nService.t mocki18nService.t.mockImplementation((key: string, value?: string) => { if (value) { @@ -70,12 +87,11 @@ describe("EventService", () => { return key; }); - // mock response for getAllDecrypted mockCipherService.getAllDecrypted.mockResolvedValue([ { id: "abcdef1234567890", name: "Test Cipher" } as CipherView, ]); - // mock response for getAllMiniUserDetails mockOrgUserApiService.getAllMiniUserDetails.mockResolvedValue(orgUserMiniResponse); + mockCollectionService.getAllDecrypted.mockResolvedValue(collectionViews); // this method will use the mocks defined above await eventService.loadAllOrganizationInfo(orgId, userId); @@ -241,4 +257,27 @@ describe("EventService", () => { }); }); }); + + describe("getEventInfo for Collections", () => { + const testCases = [ + { type: EventType.Collection_Created, eventName: "createdCollectionId" }, + { type: EventType.Collection_Updated, eventName: "editedCollectionId" }, + { type: EventType.Collection_Deleted, eventName: "deletedCollectionId" }, + ]; + + testCases.forEach(({ type, eventName }) => { + it(`should return correct info for collection event type ${type}`, async () => { + const event = { ...baseEvent, type }; + + const info = await eventService.getEventInfo(event); + + expect(info.message).toContain("Test Collection"); + expect(info.humanReadableMessage).toContain(eventName); + expect(info.appIcon).toBe("bwi-mobile"); + expect(info.appName).toBe("mobile - Android"); + expect(info.eventName).toBe(eventName); + expect(info.eventLink).toContain("Test Collection"); + }); + }); + }); }); diff --git a/apps/web/src/app/core/event.service.ts b/apps/web/src/app/core/event.service.ts index 79e4078f5ca..efce424705a 100644 --- a/apps/web/src/app/core/event.service.ts +++ b/apps/web/src/app/core/event.service.ts @@ -1,7 +1,7 @@ import { Injectable } from "@angular/core"; import { switchMap } from "rxjs"; -import { OrganizationUserApiService } from "@bitwarden/admin-console/common"; +import { CollectionService, OrganizationUserApiService } from "@bitwarden/admin-console/common"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { PolicyType } from "@bitwarden/common/admin-console/enums"; import { Policy } from "@bitwarden/common/admin-console/models/domain/policy"; @@ -19,6 +19,7 @@ export class EventService { private policies: Policy[] = []; private ciphers: CipherView[] = []; private organizationUserIdMap: Map = new Map(); + private collections: Map = new Map(); constructor( private i18nService: I18nService, @@ -26,6 +27,7 @@ export class EventService { accountService: AccountService, private cipherService: CipherService, private organizationUserApiService: OrganizationUserApiService, + private collectionService: CollectionService, ) { accountService.activeAccount$ .pipe( @@ -57,10 +59,13 @@ export class EventService { async loadAllOrganizationInfo(organizationId: OrganizationId, userId: UserId) { this.ciphers = await this.cipherService.getAllDecrypted(userId); - const orgUsers = await this.organizationUserApiService.getAllMiniUserDetails(organizationId); - orgUsers.data.forEach((u) => { + (await this.organizationUserApiService.getAllMiniUserDetails(organizationId)).data.map((u) => { this.organizationUserIdMap.set(u.id, { name: u.name, email: u.email }); }); + + (await this.collectionService.getAllDecrypted()).map((c) => { + this.collections.set(c.id, { name: c.name }); + }); } async getEventInfo(ev: EventResponse, options = new EventOptions()): Promise { @@ -270,6 +275,8 @@ export class EventService { "createdCollectionId", this.getShortId(ev.collectionId), ); + eventName = this.i18nService.t("createdCollectionId", ""); + eventLink = this.formatCollectionId(ev); break; case EventType.Collection_Updated: msg = this.i18nService.t("editedCollectionId", this.formatCollectionId(ev)); @@ -277,6 +284,8 @@ export class EventService { "editedCollectionId", this.getShortId(ev.collectionId), ); + eventName = this.i18nService.t("editedCollectionId", ""); + eventLink = this.formatCollectionId(ev); break; case EventType.Collection_Deleted: msg = this.i18nService.t("deletedCollectionId", this.formatCollectionId(ev)); @@ -284,6 +293,8 @@ export class EventService { "deletedCollectionId", this.getShortId(ev.collectionId), ); + eventName = this.i18nService.t("deletedCollectionId", ""); + eventLink = this.formatCollectionId(ev); break; // Group case EventType.Group_Created: @@ -679,7 +690,10 @@ export class EventService { private formatCollectionId(ev: EventResponse) { const shortId = this.getShortId(ev.collectionId); - const a = this.makeAnchor(shortId); + + const anchorName = this.collections.get(ev.collectionId)?.name ?? shortId; + + const a = this.makeAnchor(anchorName); a.setAttribute( "href", `#/organizations/${ev.organizationId}/vault?collectionId=${ev.collectionId}`,