Skip to content

Commit

Permalink
[PM-15506] Wire up vNextOrganizationService for web client (#12810)
Browse files Browse the repository at this point in the history
PR to a feature branch, no need to review until this goes to main.
  • Loading branch information
BTreston authored Jan 14, 2025
1 parent 67cea41 commit 6a59af3
Show file tree
Hide file tree
Showing 108 changed files with 1,365 additions and 529 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { CollectionService } from "@bitwarden/admin-console/common";
import { AddEditComponent as BaseAddEditComponent } from "@bitwarden/angular/vault/components/add-edit.component";
import { AuditService } from "@bitwarden/common/abstractions/audit.service";
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
import { vNextOrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/vnext.organization.service.abstraction";
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { AutofillSettingsServiceAbstraction } from "@bitwarden/common/autofill/services/autofill-settings.service";
Expand Down Expand Up @@ -66,7 +66,7 @@ export class AddEditComponent extends BaseAddEditComponent implements OnInit {
eventCollectionService: EventCollectionService,
policyService: PolicyService,
private popupCloseWarningService: PopupCloseWarningService,
organizationService: OrganizationService,
organizationService: vNextOrganizationService,
passwordRepromptService: PasswordRepromptService,
logService: LogService,
dialogService: DialogService,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ import { BehaviorSubject, firstValueFrom, timeout } from "rxjs";

import { CollectionService, CollectionView } from "@bitwarden/admin-console/common";
import { SearchService } from "@bitwarden/common/abstractions/search.service";
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
import { vNextOrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/vnext.organization.service.abstraction";
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { ProductTierType } from "@bitwarden/common/billing/enums";
import { Utils } from "@bitwarden/common/platform/misc/utils";
import { SyncService } from "@bitwarden/common/platform/sync";
import { ObservableTracker } from "@bitwarden/common/spec";
import { CipherId } from "@bitwarden/common/types/guid";
import { ObservableTracker, mockAccountServiceWith } from "@bitwarden/common/spec";
import { CipherId, UserId } from "@bitwarden/common/types/guid";
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
import { VaultSettingsService } from "@bitwarden/common/vault/abstractions/vault-settings/vault-settings.service";
import { CipherType } from "@bitwarden/common/vault/enums";
Expand All @@ -34,13 +36,15 @@ describe("VaultPopupItemsService", () => {

const cipherServiceMock = mock<CipherService>();
const vaultSettingsServiceMock = mock<VaultSettingsService>();
const organizationServiceMock = mock<OrganizationService>();
const organizationServiceMock = mock<vNextOrganizationService>();
const vaultPopupListFiltersServiceMock = mock<VaultPopupListFiltersService>();
const searchService = mock<SearchService>();
const collectionService = mock<CollectionService>();
const vaultAutofillServiceMock = mock<VaultPopupAutofillService>();
const syncServiceMock = mock<SyncService>();
const inlineMenuFieldQualificationServiceMock = mock<InlineMenuFieldQualificationService>();
const userId = Utils.newGuid() as UserId;
const accountServiceMock = mockAccountServiceWith(userId);

beforeEach(() => {
allCiphers = cipherFactory(10);
Expand Down Expand Up @@ -96,7 +100,7 @@ describe("VaultPopupItemsService", () => {
{ id: "col2", name: "Collection 2" } as CollectionView,
];

organizationServiceMock.organizations$ = new BehaviorSubject([mockOrg]);
organizationServiceMock.organizations$.mockReturnValue(new BehaviorSubject([mockOrg]));
collectionService.decryptedCollections$ = new BehaviorSubject(mockCollections);

activeUserLastSync$ = new BehaviorSubject(new Date());
Expand All @@ -107,7 +111,8 @@ describe("VaultPopupItemsService", () => {
{ provide: CipherService, useValue: cipherServiceMock },
{ provide: VaultSettingsService, useValue: vaultSettingsServiceMock },
{ provide: SearchService, useValue: searchService },
{ provide: OrganizationService, useValue: organizationServiceMock },
{ provide: vNextOrganizationService, useValue: organizationServiceMock },
{ provide: AccountService, useValue: accountServiceMock },
{ provide: VaultPopupListFiltersService, useValue: vaultPopupListFiltersServiceMock },
{ provide: CollectionService, useValue: collectionService },
{ provide: VaultPopupAutofillService, useValue: vaultAutofillServiceMock },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ import {

import { CollectionService } from "@bitwarden/admin-console/common";
import { SearchService } from "@bitwarden/common/abstractions/search.service";
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
import { vNextOrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/vnext.organization.service.abstraction";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { Utils } from "@bitwarden/common/platform/misc/utils";
import { SyncService } from "@bitwarden/common/platform/sync";
import { CollectionId, OrganizationId } from "@bitwarden/common/types/guid";
Expand Down Expand Up @@ -56,6 +57,9 @@ export class VaultPopupItemsService {

latestSearchText$: Observable<string> = this._searchText$.asObservable();

private organizations$ = this.accountService.activeAccount$.pipe(
switchMap((account) => this.organizationService.organizations$(account?.id)),
);
/**
* Observable that contains the list of other cipher types that should be shown
* in the autofill section of the Vault tab. Depends on vault settings.
Expand Down Expand Up @@ -95,10 +99,7 @@ export class VaultPopupItemsService {

private _activeCipherList$: Observable<PopupCipherView[]> = this._allDecryptedCiphers$.pipe(
switchMap((ciphers) =>
combineLatest([
this.organizationService.organizations$,
this.collectionService.decryptedCollections$,
]).pipe(
combineLatest([this.organizations$, this.collectionService.decryptedCollections$]).pipe(
map(([organizations, collections]) => {
const orgMap = Object.fromEntries(organizations.map((org) => [org.id, org]));
const collectionMap = Object.fromEntries(collections.map((col) => [col.id, col]));
Expand Down Expand Up @@ -235,7 +236,7 @@ export class VaultPopupItemsService {
/** Observable that indicates when the user should see the deactivated org state */
showDeactivatedOrg$: Observable<boolean> = combineLatest([
this.vaultPopupListFiltersService.filters$.pipe(distinctUntilKeyChanged("organization")),
this.organizationService.organizations$,
this.organizations$,
]).pipe(
map(([filters, orgs]) => {
if (!filters.organization || filters.organization.id === MY_VAULT_ID) {
Expand All @@ -259,11 +260,12 @@ export class VaultPopupItemsService {
private cipherService: CipherService,
private vaultSettingsService: VaultSettingsService,
private vaultPopupListFiltersService: VaultPopupListFiltersService,
private organizationService: OrganizationService,
private organizationService: vNextOrganizationService,
private searchService: SearchService,
private collectionService: CollectionService,
private vaultPopupAutofillService: VaultPopupAutofillService,
private syncService: SyncService,
private accountService: AccountService,
) {}

applyFilter(newSearchText: string) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,17 @@ import { FormBuilder } from "@angular/forms";
import { BehaviorSubject, skipWhile } from "rxjs";

import { CollectionService, Collection, CollectionView } from "@bitwarden/admin-console/common";
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
import { vNextOrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/vnext.organization.service.abstraction";
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
import { PolicyType } from "@bitwarden/common/admin-console/enums";
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { ProductTierType } from "@bitwarden/common/billing/enums";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { Utils } from "@bitwarden/common/platform/misc/utils";
import { StateProvider } from "@bitwarden/common/platform/state";
import { mockAccountServiceWith } from "@bitwarden/common/spec";
import { UserId } from "@bitwarden/common/types/guid";
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
import { CipherType } from "@bitwarden/common/vault/enums";
Expand All @@ -20,7 +24,9 @@ import { MY_VAULT_ID, VaultPopupListFiltersService } from "./vault-popup-list-fi

describe("VaultPopupListFiltersService", () => {
let service: VaultPopupListFiltersService;
const memberOrganizations$ = new BehaviorSubject<Organization[]>([]);
const _memberOrganizations$ = new BehaviorSubject<Organization[]>([]);
const memberOrganizations$ = (userId: UserId) => _memberOrganizations$;
const organizations$ = new BehaviorSubject<Organization[]>([]);
const folderViews$ = new BehaviorSubject([]);
const cipherViews$ = new BehaviorSubject({});
const decryptedCollections$ = new BehaviorSubject<CollectionView[]>([]);
Expand All @@ -41,7 +47,8 @@ describe("VaultPopupListFiltersService", () => {

const organizationService = {
memberOrganizations$,
} as unknown as OrganizationService;
organizations$,
} as unknown as vNextOrganizationService;

const i18nService = {
t: (key: string) => key,
Expand All @@ -51,11 +58,14 @@ describe("VaultPopupListFiltersService", () => {
policyAppliesToActiveUser$: jest.fn(() => policyAppliesToActiveUser$),
};

const userId = Utils.newGuid() as UserId;
const accountService = mockAccountServiceWith(userId);

const state$ = new BehaviorSubject<boolean>(false);
const update = jest.fn().mockResolvedValue(undefined);

beforeEach(() => {
memberOrganizations$.next([]);
_memberOrganizations$.next([]);
decryptedCollections$.next([]);
policyAppliesToActiveUser$.next(false);
policyService.policyAppliesToActiveUser$.mockClear();
Expand All @@ -72,7 +82,7 @@ describe("VaultPopupListFiltersService", () => {
useValue: cipherService,
},
{
provide: OrganizationService,
provide: vNextOrganizationService,
useValue: organizationService,
},
{
Expand All @@ -92,6 +102,10 @@ describe("VaultPopupListFiltersService", () => {
useValue: { getGlobal: () => ({ state$, update }) },
},
{ provide: FormBuilder, useClass: FormBuilder },
{
provide: AccountService,
useValue: accountService,
},
],
});

Expand Down Expand Up @@ -126,7 +140,7 @@ describe("VaultPopupListFiltersService", () => {

describe("organizations$", () => {
it('does not add "myVault" to the list of organizations when there are no organizations', (done) => {
memberOrganizations$.next([]);
_memberOrganizations$.next([]);

service.organizations$.subscribe((organizations) => {
expect(organizations.map((o) => o.label)).toEqual([]);
Expand All @@ -136,7 +150,7 @@ describe("VaultPopupListFiltersService", () => {

it('adds "myVault" to the list of organizations when there are other organizations', (done) => {
const orgs = [{ name: "bobby's org", id: "1234-3323-23223" }] as Organization[];
memberOrganizations$.next(orgs);
_memberOrganizations$.next(orgs);

service.organizations$.subscribe((organizations) => {
expect(organizations.map((o) => o.label)).toEqual(["myVault", "bobby's org"]);
Expand All @@ -149,7 +163,7 @@ describe("VaultPopupListFiltersService", () => {
{ name: "bobby's org", id: "1234-3323-23223" },
{ name: "alice's org", id: "2223-4343-99888" },
] as Organization[];
memberOrganizations$.next(orgs);
_memberOrganizations$.next(orgs);

service.organizations$.subscribe((organizations) => {
expect(organizations.map((o) => o.label)).toEqual([
Expand All @@ -170,7 +184,7 @@ describe("VaultPopupListFiltersService", () => {

it("returns an empty array when the policy applies and there is a single organization", (done) => {
policyAppliesToActiveUser$.next(true);
memberOrganizations$.next([
_memberOrganizations$.next([
{ name: "bobby's org", id: "1234-3323-23223" },
] as Organization[]);

Expand All @@ -187,7 +201,7 @@ describe("VaultPopupListFiltersService", () => {
{ name: "alice's org", id: "2223-4343-99888" },
] as Organization[];

memberOrganizations$.next(orgs);
_memberOrganizations$.next(orgs);

service.organizations$.subscribe((organizations) => {
expect(organizations.map((o) => o.label)).toEqual([
Expand All @@ -207,7 +221,7 @@ describe("VaultPopupListFiltersService", () => {
{ name: "catherine's org", id: "77733-4343-99888" },
] as Organization[];

memberOrganizations$.next(orgs);
_memberOrganizations$.next(orgs);

service.organizations$.subscribe((organizations) => {
expect(organizations.map((o) => o.label)).toEqual([
Expand All @@ -231,7 +245,7 @@ describe("VaultPopupListFiltersService", () => {
},
] as Organization[];

memberOrganizations$.next(orgs);
_memberOrganizations$.next(orgs);

service.organizations$.subscribe((organizations) => {
expect(organizations.map((o) => o.icon)).toEqual(["bwi-user", "bwi-family"]);
Expand All @@ -249,7 +263,7 @@ describe("VaultPopupListFiltersService", () => {
},
] as Organization[];

memberOrganizations$.next(orgs);
_memberOrganizations$.next(orgs);

service.organizations$.subscribe((organizations) => {
expect(organizations.map((o) => o.icon)).toEqual(["bwi-user", "bwi-family"]);
Expand All @@ -267,7 +281,7 @@ describe("VaultPopupListFiltersService", () => {
},
] as Organization[];

memberOrganizations$.next(orgs);
_memberOrganizations$.next(orgs);

service.organizations$.subscribe((organizations) => {
expect(organizations.map((o) => o.icon)).toEqual([
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,11 @@ import {

import { CollectionService, Collection, CollectionView } from "@bitwarden/admin-console/common";
import { DynamicTreeNode } from "@bitwarden/angular/vault/vault-filter/models/dynamic-tree-node.model";
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
import { vNextOrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/vnext.organization.service.abstraction";
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
import { PolicyType } from "@bitwarden/common/admin-console/enums";
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { ProductTierType } from "@bitwarden/common/billing/enums";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { Utils } from "@bitwarden/common/platform/misc/utils";
Expand Down Expand Up @@ -105,12 +106,13 @@ export class VaultPopupListFiltersService {
constructor(
private folderService: FolderService,
private cipherService: CipherService,
private organizationService: OrganizationService,
private organizationService: vNextOrganizationService,
private i18nService: I18nService,
private collectionService: CollectionService,
private formBuilder: FormBuilder,
private policyService: PolicyService,
private stateProvider: StateProvider,
private accountServcie: AccountService,
) {
this.filterForm.controls.organization.valueChanges
.pipe(takeUntilDestroyed())
Expand Down Expand Up @@ -204,7 +206,9 @@ export class VaultPopupListFiltersService {
* Organization array structured to be directly passed to `ChipSelectComponent`
*/
organizations$: Observable<ChipSelectOption<Organization>[]> = combineLatest([
this.organizationService.memberOrganizations$,
this.accountServcie.activeAccount$.pipe(
switchMap((account) => this.organizationService.memberOrganizations$(account?.id)),
),
this.policyService.policyAppliesToActiveUser$(PolicyType.PersonalOwnership),
]).pipe(
map(([orgs, personalOwnershipApplies]): [Organization[], boolean] => [
Expand Down
3 changes: 2 additions & 1 deletion apps/cli/src/commands/get.command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { SearchService } from "@bitwarden/common/abstractions/search.service";
import { vNextOrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/vnext.organization.service.abstraction";
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { getUserId } from "@bitwarden/common/auth/services/account.service";
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
import { EventType } from "@bitwarden/common/enums";
import { CardExport } from "@bitwarden/common/models/export/card.export";
Expand Down Expand Up @@ -478,7 +479,7 @@ export class GetCommand extends DownloadCommand {

private async getOrganization(id: string) {
let org: Organization = null;
const userId = await firstValueFrom(this.accountService.activeAccount$.pipe(map((a) => a?.id)));
const userId = await firstValueFrom(getUserId(this.accountService.activeAccount$));
if (!userId) {
return Response.badRequest("No user found.");
}
Expand Down
Loading

0 comments on commit 6a59af3

Please sign in to comment.