From a9548f519e094086d3418acf24f7d0da1a6a797f Mon Sep 17 00:00:00 2001 From: Vijay Oommen Date: Mon, 16 Jun 2025 16:33:07 -0500 Subject: [PATCH] [PM-20112] Update Member Access report to use new server model (#15155) --- .../member-access-report.component.html | 2 +- .../response/member-access-report.response.ts | 49 +- .../services/member-access-report.mock.ts | 514 ++++++++++-------- .../member-access-report.service.spec.ts | 34 +- .../services/member-access-report.service.ts | 136 ++--- 5 files changed, 396 insertions(+), 339 deletions(-) diff --git a/bitwarden_license/bit-web/src/app/dirt/reports/member-access-report/member-access-report.component.html b/bitwarden_license/bit-web/src/app/dirt/reports/member-access-report/member-access-report.component.html index 31eb54d6110..0200e206327 100644 --- a/bitwarden_license/bit-web/src/app/dirt/reports/member-access-report/member-access-report.component.html +++ b/bitwarden_license/bit-web/src/app/dirt/reports/member-access-report/member-access-report.component.html @@ -36,7 +36,7 @@ - {{ "members" | i18n }} + {{ "members" | i18n }} {{ "groups" | i18n }} {{ "collections" | i18n }} {{ "items" | i18n }} diff --git a/bitwarden_license/bit-web/src/app/dirt/reports/member-access-report/response/member-access-report.response.ts b/bitwarden_license/bit-web/src/app/dirt/reports/member-access-report/response/member-access-report.response.ts index 959b70b9729..c500c6c0aec 100644 --- a/bitwarden_license/bit-web/src/app/dirt/reports/member-access-report/response/member-access-report.response.ts +++ b/bitwarden_license/bit-web/src/app/dirt/reports/member-access-report/response/member-access-report.response.ts @@ -2,7 +2,15 @@ import { BaseResponse } from "@bitwarden/common/models/response/base.response"; import { EncString } from "@bitwarden/common/platform/models/domain/enc-string"; import { Guid } from "@bitwarden/common/types/guid"; -export class MemberAccessDetails extends BaseResponse { +export class MemberAccessResponse extends BaseResponse { + userName: string; + email: string; + twoFactorEnabled: boolean; + accountRecoveryEnabled: boolean; + userGuid: Guid; + usesKeyConnector: boolean; + + cipherIds: Guid[] = []; collectionId: string; groupId: string; groupName: string; @@ -14,6 +22,14 @@ export class MemberAccessDetails extends BaseResponse { constructor(response: any) { super(response); + this.userName = this.getResponseProperty("UserName"); + this.email = this.getResponseProperty("Email"); + this.twoFactorEnabled = this.getResponseProperty("TwoFactorEnabled"); + this.accountRecoveryEnabled = this.getResponseProperty("AccountRecoveryEnabled"); + this.userGuid = this.getResponseProperty("UserGuid"); + this.usesKeyConnector = this.getResponseProperty("UsesKeyConnector"); + + this.cipherIds = this.getResponseProperty("CipherIds") || []; this.groupId = this.getResponseProperty("GroupId"); this.collectionId = this.getResponseProperty("CollectionId"); this.groupName = this.getResponseProperty("GroupName"); @@ -24,34 +40,3 @@ export class MemberAccessDetails extends BaseResponse { this.manage = this.getResponseProperty("Manage"); } } - -export class MemberAccessResponse extends BaseResponse { - userName: string; - email: string; - twoFactorEnabled: boolean; - accountRecoveryEnabled: boolean; - collectionsCount: number; - groupsCount: number; - totalItemCount: number; - accessDetails: MemberAccessDetails[] = []; - userGuid: Guid; - usesKeyConnector: boolean; - - constructor(response: any) { - super(response); - this.userName = this.getResponseProperty("UserName"); - this.email = this.getResponseProperty("Email"); - this.twoFactorEnabled = this.getResponseProperty("TwoFactorEnabled"); - this.accountRecoveryEnabled = this.getResponseProperty("AccountRecoveryEnabled"); - this.collectionsCount = this.getResponseProperty("CollectionsCount"); - this.groupsCount = this.getResponseProperty("GroupsCount"); - this.totalItemCount = this.getResponseProperty("TotalItemCount"); - this.userGuid = this.getResponseProperty("UserGuid"); - this.usesKeyConnector = this.getResponseProperty("UsesKeyConnector"); - - const details = this.getResponseProperty("AccessDetails"); - if (details != null) { - this.accessDetails = details.map((o: any) => new MemberAccessDetails(o)); - } - } -} diff --git a/bitwarden_license/bit-web/src/app/dirt/reports/member-access-report/services/member-access-report.mock.ts b/bitwarden_license/bit-web/src/app/dirt/reports/member-access-report/services/member-access-report.mock.ts index b07e4946ca7..ebf2b9abfc8 100644 --- a/bitwarden_license/bit-web/src/app/dirt/reports/member-access-report/services/member-access-report.mock.ts +++ b/bitwarden_license/bit-web/src/app/dirt/reports/member-access-report/services/member-access-report.mock.ts @@ -1,9 +1,7 @@ import { EncString } from "@bitwarden/common/platform/models/domain/enc-string"; +import { Guid } from "@bitwarden/common/types/guid"; -import { - MemberAccessDetails, - MemberAccessResponse, -} from "../response/member-access-report.response"; +import { MemberAccessResponse } from "../response/member-access-report.response"; export const memberAccessReportsMock: MemberAccessResponse[] = [ { @@ -11,223 +9,290 @@ export const memberAccessReportsMock: MemberAccessResponse[] = [ email: "sjohnson@email.com", twoFactorEnabled: true, accountRecoveryEnabled: true, - groupsCount: 2, - collectionsCount: 4, - totalItemCount: 20, - userGuid: "1234", + userGuid: "1001" as Guid, usesKeyConnector: false, - accessDetails: [ - { - groupId: "", - collectionId: "c1", - collectionName: new EncString("Collection 1"), - groupName: "", - itemCount: 10, - readOnly: false, - hidePasswords: false, - manage: false, - } as MemberAccessDetails, - { - groupId: "", - collectionId: "c2", - collectionName: new EncString("Collection 2"), - groupName: "", - itemCount: 20, - readOnly: false, - hidePasswords: false, - manage: false, - } as MemberAccessDetails, - { - groupId: "", - collectionId: "c3", - collectionName: new EncString("Collection 3"), - groupName: "", - itemCount: 30, - readOnly: false, - hidePasswords: false, - manage: false, - } as MemberAccessDetails, - { - groupId: "g1", - collectionId: "c1", - collectionName: new EncString("Collection 1"), - groupName: "Group 1", - itemCount: 30, - readOnly: false, - hidePasswords: false, - manage: false, - } as MemberAccessDetails, - { - groupId: "g1", - collectionId: "c2", - collectionName: new EncString("Collection 2"), - groupName: "Group 1", - itemCount: 20, - readOnly: false, - hidePasswords: false, - manage: false, - } as MemberAccessDetails, - ], - } as MemberAccessResponse, + groupId: "", + collectionId: "c1", + collectionName: new EncString("Collection 1"), + groupName: "", + itemCount: 10, + readOnly: false, + hidePasswords: false, + manage: false, + cipherIds: [], + } as unknown as MemberAccessResponse, + { + userName: "Sarah Johnson", + email: "sjohnson@email.com", + twoFactorEnabled: true, + accountRecoveryEnabled: true, + userGuid: "1001" as Guid, + usesKeyConnector: false, + groupId: "", + collectionId: "c2", + collectionName: new EncString("Collection 2"), + groupName: "", + itemCount: 20, + readOnly: false, + hidePasswords: false, + manage: false, + cipherIds: [], + } as unknown as MemberAccessResponse, + { + userName: "Sarah Johnson", + email: "sjohnson@email.com", + twoFactorEnabled: true, + accountRecoveryEnabled: true, + userGuid: "1001" as Guid, + usesKeyConnector: false, + groupId: "", + collectionId: "c3", + collectionName: new EncString("Collection 3"), + groupName: "", + itemCount: 30, + readOnly: false, + hidePasswords: false, + manage: false, + cipherIds: [], + } as unknown as MemberAccessResponse, + { + userName: "Sarah Johnson", + email: "sjohnson@email.com", + twoFactorEnabled: true, + accountRecoveryEnabled: true, + userGuid: "1001", + usesKeyConnector: false, + groupId: "g1", + collectionId: "c1", + collectionName: new EncString("Collection 1"), + groupName: "Group 1", + itemCount: 30, + readOnly: false, + hidePasswords: false, + manage: false, + cipherIds: [], + } as unknown as MemberAccessResponse, + { + userName: "Sarah Johnson", + email: "sjohnson@email.com", + twoFactorEnabled: true, + accountRecoveryEnabled: true, + userGuid: "1001", + usesKeyConnector: false, + groupId: "g1", + collectionId: "c2", + collectionName: new EncString("Collection 2"), + groupName: "Group 1", + itemCount: 20, + readOnly: false, + hidePasswords: false, + manage: false, + cipherIds: [], + } as unknown as MemberAccessResponse, { userName: "James Lull", email: "jlull@email.com", twoFactorEnabled: false, accountRecoveryEnabled: false, - groupsCount: 2, - collectionsCount: 4, - totalItemCount: 20, - userGuid: "1234", + userGuid: "2001", usesKeyConnector: false, - accessDetails: [ - { - groupId: "g4", - collectionId: "c4", - groupName: "Group 4", - collectionName: new EncString("Collection 4"), - itemCount: 5, - readOnly: false, - hidePasswords: false, - manage: false, - } as MemberAccessDetails, - { - groupId: "g4", - collectionId: "c5", - groupName: "Group 4", - collectionName: new EncString("Collection 5"), - itemCount: 15, - readOnly: false, - hidePasswords: false, - manage: false, - } as MemberAccessDetails, - { - groupId: "", - collectionId: "c4", - groupName: "", - collectionName: new EncString("Collection 4"), - itemCount: 5, - readOnly: false, - hidePasswords: false, - manage: false, - } as MemberAccessDetails, - { - groupId: "", - collectionId: "c5", - groupName: "", - collectionName: new EncString("Collection 5"), - itemCount: 15, - readOnly: false, - hidePasswords: false, - manage: false, - } as MemberAccessDetails, - ], - } as MemberAccessResponse, + groupId: "g4", + collectionId: "c4", + groupName: "Group 4", + collectionName: new EncString("Collection 4"), + itemCount: 5, + readOnly: false, + hidePasswords: false, + manage: false, + cipherIds: [], + } as unknown as MemberAccessResponse, + { + userName: "James Lull", + email: "jlull@email.com", + twoFactorEnabled: false, + accountRecoveryEnabled: false, + userGuid: "2001", + usesKeyConnector: false, + groupId: "g4", + collectionId: "c5", + groupName: "Group 4", + collectionName: new EncString("Collection 5"), + itemCount: 15, + readOnly: false, + hidePasswords: false, + manage: false, + cipherIds: [], + } as unknown as MemberAccessResponse, + { + userName: "James Lull", + email: "jlull@email.com", + twoFactorEnabled: false, + accountRecoveryEnabled: false, + userGuid: "2001", + usesKeyConnector: false, + groupId: "", + collectionId: "c4", + groupName: "", + collectionName: new EncString("Collection 4"), + itemCount: 5, + readOnly: false, + hidePasswords: false, + manage: false, + cipherIds: [], + } as unknown as MemberAccessResponse, + { + userName: "James Lull", + email: "jlull@email.com", + twoFactorEnabled: false, + accountRecoveryEnabled: false, + userGuid: "2001", + usesKeyConnector: false, + groupId: "", + collectionId: "c5", + groupName: "", + collectionName: new EncString("Collection 5"), + itemCount: 15, + readOnly: false, + hidePasswords: false, + manage: false, + cipherIds: [], + } as unknown as MemberAccessResponse, { userName: "Beth Williams", email: "bwilliams@email.com", twoFactorEnabled: true, accountRecoveryEnabled: true, - groupsCount: 2, - collectionsCount: 4, - totalItemCount: 20, - userGuid: "1234", + userGuid: "3001", usesKeyConnector: false, - accessDetails: [ - { - groupId: "", - collectionId: "c6", - groupName: "", - collectionName: new EncString("Collection 6"), - itemCount: 25, - readOnly: false, - hidePasswords: false, - manage: false, - } as MemberAccessDetails, - { - groupId: "g6", - collectionId: "c4", - groupName: "Group 6", - collectionName: new EncString("Collection 4"), - itemCount: 35, - readOnly: false, - hidePasswords: false, - manage: false, - } as MemberAccessDetails, - ], - } as MemberAccessResponse, + groupId: "", + collectionId: "c6", + groupName: "", + collectionName: new EncString("Collection 6"), + itemCount: 25, + readOnly: false, + hidePasswords: false, + manage: false, + cipherIds: [], + } as unknown as MemberAccessResponse, + { + userName: "Beth Williams", + email: "bwilliams@email.com", + twoFactorEnabled: true, + accountRecoveryEnabled: true, + userGuid: "3001", + usesKeyConnector: false, + groupId: "g6", + collectionId: "c4", + groupName: "Group 6", + collectionName: new EncString("Collection 4"), + itemCount: 35, + readOnly: false, + hidePasswords: false, + manage: false, + cipherIds: [], + } as unknown as MemberAccessResponse, { userName: "Ray Williams", email: "rwilliams@email.com", twoFactorEnabled: false, accountRecoveryEnabled: false, - groupsCount: 2, - collectionsCount: 4, - totalItemCount: 20, - userGuid: "1234", + userGuid: "4000", usesKeyConnector: false, - accessDetails: [ - { - groupId: "", - collectionId: "c7", - groupName: "", - collectionName: new EncString("Collection 7"), - itemCount: 8, - readOnly: false, - hidePasswords: false, - manage: false, - } as MemberAccessDetails, - { - groupId: "", - collectionId: "c8", - groupName: "", - collectionName: new EncString("Collection 8"), - itemCount: 12, - readOnly: false, - hidePasswords: false, - manage: false, - } as MemberAccessDetails, - { - groupId: "", - collectionId: "c9", - groupName: "", - collectionName: new EncString("Collection 9"), - itemCount: 16, - readOnly: false, - hidePasswords: false, - manage: false, - } as MemberAccessDetails, - { - groupId: "g9", - collectionId: "c7", - groupName: "Group 9", - collectionName: new EncString("Collection 7"), - itemCount: 8, - readOnly: false, - hidePasswords: false, - manage: false, - } as MemberAccessDetails, - { - groupId: "g10", - collectionId: "c8", - groupName: "Group 10", - collectionName: new EncString("Collection 8"), - itemCount: 12, - readOnly: false, - hidePasswords: false, - manage: false, - } as MemberAccessDetails, - { - groupId: "g11", - collectionId: "c9", - groupName: "Group 11", - collectionName: new EncString("Collection 9"), - itemCount: 16, - readOnly: false, - hidePasswords: false, - manage: false, - } as MemberAccessDetails, - ], - } as MemberAccessResponse, + groupId: "", + collectionId: "c7", + groupName: "", + collectionName: new EncString("Collection 7"), + itemCount: 8, + readOnly: false, + hidePasswords: false, + manage: false, + cipherIds: [], + } as unknown as MemberAccessResponse, + { + userName: "Ray Williams", + email: "rwilliams@email.com", + twoFactorEnabled: false, + accountRecoveryEnabled: false, + userGuid: "4000", + usesKeyConnector: false, + groupId: "", + collectionId: "c8", + groupName: "", + collectionName: new EncString("Collection 8"), + itemCount: 12, + readOnly: false, + hidePasswords: false, + manage: false, + cipherIds: [], + } as unknown as MemberAccessResponse, + { + userName: "Ray Williams", + email: "rwilliams@email.com", + twoFactorEnabled: false, + accountRecoveryEnabled: false, + userGuid: "4000", + usesKeyConnector: false, + groupId: "", + collectionId: "c9", + groupName: "", + collectionName: new EncString("Collection 9"), + itemCount: 16, + readOnly: false, + hidePasswords: false, + manage: false, + cipherIds: [], + } as unknown as MemberAccessResponse, + { + userName: "Ray Williams", + email: "rwilliams@email.com", + twoFactorEnabled: false, + accountRecoveryEnabled: false, + userGuid: "4000", + usesKeyConnector: false, + groupId: "g9", + collectionId: "c7", + groupName: "Group 9", + collectionName: new EncString("Collection 7"), + itemCount: 8, + readOnly: false, + hidePasswords: false, + manage: false, + cipherIds: [], + } as unknown as MemberAccessResponse, + { + userName: "Ray Williams", + email: "rwilliams@email.com", + twoFactorEnabled: false, + accountRecoveryEnabled: false, + userGuid: "4000", + usesKeyConnector: false, + groupId: "g10", + collectionId: "c8", + groupName: "Group 10", + collectionName: new EncString("Collection 8"), + itemCount: 12, + readOnly: false, + hidePasswords: false, + manage: false, + cipherIds: [], + } as unknown as MemberAccessResponse, + { + userName: "Ray Williams", + email: "rwilliams@email.com", + twoFactorEnabled: false, + accountRecoveryEnabled: false, + userGuid: "4000", + usesKeyConnector: false, + groupId: "g11", + collectionId: "c9", + groupName: "Group 11", + collectionName: new EncString("Collection 9"), + itemCount: 16, + readOnly: false, + hidePasswords: false, + manage: false, + cipherIds: [], + } as unknown as MemberAccessResponse, ]; export const memberAccessWithoutAccessDetailsReportsMock: MemberAccessResponse[] = [ @@ -236,34 +301,33 @@ export const memberAccessWithoutAccessDetailsReportsMock: MemberAccessResponse[] email: "asmith@email.com", twoFactorEnabled: true, accountRecoveryEnabled: true, - groupsCount: 2, - collectionsCount: 4, - totalItemCount: 20, - userGuid: "1234", + userGuid: "1234" as Guid, usesKeyConnector: false, - accessDetails: [ - { - groupId: "", - collectionId: "c1", - collectionName: new EncString("Collection 1"), - groupName: "Alice Group 1", - itemCount: 10, - readOnly: false, - hidePasswords: false, - manage: false, - } as MemberAccessDetails, - ], - } as MemberAccessResponse, + groupId: "", + collectionId: "c1", + collectionName: new EncString("Collection 1"), + groupName: "Alice Group 1", + itemCount: 10, + readOnly: false, + hidePasswords: false, + manage: false, + cipherIds: [], + } as unknown as MemberAccessResponse, { userName: "Robert Brown", email: "rbrown@email.com", twoFactorEnabled: false, accountRecoveryEnabled: false, - groupsCount: 2, - collectionsCount: 4, - totalItemCount: 20, - userGuid: "5678", + userGuid: "5678" as Guid, usesKeyConnector: false, - accessDetails: [] as MemberAccessDetails[], - } as MemberAccessResponse, + groupId: "", + collectionId: "c1", + collectionName: new EncString("Collection 1"), + groupName: "", + itemCount: 10, + readOnly: false, + hidePasswords: false, + manage: false, + cipherIds: [], + } as unknown as MemberAccessResponse, ]; diff --git a/bitwarden_license/bit-web/src/app/dirt/reports/member-access-report/services/member-access-report.service.spec.ts b/bitwarden_license/bit-web/src/app/dirt/reports/member-access-report/services/member-access-report.service.spec.ts index e6efac83616..ad388cfed04 100644 --- a/bitwarden_license/bit-web/src/app/dirt/reports/member-access-report/services/member-access-report.service.spec.ts +++ b/bitwarden_license/bit-web/src/app/dirt/reports/member-access-report/services/member-access-report.service.spec.ts @@ -35,36 +35,36 @@ describe("ImportService", () => { { name: "Sarah Johnson", email: "sjohnson@email.com", - collectionsCount: 4, - groupsCount: 2, - itemsCount: 20, + collectionsCount: 3, + groupsCount: 1, + itemsCount: 0, userGuid: expect.any(String), usesKeyConnector: expect.any(Boolean), }, { name: "James Lull", email: "jlull@email.com", - collectionsCount: 4, - groupsCount: 2, - itemsCount: 20, + collectionsCount: 2, + groupsCount: 1, + itemsCount: 0, userGuid: expect.any(String), usesKeyConnector: expect.any(Boolean), }, { name: "Beth Williams", email: "bwilliams@email.com", - collectionsCount: 4, - groupsCount: 2, - itemsCount: 20, + collectionsCount: 2, + groupsCount: 1, + itemsCount: 0, userGuid: expect.any(String), usesKeyConnector: expect.any(Boolean), }, { name: "Ray Williams", email: "rwilliams@email.com", - collectionsCount: 4, - groupsCount: 2, - itemsCount: 20, + collectionsCount: 3, + groupsCount: 3, + itemsCount: 0, userGuid: expect.any(String), usesKeyConnector: expect.any(Boolean), }, @@ -82,8 +82,8 @@ describe("ImportService", () => { (item) => (item.name === "Sarah Johnson" && item.group === "Group 1" && - item.totalItems === "20") || - (item.name === "James Lull" && item.group === "Group 4" && item.totalItems === "5"), + item.totalItems === "0") || + (item.name === "James Lull" && item.group === "Group 4" && item.totalItems === "0"), ) .map((item) => ({ name: item.name, @@ -102,7 +102,7 @@ describe("ImportService", () => { twoStepLogin: "memberAccessReportTwoFactorEnabledTrue", accountRecovery: "memberAccessReportAuthenticationEnabledTrue", group: "Group 1", - totalItems: "20", + totalItems: "0", }), expect.objectContaining({ email: "jlull@email.com", @@ -110,7 +110,7 @@ describe("ImportService", () => { twoStepLogin: "memberAccessReportTwoFactorEnabledFalse", accountRecovery: "memberAccessReportAuthenticationEnabledFalse", group: "Group 4", - totalItems: "5", + totalItems: "0", }), ]), ); @@ -131,7 +131,7 @@ describe("ImportService", () => { twoStepLogin: "memberAccessReportTwoFactorEnabledTrue", accountRecovery: "memberAccessReportAuthenticationEnabledTrue", group: "Alice Group 1", - totalItems: "10", + totalItems: "0", }), expect.objectContaining({ email: "rbrown@email.com", diff --git a/bitwarden_license/bit-web/src/app/dirt/reports/member-access-report/services/member-access-report.service.ts b/bitwarden_license/bit-web/src/app/dirt/reports/member-access-report/services/member-access-report.service.ts index 029dce8a404..0039788709e 100644 --- a/bitwarden_license/bit-web/src/app/dirt/reports/member-access-report/services/member-access-report.service.ts +++ b/bitwarden_license/bit-web/src/app/dirt/reports/member-access-report/services/member-access-report.service.ts @@ -5,13 +5,13 @@ import { Injectable } from "@angular/core"; import { CollectionAccessSelectionView } from "@bitwarden/admin-console/common"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { EncString } from "@bitwarden/common/platform/models/domain/enc-string"; -import { OrganizationId } from "@bitwarden/common/types/guid"; +import { Guid, OrganizationId } from "@bitwarden/common/types/guid"; import { getPermissionList, convertToPermission, } from "@bitwarden/web-vault/app/admin-console/organizations/shared/components/access-selector"; -import { MemberAccessDetails } from "../response/member-access-report.response"; +import { MemberAccessResponse } from "../response/member-access-report.response"; import { MemberAccessExportItem } from "../view/member-access-export.view"; import { MemberAccessReportView } from "../view/member-access-report.view"; @@ -34,15 +34,44 @@ export class MemberAccessReportService { organizationId: OrganizationId, ): Promise { const memberAccessData = await this.reportApiService.getMemberAccessData(organizationId); - const memberAccessReportViewCollection = memberAccessData.map((userData) => ({ - name: userData.userName, - email: userData.email, - collectionsCount: userData.collectionsCount, - groupsCount: userData.groupsCount, - itemsCount: userData.totalItemCount, - userGuid: userData.userGuid, - usesKeyConnector: userData.usesKeyConnector, - })); + + // group member access data by userGuid + const userMap = new Map(); + memberAccessData.forEach((userData) => { + const userGuid = userData.userGuid; + if (!userMap.has(userGuid)) { + userMap.set(userGuid, []); + } + userMap.get(userGuid)?.push(userData); + }); + + // aggregate user data + const memberAccessReportViewCollection: MemberAccessReportView[] = []; + userMap.forEach((userDataArray, userGuid) => { + const collectionCount = this.getDistinctCount( + userDataArray.map((data) => data.collectionId).filter((id) => !!id), + ); + const groupCount = this.getDistinctCount( + userDataArray.map((data) => data.groupId).filter((id) => !!id), + ); + const itemsCount = this.getDistinctCount( + userDataArray + .flatMap((data) => data.cipherIds) + .filter((id) => id !== "00000000-0000-0000-0000-000000000000"), + ); + const aggregatedData = { + userGuid: userGuid, + name: userDataArray[0].userName, + email: userDataArray[0].email, + collectionsCount: collectionCount, + groupsCount: groupCount, + itemsCount: itemsCount, + usesKeyConnector: userDataArray.some((data) => data.usesKeyConnector), + }; + + memberAccessReportViewCollection.push(aggregatedData); + }); + return memberAccessReportViewCollection; } @@ -50,13 +79,8 @@ export class MemberAccessReportService { organizationId: OrganizationId, ): Promise { const memberAccessReports = await this.reportApiService.getMemberAccessData(organizationId); - const collectionNames = memberAccessReports.flatMap((item) => - item.accessDetails.map((dtl) => { - if (dtl.collectionName) { - return dtl.collectionName.encryptedString; - } - }), - ); + const collectionNames = memberAccessReports.map((item) => item.collectionName.encryptedString); + const collectionNameMap = new Map(collectionNames.map((col) => [col, ""])); for await (const key of collectionNameMap.keys()) { const decrypted = new EncString(key); @@ -64,56 +88,35 @@ export class MemberAccessReportService { collectionNameMap.set(key, decrypted.decryptedValue); } - const exportItems = memberAccessReports.flatMap((report) => { - // to include users without access details - // which means a user has no groups, collections or items - if (report.accessDetails.length === 0) { - return [ - { - email: report.email, - name: report.userName, - twoStepLogin: report.twoFactorEnabled - ? this.i18nService.t("memberAccessReportTwoFactorEnabledTrue") - : this.i18nService.t("memberAccessReportTwoFactorEnabledFalse"), - accountRecovery: report.accountRecoveryEnabled - ? this.i18nService.t("memberAccessReportAuthenticationEnabledTrue") - : this.i18nService.t("memberAccessReportAuthenticationEnabledFalse"), - group: this.i18nService.t("memberAccessReportNoGroup"), - collection: this.i18nService.t("memberAccessReportNoCollection"), - collectionPermission: this.i18nService.t("memberAccessReportNoCollectionPermission"), - totalItems: "0", - }, - ]; - } - const userDetails = report.accessDetails.map((detail) => { - const collectionName = collectionNameMap.get(detail.collectionName.encryptedString); - return { - email: report.email, - name: report.userName, - twoStepLogin: report.twoFactorEnabled - ? this.i18nService.t("memberAccessReportTwoFactorEnabledTrue") - : this.i18nService.t("memberAccessReportTwoFactorEnabledFalse"), - accountRecovery: report.accountRecoveryEnabled - ? this.i18nService.t("memberAccessReportAuthenticationEnabledTrue") - : this.i18nService.t("memberAccessReportAuthenticationEnabledFalse"), - group: detail.groupName - ? detail.groupName - : this.i18nService.t("memberAccessReportNoGroup"), - collection: collectionName - ? collectionName - : this.i18nService.t("memberAccessReportNoCollection"), - collectionPermission: detail.collectionId - ? this.getPermissionText(detail) - : this.i18nService.t("memberAccessReportNoCollectionPermission"), - totalItems: detail.itemCount.toString(), - }; - }); - return userDetails; + const exportItems = memberAccessReports.map((report) => { + const collectionName = collectionNameMap.get(report.collectionName.encryptedString); + return { + email: report.email, + name: report.userName, + twoStepLogin: report.twoFactorEnabled + ? this.i18nService.t("memberAccessReportTwoFactorEnabledTrue") + : this.i18nService.t("memberAccessReportTwoFactorEnabledFalse"), + accountRecovery: report.accountRecoveryEnabled + ? this.i18nService.t("memberAccessReportAuthenticationEnabledTrue") + : this.i18nService.t("memberAccessReportAuthenticationEnabledFalse"), + group: report.groupName + ? report.groupName + : this.i18nService.t("memberAccessReportNoGroup"), + collection: collectionName + ? collectionName + : this.i18nService.t("memberAccessReportNoCollection"), + collectionPermission: report.collectionId + ? this.getPermissionText(report) + : this.i18nService.t("memberAccessReportNoCollectionPermission"), + totalItems: report.cipherIds + .filter((_) => _ != "00000000-0000-0000-0000-000000000000") + .length.toString(), + }; }); return exportItems.flat(); } - private getPermissionText(accessDetails: MemberAccessDetails): string { + private getPermissionText(accessDetails: MemberAccessResponse): string { const permissionList = getPermissionList(); const collectionSelectionView = new CollectionAccessSelectionView({ id: accessDetails.groupId ?? accessDetails.collectionId, @@ -125,4 +128,9 @@ export class MemberAccessReportService { permissionList.find((p) => p.perm === convertToPermission(collectionSelectionView))?.labelId, ); } + + private getDistinctCount(items: T[]): number { + const uniqueItems = new Set(items); + return uniqueItems.size; + } }