1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-11 22:03:36 +00:00

[PM-20112] Update Member Access report to use new server model (#15155)

This commit is contained in:
Vijay Oommen
2025-06-16 16:33:07 -05:00
committed by GitHub
parent fcd24a4d60
commit a9548f519e
5 changed files with 396 additions and 339 deletions

View File

@@ -36,7 +36,7 @@
</ng-container> </ng-container>
<bit-table-scroll *ngIf="!(isLoading$ | async)" [dataSource]="dataSource" [rowSize]="53"> <bit-table-scroll *ngIf="!(isLoading$ | async)" [dataSource]="dataSource" [rowSize]="53">
<ng-container header> <ng-container header>
<th bitCell bitSortable="name" default>{{ "members" | i18n }}</th> <th bitCell bitSortable="email" default>{{ "members" | i18n }}</th>
<th bitCell bitSortable="groupsCount" class="tw-w-[278px]">{{ "groups" | i18n }}</th> <th bitCell bitSortable="groupsCount" class="tw-w-[278px]">{{ "groups" | i18n }}</th>
<th bitCell bitSortable="collectionsCount" class="tw-w-[278px]">{{ "collections" | i18n }}</th> <th bitCell bitSortable="collectionsCount" class="tw-w-[278px]">{{ "collections" | i18n }}</th>
<th bitCell bitSortable="itemsCount" class="tw-w-[278px]">{{ "items" | i18n }}</th> <th bitCell bitSortable="itemsCount" class="tw-w-[278px]">{{ "items" | i18n }}</th>

View File

@@ -2,7 +2,15 @@ import { BaseResponse } from "@bitwarden/common/models/response/base.response";
import { EncString } from "@bitwarden/common/platform/models/domain/enc-string"; import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
import { Guid } from "@bitwarden/common/types/guid"; 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; collectionId: string;
groupId: string; groupId: string;
groupName: string; groupName: string;
@@ -14,6 +22,14 @@ export class MemberAccessDetails extends BaseResponse {
constructor(response: any) { constructor(response: any) {
super(response); 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.groupId = this.getResponseProperty("GroupId");
this.collectionId = this.getResponseProperty("CollectionId"); this.collectionId = this.getResponseProperty("CollectionId");
this.groupName = this.getResponseProperty("GroupName"); this.groupName = this.getResponseProperty("GroupName");
@@ -24,34 +40,3 @@ export class MemberAccessDetails extends BaseResponse {
this.manage = this.getResponseProperty("Manage"); 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));
}
}
}

View File

@@ -1,9 +1,7 @@
import { EncString } from "@bitwarden/common/platform/models/domain/enc-string"; import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
import { Guid } from "@bitwarden/common/types/guid";
import { import { MemberAccessResponse } from "../response/member-access-report.response";
MemberAccessDetails,
MemberAccessResponse,
} from "../response/member-access-report.response";
export const memberAccessReportsMock: MemberAccessResponse[] = [ export const memberAccessReportsMock: MemberAccessResponse[] = [
{ {
@@ -11,223 +9,290 @@ export const memberAccessReportsMock: MemberAccessResponse[] = [
email: "sjohnson@email.com", email: "sjohnson@email.com",
twoFactorEnabled: true, twoFactorEnabled: true,
accountRecoveryEnabled: true, accountRecoveryEnabled: true,
groupsCount: 2, userGuid: "1001" as Guid,
collectionsCount: 4,
totalItemCount: 20,
userGuid: "1234",
usesKeyConnector: false, usesKeyConnector: false,
accessDetails: [ groupId: "",
{ collectionId: "c1",
groupId: "", collectionName: new EncString("Collection 1"),
collectionId: "c1", groupName: "",
collectionName: new EncString("Collection 1"), itemCount: 10,
groupName: "", readOnly: false,
itemCount: 10, hidePasswords: false,
readOnly: false, manage: false,
hidePasswords: false, cipherIds: [],
manage: false, } as unknown as MemberAccessResponse,
} as MemberAccessDetails, {
{ userName: "Sarah Johnson",
groupId: "", email: "sjohnson@email.com",
collectionId: "c2", twoFactorEnabled: true,
collectionName: new EncString("Collection 2"), accountRecoveryEnabled: true,
groupName: "", userGuid: "1001" as Guid,
itemCount: 20, usesKeyConnector: false,
readOnly: false, groupId: "",
hidePasswords: false, collectionId: "c2",
manage: false, collectionName: new EncString("Collection 2"),
} as MemberAccessDetails, groupName: "",
{ itemCount: 20,
groupId: "", readOnly: false,
collectionId: "c3", hidePasswords: false,
collectionName: new EncString("Collection 3"), manage: false,
groupName: "", cipherIds: [],
itemCount: 30, } as unknown as MemberAccessResponse,
readOnly: false, {
hidePasswords: false, userName: "Sarah Johnson",
manage: false, email: "sjohnson@email.com",
} as MemberAccessDetails, twoFactorEnabled: true,
{ accountRecoveryEnabled: true,
groupId: "g1", userGuid: "1001" as Guid,
collectionId: "c1", usesKeyConnector: false,
collectionName: new EncString("Collection 1"), groupId: "",
groupName: "Group 1", collectionId: "c3",
itemCount: 30, collectionName: new EncString("Collection 3"),
readOnly: false, groupName: "",
hidePasswords: false, itemCount: 30,
manage: false, readOnly: false,
} as MemberAccessDetails, hidePasswords: false,
{ manage: false,
groupId: "g1", cipherIds: [],
collectionId: "c2", } as unknown as MemberAccessResponse,
collectionName: new EncString("Collection 2"), {
groupName: "Group 1", userName: "Sarah Johnson",
itemCount: 20, email: "sjohnson@email.com",
readOnly: false, twoFactorEnabled: true,
hidePasswords: false, accountRecoveryEnabled: true,
manage: false, userGuid: "1001",
} as MemberAccessDetails, usesKeyConnector: false,
], groupId: "g1",
} as MemberAccessResponse, 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", userName: "James Lull",
email: "jlull@email.com", email: "jlull@email.com",
twoFactorEnabled: false, twoFactorEnabled: false,
accountRecoveryEnabled: false, accountRecoveryEnabled: false,
groupsCount: 2, userGuid: "2001",
collectionsCount: 4,
totalItemCount: 20,
userGuid: "1234",
usesKeyConnector: false, usesKeyConnector: false,
accessDetails: [ groupId: "g4",
{ collectionId: "c4",
groupId: "g4", groupName: "Group 4",
collectionId: "c4", collectionName: new EncString("Collection 4"),
groupName: "Group 4", itemCount: 5,
collectionName: new EncString("Collection 4"), readOnly: false,
itemCount: 5, hidePasswords: false,
readOnly: false, manage: false,
hidePasswords: false, cipherIds: [],
manage: false, } as unknown as MemberAccessResponse,
} as MemberAccessDetails, {
{ userName: "James Lull",
groupId: "g4", email: "jlull@email.com",
collectionId: "c5", twoFactorEnabled: false,
groupName: "Group 4", accountRecoveryEnabled: false,
collectionName: new EncString("Collection 5"), userGuid: "2001",
itemCount: 15, usesKeyConnector: false,
readOnly: false, groupId: "g4",
hidePasswords: false, collectionId: "c5",
manage: false, groupName: "Group 4",
} as MemberAccessDetails, collectionName: new EncString("Collection 5"),
{ itemCount: 15,
groupId: "", readOnly: false,
collectionId: "c4", hidePasswords: false,
groupName: "", manage: false,
collectionName: new EncString("Collection 4"), cipherIds: [],
itemCount: 5, } as unknown as MemberAccessResponse,
readOnly: false, {
hidePasswords: false, userName: "James Lull",
manage: false, email: "jlull@email.com",
} as MemberAccessDetails, twoFactorEnabled: false,
{ accountRecoveryEnabled: false,
groupId: "", userGuid: "2001",
collectionId: "c5", usesKeyConnector: false,
groupName: "", groupId: "",
collectionName: new EncString("Collection 5"), collectionId: "c4",
itemCount: 15, groupName: "",
readOnly: false, collectionName: new EncString("Collection 4"),
hidePasswords: false, itemCount: 5,
manage: false, readOnly: false,
} as MemberAccessDetails, hidePasswords: false,
], manage: false,
} as MemberAccessResponse, 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", userName: "Beth Williams",
email: "bwilliams@email.com", email: "bwilliams@email.com",
twoFactorEnabled: true, twoFactorEnabled: true,
accountRecoveryEnabled: true, accountRecoveryEnabled: true,
groupsCount: 2, userGuid: "3001",
collectionsCount: 4,
totalItemCount: 20,
userGuid: "1234",
usesKeyConnector: false, usesKeyConnector: false,
accessDetails: [ groupId: "",
{ collectionId: "c6",
groupId: "", groupName: "",
collectionId: "c6", collectionName: new EncString("Collection 6"),
groupName: "", itemCount: 25,
collectionName: new EncString("Collection 6"), readOnly: false,
itemCount: 25, hidePasswords: false,
readOnly: false, manage: false,
hidePasswords: false, cipherIds: [],
manage: false, } as unknown as MemberAccessResponse,
} as MemberAccessDetails, {
{ userName: "Beth Williams",
groupId: "g6", email: "bwilliams@email.com",
collectionId: "c4", twoFactorEnabled: true,
groupName: "Group 6", accountRecoveryEnabled: true,
collectionName: new EncString("Collection 4"), userGuid: "3001",
itemCount: 35, usesKeyConnector: false,
readOnly: false, groupId: "g6",
hidePasswords: false, collectionId: "c4",
manage: false, groupName: "Group 6",
} as MemberAccessDetails, collectionName: new EncString("Collection 4"),
], itemCount: 35,
} as MemberAccessResponse, readOnly: false,
hidePasswords: false,
manage: false,
cipherIds: [],
} as unknown as MemberAccessResponse,
{ {
userName: "Ray Williams", userName: "Ray Williams",
email: "rwilliams@email.com", email: "rwilliams@email.com",
twoFactorEnabled: false, twoFactorEnabled: false,
accountRecoveryEnabled: false, accountRecoveryEnabled: false,
groupsCount: 2, userGuid: "4000",
collectionsCount: 4,
totalItemCount: 20,
userGuid: "1234",
usesKeyConnector: false, usesKeyConnector: false,
accessDetails: [ groupId: "",
{ collectionId: "c7",
groupId: "", groupName: "",
collectionId: "c7", collectionName: new EncString("Collection 7"),
groupName: "", itemCount: 8,
collectionName: new EncString("Collection 7"), readOnly: false,
itemCount: 8, hidePasswords: false,
readOnly: false, manage: false,
hidePasswords: false, cipherIds: [],
manage: false, } as unknown as MemberAccessResponse,
} as MemberAccessDetails, {
{ userName: "Ray Williams",
groupId: "", email: "rwilliams@email.com",
collectionId: "c8", twoFactorEnabled: false,
groupName: "", accountRecoveryEnabled: false,
collectionName: new EncString("Collection 8"), userGuid: "4000",
itemCount: 12, usesKeyConnector: false,
readOnly: false, groupId: "",
hidePasswords: false, collectionId: "c8",
manage: false, groupName: "",
} as MemberAccessDetails, collectionName: new EncString("Collection 8"),
{ itemCount: 12,
groupId: "", readOnly: false,
collectionId: "c9", hidePasswords: false,
groupName: "", manage: false,
collectionName: new EncString("Collection 9"), cipherIds: [],
itemCount: 16, } as unknown as MemberAccessResponse,
readOnly: false, {
hidePasswords: false, userName: "Ray Williams",
manage: false, email: "rwilliams@email.com",
} as MemberAccessDetails, twoFactorEnabled: false,
{ accountRecoveryEnabled: false,
groupId: "g9", userGuid: "4000",
collectionId: "c7", usesKeyConnector: false,
groupName: "Group 9", groupId: "",
collectionName: new EncString("Collection 7"), collectionId: "c9",
itemCount: 8, groupName: "",
readOnly: false, collectionName: new EncString("Collection 9"),
hidePasswords: false, itemCount: 16,
manage: false, readOnly: false,
} as MemberAccessDetails, hidePasswords: false,
{ manage: false,
groupId: "g10", cipherIds: [],
collectionId: "c8", } as unknown as MemberAccessResponse,
groupName: "Group 10", {
collectionName: new EncString("Collection 8"), userName: "Ray Williams",
itemCount: 12, email: "rwilliams@email.com",
readOnly: false, twoFactorEnabled: false,
hidePasswords: false, accountRecoveryEnabled: false,
manage: false, userGuid: "4000",
} as MemberAccessDetails, usesKeyConnector: false,
{ groupId: "g9",
groupId: "g11", collectionId: "c7",
collectionId: "c9", groupName: "Group 9",
groupName: "Group 11", collectionName: new EncString("Collection 7"),
collectionName: new EncString("Collection 9"), itemCount: 8,
itemCount: 16, readOnly: false,
readOnly: false, hidePasswords: false,
hidePasswords: false, manage: false,
manage: false, cipherIds: [],
} as MemberAccessDetails, } as unknown as MemberAccessResponse,
], {
} 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[] = [ export const memberAccessWithoutAccessDetailsReportsMock: MemberAccessResponse[] = [
@@ -236,34 +301,33 @@ export const memberAccessWithoutAccessDetailsReportsMock: MemberAccessResponse[]
email: "asmith@email.com", email: "asmith@email.com",
twoFactorEnabled: true, twoFactorEnabled: true,
accountRecoveryEnabled: true, accountRecoveryEnabled: true,
groupsCount: 2, userGuid: "1234" as Guid,
collectionsCount: 4,
totalItemCount: 20,
userGuid: "1234",
usesKeyConnector: false, usesKeyConnector: false,
accessDetails: [ groupId: "",
{ collectionId: "c1",
groupId: "", collectionName: new EncString("Collection 1"),
collectionId: "c1", groupName: "Alice Group 1",
collectionName: new EncString("Collection 1"), itemCount: 10,
groupName: "Alice Group 1", readOnly: false,
itemCount: 10, hidePasswords: false,
readOnly: false, manage: false,
hidePasswords: false, cipherIds: [],
manage: false, } as unknown as MemberAccessResponse,
} as MemberAccessDetails,
],
} as MemberAccessResponse,
{ {
userName: "Robert Brown", userName: "Robert Brown",
email: "rbrown@email.com", email: "rbrown@email.com",
twoFactorEnabled: false, twoFactorEnabled: false,
accountRecoveryEnabled: false, accountRecoveryEnabled: false,
groupsCount: 2, userGuid: "5678" as Guid,
collectionsCount: 4,
totalItemCount: 20,
userGuid: "5678",
usesKeyConnector: false, usesKeyConnector: false,
accessDetails: [] as MemberAccessDetails[], groupId: "",
} as MemberAccessResponse, collectionId: "c1",
collectionName: new EncString("Collection 1"),
groupName: "",
itemCount: 10,
readOnly: false,
hidePasswords: false,
manage: false,
cipherIds: [],
} as unknown as MemberAccessResponse,
]; ];

View File

@@ -35,36 +35,36 @@ describe("ImportService", () => {
{ {
name: "Sarah Johnson", name: "Sarah Johnson",
email: "sjohnson@email.com", email: "sjohnson@email.com",
collectionsCount: 4, collectionsCount: 3,
groupsCount: 2, groupsCount: 1,
itemsCount: 20, itemsCount: 0,
userGuid: expect.any(String), userGuid: expect.any(String),
usesKeyConnector: expect.any(Boolean), usesKeyConnector: expect.any(Boolean),
}, },
{ {
name: "James Lull", name: "James Lull",
email: "jlull@email.com", email: "jlull@email.com",
collectionsCount: 4, collectionsCount: 2,
groupsCount: 2, groupsCount: 1,
itemsCount: 20, itemsCount: 0,
userGuid: expect.any(String), userGuid: expect.any(String),
usesKeyConnector: expect.any(Boolean), usesKeyConnector: expect.any(Boolean),
}, },
{ {
name: "Beth Williams", name: "Beth Williams",
email: "bwilliams@email.com", email: "bwilliams@email.com",
collectionsCount: 4, collectionsCount: 2,
groupsCount: 2, groupsCount: 1,
itemsCount: 20, itemsCount: 0,
userGuid: expect.any(String), userGuid: expect.any(String),
usesKeyConnector: expect.any(Boolean), usesKeyConnector: expect.any(Boolean),
}, },
{ {
name: "Ray Williams", name: "Ray Williams",
email: "rwilliams@email.com", email: "rwilliams@email.com",
collectionsCount: 4, collectionsCount: 3,
groupsCount: 2, groupsCount: 3,
itemsCount: 20, itemsCount: 0,
userGuid: expect.any(String), userGuid: expect.any(String),
usesKeyConnector: expect.any(Boolean), usesKeyConnector: expect.any(Boolean),
}, },
@@ -82,8 +82,8 @@ describe("ImportService", () => {
(item) => (item) =>
(item.name === "Sarah Johnson" && (item.name === "Sarah Johnson" &&
item.group === "Group 1" && item.group === "Group 1" &&
item.totalItems === "20") || item.totalItems === "0") ||
(item.name === "James Lull" && item.group === "Group 4" && item.totalItems === "5"), (item.name === "James Lull" && item.group === "Group 4" && item.totalItems === "0"),
) )
.map((item) => ({ .map((item) => ({
name: item.name, name: item.name,
@@ -102,7 +102,7 @@ describe("ImportService", () => {
twoStepLogin: "memberAccessReportTwoFactorEnabledTrue", twoStepLogin: "memberAccessReportTwoFactorEnabledTrue",
accountRecovery: "memberAccessReportAuthenticationEnabledTrue", accountRecovery: "memberAccessReportAuthenticationEnabledTrue",
group: "Group 1", group: "Group 1",
totalItems: "20", totalItems: "0",
}), }),
expect.objectContaining({ expect.objectContaining({
email: "jlull@email.com", email: "jlull@email.com",
@@ -110,7 +110,7 @@ describe("ImportService", () => {
twoStepLogin: "memberAccessReportTwoFactorEnabledFalse", twoStepLogin: "memberAccessReportTwoFactorEnabledFalse",
accountRecovery: "memberAccessReportAuthenticationEnabledFalse", accountRecovery: "memberAccessReportAuthenticationEnabledFalse",
group: "Group 4", group: "Group 4",
totalItems: "5", totalItems: "0",
}), }),
]), ]),
); );
@@ -131,7 +131,7 @@ describe("ImportService", () => {
twoStepLogin: "memberAccessReportTwoFactorEnabledTrue", twoStepLogin: "memberAccessReportTwoFactorEnabledTrue",
accountRecovery: "memberAccessReportAuthenticationEnabledTrue", accountRecovery: "memberAccessReportAuthenticationEnabledTrue",
group: "Alice Group 1", group: "Alice Group 1",
totalItems: "10", totalItems: "0",
}), }),
expect.objectContaining({ expect.objectContaining({
email: "rbrown@email.com", email: "rbrown@email.com",

View File

@@ -5,13 +5,13 @@ import { Injectable } from "@angular/core";
import { CollectionAccessSelectionView } from "@bitwarden/admin-console/common"; import { CollectionAccessSelectionView } from "@bitwarden/admin-console/common";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { EncString } from "@bitwarden/common/platform/models/domain/enc-string"; 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 { import {
getPermissionList, getPermissionList,
convertToPermission, convertToPermission,
} from "@bitwarden/web-vault/app/admin-console/organizations/shared/components/access-selector"; } 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 { MemberAccessExportItem } from "../view/member-access-export.view";
import { MemberAccessReportView } from "../view/member-access-report.view"; import { MemberAccessReportView } from "../view/member-access-report.view";
@@ -34,15 +34,44 @@ export class MemberAccessReportService {
organizationId: OrganizationId, organizationId: OrganizationId,
): Promise<MemberAccessReportView[]> { ): Promise<MemberAccessReportView[]> {
const memberAccessData = await this.reportApiService.getMemberAccessData(organizationId); const memberAccessData = await this.reportApiService.getMemberAccessData(organizationId);
const memberAccessReportViewCollection = memberAccessData.map((userData) => ({
name: userData.userName, // group member access data by userGuid
email: userData.email, const userMap = new Map<Guid, MemberAccessResponse[]>();
collectionsCount: userData.collectionsCount, memberAccessData.forEach((userData) => {
groupsCount: userData.groupsCount, const userGuid = userData.userGuid;
itemsCount: userData.totalItemCount, if (!userMap.has(userGuid)) {
userGuid: userData.userGuid, userMap.set(userGuid, []);
usesKeyConnector: userData.usesKeyConnector, }
})); userMap.get(userGuid)?.push(userData);
});
// aggregate user data
const memberAccessReportViewCollection: MemberAccessReportView[] = [];
userMap.forEach((userDataArray, userGuid) => {
const collectionCount = this.getDistinctCount<string>(
userDataArray.map((data) => data.collectionId).filter((id) => !!id),
);
const groupCount = this.getDistinctCount<string>(
userDataArray.map((data) => data.groupId).filter((id) => !!id),
);
const itemsCount = this.getDistinctCount<Guid>(
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; return memberAccessReportViewCollection;
} }
@@ -50,13 +79,8 @@ export class MemberAccessReportService {
organizationId: OrganizationId, organizationId: OrganizationId,
): Promise<MemberAccessExportItem[]> { ): Promise<MemberAccessExportItem[]> {
const memberAccessReports = await this.reportApiService.getMemberAccessData(organizationId); const memberAccessReports = await this.reportApiService.getMemberAccessData(organizationId);
const collectionNames = memberAccessReports.flatMap((item) => const collectionNames = memberAccessReports.map((item) => item.collectionName.encryptedString);
item.accessDetails.map((dtl) => {
if (dtl.collectionName) {
return dtl.collectionName.encryptedString;
}
}),
);
const collectionNameMap = new Map(collectionNames.map((col) => [col, ""])); const collectionNameMap = new Map(collectionNames.map((col) => [col, ""]));
for await (const key of collectionNameMap.keys()) { for await (const key of collectionNameMap.keys()) {
const decrypted = new EncString(key); const decrypted = new EncString(key);
@@ -64,56 +88,35 @@ export class MemberAccessReportService {
collectionNameMap.set(key, decrypted.decryptedValue); collectionNameMap.set(key, decrypted.decryptedValue);
} }
const exportItems = memberAccessReports.flatMap((report) => { const exportItems = memberAccessReports.map((report) => {
// to include users without access details const collectionName = collectionNameMap.get(report.collectionName.encryptedString);
// which means a user has no groups, collections or items return {
if (report.accessDetails.length === 0) { email: report.email,
return [ name: report.userName,
{ twoStepLogin: report.twoFactorEnabled
email: report.email, ? this.i18nService.t("memberAccessReportTwoFactorEnabledTrue")
name: report.userName, : this.i18nService.t("memberAccessReportTwoFactorEnabledFalse"),
twoStepLogin: report.twoFactorEnabled accountRecovery: report.accountRecoveryEnabled
? this.i18nService.t("memberAccessReportTwoFactorEnabledTrue") ? this.i18nService.t("memberAccessReportAuthenticationEnabledTrue")
: this.i18nService.t("memberAccessReportTwoFactorEnabledFalse"), : this.i18nService.t("memberAccessReportAuthenticationEnabledFalse"),
accountRecovery: report.accountRecoveryEnabled group: report.groupName
? this.i18nService.t("memberAccessReportAuthenticationEnabledTrue") ? report.groupName
: this.i18nService.t("memberAccessReportAuthenticationEnabledFalse"), : this.i18nService.t("memberAccessReportNoGroup"),
group: this.i18nService.t("memberAccessReportNoGroup"), collection: collectionName
collection: this.i18nService.t("memberAccessReportNoCollection"), ? collectionName
collectionPermission: this.i18nService.t("memberAccessReportNoCollectionPermission"), : this.i18nService.t("memberAccessReportNoCollection"),
totalItems: "0", collectionPermission: report.collectionId
}, ? this.getPermissionText(report)
]; : this.i18nService.t("memberAccessReportNoCollectionPermission"),
} totalItems: report.cipherIds
const userDetails = report.accessDetails.map((detail) => { .filter((_) => _ != "00000000-0000-0000-0000-000000000000")
const collectionName = collectionNameMap.get(detail.collectionName.encryptedString); .length.toString(),
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;
}); });
return exportItems.flat(); return exportItems.flat();
} }
private getPermissionText(accessDetails: MemberAccessDetails): string { private getPermissionText(accessDetails: MemberAccessResponse): string {
const permissionList = getPermissionList(); const permissionList = getPermissionList();
const collectionSelectionView = new CollectionAccessSelectionView({ const collectionSelectionView = new CollectionAccessSelectionView({
id: accessDetails.groupId ?? accessDetails.collectionId, id: accessDetails.groupId ?? accessDetails.collectionId,
@@ -125,4 +128,9 @@ export class MemberAccessReportService {
permissionList.find((p) => p.perm === convertToPermission(collectionSelectionView))?.labelId, permissionList.find((p) => p.perm === convertToPermission(collectionSelectionView))?.labelId,
); );
} }
private getDistinctCount<T>(items: T[]): number {
const uniqueItems = new Set(items);
return uniqueItems.size;
}
} }