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:
parent
c0b97ec21f
commit
10359328f3
1
libs/common/src/platform/misc/index.ts
Normal file
1
libs/common/src/platform/misc/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from "./rxjs-operators";
|
58
libs/common/src/platform/misc/rxjs-operators.spec.ts
Normal file
58
libs/common/src/platform/misc/rxjs-operators.spec.ts
Normal 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" },
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
9
libs/common/src/platform/misc/rxjs-operators.ts
Normal file
9
libs/common/src/platform/misc/rxjs-operators.ts
Normal 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)));
|
@ -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[]),
|
||||
);
|
||||
|
||||
|
@ -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,19 +83,18 @@ export class DefaultCipherAuthorizationService implements CipherAuthorizationSer
|
||||
}
|
||||
}
|
||||
|
||||
return this.collectionService
|
||||
.decryptedCollectionViews$(cipher.collectionIds as CollectionId[])
|
||||
.pipe(
|
||||
map((allCollections) => {
|
||||
const shouldFilter = allowedCollections?.some(Boolean);
|
||||
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;
|
||||
const collections = shouldFilter
|
||||
? cipherCollections.filter((c) => allowedCollections.includes(c.id as CollectionId))
|
||||
: cipherCollections;
|
||||
|
||||
return collections.some((collection) => collection.manage);
|
||||
}),
|
||||
);
|
||||
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 }),
|
||||
);
|
||||
|
@ -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)),
|
||||
);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user