1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-15 15:53:27 +00:00

[PM-12425] Remove FF: AC-2828_provider-portal-members-page (#11241)

* Remove FF: AC-2828_provider-portal-members-page

* Thomas' feedback: Fix provider layout
This commit is contained in:
Alex Morask
2024-10-22 08:46:45 -04:00
committed by GitHub
parent 9a1879b96c
commit 470ddf79ab
18 changed files with 164 additions and 775 deletions

View File

@@ -0,0 +1,87 @@
import { DIALOG_DATA, DialogConfig } from "@angular/cdk/dialog";
import { Component, Inject } from "@angular/core";
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
import { firstValueFrom, map, Observable, switchMap } from "rxjs";
import {
OrganizationUserApiService,
OrganizationUserBulkConfirmRequest,
OrganizationUserBulkPublicKeyResponse,
OrganizationUserBulkResponse,
} from "@bitwarden/admin-console/common";
import { OrganizationUserStatusType } from "@bitwarden/common/admin-console/enums";
import { ProviderUserBulkPublicKeyResponse } from "@bitwarden/common/admin-console/models/response/provider/provider-user-bulk-public-key.response";
import { ProviderUserBulkResponse } from "@bitwarden/common/admin-console/models/response/provider/provider-user-bulk.response";
import { ListResponse } from "@bitwarden/common/models/response/list.response";
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
import { StateProvider } from "@bitwarden/common/platform/state";
import { OrganizationId } from "@bitwarden/common/types/guid";
import { OrgKey } from "@bitwarden/common/types/key";
import { DialogService } from "@bitwarden/components";
import { BaseBulkConfirmComponent } from "./base-bulk-confirm.component";
import { BulkUserDetails } from "./bulk-status.component";
type BulkConfirmDialogParams = {
organizationId: string;
users: BulkUserDetails[];
};
@Component({
templateUrl: "bulk-confirm-dialog.component.html",
})
export class BulkConfirmDialogComponent extends BaseBulkConfirmComponent {
organizationId: string;
organizationKey$: Observable<OrgKey>;
users: BulkUserDetails[];
constructor(
protected cryptoService: CryptoService,
@Inject(DIALOG_DATA) protected dialogParams: BulkConfirmDialogParams,
protected encryptService: EncryptService,
private organizationUserApiService: OrganizationUserApiService,
protected i18nService: I18nService,
private stateProvider: StateProvider,
) {
super(cryptoService, encryptService, i18nService);
this.organizationId = dialogParams.organizationId;
this.organizationKey$ = this.stateProvider.activeUserId$.pipe(
switchMap((userId) => this.cryptoService.orgKeys$(userId)),
map((organizationKeysById) => organizationKeysById[this.organizationId as OrganizationId]),
takeUntilDestroyed(),
);
this.users = dialogParams.users;
}
protected getCryptoKey = async (): Promise<SymmetricCryptoKey> =>
await firstValueFrom(this.organizationKey$);
protected getPublicKeys = async (): Promise<
ListResponse<OrganizationUserBulkPublicKeyResponse | ProviderUserBulkPublicKeyResponse>
> =>
await this.organizationUserApiService.postOrganizationUsersPublicKey(
this.organizationId,
this.filteredUsers.map((user) => user.id),
);
protected isAccepted = (user: BulkUserDetails) =>
user.status === OrganizationUserStatusType.Accepted;
protected postConfirmRequest = async (
userIdsWithKeys: { id: string; key: string }[],
): Promise<ListResponse<OrganizationUserBulkResponse | ProviderUserBulkResponse>> => {
const request = new OrganizationUserBulkConfirmRequest(userIdsWithKeys);
return await this.organizationUserApiService.postOrganizationUserBulkConfirm(
this.organizationId,
request,
);
};
static open(dialogService: DialogService, config: DialogConfig<BulkConfirmDialogParams>) {
return dialogService.open(BulkConfirmDialogComponent, config);
}
}

View File

@@ -1,132 +0,0 @@
import { DIALOG_DATA, DialogConfig } from "@angular/cdk/dialog";
import { Component, Inject, OnInit } from "@angular/core";
import {
OrganizationUserApiService,
OrganizationUserBulkConfirmRequest,
} from "@bitwarden/admin-console/common";
import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { OrganizationUserStatusType } from "@bitwarden/common/admin-console/enums";
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
import { EncryptService } from "@bitwarden/common/platform/abstractions/encrypt.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { Utils } from "@bitwarden/common/platform/misc/utils";
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
import { DialogService } from "@bitwarden/components";
import { BulkUserDetails } from "./bulk-status.component";
type BulkConfirmDialogData = {
organizationId: string;
users: BulkUserDetails[];
};
@Component({
selector: "app-bulk-confirm",
templateUrl: "bulk-confirm.component.html",
})
export class BulkConfirmComponent implements OnInit {
organizationId: string;
users: BulkUserDetails[];
excludedUsers: BulkUserDetails[];
filteredUsers: BulkUserDetails[];
publicKeys: Map<string, Uint8Array> = new Map();
fingerprints: Map<string, string> = new Map();
statuses: Map<string, string> = new Map();
loading = true;
done = false;
error: string;
constructor(
@Inject(DIALOG_DATA) protected data: BulkConfirmDialogData,
protected cryptoService: CryptoService,
protected encryptService: EncryptService,
protected apiService: ApiService,
private organizationUserApiService: OrganizationUserApiService,
private i18nService: I18nService,
) {
this.organizationId = data.organizationId;
this.users = data.users;
}
async ngOnInit() {
this.excludedUsers = this.users.filter((u) => !this.isAccepted(u));
this.filteredUsers = this.users.filter((u) => this.isAccepted(u));
if (this.filteredUsers.length <= 0) {
this.done = true;
}
const response = await this.getPublicKeys();
for (const entry of response.data) {
const publicKey = Utils.fromB64ToArray(entry.key);
const fingerprint = await this.cryptoService.getFingerprint(entry.userId, publicKey);
if (fingerprint != null) {
this.publicKeys.set(entry.id, publicKey);
this.fingerprints.set(entry.id, fingerprint.join("-"));
}
}
this.loading = false;
}
async submit() {
this.loading = true;
try {
const key = await this.getCryptoKey();
const userIdsWithKeys: any[] = [];
for (const user of this.filteredUsers) {
const publicKey = this.publicKeys.get(user.id);
if (publicKey == null) {
continue;
}
const encryptedKey = await this.encryptService.rsaEncrypt(key.key, publicKey);
userIdsWithKeys.push({
id: user.id,
key: encryptedKey.encryptedString,
});
}
const response = await this.postConfirmRequest(userIdsWithKeys);
response.data.forEach((entry) => {
const error = entry.error !== "" ? entry.error : this.i18nService.t("bulkConfirmMessage");
this.statuses.set(entry.id, error);
});
this.done = true;
} catch (e) {
this.error = e.message;
}
this.loading = false;
}
protected isAccepted(user: BulkUserDetails) {
return user.status === OrganizationUserStatusType.Accepted;
}
protected async getPublicKeys() {
return await this.organizationUserApiService.postOrganizationUsersPublicKey(
this.organizationId,
this.filteredUsers.map((user) => user.id),
);
}
protected getCryptoKey(): Promise<SymmetricCryptoKey> {
return this.cryptoService.getOrgKey(this.organizationId);
}
protected async postConfirmRequest(userIdsWithKeys: any[]) {
const request = new OrganizationUserBulkConfirmRequest(userIdsWithKeys);
return await this.organizationUserApiService.postOrganizationUserBulkConfirm(
this.organizationId,
request,
);
}
static open(dialogService: DialogService, config: DialogConfig<BulkConfirmDialogData>) {
return dialogService.open(BulkConfirmComponent, config);
}
}

View File

@@ -0,0 +1,54 @@
import { DIALOG_DATA, DialogConfig } from "@angular/cdk/dialog";
import { Component, Inject } from "@angular/core";
import {
OrganizationUserApiService,
OrganizationUserBulkResponse,
} from "@bitwarden/admin-console/common";
import { OrganizationUserStatusType } from "@bitwarden/common/admin-console/enums";
import { ListResponse } from "@bitwarden/common/models/response/list.response";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { DialogService } from "@bitwarden/components";
import { BaseBulkRemoveComponent } from "./base-bulk-remove.component";
import { BulkUserDetails } from "./bulk-status.component";
type BulkRemoveDialogParams = {
organizationId: string;
users: BulkUserDetails[];
};
@Component({
templateUrl: "bulk-remove-dialog.component.html",
})
export class BulkRemoveDialogComponent extends BaseBulkRemoveComponent {
organizationId: string;
users: BulkUserDetails[];
constructor(
@Inject(DIALOG_DATA) protected dialogParams: BulkRemoveDialogParams,
protected i18nService: I18nService,
private organizationUserApiService: OrganizationUserApiService,
) {
super(i18nService);
this.organizationId = dialogParams.organizationId;
this.users = dialogParams.users;
this.showNoMasterPasswordWarning = this.users.some(
(u) => u.status > OrganizationUserStatusType.Invited && u.hasMasterPassword === false,
);
}
protected deleteUsers = (): Promise<ListResponse<OrganizationUserBulkResponse>> =>
this.organizationUserApiService.removeManyOrganizationUsers(
this.organizationId,
this.users.map((user) => user.id),
);
protected get removeUsersWarning() {
return this.i18nService.t("removeOrgUsersConfirmation");
}
static open(dialogService: DialogService, config: DialogConfig<BulkRemoveDialogParams>) {
return dialogService.open(BulkRemoveDialogComponent, config);
}
}

View File

@@ -1,76 +0,0 @@
import { DIALOG_DATA, DialogConfig } from "@angular/cdk/dialog";
import { Component, Inject } from "@angular/core";
import { OrganizationUserApiService } from "@bitwarden/admin-console/common";
import { ApiService } from "@bitwarden/common/abstractions/api.service";
import { OrganizationUserStatusType } from "@bitwarden/common/admin-console/enums";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { DialogService } from "@bitwarden/components";
import { BulkUserDetails } from "./bulk-status.component";
type BulkRemoveDialogData = {
organizationId: string;
users: BulkUserDetails[];
};
@Component({
selector: "app-bulk-remove",
templateUrl: "bulk-remove.component.html",
})
export class BulkRemoveComponent {
organizationId: string;
users: BulkUserDetails[];
statuses: Map<string, string> = new Map();
loading = false;
done = false;
error: string;
showNoMasterPasswordWarning = false;
constructor(
@Inject(DIALOG_DATA) protected data: BulkRemoveDialogData,
protected apiService: ApiService,
protected i18nService: I18nService,
private organizationUserApiService: OrganizationUserApiService,
) {
this.organizationId = data.organizationId;
this.users = data.users;
this.showNoMasterPasswordWarning = this.users.some(
(u) => u.status > OrganizationUserStatusType.Invited && u.hasMasterPassword === false,
);
}
submit = async () => {
this.loading = true;
try {
const response = await this.removeUsers();
response.data.forEach((entry) => {
const error = entry.error !== "" ? entry.error : this.i18nService.t("bulkRemovedMessage");
this.statuses.set(entry.id, error);
});
this.done = true;
} catch (e) {
this.error = e.message;
}
this.loading = false;
};
protected async removeUsers() {
return await this.organizationUserApiService.removeManyOrganizationUsers(
this.organizationId,
this.users.map((user) => user.id),
);
}
protected get removeUsersWarning() {
return this.i18nService.t("removeOrgUsersConfirmation");
}
static open(dialogService: DialogService, config: DialogConfig<BulkRemoveDialogData>) {
return dialogService.open(BulkRemoveComponent, config);
}
}

View File

@@ -60,9 +60,9 @@ import { GroupService } from "../core";
import { OrganizationUserView } from "../core/views/organization-user.view";
import { openEntityEventsDialog } from "../manage/entity-events.component";
import { BulkConfirmComponent } from "./components/bulk/bulk-confirm.component";
import { BulkConfirmDialogComponent } from "./components/bulk/bulk-confirm-dialog.component";
import { BulkEnableSecretsManagerDialogComponent } from "./components/bulk/bulk-enable-sm-dialog.component";
import { BulkRemoveComponent } from "./components/bulk/bulk-remove.component";
import { BulkRemoveDialogComponent } from "./components/bulk/bulk-remove-dialog.component";
import { BulkRestoreRevokeComponent } from "./components/bulk/bulk-restore-revoke.component";
import { BulkStatusComponent } from "./components/bulk/bulk-status.component";
import {
@@ -541,7 +541,7 @@ export class MembersComponent extends BaseMembersComponent<OrganizationUserView>
return;
}
const dialogRef = BulkRemoveComponent.open(this.dialogService, {
const dialogRef = BulkRemoveDialogComponent.open(this.dialogService, {
data: {
organizationId: this.organization.id,
users: this.dataSource.getCheckedUsers(),
@@ -620,7 +620,7 @@ export class MembersComponent extends BaseMembersComponent<OrganizationUserView>
return;
}
const dialogRef = BulkConfirmComponent.open(this.dialogService, {
const dialogRef = BulkConfirmDialogComponent.open(this.dialogService, {
data: {
organizationId: this.organization.id,
users: this.dataSource.getCheckedUsers(),

View File

@@ -7,9 +7,9 @@ import { PasswordCalloutComponent } from "@bitwarden/auth/angular";
import { LooseComponentsModule } from "../../../shared";
import { SharedOrganizationModule } from "../shared";
import { BulkConfirmComponent } from "./components/bulk/bulk-confirm.component";
import { BulkConfirmDialogComponent } from "./components/bulk/bulk-confirm-dialog.component";
import { BulkEnableSecretsManagerDialogComponent } from "./components/bulk/bulk-enable-sm-dialog.component";
import { BulkRemoveComponent } from "./components/bulk/bulk-remove.component";
import { BulkRemoveDialogComponent } from "./components/bulk/bulk-remove-dialog.component";
import { BulkRestoreRevokeComponent } from "./components/bulk/bulk-restore-revoke.component";
import { BulkStatusComponent } from "./components/bulk/bulk-status.component";
import { UserDialogModule } from "./components/member-dialog";
@@ -28,9 +28,9 @@ import { MembersComponent } from "./members.component";
PasswordStrengthV2Component,
],
declarations: [
BulkConfirmComponent,
BulkConfirmDialogComponent,
BulkEnableSecretsManagerDialogComponent,
BulkRemoveComponent,
BulkRemoveDialogComponent,
BulkRestoreRevokeComponent,
BulkStatusComponent,
MembersComponent,