mirror of
https://github.com/bitwarden/browser
synced 2025-12-10 21:33:27 +00:00
[AC-1344] Provider users unable to bulk restore vault items for client organizations (#5259)
* [AC-1344] Simplified DeleteMany and SoftDeleteMany request creation * [AC-1344] Added method putRestoreManyCiphersAdmin to apiService * [AC-1344] Added method restoreManyWithServer to cipherService * [AC-1344] Rewrote if statements and changed the method return type
This commit is contained in:
@@ -2,12 +2,14 @@ import { DialogConfig, DialogRef, DIALOG_DATA } from "@angular/cdk/dialog";
|
|||||||
import { Component, Inject } from "@angular/core";
|
import { Component, Inject } from "@angular/core";
|
||||||
|
|
||||||
import { DialogServiceAbstraction } from "@bitwarden/angular/services/dialog";
|
import { DialogServiceAbstraction } from "@bitwarden/angular/services/dialog";
|
||||||
|
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||||
|
|
||||||
export interface BulkRestoreDialogParams {
|
export interface BulkRestoreDialogParams {
|
||||||
cipherIds: string[];
|
cipherIds: string[];
|
||||||
|
organization?: Organization;
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum BulkRestoreDialogResult {
|
export enum BulkRestoreDialogResult {
|
||||||
@@ -35,6 +37,7 @@ export const openBulkRestoreDialog = (
|
|||||||
})
|
})
|
||||||
export class BulkRestoreDialogComponent {
|
export class BulkRestoreDialogComponent {
|
||||||
cipherIds: string[];
|
cipherIds: string[];
|
||||||
|
organization?: Organization;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@Inject(DIALOG_DATA) params: BulkRestoreDialogParams,
|
@Inject(DIALOG_DATA) params: BulkRestoreDialogParams,
|
||||||
@@ -44,10 +47,12 @@ export class BulkRestoreDialogComponent {
|
|||||||
private i18nService: I18nService
|
private i18nService: I18nService
|
||||||
) {
|
) {
|
||||||
this.cipherIds = params.cipherIds ?? [];
|
this.cipherIds = params.cipherIds ?? [];
|
||||||
|
this.organization = params.organization;
|
||||||
}
|
}
|
||||||
|
|
||||||
submit = async () => {
|
submit = async () => {
|
||||||
await this.cipherService.restoreManyWithServer(this.cipherIds);
|
const asAdmin = this.organization?.canEditAnyCollection;
|
||||||
|
await this.cipherService.restoreManyWithServer(this.cipherIds, this.organization?.id, asAdmin);
|
||||||
this.platformUtilsService.showToast("success", null, this.i18nService.t("restoredItems"));
|
this.platformUtilsService.showToast("success", null, this.i18nService.t("restoredItems"));
|
||||||
this.close(BulkRestoreDialogResult.Restored);
|
this.close(BulkRestoreDialogResult.Restored);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -695,7 +695,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const dialog = openBulkRestoreDialog(this.dialogService, {
|
const dialog = openBulkRestoreDialog(this.dialogService, {
|
||||||
data: { cipherIds: selectedCipherIds },
|
data: { cipherIds: selectedCipherIds, organization: this.organization },
|
||||||
});
|
});
|
||||||
|
|
||||||
const result = await lastValueFrom(dialog.closed);
|
const result = await lastValueFrom(dialog.closed);
|
||||||
|
|||||||
@@ -243,6 +243,9 @@ export abstract class ApiService {
|
|||||||
putRestoreManyCiphers: (
|
putRestoreManyCiphers: (
|
||||||
request: CipherBulkRestoreRequest
|
request: CipherBulkRestoreRequest
|
||||||
) => Promise<ListResponse<CipherResponse>>;
|
) => Promise<ListResponse<CipherResponse>>;
|
||||||
|
putRestoreManyCiphersAdmin: (
|
||||||
|
request: CipherBulkRestoreRequest
|
||||||
|
) => Promise<ListResponse<CipherResponse>>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated Mar 25 2021: This method has been deprecated in favor of direct uploads.
|
* @deprecated Mar 25 2021: This method has been deprecated in favor of direct uploads.
|
||||||
|
|||||||
@@ -133,6 +133,7 @@ import { Utils } from "../platform/misc/utils";
|
|||||||
import { AttachmentRequest } from "../vault/models/request/attachment.request";
|
import { AttachmentRequest } from "../vault/models/request/attachment.request";
|
||||||
import { CipherBulkDeleteRequest } from "../vault/models/request/cipher-bulk-delete.request";
|
import { CipherBulkDeleteRequest } from "../vault/models/request/cipher-bulk-delete.request";
|
||||||
import { CipherBulkMoveRequest } from "../vault/models/request/cipher-bulk-move.request";
|
import { CipherBulkMoveRequest } from "../vault/models/request/cipher-bulk-move.request";
|
||||||
|
import { CipherBulkRestoreRequest } from "../vault/models/request/cipher-bulk-restore.request";
|
||||||
import { CipherBulkShareRequest } from "../vault/models/request/cipher-bulk-share.request";
|
import { CipherBulkShareRequest } from "../vault/models/request/cipher-bulk-share.request";
|
||||||
import { CipherCollectionsRequest } from "../vault/models/request/cipher-collections.request";
|
import { CipherCollectionsRequest } from "../vault/models/request/cipher-collections.request";
|
||||||
import { CipherCreateRequest } from "../vault/models/request/cipher-create.request";
|
import { CipherCreateRequest } from "../vault/models/request/cipher-create.request";
|
||||||
@@ -614,12 +615,19 @@ export class ApiService implements ApiServiceAbstraction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async putRestoreManyCiphers(
|
async putRestoreManyCiphers(
|
||||||
request: CipherBulkDeleteRequest
|
request: CipherBulkRestoreRequest
|
||||||
): Promise<ListResponse<CipherResponse>> {
|
): Promise<ListResponse<CipherResponse>> {
|
||||||
const r = await this.send("PUT", "/ciphers/restore", request, true, true);
|
const r = await this.send("PUT", "/ciphers/restore", request, true, true);
|
||||||
return new ListResponse<CipherResponse>(r, CipherResponse);
|
return new ListResponse<CipherResponse>(r, CipherResponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async putRestoreManyCiphersAdmin(
|
||||||
|
request: CipherBulkRestoreRequest
|
||||||
|
): Promise<ListResponse<CipherResponse>> {
|
||||||
|
const r = await this.send("PUT", "/ciphers/restore-admin", request, true, true);
|
||||||
|
return new ListResponse<CipherResponse>(r, CipherResponse);
|
||||||
|
}
|
||||||
|
|
||||||
// Attachments APIs
|
// Attachments APIs
|
||||||
|
|
||||||
async getAttachmentData(
|
async getAttachmentData(
|
||||||
|
|||||||
@@ -76,5 +76,9 @@ export abstract class CipherService {
|
|||||||
cipher: { id: string; revisionDate: string } | { id: string; revisionDate: string }[]
|
cipher: { id: string; revisionDate: string } | { id: string; revisionDate: string }[]
|
||||||
) => Promise<any>;
|
) => Promise<any>;
|
||||||
restoreWithServer: (id: string, asAdmin?: boolean) => Promise<any>;
|
restoreWithServer: (id: string, asAdmin?: boolean) => Promise<any>;
|
||||||
restoreManyWithServer: (ids: string[]) => Promise<any>;
|
restoreManyWithServer: (
|
||||||
|
ids: string[],
|
||||||
|
organizationId?: string,
|
||||||
|
asAdmin?: boolean
|
||||||
|
) => Promise<void>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
export class CipherBulkRestoreRequest {
|
export class CipherBulkRestoreRequest {
|
||||||
ids: string[];
|
ids: string[];
|
||||||
|
organizationId: string;
|
||||||
|
|
||||||
constructor(ids: string[]) {
|
constructor(ids: string[], organizationId?: string) {
|
||||||
this.ids = ids == null ? [] : ids;
|
this.ids = ids == null ? [] : ids;
|
||||||
|
this.organizationId = organizationId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -740,10 +740,11 @@ export class CipherService implements CipherServiceAbstraction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async deleteManyWithServer(ids: string[], asAdmin = false): Promise<any> {
|
async deleteManyWithServer(ids: string[], asAdmin = false): Promise<any> {
|
||||||
|
const request = new CipherBulkDeleteRequest(ids);
|
||||||
if (asAdmin) {
|
if (asAdmin) {
|
||||||
await this.apiService.deleteManyCiphersAdmin(new CipherBulkDeleteRequest(ids));
|
await this.apiService.deleteManyCiphersAdmin(request);
|
||||||
} else {
|
} else {
|
||||||
await this.apiService.deleteManyCiphers(new CipherBulkDeleteRequest(ids));
|
await this.apiService.deleteManyCiphers(request);
|
||||||
}
|
}
|
||||||
await this.delete(ids);
|
await this.delete(ids);
|
||||||
}
|
}
|
||||||
@@ -879,10 +880,11 @@ export class CipherService implements CipherServiceAbstraction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async softDeleteManyWithServer(ids: string[], asAdmin = false): Promise<any> {
|
async softDeleteManyWithServer(ids: string[], asAdmin = false): Promise<any> {
|
||||||
|
const request = new CipherBulkDeleteRequest(ids);
|
||||||
if (asAdmin) {
|
if (asAdmin) {
|
||||||
await this.apiService.putDeleteManyCiphersAdmin(new CipherBulkDeleteRequest(ids));
|
await this.apiService.putDeleteManyCiphersAdmin(request);
|
||||||
} else {
|
} else {
|
||||||
await this.apiService.putDeleteManyCiphers(new CipherBulkDeleteRequest(ids));
|
await this.apiService.putDeleteManyCiphers(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.softDelete(ids);
|
await this.softDelete(ids);
|
||||||
@@ -915,14 +917,30 @@ export class CipherService implements CipherServiceAbstraction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async restoreWithServer(id: string, asAdmin = false): Promise<any> {
|
async restoreWithServer(id: string, asAdmin = false): Promise<any> {
|
||||||
const response = asAdmin
|
let response;
|
||||||
? await this.apiService.putRestoreCipherAdmin(id)
|
if (asAdmin) {
|
||||||
: await this.apiService.putRestoreCipher(id);
|
response = await this.apiService.putRestoreCipherAdmin(id);
|
||||||
|
} else {
|
||||||
|
response = await this.apiService.putRestoreCipher(id);
|
||||||
|
}
|
||||||
|
|
||||||
await this.restore({ id: id, revisionDate: response.revisionDate });
|
await this.restore({ id: id, revisionDate: response.revisionDate });
|
||||||
}
|
}
|
||||||
|
|
||||||
async restoreManyWithServer(ids: string[]): Promise<any> {
|
async restoreManyWithServer(
|
||||||
const response = await this.apiService.putRestoreManyCiphers(new CipherBulkRestoreRequest(ids));
|
ids: string[],
|
||||||
|
organizationId: string = null,
|
||||||
|
asAdmin = false
|
||||||
|
): Promise<void> {
|
||||||
|
let response;
|
||||||
|
if (asAdmin) {
|
||||||
|
const request = new CipherBulkRestoreRequest(ids, organizationId);
|
||||||
|
response = await this.apiService.putRestoreManyCiphersAdmin(request);
|
||||||
|
} else {
|
||||||
|
const request = new CipherBulkRestoreRequest(ids);
|
||||||
|
response = await this.apiService.putRestoreManyCiphers(request);
|
||||||
|
}
|
||||||
|
|
||||||
const restores: { id: string; revisionDate: string }[] = [];
|
const restores: { id: string; revisionDate: string }[] = [];
|
||||||
for (const cipher of response.data) {
|
for (const cipher of response.data) {
|
||||||
restores.push({ id: cipher.id, revisionDate: cipher.revisionDate });
|
restores.push({ id: cipher.id, revisionDate: cipher.revisionDate });
|
||||||
|
|||||||
Reference in New Issue
Block a user