diff --git a/apps/web/src/app/vault/individual-vault/bulk-action-dialogs/bulk-restore-dialog/bulk-restore-dialog.component.ts b/apps/web/src/app/vault/individual-vault/bulk-action-dialogs/bulk-restore-dialog/bulk-restore-dialog.component.ts index 62722978c8..94685f9fda 100644 --- a/apps/web/src/app/vault/individual-vault/bulk-action-dialogs/bulk-restore-dialog/bulk-restore-dialog.component.ts +++ b/apps/web/src/app/vault/individual-vault/bulk-action-dialogs/bulk-restore-dialog/bulk-restore-dialog.component.ts @@ -2,12 +2,14 @@ import { DialogConfig, DialogRef, DIALOG_DATA } from "@angular/cdk/dialog"; import { Component, Inject } from "@angular/core"; 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 { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; export interface BulkRestoreDialogParams { cipherIds: string[]; + organization?: Organization; } export enum BulkRestoreDialogResult { @@ -35,6 +37,7 @@ export const openBulkRestoreDialog = ( }) export class BulkRestoreDialogComponent { cipherIds: string[]; + organization?: Organization; constructor( @Inject(DIALOG_DATA) params: BulkRestoreDialogParams, @@ -44,10 +47,12 @@ export class BulkRestoreDialogComponent { private i18nService: I18nService ) { this.cipherIds = params.cipherIds ?? []; + this.organization = params.organization; } 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.close(BulkRestoreDialogResult.Restored); }; diff --git a/apps/web/src/app/vault/org-vault/vault.component.ts b/apps/web/src/app/vault/org-vault/vault.component.ts index 106d8f9ff8..63f92e64ea 100644 --- a/apps/web/src/app/vault/org-vault/vault.component.ts +++ b/apps/web/src/app/vault/org-vault/vault.component.ts @@ -695,7 +695,7 @@ export class VaultComponent implements OnInit, OnDestroy { } const dialog = openBulkRestoreDialog(this.dialogService, { - data: { cipherIds: selectedCipherIds }, + data: { cipherIds: selectedCipherIds, organization: this.organization }, }); const result = await lastValueFrom(dialog.closed); diff --git a/libs/common/src/abstractions/api.service.ts b/libs/common/src/abstractions/api.service.ts index d21de91718..51027b3405 100644 --- a/libs/common/src/abstractions/api.service.ts +++ b/libs/common/src/abstractions/api.service.ts @@ -243,6 +243,9 @@ export abstract class ApiService { putRestoreManyCiphers: ( request: CipherBulkRestoreRequest ) => Promise>; + putRestoreManyCiphersAdmin: ( + request: CipherBulkRestoreRequest + ) => Promise>; /** * @deprecated Mar 25 2021: This method has been deprecated in favor of direct uploads. diff --git a/libs/common/src/services/api.service.ts b/libs/common/src/services/api.service.ts index 9c098632b1..0e03231652 100644 --- a/libs/common/src/services/api.service.ts +++ b/libs/common/src/services/api.service.ts @@ -133,6 +133,7 @@ import { Utils } from "../platform/misc/utils"; import { AttachmentRequest } from "../vault/models/request/attachment.request"; import { CipherBulkDeleteRequest } from "../vault/models/request/cipher-bulk-delete.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 { CipherCollectionsRequest } from "../vault/models/request/cipher-collections.request"; import { CipherCreateRequest } from "../vault/models/request/cipher-create.request"; @@ -614,12 +615,19 @@ export class ApiService implements ApiServiceAbstraction { } async putRestoreManyCiphers( - request: CipherBulkDeleteRequest + request: CipherBulkRestoreRequest ): Promise> { const r = await this.send("PUT", "/ciphers/restore", request, true, true); return new ListResponse(r, CipherResponse); } + async putRestoreManyCiphersAdmin( + request: CipherBulkRestoreRequest + ): Promise> { + const r = await this.send("PUT", "/ciphers/restore-admin", request, true, true); + return new ListResponse(r, CipherResponse); + } + // Attachments APIs async getAttachmentData( diff --git a/libs/common/src/vault/abstractions/cipher.service.ts b/libs/common/src/vault/abstractions/cipher.service.ts index 574b96d9ec..edb4ab6460 100644 --- a/libs/common/src/vault/abstractions/cipher.service.ts +++ b/libs/common/src/vault/abstractions/cipher.service.ts @@ -76,5 +76,9 @@ export abstract class CipherService { cipher: { id: string; revisionDate: string } | { id: string; revisionDate: string }[] ) => Promise; restoreWithServer: (id: string, asAdmin?: boolean) => Promise; - restoreManyWithServer: (ids: string[]) => Promise; + restoreManyWithServer: ( + ids: string[], + organizationId?: string, + asAdmin?: boolean + ) => Promise; } diff --git a/libs/common/src/vault/models/request/cipher-bulk-restore.request.ts b/libs/common/src/vault/models/request/cipher-bulk-restore.request.ts index 70e5a4e82a..89dc0cb5c1 100644 --- a/libs/common/src/vault/models/request/cipher-bulk-restore.request.ts +++ b/libs/common/src/vault/models/request/cipher-bulk-restore.request.ts @@ -1,7 +1,9 @@ export class CipherBulkRestoreRequest { ids: string[]; + organizationId: string; - constructor(ids: string[]) { + constructor(ids: string[], organizationId?: string) { this.ids = ids == null ? [] : ids; + this.organizationId = organizationId; } } diff --git a/libs/common/src/vault/services/cipher.service.ts b/libs/common/src/vault/services/cipher.service.ts index 122eea4ee6..24167082d9 100644 --- a/libs/common/src/vault/services/cipher.service.ts +++ b/libs/common/src/vault/services/cipher.service.ts @@ -740,10 +740,11 @@ export class CipherService implements CipherServiceAbstraction { } async deleteManyWithServer(ids: string[], asAdmin = false): Promise { + const request = new CipherBulkDeleteRequest(ids); if (asAdmin) { - await this.apiService.deleteManyCiphersAdmin(new CipherBulkDeleteRequest(ids)); + await this.apiService.deleteManyCiphersAdmin(request); } else { - await this.apiService.deleteManyCiphers(new CipherBulkDeleteRequest(ids)); + await this.apiService.deleteManyCiphers(request); } await this.delete(ids); } @@ -879,10 +880,11 @@ export class CipherService implements CipherServiceAbstraction { } async softDeleteManyWithServer(ids: string[], asAdmin = false): Promise { + const request = new CipherBulkDeleteRequest(ids); if (asAdmin) { - await this.apiService.putDeleteManyCiphersAdmin(new CipherBulkDeleteRequest(ids)); + await this.apiService.putDeleteManyCiphersAdmin(request); } else { - await this.apiService.putDeleteManyCiphers(new CipherBulkDeleteRequest(ids)); + await this.apiService.putDeleteManyCiphers(request); } await this.softDelete(ids); @@ -915,14 +917,30 @@ export class CipherService implements CipherServiceAbstraction { } async restoreWithServer(id: string, asAdmin = false): Promise { - const response = asAdmin - ? await this.apiService.putRestoreCipherAdmin(id) - : await this.apiService.putRestoreCipher(id); + let response; + if (asAdmin) { + response = await this.apiService.putRestoreCipherAdmin(id); + } else { + response = await this.apiService.putRestoreCipher(id); + } + await this.restore({ id: id, revisionDate: response.revisionDate }); } - async restoreManyWithServer(ids: string[]): Promise { - const response = await this.apiService.putRestoreManyCiphers(new CipherBulkRestoreRequest(ids)); + async restoreManyWithServer( + ids: string[], + organizationId: string = null, + asAdmin = false + ): Promise { + 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 }[] = []; for (const cipher of response.data) { restores.push({ id: cipher.id, revisionDate: cipher.revisionDate });