Skip to content

Commit ff35821

Browse files
authored
[PM-28746] Item transfer event logs (bitwarden#18032)
* [PM-28746] Add item organization event types and i18n strings * [PM-28746] Log event when transfer is accepted or declined
1 parent 524bd9a commit ff35821

File tree

5 files changed

+95
-2
lines changed

5 files changed

+95
-2
lines changed

apps/web/src/app/core/event.service.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,12 @@ export class EventService {
452452
this.getShortId(ev.organizationId),
453453
);
454454
break;
455+
case EventType.Organization_ItemOrganization_Accepted:
456+
msg = humanReadableMsg = this.i18nService.t("userAcceptedTransfer");
457+
break;
458+
case EventType.Organization_ItemOrganization_Declined:
459+
msg = humanReadableMsg = this.i18nService.t("userDeclinedTransfer");
460+
break;
455461

456462
// Policies
457463
case EventType.Policy_Updated: {

apps/web/src/locales/en/messages.json

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4214,6 +4214,12 @@
42144214
}
42154215
}
42164216
},
4217+
"userAcceptedTransfer": {
4218+
"message": "Accepted transfer to organization ownership."
4219+
},
4220+
"userDeclinedTransfer": {
4221+
"message": "Revoked for declining transfer to organization ownership."
4222+
},
42174223
"invitedUserId": {
42184224
"message": "Invited user $ID$.",
42194225
"placeholders": {
@@ -12411,7 +12417,7 @@
1241112417
"placeholders": {
1241212418
"organization": {
1241312419
"content": "$1",
12414-
"example": "My Org Name"
12420+
"example": "My Org Name"
1241512421
}
1241612422
}
1241712423
},
@@ -12420,7 +12426,7 @@
1242012426
"placeholders": {
1242112427
"organization": {
1242212428
"content": "$1",
12423-
"example": "My Org Name"
12429+
"example": "My Org Name"
1242412430
}
1242512431
}
1242612432
},

libs/common/src/enums/event-type.enum.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ export enum EventType {
7979
Organization_CollectionManagement_LimitItemDeletionDisabled = 1615,
8080
Organization_CollectionManagement_AllowAdminAccessToAllCollectionItemsEnabled = 1616,
8181
Organization_CollectionManagement_AllowAdminAccessToAllCollectionItemsDisabled = 1617,
82+
Organization_ItemOrganization_Accepted = 1618,
83+
Organization_ItemOrganization_Declined = 1619,
8284

8385
Policy_Updated = 1700,
8486

libs/vault/src/services/default-vault-items-transfer.service.spec.ts

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@ import { firstValueFrom, of, Subject } from "rxjs";
33

44
// eslint-disable-next-line no-restricted-imports
55
import { CollectionService, CollectionView } from "@bitwarden/admin-console/common";
6+
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
67
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
78
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
89
import { PolicyType } from "@bitwarden/common/admin-console/enums";
910
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
1011
import { Policy } from "@bitwarden/common/admin-console/models/domain/policy";
12+
import { EventType } from "@bitwarden/common/enums";
1113
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
1214
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
1315
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
@@ -37,6 +39,7 @@ describe("DefaultVaultItemsTransferService", () => {
3739
let mockI18nService: MockProxy<I18nService>;
3840
let mockDialogService: MockProxy<DialogService>;
3941
let mockToastService: MockProxy<ToastService>;
42+
let mockEventCollectionService: MockProxy<EventCollectionService>;
4043
let mockConfigService: MockProxy<ConfigService>;
4144

4245
const userId = "user-id" as UserId;
@@ -71,6 +74,7 @@ describe("DefaultVaultItemsTransferService", () => {
7174
mockI18nService = mock<I18nService>();
7275
mockDialogService = mock<DialogService>();
7376
mockToastService = mock<ToastService>();
77+
mockEventCollectionService = mock<EventCollectionService>();
7478
mockConfigService = mock<ConfigService>();
7579

7680
mockI18nService.t.mockImplementation((key) => key);
@@ -85,6 +89,7 @@ describe("DefaultVaultItemsTransferService", () => {
8589
mockI18nService,
8690
mockDialogService,
8791
mockToastService,
92+
mockEventCollectionService,
8893
mockConfigService,
8994
);
9095
});
@@ -774,6 +779,63 @@ describe("DefaultVaultItemsTransferService", () => {
774779
expect(mockDialogService.open).toHaveBeenCalledTimes(4);
775780
expect(mockCipherService.shareManyWithServer).not.toHaveBeenCalled();
776781
});
782+
783+
describe("event logs", () => {
784+
it("logs accepted event when user accepts transfer", async () => {
785+
const personalCiphers = [{ id: "cipher-1" } as CipherView];
786+
setupMocksForEnforcementScenario({
787+
policies: [policy],
788+
organizations: [organization],
789+
ciphers: personalCiphers,
790+
defaultCollection: {
791+
id: collectionId,
792+
organizationId: organizationId,
793+
isDefaultCollection: true,
794+
} as CollectionView,
795+
});
796+
797+
mockDialogService.open.mockReturnValueOnce(
798+
createMockDialogRef(TransferItemsDialogResult.Accepted),
799+
);
800+
mockCipherService.shareManyWithServer.mockResolvedValue(undefined);
801+
802+
await service.enforceOrganizationDataOwnership(userId);
803+
804+
expect(mockEventCollectionService.collect).toHaveBeenCalledWith(
805+
EventType.Organization_ItemOrganization_Accepted,
806+
undefined,
807+
undefined,
808+
organizationId,
809+
);
810+
});
811+
812+
it("logs declined event when user rejects transfer", async () => {
813+
const personalCiphers = [{ id: "cipher-1" } as CipherView];
814+
setupMocksForEnforcementScenario({
815+
policies: [policy],
816+
organizations: [organization],
817+
ciphers: personalCiphers,
818+
defaultCollection: {
819+
id: collectionId,
820+
organizationId: organizationId,
821+
isDefaultCollection: true,
822+
} as CollectionView,
823+
});
824+
825+
mockDialogService.open
826+
.mockReturnValueOnce(createMockDialogRef(TransferItemsDialogResult.Declined))
827+
.mockReturnValueOnce(createMockDialogRef(LeaveConfirmationDialogResult.Confirmed));
828+
829+
await service.enforceOrganizationDataOwnership(userId);
830+
831+
expect(mockEventCollectionService.collect).toHaveBeenCalledWith(
832+
EventType.Organization_ItemOrganization_Declined,
833+
undefined,
834+
undefined,
835+
organizationId,
836+
);
837+
});
838+
});
777839
});
778840

779841
describe("transferInProgress$", () => {

libs/vault/src/services/default-vault-items-transfer.service.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,12 @@ import {
1111

1212
// eslint-disable-next-line no-restricted-imports
1313
import { CollectionService } from "@bitwarden/admin-console/common";
14+
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
1415
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
1516
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
1617
import { PolicyType } from "@bitwarden/common/admin-console/enums";
1718
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
19+
import { EventType } from "@bitwarden/common/enums";
1820
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
1921
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
2022
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
@@ -49,6 +51,7 @@ export class DefaultVaultItemsTransferService implements VaultItemsTransferServi
4951
private i18nService: I18nService,
5052
private dialogService: DialogService,
5153
private toastService: ToastService,
54+
private eventCollectionService: EventCollectionService,
5255
private configService: ConfigService,
5356
) {}
5457

@@ -160,6 +163,13 @@ export class DefaultVaultItemsTransferService implements VaultItemsTransferServi
160163

161164
if (!userAcceptedTransfer) {
162165
// TODO: Revoke user from organization if they decline migration and show toast PM-29465
166+
167+
await this.eventCollectionService.collect(
168+
EventType.Organization_ItemOrganization_Declined,
169+
undefined,
170+
undefined,
171+
migrationInfo.enforcingOrganization.id,
172+
);
163173
return;
164174
}
165175

@@ -175,6 +185,13 @@ export class DefaultVaultItemsTransferService implements VaultItemsTransferServi
175185
variant: "success",
176186
message: this.i18nService.t("itemsTransferred"),
177187
});
188+
189+
await this.eventCollectionService.collect(
190+
EventType.Organization_ItemOrganization_Accepted,
191+
undefined,
192+
undefined,
193+
migrationInfo.enforcingOrganization.id,
194+
);
178195
} catch (error) {
179196
this._transferInProgressSubject.next(false);
180197
this.logService.error("Error transferring personal items to organization", error);

0 commit comments

Comments
 (0)