mirror of
https://github.com/bitwarden/browser
synced 2026-02-10 05:30:01 +00:00
Archive, Unarchive, BulkArchive and BulkUnarchive in Web in the menu drop downs
This commit is contained in:
@@ -143,6 +143,14 @@
|
||||
<i class="bwi bwi-fw bwi-files" aria-hidden="true"></i>
|
||||
{{ "clone" | i18n }}
|
||||
</button>
|
||||
<button bitMenuItem *ngIf="showArchive" type="button" (click)="archive()">
|
||||
<i class="bwi bwi-fw bwi-archive" aria-hidden="true"></i>
|
||||
{{ "archive" | i18n }}
|
||||
</button>
|
||||
<button bitMenuItem *ngIf="showUnarchive" type="button" (click)="unarchive()">
|
||||
<i class="bwi bwi-fw bwi-undo" aria-hidden="true"></i>
|
||||
{{ "unarchive" | i18n }}
|
||||
</button>
|
||||
<button
|
||||
bitMenuItem
|
||||
*ngIf="showAssignToCollections"
|
||||
|
||||
@@ -32,6 +32,8 @@ export class VaultCipherRowComponent implements OnInit {
|
||||
@Input() showPremiumFeatures: boolean;
|
||||
@Input() useEvents: boolean;
|
||||
@Input() cloneable: boolean;
|
||||
@Input() archivable: boolean;
|
||||
@Input() unarchivable: boolean;
|
||||
@Input() organizations: Organization[];
|
||||
@Input() collections: CollectionView[];
|
||||
@Input() viewingOrgVault: boolean;
|
||||
@@ -108,6 +110,24 @@ export class VaultCipherRowComponent implements OnInit {
|
||||
return this.cloneable && !this.cipher.isDeleted;
|
||||
}
|
||||
|
||||
protected get showArchive() {
|
||||
return (
|
||||
this.archivable &&
|
||||
this.cipher.organizationId == null &&
|
||||
!this.cipher.isDeleted &&
|
||||
!this.cipher.isArchived
|
||||
);
|
||||
}
|
||||
|
||||
protected get showUnarchive() {
|
||||
return (
|
||||
this.unarchivable &&
|
||||
this.cipher.organizationId == null &&
|
||||
this.cipher.isArchived &&
|
||||
!this.cipher.isDeleted
|
||||
);
|
||||
}
|
||||
|
||||
protected get showEventLogs() {
|
||||
return this.useEvents && this.cipher.organizationId;
|
||||
}
|
||||
@@ -183,6 +203,14 @@ export class VaultCipherRowComponent implements OnInit {
|
||||
this.onEvent.emit({ type: "clone", item: this.cipher });
|
||||
}
|
||||
|
||||
protected archive() {
|
||||
this.onEvent.emit({ type: "archive", item: this.cipher });
|
||||
}
|
||||
|
||||
protected unarchive() {
|
||||
this.onEvent.emit({ type: "unarchive", item: this.cipher });
|
||||
}
|
||||
|
||||
protected events() {
|
||||
this.onEvent.emit({ type: "viewEvents", item: this.cipher });
|
||||
}
|
||||
|
||||
@@ -10,6 +10,10 @@ export type VaultItemEvent =
|
||||
| { type: "viewEvents"; item: CipherView }
|
||||
| { type: "editCollection"; item: CollectionView; readonly: boolean }
|
||||
| { type: "clone"; item: CipherView }
|
||||
| { type: "archive"; item: CipherView }
|
||||
| { type: "bulkArchive"; items: CipherView[] }
|
||||
| { type: "bulkUnarchive"; items: CipherView[] }
|
||||
| { type: "unarchive"; item: CipherView }
|
||||
| { type: "restore"; items: CipherView[] }
|
||||
| { type: "delete"; items: VaultItem[] }
|
||||
| { type: "copyField"; item: CipherView; field: "username" | "password" | "totp" }
|
||||
|
||||
@@ -66,6 +66,19 @@
|
||||
<i class="bwi bwi-fw bwi-folder" aria-hidden="true"></i>
|
||||
{{ "addToFolder" | i18n }}
|
||||
</button>
|
||||
<button *ngIf="bulkArchiveAllowed" type="button" bitMenuItem (click)="bulkArchive()">
|
||||
<i class="bwi bwi-fw bwi-folder" aria-hidden="true"></i>
|
||||
{{ "archive" | i18n }}
|
||||
</button>
|
||||
<button
|
||||
*ngIf="bulkUnarchiveAllowed"
|
||||
type="button"
|
||||
bitMenuItem
|
||||
(click)="bulkUnarchive()"
|
||||
>
|
||||
<i class="bwi bwi-fw bwi-folder" aria-hidden="true"></i>
|
||||
{{ "unarchive" | i18n }}
|
||||
</button>
|
||||
<button
|
||||
*ngIf="showAdminActions && showBulkEditCollectionAccess"
|
||||
type="button"
|
||||
@@ -152,6 +165,8 @@
|
||||
[useEvents]="useEvents"
|
||||
[viewingOrgVault]="viewingOrgVault"
|
||||
[cloneable]="canClone(item)"
|
||||
[archivable]="canArchive(item)"
|
||||
[unarchivable]="canUnarchive(item)"
|
||||
[organizations]="allOrganizations"
|
||||
[collections]="allCollections"
|
||||
[checked]="selection.isSelected(item)"
|
||||
|
||||
@@ -53,6 +53,8 @@ export class VaultItemsComponent {
|
||||
@Input() allGroups: GroupView[] = [];
|
||||
@Input() showBulkEditCollectionAccess = false;
|
||||
@Input() showBulkAddToCollections = false;
|
||||
@Input() showBulkUnarchive = false;
|
||||
@Input() showBulkArchive = false;
|
||||
@Input() showPermissionsColumn = false;
|
||||
@Input() viewingOrgVault: boolean;
|
||||
@Input() addAccessStatus: number;
|
||||
@@ -161,6 +163,25 @@ export class VaultItemsComponent {
|
||||
);
|
||||
}
|
||||
|
||||
get bulkArchiveAllowed() {
|
||||
const AllowArchiveFlagOn = true; //TODO implement feature flag
|
||||
return (
|
||||
AllowArchiveFlagOn &&
|
||||
this.selection.selected.filter((item) => item.collection || item.cipher.organizationId)
|
||||
.length === 0 &&
|
||||
this.selection.selected.filter((item) => item.cipher.archivedDate == null).length
|
||||
);
|
||||
}
|
||||
get bulkUnarchiveAllowed() {
|
||||
const AllowArchiveFlagOn = true; //TODO implement feature flag
|
||||
return (
|
||||
AllowArchiveFlagOn &&
|
||||
this.selection.selected.filter((item) => item.collection || item.cipher.organizationId)
|
||||
.length === 0 &&
|
||||
this.selection.selected.filter((item) => item.cipher.archivedDate !== null).length
|
||||
);
|
||||
}
|
||||
|
||||
//@TODO: remove this function when removing the limitItemDeletion$ feature flag.
|
||||
get showDelete(): boolean {
|
||||
if (this.selection.selected.length === 0) {
|
||||
@@ -195,7 +216,9 @@ export class VaultItemsComponent {
|
||||
!this.bulkMoveAllowed &&
|
||||
!this.showAssignToCollections() &&
|
||||
!this.showDelete &&
|
||||
!this.showBulkEditCollectionAccess
|
||||
!this.showBulkEditCollectionAccess &&
|
||||
!this.showBulkArchive &&
|
||||
!this.showBulkUnarchive
|
||||
);
|
||||
}
|
||||
|
||||
@@ -249,6 +272,23 @@ export class VaultItemsComponent {
|
||||
});
|
||||
}
|
||||
|
||||
protected bulkArchive() {
|
||||
this.event({
|
||||
type: "bulkArchive",
|
||||
items: this.selection.selected
|
||||
.filter((item) => item.cipher !== undefined)
|
||||
.map((item) => item.cipher),
|
||||
});
|
||||
}
|
||||
|
||||
protected bulkUnarchive() {
|
||||
this.event({
|
||||
type: "bulkUnarchive",
|
||||
items: this.selection.selected
|
||||
.filter((item) => item.cipher !== undefined)
|
||||
.map((item) => item.cipher),
|
||||
});
|
||||
}
|
||||
protected bulkRestore() {
|
||||
this.event({
|
||||
type: "restore",
|
||||
@@ -290,6 +330,22 @@ export class VaultItemsComponent {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected canArchive(vaultItem: VaultItem) {
|
||||
//TODO implement feature flag
|
||||
const canArchiveFeatureFlag = true;
|
||||
return (
|
||||
vaultItem.cipher.organizationId == null &&
|
||||
vaultItem.cipher.archivedDate == null &&
|
||||
canArchiveFeatureFlag
|
||||
);
|
||||
}
|
||||
|
||||
protected canUnarchive(vaultItem: VaultItem) {
|
||||
//TODO implement feature flag
|
||||
const canArchiveFeatureFlag = true;
|
||||
return vaultItem.cipher.archivedDate != null && canArchiveFeatureFlag;
|
||||
}
|
||||
|
||||
protected canEditCipher(cipher: CipherView) {
|
||||
if (cipher.organizationId == null) {
|
||||
return true;
|
||||
|
||||
@@ -564,6 +564,18 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
case "viewAttachments":
|
||||
await this.editCipherAttachments(event.item);
|
||||
break;
|
||||
case "archive":
|
||||
await this.archiveCipher(event.item);
|
||||
break;
|
||||
case "unarchive":
|
||||
await this.unarchiveCipher(event.item);
|
||||
break;
|
||||
case "bulkArchive":
|
||||
await this.bulkArchiveCipher(event.items);
|
||||
break;
|
||||
case "bulkUnarchive":
|
||||
await this.bulkUnarchiveCipher(event.items);
|
||||
break;
|
||||
case "clone":
|
||||
await this.cloneCipher(event.item);
|
||||
break;
|
||||
@@ -1051,6 +1063,152 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
}
|
||||
|
||||
async archiveCipher(c: CipherView): Promise<boolean> {
|
||||
if (!(await this.repromptCipher([c]))) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!c.edit) {
|
||||
this.showMissingPermissionsError();
|
||||
return;
|
||||
}
|
||||
|
||||
const confirmed = await this.dialogService.openSimpleDialog({
|
||||
title: { key: "archiveItem" },
|
||||
content: { key: "archiveItemConfirmation" },
|
||||
type: "info",
|
||||
});
|
||||
|
||||
if (!confirmed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
const activeUserId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId));
|
||||
await this.archiveCipherWithServer(c.id, activeUserId);
|
||||
|
||||
this.toastService.showToast({
|
||||
variant: "success",
|
||||
title: null,
|
||||
message: this.i18nService.t("archivedItem"),
|
||||
});
|
||||
this.refresh();
|
||||
} catch (e) {
|
||||
this.logService.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
async unarchiveCipher(c: CipherView): Promise<boolean> {
|
||||
if (!(await this.repromptCipher([c]))) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!c.edit) {
|
||||
this.showMissingPermissionsError();
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const activeUserId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId));
|
||||
await this.unarchiveCipherWithServer(c.id, activeUserId);
|
||||
|
||||
this.toastService.showToast({
|
||||
variant: "success",
|
||||
title: null,
|
||||
message: this.i18nService.t("unarchivedItem"),
|
||||
});
|
||||
this.refresh();
|
||||
} catch (e) {
|
||||
this.logService.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
async bulkArchiveCipher(ciphers: CipherView[]): Promise<boolean> {
|
||||
if (!(await this.repromptCipher(ciphers))) {
|
||||
return;
|
||||
}
|
||||
|
||||
const confirmed = await this.dialogService.openSimpleDialog({
|
||||
title: { key: "archiveItems" },
|
||||
content: { key: "archiveItemsConfirmation" },
|
||||
type: "info",
|
||||
});
|
||||
|
||||
if (!confirmed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const canEditAll = ciphers.every((cipher) => cipher.edit);
|
||||
|
||||
if (!canEditAll) {
|
||||
this.showMissingPermissionsError();
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
const activeUserId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId));
|
||||
|
||||
const cipherIds = ciphers.map((cipher) => cipher.id);
|
||||
await this.bulkArchiveCipherWithServer(cipherIds, activeUserId);
|
||||
|
||||
this.toastService.showToast({
|
||||
variant: "success",
|
||||
title: null,
|
||||
message: this.i18nService.t("archivedItem"),
|
||||
});
|
||||
this.refresh();
|
||||
} catch (e) {
|
||||
this.logService.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
async bulkUnarchiveCipher(ciphers: CipherView[]): Promise<boolean> {
|
||||
if (!(await this.repromptCipher(ciphers))) {
|
||||
//TODO should we do this here?
|
||||
return;
|
||||
}
|
||||
|
||||
const canEditAll = ciphers.every((cipher) => cipher.edit);
|
||||
|
||||
if (!canEditAll) {
|
||||
this.showMissingPermissionsError();
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
const activeUserId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId));
|
||||
|
||||
const cipherIds = ciphers.map((cipher) => cipher.id);
|
||||
|
||||
await this.bulkUnarchiveCipherWithServer(cipherIds, activeUserId);
|
||||
|
||||
this.toastService.showToast({
|
||||
variant: "success",
|
||||
title: null,
|
||||
message: this.i18nService.t("unarchivedItems"),
|
||||
});
|
||||
this.refresh();
|
||||
} catch (e) {
|
||||
this.logService.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected archiveCipherWithServer(id: string, userId: UserId) {
|
||||
return this.cipherService.archiveWithServer(id, userId);
|
||||
}
|
||||
|
||||
protected unarchiveCipherWithServer(id: string, userId: UserId) {
|
||||
return this.cipherService.unarchiveWithServer(id, userId);
|
||||
}
|
||||
|
||||
protected bulkArchiveCipherWithServer(ids: string[], userId: UserId) {
|
||||
return this.cipherService.archiveManyWithServer(ids, userId);
|
||||
}
|
||||
|
||||
protected bulkUnarchiveCipherWithServer(ids: string[], userId: UserId) {
|
||||
return this.cipherService.unarchiveManyWithServer(ids, userId);
|
||||
}
|
||||
|
||||
async deleteCipher(c: CipherView): Promise<boolean> {
|
||||
if (!(await this.repromptCipher([c]))) {
|
||||
return;
|
||||
|
||||
@@ -10577,10 +10577,37 @@
|
||||
"archive": {
|
||||
"message": "Archive"
|
||||
},
|
||||
"unarchive": {
|
||||
"message": "Unarchive"
|
||||
},
|
||||
"noItemsInArchive": {
|
||||
"message": "No items in archive"
|
||||
},
|
||||
"archivedItemsDescription": {
|
||||
"message": "Archived items will appear here and will be excluded from general search results and autofill suggestions."
|
||||
},
|
||||
"archivedItem": {
|
||||
"message": "Item sent to archive"
|
||||
},
|
||||
"archivedItems": {
|
||||
"message": "Items sent to archive"
|
||||
},
|
||||
"unarchivedItem": {
|
||||
"message": "Item removed from archive"
|
||||
},
|
||||
"unarchivedItems": {
|
||||
"message": "Items removed from archive"
|
||||
},
|
||||
"archiveItemConfirmation": {
|
||||
"message": "Archived items are excluded from general search results and autofill suggestions. Are you sure you want to archive this item?"
|
||||
},
|
||||
"archiveItem": {
|
||||
"message": "Archive Item"
|
||||
},
|
||||
"archiveItems": {
|
||||
"message": "Archive Items"
|
||||
},
|
||||
"archiveItemsConfirmation": {
|
||||
"message": "Archived items are excluded from general search results and autofill suggestions. Are you sure you want to archive these items?"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,10 +110,12 @@ import { UserKeyResponse } from "../models/response/user-key.response";
|
||||
import { SyncResponse } from "../platform/sync";
|
||||
import { UserId } from "../types/guid";
|
||||
import { AttachmentRequest } from "../vault/models/request/attachment.request";
|
||||
import { CipherBulkArchiveRequest } from "../vault/models/request/cipher-bulk-archive.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 { CipherBulkUnarchiveRequest } from "../vault/models/request/cipher-bulk-unarchive.request";
|
||||
import { CipherCollectionsRequest } from "../vault/models/request/cipher-collections.request";
|
||||
import { CipherCreateRequest } from "../vault/models/request/cipher-create.request";
|
||||
import { CipherPartialRequest } from "../vault/models/request/cipher-partial.request";
|
||||
@@ -207,7 +209,11 @@ export abstract class ApiService {
|
||||
putPartialCipher: (id: string, request: CipherPartialRequest) => Promise<CipherResponse>;
|
||||
putCipherAdmin: (id: string, request: CipherRequest) => Promise<CipherResponse>;
|
||||
deleteCipher: (id: string) => Promise<any>;
|
||||
archiveCipher: (id: string) => Promise<any>;
|
||||
unarchiveCipher: (id: string) => Promise<any>;
|
||||
deleteCipherAdmin: (id: string) => Promise<any>;
|
||||
unarchiveManyCiphers: (request: CipherBulkUnarchiveRequest) => Promise<any>;
|
||||
archiveManyCiphers: (request: CipherBulkArchiveRequest) => Promise<any>;
|
||||
deleteManyCiphers: (request: CipherBulkDeleteRequest) => Promise<any>;
|
||||
deleteManyCiphersAdmin: (request: CipherBulkDeleteRequest) => Promise<any>;
|
||||
putMoveCiphers: (request: CipherBulkMoveRequest) => Promise<any>;
|
||||
|
||||
@@ -128,10 +128,12 @@ import { Utils } from "../platform/misc/utils";
|
||||
import { SyncResponse } from "../platform/sync";
|
||||
import { UserId } from "../types/guid";
|
||||
import { AttachmentRequest } from "../vault/models/request/attachment.request";
|
||||
import { CipherBulkArchiveRequest } from "../vault/models/request/cipher-bulk-archive.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 { CipherBulkUnarchiveRequest } from "../vault/models/request/cipher-bulk-unarchive.request";
|
||||
import { CipherCollectionsRequest } from "../vault/models/request/cipher-collections.request";
|
||||
import { CipherCreateRequest } from "../vault/models/request/cipher-create.request";
|
||||
import { CipherPartialRequest } from "../vault/models/request/cipher-partial.request";
|
||||
@@ -539,6 +541,21 @@ export class ApiService implements ApiServiceAbstraction {
|
||||
return this.send("DELETE", "/ciphers/admin", request, true, false);
|
||||
}
|
||||
|
||||
archiveCipher(id: string): Promise<any> {
|
||||
return this.send("PUT", "/ciphers/" + id + "/archive", null, true, false);
|
||||
}
|
||||
|
||||
unarchiveCipher(id: string): Promise<any> {
|
||||
return this.send("PUT", "/ciphers/" + id + "/unarchive", null, true, false);
|
||||
}
|
||||
|
||||
archiveManyCiphers(request: CipherBulkArchiveRequest): Promise<any> {
|
||||
return this.send("PUT", "/ciphers/archive", request, true, false);
|
||||
}
|
||||
unarchiveManyCiphers(request: CipherBulkUnarchiveRequest): Promise<any> {
|
||||
return this.send("PUT", "/ciphers/unarchive", request, true, false);
|
||||
}
|
||||
|
||||
putMoveCiphers(request: CipherBulkMoveRequest): Promise<any> {
|
||||
return this.send("PUT", "/ciphers/move", request, true, false);
|
||||
}
|
||||
|
||||
@@ -173,6 +173,11 @@ export abstract class CipherService implements UserKeyRotationDataProvider<Ciphe
|
||||
abstract moveManyWithServer(ids: string[], folderId: string, userId: UserId): Promise<any>;
|
||||
abstract delete(id: string | string[], userId: UserId): Promise<any>;
|
||||
abstract deleteWithServer(id: string, userId: UserId, asAdmin?: boolean): Promise<any>;
|
||||
abstract archiveWithServer(id: string, userId: UserId): Promise<any>;
|
||||
abstract unarchiveWithServer(id: string, userId: UserId): Promise<any>;
|
||||
abstract archiveManyWithServer(ids: string[], userId: UserId): Promise<any>;
|
||||
abstract unarchiveManyWithServer(ids: string[], userId: UserId): Promise<any>;
|
||||
|
||||
abstract deleteManyWithServer(ids: string[], userId: UserId, asAdmin?: boolean): Promise<any>;
|
||||
abstract deleteAttachment(
|
||||
id: string,
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
// FIXME: Update this file to be type safe and remove this and next line
|
||||
// @ts-strict-ignore
|
||||
export class CipherBulkArchiveRequest {
|
||||
ids: string[];
|
||||
|
||||
constructor(ids: string[]) {
|
||||
this.ids = ids == null ? [] : ids;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
// FIXME: Update this file to be type safe and remove this and next line
|
||||
// @ts-strict-ignore
|
||||
export class CipherBulkUnarchiveRequest {
|
||||
ids: string[];
|
||||
|
||||
constructor(ids: string[]) {
|
||||
this.ids = ids == null ? [] : ids;
|
||||
}
|
||||
}
|
||||
@@ -58,10 +58,12 @@ import { Password } from "../models/domain/password";
|
||||
import { SecureNote } from "../models/domain/secure-note";
|
||||
import { SortedCiphersCache } from "../models/domain/sorted-ciphers-cache";
|
||||
import { SshKey } from "../models/domain/ssh-key";
|
||||
import { CipherBulkArchiveRequest } from "../models/request/cipher-bulk-archive.request";
|
||||
import { CipherBulkDeleteRequest } from "../models/request/cipher-bulk-delete.request";
|
||||
import { CipherBulkMoveRequest } from "../models/request/cipher-bulk-move.request";
|
||||
import { CipherBulkRestoreRequest } from "../models/request/cipher-bulk-restore.request";
|
||||
import { CipherBulkShareRequest } from "../models/request/cipher-bulk-share.request";
|
||||
import { CipherBulkUnarchiveRequest } from "../models/request/cipher-bulk-unarchive.request";
|
||||
import { CipherBulkUpdateCollectionsRequest } from "../models/request/cipher-bulk-update-collections.request";
|
||||
import { CipherCollectionsRequest } from "../models/request/cipher-collections.request";
|
||||
import { CipherCreateRequest } from "../models/request/cipher-create.request";
|
||||
@@ -1064,6 +1066,40 @@ export class CipherService implements CipherServiceAbstraction {
|
||||
await this.encryptedCiphersState(userId).update(() => ciphers);
|
||||
}
|
||||
|
||||
async archive(id: string | string[], userId: UserId): Promise<any> {
|
||||
const ciphers = await firstValueFrom(this.ciphers$(userId));
|
||||
if (ciphers == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
const idsToArchive = Array.isArray(id) ? id : [id];
|
||||
idsToArchive.forEach((cipherId) => {
|
||||
if (cipherId in ciphers) {
|
||||
ciphers[cipherId as keyof typeof ciphers].archivedDate = new Date().toISOString();
|
||||
}
|
||||
});
|
||||
|
||||
await this.clearCache();
|
||||
await this.encryptedCiphersState(userId).update(() => ciphers);
|
||||
}
|
||||
|
||||
async unarchive(id: string | string[], userId: UserId): Promise<any> {
|
||||
const ciphers = await firstValueFrom(this.ciphers$(userId));
|
||||
if (ciphers == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
const idsToArchive = Array.isArray(id) ? id : [id];
|
||||
idsToArchive.forEach((cipherId) => {
|
||||
if (cipherId in ciphers) {
|
||||
ciphers[cipherId as keyof typeof ciphers].archivedDate = null;
|
||||
}
|
||||
});
|
||||
|
||||
await this.clearCache();
|
||||
await this.encryptedCiphersState(userId).update(() => ciphers);
|
||||
}
|
||||
|
||||
async deleteWithServer(id: string, userId: UserId, asAdmin = false): Promise<any> {
|
||||
if (asAdmin) {
|
||||
await this.apiService.deleteCipherAdmin(id);
|
||||
@@ -1074,6 +1110,30 @@ export class CipherService implements CipherServiceAbstraction {
|
||||
await this.delete(id, userId);
|
||||
}
|
||||
|
||||
async archiveWithServer(id: string, userId: UserId): Promise<any> {
|
||||
await this.apiService.archiveCipher(id);
|
||||
await this.archive(id, userId);
|
||||
}
|
||||
|
||||
async unarchiveWithServer(id: string, userId: UserId): Promise<any> {
|
||||
await this.apiService.unarchiveCipher(id);
|
||||
await this.unarchive(id, userId);
|
||||
}
|
||||
|
||||
async archiveManyWithServer(ids: string[], userId: UserId): Promise<any> {
|
||||
const request = new CipherBulkArchiveRequest(ids);
|
||||
|
||||
await this.apiService.archiveManyCiphers(request);
|
||||
await this.archive(ids, userId);
|
||||
}
|
||||
|
||||
async unarchiveManyWithServer(ids: string[], userId: UserId): Promise<any> {
|
||||
const request = new CipherBulkUnarchiveRequest(ids);
|
||||
|
||||
await this.apiService.unarchiveManyCiphers(request);
|
||||
await this.unarchive(ids, userId);
|
||||
}
|
||||
|
||||
async deleteManyWithServer(ids: string[], userId: UserId, asAdmin = false): Promise<any> {
|
||||
const request = new CipherBulkDeleteRequest(ids);
|
||||
if (asAdmin) {
|
||||
|
||||
Reference in New Issue
Block a user