mirror of
https://github.com/bitwarden/browser
synced 2026-02-08 20:50:28 +00:00
PM-23602 Collection name in event logs
This commit is contained in:
@@ -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<CipherService>();
|
||||
let mockOrgUserApiService = mock<OrganizationUserApiService>();
|
||||
let mockCollectionService = mock<CollectionService>();
|
||||
|
||||
const userId = Utils.newGuid() as UserId;
|
||||
const orgId = Utils.newGuid() as OrganizationId;
|
||||
const collectionId = Utils.newGuid() as string;
|
||||
|
||||
const orgUserMiniResponse: ListResponse<OrganizationUserUserMiniResponse> = {
|
||||
continuationToken: null,
|
||||
@@ -39,12 +43,20 @@ describe("EventService", () => {
|
||||
],
|
||||
} as ListResponse<OrganizationUserUserMiniResponse>;
|
||||
|
||||
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<CipherService>();
|
||||
mockOrgUserApiService = mock<OrganizationUserApiService>();
|
||||
mockCollectionService = mock<CollectionService>();
|
||||
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("<code>Test Collection</code>");
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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<string, { name: string; email: string }> = new Map();
|
||||
private collections: Map<string, { name: string }> = 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<EventInfo> {
|
||||
@@ -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}`,
|
||||
|
||||
Reference in New Issue
Block a user