mirror of
https://github.com/bitwarden/browser.git
synced 2024-11-27 12:36:14 +01:00
Bulk confirm (#987)
* Add bulk confirm * Add confirmation modal to the other bulk actions * Add spinner to bulk status to let the user know something is going on * Fix linting * Add await before reloading users * Close modal on error * Bump jslib
This commit is contained in:
parent
d566c963c1
commit
d31130b79f
2
jslib
2
jslib
@ -1 +1 @@
|
||||
Subproject commit 6b9246c272fc74cd644bc4b94cb99f936c6f44f8
|
||||
Subproject commit bacb84ca78a2f0642e8d041157a88e8543577d8a
|
@ -38,6 +38,7 @@ import { TwoFactorComponent } from './accounts/two-factor.component';
|
||||
import { VerifyEmailTokenComponent } from './accounts/verify-email-token.component';
|
||||
import { VerifyRecoverDeleteComponent } from './accounts/verify-recover-delete.component';
|
||||
|
||||
import { BulkStatusComponent as OrgBulkStatusComponent } from './organizations/manage/bulk-status.component';
|
||||
import {
|
||||
CollectionAddEditComponent as OrgCollectionAddEditComponent,
|
||||
} from './organizations/manage/collection-add-edit.component';
|
||||
@ -348,6 +349,7 @@ registerLocaleData(localeZhTw, 'zh-TW');
|
||||
OrganizationPlansComponent,
|
||||
OrganizationSubscriptionComponent,
|
||||
OrgAttachmentsComponent,
|
||||
OrgBulkStatusComponent,
|
||||
OrgCiphersComponent,
|
||||
OrgCollectionAddEditComponent,
|
||||
OrgCollectionsComponent,
|
||||
@ -447,6 +449,7 @@ registerLocaleData(localeZhTw, 'zh-TW');
|
||||
ModalComponent,
|
||||
OrgAddEditComponent,
|
||||
OrgAttachmentsComponent,
|
||||
OrgBulkStatusComponent,
|
||||
OrgCollectionAddEditComponent,
|
||||
OrgCollectionsComponent,
|
||||
OrgEntityEventsComponent,
|
||||
|
47
src/app/organizations/manage/bulk-status.component.html
Normal file
47
src/app/organizations/manage/bulk-status.component.html
Normal file
@ -0,0 +1,47 @@
|
||||
<div class="modal fade" tabindex="-1" role="dialog" aria-modal="true" aria-labelledby="bulkTitle">
|
||||
<div class="modal-dialog modal-dialog-scrollable modal-lg" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h2 class="modal-title" id="bulkTitle">
|
||||
{{'bulkConfirmStatus' | i18n}}
|
||||
</h2>
|
||||
<button type="button" class="close" data-dismiss="modal" appA11yTitle="{{'close' | i18n}}">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="card-body text-center" *ngIf="loading">
|
||||
<i class="fa fa-spinner fa-spin" title="{{'loading' | i18n}}" aria-hidden="true"></i>
|
||||
{{'loading' | i18n}}
|
||||
</div>
|
||||
<table class="table table-hover table-list" *ngIf="!loading">
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan="2">{{'user' | i18n}}</th>
|
||||
<th>{{'status' | i18n}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr *ngFor="let item of users">
|
||||
<td width="30">
|
||||
<app-avatar [data]="item.user.name || item.user.email" [email]="item.user.email" size="25" [circle]="true"
|
||||
[fontSize]="14"></app-avatar>
|
||||
</td>
|
||||
<td>
|
||||
{{item.user.email}}
|
||||
<small class="text-muted d-block" *ngIf="item.user.name">{{item.user.name}}</small>
|
||||
</td>
|
||||
<td class="text-danger" *ngIf="item.error">
|
||||
{{item.message}}
|
||||
</td>
|
||||
<td *ngIf="!item.error">
|
||||
{{item.message}}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-outline-secondary" data-dismiss="modal">{{'close' | i18n}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
20
src/app/organizations/manage/bulk-status.component.ts
Normal file
20
src/app/organizations/manage/bulk-status.component.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
import { OrganizationUserUserDetailsResponse } from 'jslib/models/response/organizationUserResponse';
|
||||
|
||||
type BulkStatusEntry = {
|
||||
user: OrganizationUserUserDetailsResponse,
|
||||
error: boolean,
|
||||
message: string,
|
||||
};
|
||||
|
||||
@Component({
|
||||
selector: 'app-bulk-status',
|
||||
templateUrl: 'bulk-status.component.html',
|
||||
})
|
||||
export class BulkStatusComponent {
|
||||
|
||||
users: BulkStatusEntry[];
|
||||
loading: boolean = false;
|
||||
|
||||
}
|
@ -35,6 +35,10 @@
|
||||
<i class="fa fa-fw fa-envelope-o" aria-hidden="true"></i>
|
||||
{{'reinviteSelected' | i18n}}
|
||||
</button>
|
||||
<button class="dropdown-item text-success" appStopClick (click)="bulkConfirm()" *ngIf="showConfirmUsers">
|
||||
<i class="fa fa-fw fa-check" aria-hidden="true"></i>
|
||||
{{'confirmSelected' | i18n}}
|
||||
</button>
|
||||
<button class="dropdown-item text-danger" appStopClick (click)="bulkRemove()">
|
||||
<i class="fa fa-fw fa-remove" aria-hidden="true"></i>
|
||||
{{'remove' | i18n}}
|
||||
@ -142,3 +146,4 @@
|
||||
<ng-template #groupsTemplate></ng-template>
|
||||
<ng-template #eventsTemplate></ng-template>
|
||||
<ng-template #confirmTemplate></ng-template>
|
||||
<ng-template #bulkStatusTemplate></ng-template>
|
||||
|
@ -23,6 +23,7 @@ import { SearchService } from 'jslib/abstractions/search.service';
|
||||
import { StorageService } from 'jslib/abstractions/storage.service';
|
||||
import { UserService } from 'jslib/abstractions/user.service';
|
||||
|
||||
import { OrganizationUserBulkConfirmRequest } from 'jslib/models/request/organizationUserBulkConfirmRequest';
|
||||
import { OrganizationUserConfirmRequest } from 'jslib/models/request/organizationUserConfirmRequest';
|
||||
|
||||
import { OrganizationUserBulkRequest } from 'jslib/models/request/organizationUserBulkRequest';
|
||||
@ -33,7 +34,10 @@ import { OrganizationUserType } from 'jslib/enums/organizationUserType';
|
||||
|
||||
import { Utils } from 'jslib/misc/utils';
|
||||
|
||||
import { ListResponse } from 'jslib/models/response';
|
||||
import { OrganizationUserBulkResponse } from 'jslib/models/response/organizationUserBulkResponse';
|
||||
import { ModalComponent } from '../../modal.component';
|
||||
import { BulkStatusComponent } from './bulk-status.component';
|
||||
import { EntityEventsComponent } from './entity-events.component';
|
||||
import { UserAddEditComponent } from './user-add-edit.component';
|
||||
import { UserConfirmComponent } from './user-confirm.component';
|
||||
@ -50,6 +54,7 @@ export class PeopleComponent implements OnInit {
|
||||
@ViewChild('groupsTemplate', { read: ViewContainerRef, static: true }) groupsModalRef: ViewContainerRef;
|
||||
@ViewChild('eventsTemplate', { read: ViewContainerRef, static: true }) eventsModalRef: ViewContainerRef;
|
||||
@ViewChild('confirmTemplate', { read: ViewContainerRef, static: true }) confirmModalRef: ViewContainerRef;
|
||||
@ViewChild('bulkStatusTemplate', { read: ViewContainerRef, static: true }) bulkStatusModalRef: ViewContainerRef;
|
||||
|
||||
loading = true;
|
||||
organizationId: string;
|
||||
@ -279,11 +284,11 @@ export class PeopleComponent implements OnInit {
|
||||
return false;
|
||||
}
|
||||
|
||||
const request = new OrganizationUserBulkRequest(users.map(user => user.id));
|
||||
this.actionPromise = this.apiService.deleteManyOrganizationUsers(this.organizationId, request);
|
||||
try {
|
||||
await this.actionPromise;
|
||||
this.toasterService.popAsync('success', null, this.i18nService.t('usersHasBeenRemoved'));
|
||||
const request = new OrganizationUserBulkRequest(users.map(user => user.id));
|
||||
const response = this.apiService.deleteManyOrganizationUsers(this.organizationId, request);
|
||||
this.showBulkStatus(users, users, response, this.i18nService.t('bulkRemovedMessage'));
|
||||
await response;
|
||||
await this.load();
|
||||
} catch (e) {
|
||||
this.validationService.showError(e);
|
||||
@ -296,40 +301,108 @@ export class PeopleComponent implements OnInit {
|
||||
return;
|
||||
}
|
||||
|
||||
const users = this.getCheckedUsers().filter(u => u.status === OrganizationUserStatusType.Invited);
|
||||
const users = this.getCheckedUsers();
|
||||
const filteredUsers = users.filter(u => u.status === OrganizationUserStatusType.Invited);
|
||||
|
||||
if (users.length <= 0) {
|
||||
if (filteredUsers.length <= 0) {
|
||||
this.toasterService.popAsync('error', this.i18nService.t('errorOccurred'),
|
||||
this.i18nService.t('noSelectedUsersApplicable'));
|
||||
return;
|
||||
}
|
||||
|
||||
const request = new OrganizationUserBulkRequest(users.map(user => user.id));
|
||||
this.actionPromise = this.apiService.postManyOrganizationUserReinvite(this.organizationId, request);
|
||||
|
||||
try {
|
||||
await this.actionPromise;
|
||||
this.toasterService.popAsync('success', null, this.i18nService.t('usersHasBeenReinvited'));
|
||||
const request = new OrganizationUserBulkRequest(filteredUsers.map(user => user.id));
|
||||
const response = this.apiService.postManyOrganizationUserReinvite(this.organizationId, request);
|
||||
this.showBulkStatus(users, filteredUsers, response, this.i18nService.t('bulkReinviteMessage'));
|
||||
} catch (e) {
|
||||
this.validationService.showError(e);
|
||||
}
|
||||
this.actionPromise = null;
|
||||
}
|
||||
|
||||
async confirm(user: OrganizationUserUserDetailsResponse) {
|
||||
function updateUser(self: PeopleComponent) {
|
||||
user.status = OrganizationUserStatusType.Confirmed;
|
||||
const mapIndex = self.statusMap.get(OrganizationUserStatusType.Accepted).indexOf(user);
|
||||
if (mapIndex > -1) {
|
||||
self.statusMap.get(OrganizationUserStatusType.Accepted).splice(mapIndex, 1);
|
||||
self.statusMap.get(OrganizationUserStatusType.Confirmed).push(user);
|
||||
async bulkConfirm() {
|
||||
if (this.actionPromise != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
const users = this.getCheckedUsers();
|
||||
const filteredUsers = users.filter(u => u.status === OrganizationUserStatusType.Accepted);
|
||||
|
||||
if (filteredUsers.length <= 0) {
|
||||
this.toasterService.popAsync('error', this.i18nService.t('errorOccurred'),
|
||||
this.i18nService.t('noSelectedUsersApplicable'));
|
||||
return;
|
||||
}
|
||||
|
||||
const publicKeyRequest = new OrganizationUserBulkRequest(filteredUsers.map(user => user.id));
|
||||
const publicKeyResponse = await this.apiService.postOrganizationUsersPublicKey(this.organizationId, publicKeyRequest);
|
||||
|
||||
const keyMap = new Map<string, Uint8Array>();
|
||||
publicKeyResponse.data.forEach(entry => {
|
||||
keyMap.set(entry.id, Utils.fromB64ToArray(entry.key));
|
||||
});
|
||||
|
||||
const orgKey = await this.cryptoService.getOrgKey(this.organizationId);
|
||||
const userIdsWithKeys: any[] = [];
|
||||
const approvedUsers = [];
|
||||
for (const user of filteredUsers) {
|
||||
const publicKey = keyMap.get(user.id);
|
||||
if (publicKey == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (await this.promptConfirmUser(user, publicKey)) {
|
||||
const key = await this.cryptoService.rsaEncrypt(orgKey.key, publicKey.buffer);
|
||||
approvedUsers.push(user);
|
||||
userIdsWithKeys.push({
|
||||
id: user.id,
|
||||
key: key.encryptedString,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const confirmUser = async (publicKey: Uint8Array) => {
|
||||
if (userIdsWithKeys.length <= 0) {
|
||||
this.toasterService.popAsync('error', this.i18nService.t('errorOccurred'),
|
||||
this.i18nService.t('noSelectedUsersApplicable'));
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const request = new OrganizationUserBulkConfirmRequest(userIdsWithKeys);
|
||||
const response = this.apiService.postOrganizationUserBulkConfirm(this.organizationId, request);
|
||||
this.showBulkStatus(users, approvedUsers, response, this.i18nService.t('bulkConfirmMessage'));
|
||||
await response;
|
||||
await this.load();
|
||||
} catch (e) {
|
||||
this.validationService.showError(e);
|
||||
}
|
||||
}
|
||||
|
||||
async confirm(user: OrganizationUserUserDetailsResponse): Promise<void> {
|
||||
if (this.actionPromise != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const publicKeyResponse = await this.apiService.getUserPublicKey(user.userId);
|
||||
const publicKey = Utils.fromB64ToArray(publicKeyResponse.publicKey);
|
||||
|
||||
const confirmed = await this.promptConfirmUser(user, publicKey);
|
||||
if (!confirmed) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// tslint:disable-next-line
|
||||
console.log('User\'s fingerprint: ' +
|
||||
(await this.cryptoService.getFingerprint(user.userId, publicKey.buffer)).join('-'));
|
||||
} catch { }
|
||||
|
||||
try {
|
||||
this.actionPromise = this.doConfirmation(user, publicKey);
|
||||
await this.actionPromise;
|
||||
updateUser(this);
|
||||
this.confirmUser(user);
|
||||
this.toasterService.popAsync('success', null, this.i18nService.t('hasBeenConfirmed', user.name || user.email));
|
||||
} catch (e) {
|
||||
this.validationService.showError(e);
|
||||
@ -337,52 +410,6 @@ export class PeopleComponent implements OnInit {
|
||||
} finally {
|
||||
this.actionPromise = null;
|
||||
}
|
||||
};
|
||||
|
||||
if (this.actionPromise != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
const autoConfirm = await this.storageService.get<boolean>(ConstantsService.autoConfirmFingerprints);
|
||||
if (autoConfirm == null || !autoConfirm) {
|
||||
if (this.modal != null) {
|
||||
this.modal.close();
|
||||
}
|
||||
|
||||
const factory = this.componentFactoryResolver.resolveComponentFactory(ModalComponent);
|
||||
this.modal = this.confirmModalRef.createComponent(factory).instance;
|
||||
const childComponent = this.modal.show<UserConfirmComponent>(
|
||||
UserConfirmComponent, this.confirmModalRef);
|
||||
|
||||
childComponent.name = user != null ? user.name || user.email : null;
|
||||
childComponent.organizationId = this.organizationId;
|
||||
childComponent.organizationUserId = user != null ? user.id : null;
|
||||
childComponent.userId = user != null ? user.userId : null;
|
||||
childComponent.onConfirmedUser.subscribe(async (publicKey: Uint8Array) => {
|
||||
try {
|
||||
await confirmUser(publicKey);
|
||||
this.modal.close();
|
||||
} catch (e) {
|
||||
// tslint:disable-next-line
|
||||
console.error('Handled exception:', e);
|
||||
}
|
||||
});
|
||||
|
||||
this.modal.onClosed.subscribe(() => {
|
||||
this.modal = null;
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const publicKeyResponse = await this.apiService.getUserPublicKey(user.userId);
|
||||
const publicKey = Utils.fromB64ToArray(publicKeyResponse.publicKey);
|
||||
try {
|
||||
// tslint:disable-next-line
|
||||
console.log('User\'s fingerprint: ' +
|
||||
(await this.cryptoService.getFingerprint(user.userId, publicKey.buffer)).join('-'));
|
||||
} catch { }
|
||||
await confirmUser(publicKey);
|
||||
} catch (e) {
|
||||
// tslint:disable-next-line
|
||||
console.error('Handled exception:', e);
|
||||
@ -443,6 +470,57 @@ export class PeopleComponent implements OnInit {
|
||||
}
|
||||
}
|
||||
|
||||
private async showBulkStatus(users: OrganizationUserUserDetailsResponse[], filteredUsers: OrganizationUserUserDetailsResponse[],
|
||||
request: Promise<ListResponse<OrganizationUserBulkResponse>>, successfullMessage: string) {
|
||||
|
||||
const factory = this.componentFactoryResolver.resolveComponentFactory(ModalComponent);
|
||||
this.modal = this.eventsModalRef.createComponent(factory).instance;
|
||||
const childComponent = this.modal.show<BulkStatusComponent>(
|
||||
BulkStatusComponent, this.eventsModalRef);
|
||||
|
||||
childComponent.loading = true;
|
||||
|
||||
// Workaround to handle closing the modal shortly after it has been opened
|
||||
let close = false;
|
||||
this.modal.onShown.subscribe(() => {
|
||||
if (close) {
|
||||
this.modal.close();
|
||||
}
|
||||
});
|
||||
|
||||
this.modal.onClosed.subscribe(() => {
|
||||
this.modal = null;
|
||||
});
|
||||
|
||||
try {
|
||||
const response = await request;
|
||||
|
||||
if (this.modal) {
|
||||
const keyedErrors: any = response.data.filter(r => r.error !== '').reduce((a, x) => ({...a, [x.id]: x.error}), {});
|
||||
const keyedFilteredUsers: any = filteredUsers.reduce((a, x) => ({...a, [x.id]: x}), {});
|
||||
|
||||
childComponent.users = users.map(user => {
|
||||
let message = keyedErrors[user.id] ?? successfullMessage;
|
||||
if (!keyedFilteredUsers.hasOwnProperty(user.id)) {
|
||||
message = this.i18nService.t('bulkFilteredMessage');
|
||||
}
|
||||
|
||||
return {
|
||||
user: user,
|
||||
error: keyedErrors.hasOwnProperty(user.id),
|
||||
message: message,
|
||||
};
|
||||
});
|
||||
childComponent.loading = false;
|
||||
}
|
||||
} catch {
|
||||
close = true;
|
||||
if (this.modal) {
|
||||
this.modal.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async doConfirmation(user: OrganizationUserUserDetailsResponse, publicKey: Uint8Array) {
|
||||
const orgKey = await this.cryptoService.getOrgKey(this.organizationId);
|
||||
const key = await this.cryptoService.rsaEncrypt(orgKey.key, publicKey.buffer);
|
||||
@ -477,7 +555,50 @@ export class PeopleComponent implements OnInit {
|
||||
}
|
||||
}
|
||||
|
||||
private confirmUser(user: OrganizationUserUserDetailsResponse) {
|
||||
user.status = OrganizationUserStatusType.Confirmed;
|
||||
const mapIndex = this.statusMap.get(OrganizationUserStatusType.Accepted).indexOf(user);
|
||||
if (mapIndex > -1) {
|
||||
this.statusMap.get(OrganizationUserStatusType.Accepted).splice(mapIndex, 1);
|
||||
this.statusMap.get(OrganizationUserStatusType.Confirmed).push(user);
|
||||
}
|
||||
}
|
||||
|
||||
private getCheckedUsers() {
|
||||
return this.users.filter(u => (u as any).checked);
|
||||
}
|
||||
|
||||
private promptConfirmUser(user: OrganizationUserUserDetailsResponse, publicKey: Uint8Array): Promise<boolean> {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
const autoConfirm = await this.storageService.get<boolean>(ConstantsService.autoConfirmFingerprints);
|
||||
if (autoConfirm ?? false) {
|
||||
resolve(true);
|
||||
}
|
||||
let success = false;
|
||||
|
||||
if (this.modal != null) {
|
||||
this.modal.close();
|
||||
}
|
||||
|
||||
const factory = this.componentFactoryResolver.resolveComponentFactory(ModalComponent);
|
||||
this.modal = this.confirmModalRef.createComponent(factory).instance;
|
||||
const childComponent = this.modal.show<UserConfirmComponent>(
|
||||
UserConfirmComponent, this.confirmModalRef);
|
||||
|
||||
childComponent.name = user != null ? user.name || user.email : null;
|
||||
childComponent.organizationId = this.organizationId;
|
||||
childComponent.organizationUserId = user != null ? user.id : null;
|
||||
childComponent.userId = user != null ? user.userId : null;
|
||||
childComponent.publicKey = publicKey;
|
||||
childComponent.onConfirmedUser.subscribe(() => {
|
||||
success = true;
|
||||
this.modal.close();
|
||||
});
|
||||
|
||||
this.modal.onClosed.subscribe(() => {
|
||||
this.modal = null;
|
||||
setTimeout(() => resolve(success), 10);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -8,12 +8,9 @@ import {
|
||||
|
||||
import { ConstantsService } from 'jslib/services/constants.service';
|
||||
|
||||
import { ApiService } from 'jslib/abstractions/api.service';
|
||||
import { CryptoService } from 'jslib/abstractions/crypto.service';
|
||||
import { StorageService } from 'jslib/abstractions/storage.service';
|
||||
|
||||
import { Utils } from 'jslib/misc/utils';
|
||||
|
||||
@Component({
|
||||
selector: 'app-user-confirm',
|
||||
templateUrl: 'user-confirm.component.html',
|
||||
@ -23,22 +20,18 @@ export class UserConfirmComponent implements OnInit {
|
||||
@Input() userId: string;
|
||||
@Input() organizationUserId: string;
|
||||
@Input() organizationId: string;
|
||||
@Input() publicKey: Uint8Array;
|
||||
@Output() onConfirmedUser = new EventEmitter();
|
||||
|
||||
dontAskAgain = false;
|
||||
loading = true;
|
||||
fingerprint: string;
|
||||
|
||||
private publicKey: Uint8Array = null;
|
||||
|
||||
constructor(private apiService: ApiService, private cryptoService: CryptoService,
|
||||
private storageService: StorageService) { }
|
||||
constructor(private cryptoService: CryptoService, private storageService: StorageService) { }
|
||||
|
||||
async ngOnInit() {
|
||||
try {
|
||||
const publicKeyResponse = await this.apiService.getUserPublicKey(this.userId);
|
||||
if (publicKeyResponse != null) {
|
||||
this.publicKey = Utils.fromB64ToArray(publicKeyResponse.publicKey);
|
||||
if (this.publicKey != null) {
|
||||
const fingerprint = await this.cryptoService.getFingerprint(this.userId, this.publicKey.buffer);
|
||||
if (fingerprint != null) {
|
||||
this.fingerprint = fingerprint.join('-');
|
||||
@ -57,6 +50,6 @@ export class UserConfirmComponent implements OnInit {
|
||||
await this.storageService.save(ConstantsService.autoConfirmFingerprints, true);
|
||||
}
|
||||
|
||||
this.onConfirmedUser.emit(this.publicKey);
|
||||
this.onConfirmedUser.emit();
|
||||
}
|
||||
}
|
||||
|
@ -201,7 +201,7 @@ export class ChangePasswordComponent extends BaseChangePasswordComponent {
|
||||
|
||||
for (const org of orgs) {
|
||||
// If not already enrolled, skip
|
||||
if (!org.isResetPasswordEnrolled) {
|
||||
if (!org.resetPasswordEnrolled) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -98,7 +98,7 @@ export class OrganizationsComponent implements OnInit {
|
||||
let toastStringRef = 'withdrawPasswordResetSuccess';
|
||||
|
||||
// Enroll - encrpyt user's encKey.key with organization key
|
||||
if (!org.isResetPasswordEnrolled) {
|
||||
if (!org.resetPasswordEnrolled) {
|
||||
const encKey = await this.cryptoService.getEncKey();
|
||||
const orgSymKey = await this.cryptoService.getOrgKey(org.id);
|
||||
const encryptedKey = await this.cryptoService.encrypt(encKey.key, orgSymKey);
|
||||
|
@ -3903,13 +3903,25 @@
|
||||
"noSelectedUsersApplicable": {
|
||||
"message": "This action is not applicable to any of the selected users."
|
||||
},
|
||||
"usersHasBeenReinvited": {
|
||||
"message": "The selected users have been reinvited."
|
||||
},
|
||||
"removeSelectedUsersConfirmation": {
|
||||
"message": "Are you sure you want to remove the selected users?"
|
||||
},
|
||||
"usersHasBeenRemoved": {
|
||||
"message": "The selected users have been removed."
|
||||
"confirmSelected": {
|
||||
"message": "Confirm Selected"
|
||||
},
|
||||
"bulkConfirmStatus": {
|
||||
"message": "Bulk action status"
|
||||
},
|
||||
"bulkConfirmMessage": {
|
||||
"message": "Confirmed successfully."
|
||||
},
|
||||
"bulkReinviteMessage": {
|
||||
"message": "Reinvited successfully."
|
||||
},
|
||||
"bulkRemovedMessage": {
|
||||
"message": "Removed successfully"
|
||||
},
|
||||
"bulkFilteredMessage": {
|
||||
"message": "Excluded, not applicable for this action."
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user