1
0
mirror of https://github.com/bitwarden/browser.git synced 2024-10-28 07:49:41 +01:00

Add rxjs operators and update last callers of decryptedCollectionViews$

This commit is contained in:
Thomas Rittson 2024-10-28 12:10:16 +10:00
parent c0b97ec21f
commit 10359328f3
No known key found for this signature in database
GPG Key ID: CDDDA03861C35E27
6 changed files with 103 additions and 44 deletions

View File

@ -0,0 +1 @@
export * from "./rxjs-operators";

View File

@ -0,0 +1,58 @@
import { firstValueFrom, of } from "rxjs";
import { getById, getByIds } from "./rxjs-operators";
describe("custom rxjs operators", () => {
describe("getById", () => {
it("returns an object with a matching id", async () => {
const input = [
{
id: 1,
data: "one",
},
{
id: 2,
data: "two",
},
{
id: 3,
data: "three",
},
];
const output = await firstValueFrom(getById(2)(of(input)));
expect(output).toEqual([{ id: 1, data: "one" }]);
});
});
describe("getByIds", () => {
it("returns an array of objects with matching ids", async () => {
const input = [
{
id: 1,
data: "one",
},
{
id: 2,
data: "two",
},
{
id: 3,
data: "three",
},
{
id: 4,
data: "four",
},
];
const output = await firstValueFrom(getByIds([2, 3])(of(input)));
expect(output).toEqual([
{ id: 2, data: "two" },
{ id: 3, data: "three" },
]);
});
});
});

View File

@ -0,0 +1,9 @@
import { map } from "rxjs";
type ObjectWithId<TId> = { id: TId };
export const getById = <TId, T extends ObjectWithId<TId>>(id: TId) =>
map<T[], T>((objects) => objects.find((o) => o.id === id));
export const getByIds = <TId, T extends ObjectWithId<TId>>(ids: TId[]) =>
map<T[], T[]>((objects) => objects.filter((o) => ids.includes(o.id)));

View File

@ -4,8 +4,9 @@ import { firstValueFrom, of } from "rxjs";
import { CollectionService, CollectionView } from "@bitwarden/admin-console/common";
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
import { CollectionId } from "@bitwarden/common/types/guid";
import { CollectionId, UserId } from "@bitwarden/common/types/guid";
import { mockAccountServiceWith } from "../../../spec";
import { CipherView } from "../models/view/cipher.view";
import {
@ -14,10 +15,13 @@ import {
} from "./cipher-authorization.service";
describe("CipherAuthorizationService", () => {
const userId = "UserId" as UserId;
let cipherAuthorizationService: CipherAuthorizationService;
const mockCollectionService = mock<CollectionService>();
const mockOrganizationService = mock<OrganizationService>();
const mockAccountService = mockAccountServiceWith(userId);
// Mock factories
const createMockCipher = (
@ -56,6 +60,7 @@ describe("CipherAuthorizationService", () => {
cipherAuthorizationService = new DefaultCipherAuthorizationService(
mockCollectionService,
mockOrganizationService,
mockAccountService,
);
});
@ -113,7 +118,7 @@ describe("CipherAuthorizationService", () => {
createMockCollection("col1", true),
createMockCollection("col2", false),
];
mockCollectionService.decryptedCollectionViews$.mockReturnValue(
mockCollectionService.decryptedCollections$.mockReturnValue(
of(allCollections as CollectionView[]),
);
@ -121,10 +126,6 @@ describe("CipherAuthorizationService", () => {
.canDeleteCipher$(cipher, [activeCollectionId])
.subscribe((result) => {
expect(result).toBe(true);
expect(mockCollectionService.decryptedCollectionViews$).toHaveBeenCalledWith([
"col1",
"col2",
] as CollectionId[]);
done();
});
});
@ -139,7 +140,7 @@ describe("CipherAuthorizationService", () => {
createMockCollection("col1", false),
createMockCollection("col2", true),
];
mockCollectionService.decryptedCollectionViews$.mockReturnValue(
mockCollectionService.decryptedCollections$.mockReturnValue(
of(allCollections as CollectionView[]),
);
@ -147,10 +148,6 @@ describe("CipherAuthorizationService", () => {
.canDeleteCipher$(cipher, [activeCollectionId])
.subscribe((result) => {
expect(result).toBe(false);
expect(mockCollectionService.decryptedCollectionViews$).toHaveBeenCalledWith([
"col1",
"col2",
] as CollectionId[]);
done();
});
});
@ -165,17 +162,12 @@ describe("CipherAuthorizationService", () => {
createMockCollection("col2", true),
createMockCollection("col3", false),
];
mockCollectionService.decryptedCollectionViews$.mockReturnValue(
mockCollectionService.decryptedCollections$.mockReturnValue(
of(allCollections as CollectionView[]),
);
cipherAuthorizationService.canDeleteCipher$(cipher).subscribe((result) => {
expect(result).toBe(true);
expect(mockCollectionService.decryptedCollectionViews$).toHaveBeenCalledWith([
"col1",
"col2",
"col3",
] as CollectionId[]);
done();
});
});
@ -189,16 +181,12 @@ describe("CipherAuthorizationService", () => {
createMockCollection("col1", false),
createMockCollection("col2", false),
];
mockCollectionService.decryptedCollectionViews$.mockReturnValue(
mockCollectionService.decryptedCollections$.mockReturnValue(
of(allCollections as CollectionView[]),
);
cipherAuthorizationService.canDeleteCipher$(cipher).subscribe((result) => {
expect(result).toBe(false);
expect(mockCollectionService.decryptedCollectionViews$).toHaveBeenCalledWith([
"col1",
"col2",
] as CollectionId[]);
done();
});
});
@ -246,7 +234,7 @@ describe("CipherAuthorizationService", () => {
createMockCollection("col1", true),
createMockCollection("col2", false),
];
mockCollectionService.decryptedCollectionViews$.mockReturnValue(
mockCollectionService.decryptedCollections$.mockReturnValue(
of(allCollections as CollectionView[]),
);
@ -263,7 +251,7 @@ describe("CipherAuthorizationService", () => {
createMockCollection("col1", false),
createMockCollection("col2", false),
];
mockCollectionService.decryptedCollectionViews$.mockReturnValue(
mockCollectionService.decryptedCollections$.mockReturnValue(
of(allCollections as CollectionView[]),
);

View File

@ -4,6 +4,9 @@ import { CollectionService } from "@bitwarden/admin-console/common";
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
import { CollectionId } from "@bitwarden/common/types/guid";
import { AccountService } from "../../auth/abstractions/account.service";
import { getUserId } from "../../auth/services/account.service";
import { getByIds } from "../../platform/misc/rxjs-operators";
import { Cipher } from "../models/domain/cipher";
import { CipherView } from "../models/view/cipher.view";
@ -46,9 +49,12 @@ export abstract class CipherAuthorizationService {
* {@link CipherAuthorizationService}
*/
export class DefaultCipherAuthorizationService implements CipherAuthorizationService {
private activeUserId$ = this.accountService.activeAccount$.pipe(getUserId);
constructor(
private collectionService: CollectionService,
private organizationService: OrganizationService,
private accountService: AccountService,
) {}
/**
@ -77,15 +83,14 @@ export class DefaultCipherAuthorizationService implements CipherAuthorizationSer
}
}
return this.collectionService
.decryptedCollectionViews$(cipher.collectionIds as CollectionId[])
.pipe(
map((allCollections) => {
return this.collectionService.decryptedCollections$(this.activeUserId$).pipe(
getByIds(cipher.collectionIds),
map((cipherCollections) => {
const shouldFilter = allowedCollections?.some(Boolean);
const collections = shouldFilter
? allCollections.filter((c) => allowedCollections.includes(c.id as CollectionId))
: allCollections;
? cipherCollections.filter((c) => allowedCollections.includes(c.id as CollectionId))
: cipherCollections;
return collections.some((collection) => collection.manage);
}),
@ -112,9 +117,10 @@ export class DefaultCipherAuthorizationService implements CipherAuthorizationSer
return of(true);
}
return this.collectionService
.decryptedCollectionViews$(cipher.collectionIds as CollectionId[])
.pipe(map((allCollections) => allCollections.some((collection) => collection.manage)));
return this.collectionService.decryptedCollections$(this.activeUserId$).pipe(
getByIds(cipher.collectionIds),
map((allCollections) => allCollections.some((collection) => collection.manage)),
);
}),
shareReplay({ bufferSize: 1, refCount: false }),
);

View File

@ -1,6 +1,6 @@
import { CommonModule } from "@angular/common";
import { Component, Input, OnChanges, OnDestroy } from "@angular/core";
import { firstValueFrom, map, Observable, Subject, takeUntil } from "rxjs";
import { firstValueFrom, Observable, Subject, takeUntil } from "rxjs";
import { CollectionService, CollectionView } from "@bitwarden/admin-console/common";
import { JslibModule } from "@bitwarden/angular/jslib.module";
@ -9,6 +9,7 @@ import { Organization } from "@bitwarden/common/admin-console/models/domain/orga
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { getUserId } from "@bitwarden/common/auth/services/account.service";
import { isCardExpired } from "@bitwarden/common/autofill/utils";
import { getByIds } from "@bitwarden/common/platform/misc";
import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
import { FolderView } from "@bitwarden/common/vault/models/view/folder.view";
@ -104,11 +105,7 @@ export class CipherViewComponent implements OnChanges, OnDestroy {
this.collections = await firstValueFrom(
this.collectionService
.decryptedCollections$(this.activeUserId$)
.pipe(
map((allCollections) =>
allCollections.filter((c) => this.cipher.collectionIds.includes(c.id)),
),
),
.pipe(getByIds(this.cipher.collectionIds)),
);
}