diff --git a/apps/web/src/app/core/event.service.spec.ts b/apps/web/src/app/core/event.service.spec.ts index 42120d607b9..27b83641040 100644 --- a/apps/web/src/app/core/event.service.spec.ts +++ b/apps/web/src/app/core/event.service.spec.ts @@ -17,6 +17,8 @@ import { OrganizationId, UserId } from "@bitwarden/common/types/guid"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; +import { GroupApiService, GroupView } from "../admin-console/organizations/core"; + import { EventService } from "./event.service"; describe("EventService", () => { @@ -27,10 +29,12 @@ describe("EventService", () => { let mockCipherService = mock(); let mockOrgUserApiService = mock(); let mockCollectionService = mock(); + let mockGroupApiService = mock(); const userId = Utils.newGuid() as UserId; const orgId = Utils.newGuid() as OrganizationId; const collectionId = Utils.newGuid() as string; + const groupId = Utils.newGuid() as string; const orgUserMiniResponse: ListResponse = { continuationToken: null, @@ -50,6 +54,13 @@ describe("EventService", () => { } as CollectionView, ]; + const groupViews = [ + { + id: groupId, + name: "Test Group", + } as GroupView, + ]; + const baseEvent = { type: EventType.Cipher_Created, cipherId: "abcdef1234567890", @@ -57,6 +68,7 @@ describe("EventService", () => { organizationUserId: userId, userId: userId, collectionId: collectionId, + groupId: groupId, deviceType: 0, // Android } as any; @@ -67,6 +79,7 @@ describe("EventService", () => { mockCipherService = mock(); mockOrgUserApiService = mock(); mockCollectionService = mock(); + mockGroupApiService = mock(); eventService = new EventService( mocki18nService, mockPolicyService, @@ -74,6 +87,7 @@ describe("EventService", () => { mockCipherService, mockOrgUserApiService, mockCollectionService, + mockGroupApiService, ); // reset mocks @@ -92,6 +106,7 @@ describe("EventService", () => { ]); mockOrgUserApiService.getAllMiniUserDetails.mockResolvedValue(orgUserMiniResponse); mockCollectionService.getAllDecrypted.mockResolvedValue(collectionViews); + mockGroupApiService.getAll.mockResolvedValue(groupViews); // this method will use the mocks defined above await eventService.loadAllOrganizationInfo(orgId, userId); @@ -280,4 +295,27 @@ describe("EventService", () => { }); }); }); + + describe("getEventInfo for Groups", () => { + const testCases = [ + { type: EventType.Group_Created, eventName: "createdGroupId" }, + { type: EventType.Group_Updated, eventName: "editedGroupId" }, + { type: EventType.Group_Deleted, eventName: "deletedGroupId" }, + ]; + + testCases.forEach(({ type, eventName }) => { + it(`should return correct info for group event type ${type}`, async () => { + const event = { ...baseEvent, type, groupId }; + + const info = await eventService.getEventInfo(event); + + expect(info.message).toContain("Test Group"); + 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 Group"); + }); + }); + }); }); diff --git a/apps/web/src/app/core/event.service.ts b/apps/web/src/app/core/event.service.ts index efce424705a..84f51768151 100644 --- a/apps/web/src/app/core/event.service.ts +++ b/apps/web/src/app/core/event.service.ts @@ -14,12 +14,15 @@ import { OrganizationId, UserId } from "@bitwarden/common/types/guid"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; +import { GroupApiService } from "../admin-console/organizations/core"; + @Injectable() export class EventService { private policies: Policy[] = []; private ciphers: CipherView[] = []; private organizationUserIdMap: Map = new Map(); private collections: Map = new Map(); + private groupIdMap: Map = new Map(); constructor( private i18nService: I18nService, @@ -28,6 +31,7 @@ export class EventService { private cipherService: CipherService, private organizationUserApiService: OrganizationUserApiService, private collectionService: CollectionService, + private groupApiService: GroupApiService, ) { accountService.activeAccount$ .pipe( @@ -66,6 +70,10 @@ export class EventService { (await this.collectionService.getAllDecrypted()).map((c) => { this.collections.set(c.id, { name: c.name }); }); + + (await this.groupApiService.getAll(organizationId)).map((g) => { + this.groupIdMap.set(g.id, { name: g.name }); + }); } async getEventInfo(ev: EventResponse, options = new EventOptions()): Promise { @@ -300,14 +308,20 @@ export class EventService { case EventType.Group_Created: msg = this.i18nService.t("createdGroupId", this.formatGroupId(ev)); humanReadableMsg = this.i18nService.t("createdGroupId", this.getShortId(ev.groupId)); + eventName = this.i18nService.t("createdGroupId", ""); + eventLink = this.formatGroupId(ev); break; case EventType.Group_Updated: msg = this.i18nService.t("editedGroupId", this.formatGroupId(ev)); humanReadableMsg = this.i18nService.t("editedGroupId", this.getShortId(ev.groupId)); + eventName = this.i18nService.t("editedGroupId", ""); + eventLink = this.formatGroupId(ev); break; case EventType.Group_Deleted: msg = this.i18nService.t("deletedGroupId", this.formatGroupId(ev)); humanReadableMsg = this.i18nService.t("deletedGroupId", this.getShortId(ev.groupId)); + eventName = this.i18nService.t("deletedGroupId", ""); + eventLink = this.formatGroupId(ev); break; // Org user case EventType.OrganizationUser_Invited: @@ -683,7 +697,8 @@ export class EventService { private formatGroupId(ev: EventResponse) { const shortId = this.getShortId(ev.groupId); - const a = this.makeAnchor(shortId); + const anchorName = this.groupIdMap.get(ev.groupId)?.name ?? shortId; + const a = this.makeAnchor(anchorName); a.setAttribute("href", "#/organizations/" + ev.organizationId + "/groups?search=" + shortId); return a.outerHTML; }