mirror of
https://github.com/bitwarden/browser.git
synced 2025-02-06 23:51:28 +01:00
[PM-15506] Implement vNextOrganizationService (#12839)
* [PM-15506] Wire up vNextOrganizationService for libs/common and libs/angular (#12683) * Wire up vNextOrganizationService in PolicyService * Wire vNextOrganizationService in SyncService * wire vNextOrganizationService for EventCollectionService * wire vNextOrganizationService for KeyConnectorService * wire up vNextOrganizationService for CipherAuthorizationService * Wire up vNextOrganizationService in PolicyService * Wire vNextOrganizationService in SyncService * wire vNextOrganizationService for EventCollectionService * wire vNextOrganizationService for KeyConnectorService * wire up vNextOrganizationService for CipherAuthorizationService * wire vNextOrganizationService for share.component * wire vNextOrganizationService for collections.component * wire vNextOrganizationServcie for add-account-credit-dialog * wire vNextOrganizationService for vault-filter.service * fix browser errors for vNextOrganizationService implementation in libs * fix desktop errors for vNextOrganizationService implementation for libs * fix linter errors * fix CLI errors on vNextOrganizationServcie implementations for libs * [PM-15506] Wire up vNextOrganizationService for web client (#12810) PR to a feature branch, no need to review until this goes to main. * implement vNextOrganization service for browser client (#12844) PR to feature branch, no need for review yet. * wire vNextOrganizationService for licence and some web router guards * wire vNextOrganizationService in tests * remove vNext notation for OrganizationService and related * Merge branch 'main' into ac/pm-15506-vNextOrganizationService * fix tsstrict error * fix test, fix ts strict error
This commit is contained in:
parent
ba4d762dc1
commit
a949f793ed
@ -25,7 +25,7 @@ import { InternalOrganizationServiceAbstraction } from "@bitwarden/common/admin-
|
||||
import { PolicyApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/policy/policy-api.service.abstraction";
|
||||
import { InternalPolicyService as InternalPolicyServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||
import { ProviderService as ProviderServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/provider.service";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/services/organization/organization.service";
|
||||
import { DefaultOrganizationService } from "@bitwarden/common/admin-console/services/organization/default-organization.service";
|
||||
import { PolicyApiService } from "@bitwarden/common/admin-console/services/policy/policy-api.service";
|
||||
import { PolicyService } from "@bitwarden/common/admin-console/services/policy/policy.service";
|
||||
import { ProviderService } from "@bitwarden/common/admin-console/services/provider.service";
|
||||
@ -669,7 +669,7 @@ export default class MainBackground {
|
||||
this.appIdService = new AppIdService(this.storageService, this.logService);
|
||||
|
||||
this.userDecryptionOptionsService = new UserDecryptionOptionsService(this.stateProvider);
|
||||
this.organizationService = new OrganizationService(this.stateProvider);
|
||||
this.organizationService = new DefaultOrganizationService(this.stateProvider);
|
||||
this.policyService = new PolicyService(this.stateProvider, this.organizationService);
|
||||
|
||||
this.vaultTimeoutSettingsService = new VaultTimeoutSettingsService(
|
||||
@ -1248,6 +1248,7 @@ export default class MainBackground {
|
||||
this.cipherAuthorizationService = new DefaultCipherAuthorizationService(
|
||||
this.collectionService,
|
||||
this.organizationService,
|
||||
this.accountService,
|
||||
);
|
||||
|
||||
this.inlineMenuFieldQualificationService = new InlineMenuFieldQualificationService();
|
||||
|
@ -31,8 +31,8 @@ import { LockService, LoginEmailService, PinServiceAbstraction } from "@bitwarde
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { EventCollectionService as EventCollectionServiceAbstraction } from "@bitwarden/common/abstractions/event/event-collection.service";
|
||||
import { VaultTimeoutService } from "@bitwarden/common/abstractions/vault-timeout/vault-timeout.service";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||
import { DefaultOrganizationService } from "@bitwarden/common/admin-console/services/organization/default-organization.service";
|
||||
import {
|
||||
AccountService,
|
||||
AccountService as AccountServiceAbstraction,
|
||||
@ -369,7 +369,7 @@ const safeProviders: SafeProvider[] = [
|
||||
provide: VaultFilterService,
|
||||
useClass: VaultFilterService,
|
||||
deps: [
|
||||
OrganizationService,
|
||||
DefaultOrganizationService,
|
||||
FolderServiceAbstraction,
|
||||
CipherService,
|
||||
CollectionService,
|
||||
|
@ -6,6 +6,10 @@ import { OrganizationService } from "@bitwarden/common/admin-console/abstraction
|
||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
import { Policy } from "@bitwarden/common/admin-console/models/domain/policy";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { FakeAccountService, mockAccountServiceWith } from "@bitwarden/common/spec";
|
||||
import { UserId } from "@bitwarden/common/types/guid";
|
||||
|
||||
import { FamiliesPolicyService } from "./families-policy.service"; // Adjust the import as necessary
|
||||
|
||||
@ -13,16 +17,20 @@ describe("FamiliesPolicyService", () => {
|
||||
let service: FamiliesPolicyService;
|
||||
let organizationService: MockProxy<OrganizationService>;
|
||||
let policyService: MockProxy<PolicyService>;
|
||||
let accountService: FakeAccountService;
|
||||
const userId = Utils.newGuid() as UserId;
|
||||
|
||||
beforeEach(() => {
|
||||
organizationService = mock<OrganizationService>();
|
||||
policyService = mock<PolicyService>();
|
||||
accountService = mockAccountServiceWith(userId);
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
providers: [
|
||||
FamiliesPolicyService,
|
||||
{ provide: OrganizationService, useValue: organizationService },
|
||||
{ provide: PolicyService, useValue: policyService },
|
||||
{ provide: AccountService, useValue: accountService },
|
||||
],
|
||||
});
|
||||
|
||||
@ -40,7 +48,7 @@ describe("FamiliesPolicyService", () => {
|
||||
jest.spyOn(service, "hasSingleEnterpriseOrg$").mockReturnValue(of(true));
|
||||
|
||||
const organizations = [{ id: "org1", canManageSponsorships: true }] as Organization[];
|
||||
organizationService.getAll$.mockReturnValue(of(organizations));
|
||||
organizationService.organizations$.mockReturnValue(of(organizations));
|
||||
|
||||
const policies = [{ organizationId: "org1", enabled: true }] as Policy[];
|
||||
policyService.getAll$.mockReturnValue(of(policies));
|
||||
@ -53,7 +61,7 @@ describe("FamiliesPolicyService", () => {
|
||||
jest.spyOn(service, "hasSingleEnterpriseOrg$").mockReturnValue(of(true));
|
||||
|
||||
const organizations = [{ id: "org1", canManageSponsorships: true }] as Organization[];
|
||||
organizationService.getAll$.mockReturnValue(of(organizations));
|
||||
organizationService.organizations$.mockReturnValue(of(organizations));
|
||||
|
||||
const policies = [{ organizationId: "org1", enabled: false }] as Policy[];
|
||||
policyService.getAll$.mockReturnValue(of(policies));
|
||||
@ -64,7 +72,7 @@ describe("FamiliesPolicyService", () => {
|
||||
|
||||
it("should return true when there is exactly one enterprise organization that can manage sponsorships", async () => {
|
||||
const organizations = [{ id: "org1", canManageSponsorships: true }] as Organization[];
|
||||
organizationService.getAll$.mockReturnValue(of(organizations));
|
||||
organizationService.organizations$.mockReturnValue(of(organizations));
|
||||
|
||||
const result = await firstValueFrom(service.hasSingleEnterpriseOrg$());
|
||||
expect(result).toBe(true);
|
||||
@ -75,7 +83,7 @@ describe("FamiliesPolicyService", () => {
|
||||
{ id: "org1", canManageSponsorships: true },
|
||||
{ id: "org2", canManageSponsorships: true },
|
||||
] as Organization[];
|
||||
organizationService.getAll$.mockReturnValue(of(organizations));
|
||||
organizationService.organizations$.mockReturnValue(of(organizations));
|
||||
|
||||
const result = await firstValueFrom(service.hasSingleEnterpriseOrg$());
|
||||
expect(result).toBe(false);
|
||||
|
@ -4,27 +4,34 @@ import { map, Observable, of, switchMap } from "rxjs";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||
import { PolicyType } from "@bitwarden/common/admin-console/enums";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
||||
|
||||
@Injectable({ providedIn: "root" })
|
||||
export class FamiliesPolicyService {
|
||||
constructor(
|
||||
private policyService: PolicyService,
|
||||
private organizationService: OrganizationService,
|
||||
private accountService: AccountService,
|
||||
) {}
|
||||
|
||||
hasSingleEnterpriseOrg$(): Observable<boolean> {
|
||||
// Retrieve all organizations the user is part of
|
||||
return this.organizationService.getAll$().pipe(
|
||||
map((organizations) => {
|
||||
// Filter to only those organizations that can manage sponsorships
|
||||
const sponsorshipOrgs = organizations.filter((org) => org.canManageSponsorships);
|
||||
return getUserId(this.accountService.activeAccount$).pipe(
|
||||
switchMap((userId) =>
|
||||
this.organizationService.organizations$(userId).pipe(
|
||||
map((organizations) => {
|
||||
// Filter to only those organizations that can manage sponsorships
|
||||
const sponsorshipOrgs = organizations.filter((org) => org.canManageSponsorships);
|
||||
|
||||
// Check if there is exactly one organization that can manage sponsorships.
|
||||
// This is important because users that are part of multiple organizations
|
||||
// may always access free bitwarden family menu. We want to restrict access
|
||||
// to the policy only when there is a single enterprise organization and the free family policy is turn.
|
||||
return sponsorshipOrgs.length === 1;
|
||||
}),
|
||||
// Check if there is exactly one organization that can manage sponsorships.
|
||||
// This is important because users that are part of multiple organizations
|
||||
// may always access free bitwarden family menu. We want to restrict access
|
||||
// to the policy only when there is a single enterprise organization and the free family policy is turn.
|
||||
return sponsorshipOrgs.length === 1;
|
||||
}),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@ -34,18 +41,22 @@ export class FamiliesPolicyService {
|
||||
if (!hasSingleEnterpriseOrg) {
|
||||
return of(false);
|
||||
}
|
||||
return this.organizationService.getAll$().pipe(
|
||||
map((organizations) => organizations.find((org) => org.canManageSponsorships)?.id),
|
||||
switchMap((enterpriseOrgId) =>
|
||||
this.policyService
|
||||
.getAll$(PolicyType.FreeFamiliesSponsorshipPolicy)
|
||||
.pipe(
|
||||
map(
|
||||
(policies) =>
|
||||
policies.find((policy) => policy.organizationId === enterpriseOrgId)?.enabled ??
|
||||
false,
|
||||
),
|
||||
return getUserId(this.accountService.activeAccount$).pipe(
|
||||
switchMap((userId) =>
|
||||
this.organizationService.organizations$(userId).pipe(
|
||||
map((organizations) => organizations.find((org) => org.canManageSponsorships)?.id),
|
||||
switchMap((enterpriseOrgId) =>
|
||||
this.policyService
|
||||
.getAll$(PolicyType.FreeFamiliesSponsorshipPolicy)
|
||||
.pipe(
|
||||
map(
|
||||
(policies) =>
|
||||
policies.find((policy) => policy.organizationId === enterpriseOrgId)
|
||||
?.enabled ?? false,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}),
|
||||
|
@ -6,6 +6,7 @@ import { Observable, firstValueFrom, of, switchMap } from "rxjs";
|
||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
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 { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
||||
import { DialogService, ItemModule } from "@bitwarden/components";
|
||||
@ -43,6 +44,9 @@ export class MoreFromBitwardenPageV2Component {
|
||||
private familiesPolicyService: FamiliesPolicyService,
|
||||
private accountService: AccountService,
|
||||
) {
|
||||
this.familySponsorshipAvailable$ = getUserId(this.accountService.activeAccount$).pipe(
|
||||
switchMap((userId) => this.organizationService.familySponsorshipAvailable$(userId)),
|
||||
);
|
||||
this.canAccessPremium$ = this.accountService.activeAccount$.pipe(
|
||||
switchMap((account) =>
|
||||
account
|
||||
@ -50,7 +54,6 @@ export class MoreFromBitwardenPageV2Component {
|
||||
: of(false),
|
||||
),
|
||||
);
|
||||
this.familySponsorshipAvailable$ = this.organizationService.familySponsorshipAvailable$;
|
||||
this.hasSingleEnterpriseOrg$ = this.familiesPolicyService.hasSingleEnterpriseOrg$();
|
||||
this.isFreeFamilyPolicyEnabled$ = this.familiesPolicyService.isFreeFamilyPolicyEnabled$();
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ describe("OpenAttachmentsComponent", () => {
|
||||
} as Organization;
|
||||
|
||||
const getCipher = jest.fn().mockResolvedValue(cipherDomain);
|
||||
const getOrganization = jest.fn().mockResolvedValue(org);
|
||||
const organizations$ = jest.fn().mockReturnValue(of([org]));
|
||||
const showFilePopoutMessage = jest.fn().mockReturnValue(false);
|
||||
|
||||
const mockUserId = Utils.newGuid() as UserId;
|
||||
@ -67,7 +67,7 @@ describe("OpenAttachmentsComponent", () => {
|
||||
openCurrentPagePopout.mockClear();
|
||||
getCipher.mockClear();
|
||||
showToast.mockClear();
|
||||
getOrganization.mockClear();
|
||||
organizations$.mockClear();
|
||||
showFilePopoutMessage.mockClear();
|
||||
hasPremiumFromAnySource$.next(true);
|
||||
|
||||
@ -89,7 +89,7 @@ describe("OpenAttachmentsComponent", () => {
|
||||
},
|
||||
{
|
||||
provide: OrganizationService,
|
||||
useValue: { get: getOrganization },
|
||||
useValue: { organizations$ },
|
||||
},
|
||||
{
|
||||
provide: FilePopoutUtilsService,
|
||||
@ -148,11 +148,11 @@ describe("OpenAttachmentsComponent", () => {
|
||||
|
||||
describe("Free Orgs", () => {
|
||||
beforeEach(() => {
|
||||
component.cipherIsAPartOfFreeOrg = undefined;
|
||||
component.cipherIsAPartOfFreeOrg = false;
|
||||
});
|
||||
|
||||
it("sets `cipherIsAPartOfFreeOrg` to false when the cipher is not a part of an organization", async () => {
|
||||
cipherView.organizationId = null;
|
||||
cipherView.organizationId = "";
|
||||
|
||||
await component.ngOnInit();
|
||||
|
||||
@ -162,6 +162,7 @@ describe("OpenAttachmentsComponent", () => {
|
||||
it("sets `cipherIsAPartOfFreeOrg` to true when the cipher is a part of a free organization", async () => {
|
||||
cipherView.organizationId = "888-333-333";
|
||||
org.productTierType = ProductTierType.Free;
|
||||
org.id = cipherView.organizationId;
|
||||
|
||||
await component.ngOnInit();
|
||||
|
||||
@ -171,6 +172,7 @@ describe("OpenAttachmentsComponent", () => {
|
||||
it("sets `cipherIsAPartOfFreeOrg` to false when the organization is not free", async () => {
|
||||
cipherView.organizationId = "888-333-333";
|
||||
org.productTierType = ProductTierType.Families;
|
||||
org.id = cipherView.organizationId;
|
||||
|
||||
await component.ngOnInit();
|
||||
|
||||
|
@ -7,8 +7,12 @@ import { Router } from "@angular/router";
|
||||
import { firstValueFrom, map, switchMap } from "rxjs";
|
||||
|
||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import {
|
||||
getOrganizationById,
|
||||
OrganizationService,
|
||||
} from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
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";
|
||||
import { ProductTierType } from "@bitwarden/common/billing/enums";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
@ -86,7 +90,12 @@ export class OpenAttachmentsComponent implements OnInit {
|
||||
return;
|
||||
}
|
||||
|
||||
const org = await this.organizationService.get(cipher.organizationId);
|
||||
const userId = await firstValueFrom(getUserId(this.accountService.activeAccount$));
|
||||
const org = await firstValueFrom(
|
||||
this.organizationService
|
||||
.organizations$(userId)
|
||||
.pipe(getOrganizationById(cipher.organizationId)),
|
||||
);
|
||||
|
||||
this.cipherIsAPartOfFreeOrg = org.productTierType === ProductTierType.Free;
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ import { filter } from "rxjs/operators";
|
||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { CipherRepromptType, CipherType } from "@bitwarden/common/vault/enums";
|
||||
@ -88,7 +89,8 @@ export class ItemMoreOptionsComponent implements OnInit {
|
||||
) {}
|
||||
|
||||
async ngOnInit(): Promise<void> {
|
||||
this.hasOrganizations = await this.organizationService.hasOrganizations();
|
||||
const userId = await firstValueFrom(getUserId(this.accountService.activeAccount$));
|
||||
this.hasOrganizations = await firstValueFrom(this.organizationService.hasOrganizations(userId));
|
||||
}
|
||||
|
||||
get canEdit() {
|
||||
|
@ -6,10 +6,12 @@ import { CollectionService, CollectionView } from "@bitwarden/admin-console/comm
|
||||
import { SearchService } from "@bitwarden/common/abstractions/search.service";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/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";
|
||||
@ -43,6 +45,8 @@ describe("VaultPopupItemsService", () => {
|
||||
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);
|
||||
@ -99,7 +103,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());
|
||||
@ -111,6 +115,7 @@ describe("VaultPopupItemsService", () => {
|
||||
{ provide: VaultSettingsService, useValue: vaultSettingsServiceMock },
|
||||
{ provide: SearchService, useValue: searchService },
|
||||
{ provide: OrganizationService, useValue: organizationServiceMock },
|
||||
{ provide: AccountService, useValue: accountServiceMock },
|
||||
{ provide: VaultPopupListFiltersService, useValue: vaultPopupListFiltersServiceMock },
|
||||
{ provide: CollectionService, useValue: collectionService },
|
||||
{ provide: VaultPopupAutofillService, useValue: vaultAutofillServiceMock },
|
||||
|
@ -24,6 +24,7 @@ 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 { 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";
|
||||
@ -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.
|
||||
@ -97,10 +101,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]));
|
||||
@ -232,7 +233,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) {
|
||||
@ -249,10 +250,7 @@ export class VaultPopupItemsService {
|
||||
*/
|
||||
deletedCiphers$: 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]));
|
||||
@ -281,6 +279,7 @@ export class VaultPopupItemsService {
|
||||
private collectionService: CollectionService,
|
||||
private vaultPopupAutofillService: VaultPopupAutofillService,
|
||||
private syncService: SyncService,
|
||||
private accountService: AccountService,
|
||||
) {}
|
||||
|
||||
applyFilter(newSearchText: string) {
|
||||
|
@ -23,7 +23,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[]>([]);
|
||||
@ -44,6 +46,7 @@ describe("VaultPopupListFiltersService", () => {
|
||||
|
||||
const organizationService = {
|
||||
memberOrganizations$,
|
||||
organizations$,
|
||||
} as unknown as OrganizationService;
|
||||
|
||||
const i18nService = {
|
||||
@ -58,7 +61,7 @@ describe("VaultPopupListFiltersService", () => {
|
||||
const update = jest.fn().mockResolvedValue(undefined);
|
||||
|
||||
beforeEach(() => {
|
||||
memberOrganizations$.next([]);
|
||||
_memberOrganizations$.next([]);
|
||||
decryptedCollections$.next([]);
|
||||
policyAppliesToActiveUser$.next(false);
|
||||
policyService.policyAppliesToActiveUser$.mockClear();
|
||||
@ -135,7 +138,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([]);
|
||||
@ -145,7 +148,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"]);
|
||||
@ -158,7 +161,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([
|
||||
@ -179,7 +182,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[]);
|
||||
|
||||
@ -196,7 +199,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([
|
||||
@ -216,7 +219,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([
|
||||
@ -240,7 +243,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"]);
|
||||
@ -258,7 +261,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"]);
|
||||
@ -276,7 +279,7 @@ describe("VaultPopupListFiltersService", () => {
|
||||
},
|
||||
] as Organization[];
|
||||
|
||||
memberOrganizations$.next(orgs);
|
||||
_memberOrganizations$.next(orgs);
|
||||
|
||||
service.organizations$.subscribe((organizations) => {
|
||||
expect(organizations.map((o) => o.icon)).toEqual([
|
||||
|
@ -208,7 +208,9 @@ export class VaultPopupListFiltersService {
|
||||
* Organization array structured to be directly passed to `ChipSelectComponent`
|
||||
*/
|
||||
organizations$: Observable<ChipSelectOption<Organization>[]> = combineLatest([
|
||||
this.organizationService.memberOrganizations$,
|
||||
this.accountService.activeAccount$.pipe(
|
||||
switchMap((account) => this.organizationService.memberOrganizations$(account?.id)),
|
||||
),
|
||||
this.policyService.policyAppliesToActiveUser$(PolicyType.PersonalOwnership),
|
||||
]).pipe(
|
||||
map(([orgs, personalOwnershipApplies]): [Organization[], boolean] => [
|
||||
|
@ -38,7 +38,7 @@ export class VaultFilterService extends BaseVaultFilterService {
|
||||
this.vaultFilter.myVaultOnly = false;
|
||||
this.vaultFilter.selectedOrganizationId = null;
|
||||
|
||||
this.accountService.activeAccount$.subscribe((account) => {
|
||||
accountService.activeAccount$.subscribe((account) => {
|
||||
this.setVaultFilter(this.allVaults);
|
||||
});
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ import { SearchService } from "@bitwarden/common/abstractions/search.service";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/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";
|
||||
@ -479,10 +480,18 @@ export class GetCommand extends DownloadCommand {
|
||||
|
||||
private async getOrganization(id: string) {
|
||||
let org: Organization = null;
|
||||
const userId = await firstValueFrom(getUserId(this.accountService.activeAccount$));
|
||||
if (!userId) {
|
||||
return Response.badRequest("No user found.");
|
||||
}
|
||||
if (Utils.isGuid(id)) {
|
||||
org = await this.organizationService.getFromState(id);
|
||||
org = await firstValueFrom(
|
||||
this.organizationService
|
||||
.organizations$(userId)
|
||||
.pipe(map((organizations) => organizations.find((o) => o.id === id))),
|
||||
);
|
||||
} else if (id.trim() !== "") {
|
||||
let orgs = await firstValueFrom(this.organizationService.organizations$);
|
||||
let orgs = await firstValueFrom(this.organizationService.organizations$(userId));
|
||||
orgs = CliUtils.searchOrganizations(orgs, id);
|
||||
if (orgs.length > 1) {
|
||||
return Response.multipleResults(orgs.map((c) => c.id));
|
||||
|
@ -13,6 +13,7 @@ import { EventCollectionService } from "@bitwarden/common/abstractions/event/eve
|
||||
import { SearchService } from "@bitwarden/common/abstractions/search.service";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
||||
import { EventType } from "@bitwarden/common/enums";
|
||||
import { ListResponse as ApiListResponse } from "@bitwarden/common/models/response/list.response";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
@ -177,7 +178,15 @@ export class ListCommand {
|
||||
if (!Utils.isGuid(options.organizationId)) {
|
||||
return Response.badRequest("`" + options.organizationId + "` is not a GUID.");
|
||||
}
|
||||
const organization = await this.organizationService.getFromState(options.organizationId);
|
||||
const userId = await firstValueFrom(getUserId(this.accountService.activeAccount$));
|
||||
if (!userId) {
|
||||
return Response.badRequest("No user found.");
|
||||
}
|
||||
const organization = await firstValueFrom(
|
||||
this.organizationService
|
||||
.organizations$(userId)
|
||||
.pipe(map((organizatons) => organizatons.find((o) => o.id == options.organizationId))),
|
||||
);
|
||||
if (organization == null) {
|
||||
return Response.error("Organization not found.");
|
||||
}
|
||||
@ -210,7 +219,16 @@ export class ListCommand {
|
||||
if (!Utils.isGuid(options.organizationId)) {
|
||||
return Response.badRequest("`" + options.organizationId + "` is not a GUID.");
|
||||
}
|
||||
const organization = await this.organizationService.getFromState(options.organizationId);
|
||||
const userId = await firstValueFrom(getUserId(this.accountService.activeAccount$));
|
||||
|
||||
if (!userId) {
|
||||
return Response.badRequest("No user found.");
|
||||
}
|
||||
const organization = await firstValueFrom(
|
||||
this.organizationService
|
||||
.organizations$(userId)
|
||||
.pipe(map((organizatons) => organizatons.find((o) => o.id == options.organizationId))),
|
||||
);
|
||||
if (organization == null) {
|
||||
return Response.error("Organization not found.");
|
||||
}
|
||||
@ -236,7 +254,12 @@ export class ListCommand {
|
||||
}
|
||||
|
||||
private async listOrganizations(options: Options) {
|
||||
let organizations = await firstValueFrom(this.organizationService.memberOrganizations$);
|
||||
const userId = await firstValueFrom(getUserId(this.accountService.activeAccount$));
|
||||
|
||||
if (!userId) {
|
||||
return Response.badRequest("No user found.");
|
||||
}
|
||||
let organizations = await firstValueFrom(this.organizationService.memberOrganizations$(userId));
|
||||
|
||||
if (options.search != null && options.search.trim() !== "") {
|
||||
organizations = CliUtils.searchOrganizations(organizations, options.search);
|
||||
|
@ -4,7 +4,7 @@ import * as fs from "fs";
|
||||
import * as path from "path";
|
||||
|
||||
import * as jsdom from "jsdom";
|
||||
import { firstValueFrom, map } from "rxjs";
|
||||
import { firstValueFrom } from "rxjs";
|
||||
|
||||
import {
|
||||
OrganizationUserApiService,
|
||||
@ -25,8 +25,8 @@ import { EventUploadService as EventUploadServiceAbstraction } from "@bitwarden/
|
||||
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction";
|
||||
import { PolicyApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/policy/policy-api.service.abstraction";
|
||||
import { ProviderApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/provider/provider-api.service.abstraction";
|
||||
import { DefaultOrganizationService } from "@bitwarden/common/admin-console/services/organization/default-organization.service";
|
||||
import { OrganizationApiService } from "@bitwarden/common/admin-console/services/organization/organization-api.service";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/services/organization/organization.service";
|
||||
import { PolicyApiService } from "@bitwarden/common/admin-console/services/policy/policy-api.service";
|
||||
import { PolicyService } from "@bitwarden/common/admin-console/services/policy/policy.service";
|
||||
import { ProviderApiService } from "@bitwarden/common/admin-console/services/provider/provider-api.service";
|
||||
@ -36,7 +36,10 @@ import { AvatarService as AvatarServiceAbstraction } from "@bitwarden/common/aut
|
||||
import { DeviceTrustServiceAbstraction } from "@bitwarden/common/auth/abstractions/device-trust.service.abstraction";
|
||||
import { DevicesApiServiceAbstraction } from "@bitwarden/common/auth/abstractions/devices-api.service.abstraction";
|
||||
import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction";
|
||||
import { AccountServiceImplementation } from "@bitwarden/common/auth/services/account.service";
|
||||
import {
|
||||
AccountServiceImplementation,
|
||||
getUserId,
|
||||
} from "@bitwarden/common/auth/services/account.service";
|
||||
import { AuthService } from "@bitwarden/common/auth/services/auth.service";
|
||||
import { AvatarService } from "@bitwarden/common/auth/services/avatar.service";
|
||||
import { DeviceTrustService } from "@bitwarden/common/auth/services/device-trust.service.implementation";
|
||||
@ -238,7 +241,8 @@ export class ServiceContainer {
|
||||
stateService: StateService;
|
||||
autofillSettingsService: AutofillSettingsServiceAbstraction;
|
||||
domainSettingsService: DomainSettingsService;
|
||||
organizationService: OrganizationService;
|
||||
organizationService: DefaultOrganizationService;
|
||||
DefaultOrganizationService: DefaultOrganizationService;
|
||||
providerService: ProviderService;
|
||||
twoFactorService: TwoFactorService;
|
||||
folderApiService: FolderApiService;
|
||||
@ -450,7 +454,7 @@ export class ServiceContainer {
|
||||
this.biometricStateService = new DefaultBiometricStateService(this.stateProvider);
|
||||
this.userDecryptionOptionsService = new UserDecryptionOptionsService(this.stateProvider);
|
||||
|
||||
this.organizationService = new OrganizationService(this.stateProvider);
|
||||
this.organizationService = new DefaultOrganizationService(this.stateProvider);
|
||||
this.policyService = new PolicyService(this.stateProvider, this.organizationService);
|
||||
|
||||
this.vaultTimeoutSettingsService = new VaultTimeoutSettingsService(
|
||||
@ -824,6 +828,7 @@ export class ServiceContainer {
|
||||
this.cipherAuthorizationService = new DefaultCipherAuthorizationService(
|
||||
this.collectionService,
|
||||
this.organizationService,
|
||||
this.accountService,
|
||||
);
|
||||
}
|
||||
|
||||
@ -831,7 +836,7 @@ export class ServiceContainer {
|
||||
this.authService.logOut(() => {
|
||||
/* Do nothing */
|
||||
});
|
||||
const userId = await firstValueFrom(this.accountService.activeAccount$.pipe(map((a) => a?.id)));
|
||||
const userId = await firstValueFrom(getUserId(this.accountService.activeAccount$));
|
||||
await Promise.all([
|
||||
this.eventUploadService.uploadEvents(userId as UserId),
|
||||
this.keyService.clearKeys(),
|
||||
|
@ -2,8 +2,10 @@
|
||||
// @ts-strict-ignore
|
||||
import { OptionValues } from "commander";
|
||||
import * as inquirer from "inquirer";
|
||||
import { firstValueFrom, map } from "rxjs";
|
||||
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
|
||||
import { ImportServiceAbstraction, ImportType } from "@bitwarden/importer/core";
|
||||
|
||||
@ -16,12 +18,23 @@ export class ImportCommand {
|
||||
private importService: ImportServiceAbstraction,
|
||||
private organizationService: OrganizationService,
|
||||
private syncService: SyncService,
|
||||
private accountService: AccountService,
|
||||
) {}
|
||||
|
||||
async run(format: ImportType, filepath: string, options: OptionValues): Promise<Response> {
|
||||
const organizationId = options.organizationid;
|
||||
if (organizationId != null) {
|
||||
const organization = await this.organizationService.getFromState(organizationId);
|
||||
const userId = await firstValueFrom(
|
||||
this.accountService.activeAccount$.pipe(map((a) => a?.id)),
|
||||
);
|
||||
if (!userId) {
|
||||
return Response.badRequest("No user found.");
|
||||
}
|
||||
const organization = await firstValueFrom(
|
||||
this.organizationService
|
||||
.organizations$(userId)
|
||||
.pipe(map((organizations) => organizations.find((o) => o.id === organizationId))),
|
||||
);
|
||||
|
||||
if (organization == null) {
|
||||
return Response.badRequest(
|
||||
|
@ -450,6 +450,7 @@ export class VaultProgram extends BaseProgram {
|
||||
this.serviceContainer.importService,
|
||||
this.serviceContainer.organizationService,
|
||||
this.serviceContainer.syncService,
|
||||
this.serviceContainer.accountService,
|
||||
);
|
||||
const response = await command.run(format, filepath, options);
|
||||
this.processResponse(response);
|
||||
|
@ -202,7 +202,17 @@ export class CreateCommand {
|
||||
if (orgKey == null) {
|
||||
throw new Error("No encryption key for this organization.");
|
||||
}
|
||||
const organization = await this.organizationService.get(req.organizationId);
|
||||
const userId = await firstValueFrom(
|
||||
this.accountService.activeAccount$.pipe(map((a) => a?.id)),
|
||||
);
|
||||
if (!userId) {
|
||||
return Response.badRequest("No user found.");
|
||||
}
|
||||
const organization = await firstValueFrom(
|
||||
this.organizationService
|
||||
.organizations$(userId)
|
||||
.pipe(map((organizations) => organizations.find((o) => o.id === req.organizationId))),
|
||||
);
|
||||
const currentOrgUserId = organization.organizationUserId;
|
||||
|
||||
const groups =
|
||||
|
@ -32,6 +32,7 @@ import { MasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstrac
|
||||
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
||||
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
|
||||
import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason";
|
||||
import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||
import { VaultTimeoutAction } from "@bitwarden/common/enums/vault-timeout-action.enum";
|
||||
import { ProcessReloadServiceAbstraction } from "@bitwarden/common/key-management/abstractions/process-reload.service";
|
||||
@ -872,9 +873,10 @@ export class AppComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
private async deleteAccount() {
|
||||
const userId = await firstValueFrom(getUserId(this.accountService.activeAccount$));
|
||||
await firstValueFrom(
|
||||
this.configService.getFeatureFlag$(FeatureFlag.AccountDeprovisioning).pipe(
|
||||
withLatestFrom(this.organizationService.organizations$),
|
||||
withLatestFrom(this.organizationService.organizations$(userId)),
|
||||
map(async ([accountDeprovisioningEnabled, organization]) => {
|
||||
if (
|
||||
accountDeprovisioningEnabled &&
|
||||
|
@ -5,11 +5,16 @@ import { TestBed } from "@angular/core/testing";
|
||||
import { provideRouter } from "@angular/router";
|
||||
import { RouterTestingHarness } from "@angular/router/testing";
|
||||
import { MockProxy, any, mock } from "jest-mock-extended";
|
||||
import { of } from "rxjs";
|
||||
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { OrganizationUserType } 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 { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { FakeAccountService, mockAccountServiceWith } from "@bitwarden/common/spec";
|
||||
import { UserId } from "@bitwarden/common/types/guid";
|
||||
import { DialogService } from "@bitwarden/components";
|
||||
|
||||
import { isEnterpriseOrgGuard } from "./is-enterprise-org.guard";
|
||||
@ -44,15 +49,19 @@ describe("Is Enterprise Org Guard", () => {
|
||||
let organizationService: MockProxy<OrganizationService>;
|
||||
let dialogService: MockProxy<DialogService>;
|
||||
let routerHarness: RouterTestingHarness;
|
||||
let accountService: FakeAccountService;
|
||||
const userId = Utils.newGuid() as UserId;
|
||||
|
||||
beforeEach(async () => {
|
||||
organizationService = mock<OrganizationService>();
|
||||
dialogService = mock<DialogService>();
|
||||
accountService = mockAccountServiceWith(userId);
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
providers: [
|
||||
{ provide: OrganizationService, useValue: organizationService },
|
||||
{ provide: DialogService, useValue: dialogService },
|
||||
{ provide: AccountService, useValue: accountService },
|
||||
provideRouter([
|
||||
{
|
||||
path: "",
|
||||
@ -82,7 +91,7 @@ describe("Is Enterprise Org Guard", () => {
|
||||
|
||||
it("redirects to `/` if the organization id provided is not found", async () => {
|
||||
const org = orgFactory();
|
||||
organizationService.get.calledWith(org.id).mockResolvedValue(null);
|
||||
organizationService.organizations$.calledWith(userId).mockReturnValue(of([]));
|
||||
await routerHarness.navigateByUrl(`organizations/${org.id}/enterpriseOrgsOnly`);
|
||||
expect(routerHarness.routeNativeElement?.querySelector("h1")?.textContent?.trim() ?? "").toBe(
|
||||
"This is the home screen!",
|
||||
@ -101,7 +110,7 @@ describe("Is Enterprise Org Guard", () => {
|
||||
type: OrganizationUserType.User,
|
||||
productTierType: productTierType,
|
||||
});
|
||||
organizationService.get.calledWith(org.id).mockResolvedValue(org);
|
||||
organizationService.organizations$.calledWith(userId).mockReturnValue(of([org]));
|
||||
await routerHarness.navigateByUrl(`organizations/${org.id}/enterpriseOrgsOnly`);
|
||||
expect(dialogService.openSimpleDialog).toHaveBeenCalled();
|
||||
expect(
|
||||
@ -115,7 +124,7 @@ describe("Is Enterprise Org Guard", () => {
|
||||
type: OrganizationUserType.Owner,
|
||||
productTierType: ProductTierType.Teams,
|
||||
});
|
||||
organizationService.get.calledWith(org.id).mockResolvedValue(org);
|
||||
organizationService.organizations$.calledWith(userId).mockReturnValue(of([org]));
|
||||
dialogService.openSimpleDialog.calledWith(any()).mockResolvedValue(true);
|
||||
await routerHarness.navigateByUrl(`organizations/${org.id}/enterpriseOrgsOnly`);
|
||||
expect(routerHarness.routeNativeElement?.querySelector("h1")?.textContent?.trim() ?? "").toBe(
|
||||
@ -133,7 +142,7 @@ describe("Is Enterprise Org Guard", () => {
|
||||
type: OrganizationUserType.User,
|
||||
productTierType: productTierType,
|
||||
});
|
||||
organizationService.get.calledWith(org.id).mockResolvedValue(org);
|
||||
organizationService.organizations$.calledWith(userId).mockReturnValue(of([org]));
|
||||
await routerHarness.navigateByUrl(`organizations/${org.id}/enterpriseOrgsOnlyNoError`);
|
||||
expect(dialogService.openSimpleDialog).not.toHaveBeenCalled();
|
||||
expect(
|
||||
@ -143,7 +152,7 @@ describe("Is Enterprise Org Guard", () => {
|
||||
|
||||
it("proceeds with navigation if the organization in question is a enterprise organization", async () => {
|
||||
const org = orgFactory({ productTierType: ProductTierType.Enterprise });
|
||||
organizationService.get.calledWith(org.id).mockResolvedValue(org);
|
||||
organizationService.organizations$.calledWith(userId).mockReturnValue(of([org]));
|
||||
await routerHarness.navigateByUrl(`organizations/${org.id}/enterpriseOrgsOnly`);
|
||||
expect(routerHarness.routeNativeElement?.querySelector("h1")?.textContent?.trim() ?? "").toBe(
|
||||
"This component can only be accessed by a enterprise organization!",
|
||||
|
@ -7,8 +7,13 @@ import {
|
||||
Router,
|
||||
RouterStateSnapshot,
|
||||
} from "@angular/router";
|
||||
import { firstValueFrom, map } from "rxjs";
|
||||
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import {
|
||||
getOrganizationById,
|
||||
OrganizationService,
|
||||
} from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { ProductTierType } from "@bitwarden/common/billing/enums";
|
||||
import { DialogService } from "@bitwarden/components";
|
||||
|
||||
@ -23,9 +28,15 @@ export function isEnterpriseOrgGuard(showError: boolean = true): CanActivateFn {
|
||||
return async (route: ActivatedRouteSnapshot, _state: RouterStateSnapshot) => {
|
||||
const router = inject(Router);
|
||||
const organizationService = inject(OrganizationService);
|
||||
const accountService = inject(AccountService);
|
||||
const dialogService = inject(DialogService);
|
||||
|
||||
const org = await organizationService.get(route.params.organizationId);
|
||||
const userId = await firstValueFrom(accountService.activeAccount$.pipe(map((a) => a?.id)));
|
||||
const org = await firstValueFrom(
|
||||
organizationService
|
||||
.organizations$(userId)
|
||||
.pipe(getOrganizationById(route.params.organizationId)),
|
||||
);
|
||||
|
||||
if (org == null) {
|
||||
return router.createUrlTree(["/"]);
|
||||
|
@ -5,10 +5,15 @@ import { TestBed } from "@angular/core/testing";
|
||||
import { provideRouter } from "@angular/router";
|
||||
import { RouterTestingHarness } from "@angular/router/testing";
|
||||
import { MockProxy, any, mock } from "jest-mock-extended";
|
||||
import { of } from "rxjs";
|
||||
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { OrganizationUserType } 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 { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { FakeAccountService, mockAccountServiceWith } from "@bitwarden/common/spec";
|
||||
import { UserId } from "@bitwarden/common/types/guid";
|
||||
import { DialogService } from "@bitwarden/components";
|
||||
|
||||
import { isPaidOrgGuard } from "./is-paid-org.guard";
|
||||
@ -43,15 +48,19 @@ describe("Is Paid Org Guard", () => {
|
||||
let organizationService: MockProxy<OrganizationService>;
|
||||
let dialogService: MockProxy<DialogService>;
|
||||
let routerHarness: RouterTestingHarness;
|
||||
let accountService: FakeAccountService;
|
||||
const userId = Utils.newGuid() as UserId;
|
||||
|
||||
beforeEach(async () => {
|
||||
organizationService = mock<OrganizationService>();
|
||||
dialogService = mock<DialogService>();
|
||||
accountService = mockAccountServiceWith(userId);
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
providers: [
|
||||
{ provide: OrganizationService, useValue: organizationService },
|
||||
{ provide: DialogService, useValue: dialogService },
|
||||
{ provide: AccountService, useValue: accountService },
|
||||
provideRouter([
|
||||
{
|
||||
path: "",
|
||||
@ -75,7 +84,7 @@ describe("Is Paid Org Guard", () => {
|
||||
|
||||
it("redirects to `/` if the organization id provided is not found", async () => {
|
||||
const org = orgFactory();
|
||||
organizationService.get.calledWith(org.id).mockResolvedValue(null);
|
||||
organizationService.organizations$.calledWith(userId).mockReturnValue(of([]));
|
||||
await routerHarness.navigateByUrl(`organizations/${org.id}/paidOrganizationsOnly`);
|
||||
expect(routerHarness.routeNativeElement?.querySelector("h1")?.textContent?.trim() ?? "").toBe(
|
||||
"This is the home screen!",
|
||||
@ -86,7 +95,7 @@ describe("Is Paid Org Guard", () => {
|
||||
// `useTotp` is the current indicator of a free org, it is the baseline
|
||||
// feature offered above the free organization level.
|
||||
const org = orgFactory({ type: OrganizationUserType.User, useTotp: false });
|
||||
organizationService.get.calledWith(org.id).mockResolvedValue(org);
|
||||
organizationService.organizations$.calledWith(userId).mockReturnValue(of([org]));
|
||||
await routerHarness.navigateByUrl(`organizations/${org.id}/paidOrganizationsOnly`);
|
||||
expect(dialogService.openSimpleDialog).toHaveBeenCalled();
|
||||
expect(
|
||||
@ -98,7 +107,7 @@ describe("Is Paid Org Guard", () => {
|
||||
// `useTotp` is the current indicator of a free org, it is the baseline
|
||||
// feature offered above the free organization level.
|
||||
const org = orgFactory({ type: OrganizationUserType.Owner, useTotp: false });
|
||||
organizationService.get.calledWith(org.id).mockResolvedValue(org);
|
||||
organizationService.organizations$.calledWith(userId).mockReturnValue(of([org]));
|
||||
dialogService.openSimpleDialog.calledWith(any()).mockResolvedValue(true);
|
||||
await routerHarness.navigateByUrl(`organizations/${org.id}/paidOrganizationsOnly`);
|
||||
expect(routerHarness.routeNativeElement?.querySelector("h1")?.textContent?.trim() ?? "").toBe(
|
||||
@ -108,7 +117,7 @@ describe("Is Paid Org Guard", () => {
|
||||
|
||||
it("proceeds with navigation if the organization in question is a paid organization", async () => {
|
||||
const org = orgFactory({ useTotp: true });
|
||||
organizationService.get.calledWith(org.id).mockResolvedValue(org);
|
||||
organizationService.organizations$.calledWith(userId).mockReturnValue(of([org]));
|
||||
await routerHarness.navigateByUrl(`organizations/${org.id}/paidOrganizationsOnly`);
|
||||
expect(routerHarness.routeNativeElement?.querySelector("h1")?.textContent?.trim() ?? "").toBe(
|
||||
"This component can only be accessed by a paid organization!",
|
||||
|
@ -7,8 +7,13 @@ import {
|
||||
Router,
|
||||
RouterStateSnapshot,
|
||||
} from "@angular/router";
|
||||
import { firstValueFrom, map } from "rxjs";
|
||||
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import {
|
||||
getOrganizationById,
|
||||
OrganizationService,
|
||||
} from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { DialogService } from "@bitwarden/components";
|
||||
|
||||
/**
|
||||
@ -22,9 +27,15 @@ export function isPaidOrgGuard(): CanActivateFn {
|
||||
return async (route: ActivatedRouteSnapshot, _state: RouterStateSnapshot) => {
|
||||
const router = inject(Router);
|
||||
const organizationService = inject(OrganizationService);
|
||||
const accountService = inject(AccountService);
|
||||
const dialogService = inject(DialogService);
|
||||
|
||||
const org = await organizationService.get(route.params.organizationId);
|
||||
const userId = await firstValueFrom(accountService.activeAccount$.pipe(map((a) => a?.id)));
|
||||
const org = await firstValueFrom(
|
||||
organizationService
|
||||
.organizations$(userId)
|
||||
.pipe(getOrganizationById(route.params.organizationId)),
|
||||
);
|
||||
|
||||
if (org == null) {
|
||||
return router.createUrlTree(["/"]);
|
||||
|
@ -8,11 +8,16 @@ import {
|
||||
RouterStateSnapshot,
|
||||
} from "@angular/router";
|
||||
import { mock, MockProxy } from "jest-mock-extended";
|
||||
import { of } from "rxjs";
|
||||
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { OrganizationUserType } 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 { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { FakeAccountService, mockAccountServiceWith } from "@bitwarden/common/spec";
|
||||
import { UserId } from "@bitwarden/common/types/guid";
|
||||
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
|
||||
import { ToastService } from "@bitwarden/components";
|
||||
|
||||
@ -34,10 +39,13 @@ describe("Organization Permissions Guard", () => {
|
||||
let organizationService: MockProxy<OrganizationService>;
|
||||
let state: MockProxy<RouterStateSnapshot>;
|
||||
let route: MockProxy<ActivatedRouteSnapshot>;
|
||||
let accountService: FakeAccountService;
|
||||
const userId = Utils.newGuid() as UserId;
|
||||
|
||||
beforeEach(() => {
|
||||
router = mock<Router>();
|
||||
organizationService = mock<OrganizationService>();
|
||||
accountService = mockAccountServiceWith(userId);
|
||||
state = mock<RouterStateSnapshot>();
|
||||
route = mock<ActivatedRouteSnapshot>({
|
||||
params: {
|
||||
@ -48,6 +56,7 @@ describe("Organization Permissions Guard", () => {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [
|
||||
{ provide: Router, useValue: router },
|
||||
{ provide: AccountService, useValue: accountService },
|
||||
{ provide: OrganizationService, useValue: organizationService },
|
||||
{ provide: ToastService, useValue: mock<ToastService>() },
|
||||
{ provide: I18nService, useValue: mock<I18nService>() },
|
||||
@ -57,7 +66,7 @@ describe("Organization Permissions Guard", () => {
|
||||
});
|
||||
|
||||
it("blocks navigation if organization does not exist", async () => {
|
||||
organizationService.get.mockReturnValue(null);
|
||||
organizationService.organizations$.mockReturnValue(of([]));
|
||||
|
||||
const actual = await TestBed.runInInjectionContext(
|
||||
async () => await organizationPermissionsGuard()(route, state),
|
||||
@ -68,7 +77,7 @@ describe("Organization Permissions Guard", () => {
|
||||
|
||||
it("permits navigation if no permissions are specified", async () => {
|
||||
const org = orgFactory();
|
||||
organizationService.get.calledWith(org.id).mockResolvedValue(org);
|
||||
organizationService.organizations$.calledWith(userId).mockReturnValue(of([org]));
|
||||
|
||||
const actual = await TestBed.runInInjectionContext(async () =>
|
||||
organizationPermissionsGuard()(route, state),
|
||||
@ -81,7 +90,7 @@ describe("Organization Permissions Guard", () => {
|
||||
const permissionsCallback = jest.fn();
|
||||
permissionsCallback.mockImplementation((_org) => true);
|
||||
const org = orgFactory();
|
||||
organizationService.get.calledWith(org.id).mockResolvedValue(org);
|
||||
organizationService.organizations$.calledWith(userId).mockReturnValue(of([org]));
|
||||
|
||||
const actual = await TestBed.runInInjectionContext(
|
||||
async () => await organizationPermissionsGuard(permissionsCallback)(route, state),
|
||||
@ -103,7 +112,7 @@ describe("Organization Permissions Guard", () => {
|
||||
});
|
||||
|
||||
const org = orgFactory();
|
||||
organizationService.get.calledWith(org.id).mockResolvedValue(org);
|
||||
organizationService.organizations$.calledWith(userId).mockReturnValue(of([org]));
|
||||
|
||||
const actual = await TestBed.runInInjectionContext(
|
||||
async () => await organizationPermissionsGuard(permissionsCallback)(route, state),
|
||||
@ -122,7 +131,7 @@ describe("Organization Permissions Guard", () => {
|
||||
}),
|
||||
});
|
||||
const org = orgFactory();
|
||||
organizationService.get.calledWith(org.id).mockResolvedValue(org);
|
||||
organizationService.organizations$.calledWith(userId).mockReturnValue(of([org]));
|
||||
|
||||
const actual = await TestBed.runInInjectionContext(
|
||||
async () => await organizationPermissionsGuard((_org: Organization) => false)(route, state),
|
||||
@ -141,7 +150,7 @@ describe("Organization Permissions Guard", () => {
|
||||
type: OrganizationUserType.Admin,
|
||||
enabled: false,
|
||||
});
|
||||
organizationService.get.calledWith(org.id).mockResolvedValue(org);
|
||||
organizationService.organizations$.calledWith(userId).mockReturnValue(of([org]));
|
||||
|
||||
const actual = await TestBed.runInInjectionContext(
|
||||
async () => await organizationPermissionsGuard()(route, state),
|
||||
@ -155,7 +164,7 @@ describe("Organization Permissions Guard", () => {
|
||||
type: OrganizationUserType.Owner,
|
||||
enabled: false,
|
||||
});
|
||||
organizationService.get.calledWith(org.id).mockResolvedValue(org);
|
||||
organizationService.organizations$.calledWith(userId).mockReturnValue(of([org]));
|
||||
|
||||
const actual = await TestBed.runInInjectionContext(
|
||||
async () => await organizationPermissionsGuard()(route, state),
|
||||
|
@ -7,12 +7,14 @@ import {
|
||||
Router,
|
||||
RouterStateSnapshot,
|
||||
} from "@angular/router";
|
||||
import { firstValueFrom, map } from "rxjs";
|
||||
|
||||
import {
|
||||
canAccessOrgAdmin,
|
||||
OrganizationService,
|
||||
} from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
|
||||
import { ToastService } from "@bitwarden/components";
|
||||
@ -46,13 +48,21 @@ export function organizationPermissionsGuard(
|
||||
const toastService = inject(ToastService);
|
||||
const i18nService = inject(I18nService);
|
||||
const syncService = inject(SyncService);
|
||||
const accountService = inject(AccountService);
|
||||
|
||||
// TODO: We need to fix issue once and for all.
|
||||
if ((await syncService.getLastSync()) == null) {
|
||||
await syncService.fullSync(false);
|
||||
}
|
||||
|
||||
const org = await organizationService.get(route.params.organizationId);
|
||||
const userId = await firstValueFrom(accountService.activeAccount$.pipe(map((a) => a?.id)));
|
||||
|
||||
const org = await firstValueFrom(
|
||||
organizationService
|
||||
.organizations$(userId)
|
||||
.pipe(map((organizations) => organizations.find((org) => route.params.organizationId))),
|
||||
);
|
||||
|
||||
if (org == null) {
|
||||
return router.createUrlTree(["/"]);
|
||||
}
|
||||
|
@ -5,10 +5,15 @@ import { TestBed } from "@angular/core/testing";
|
||||
import { provideRouter } from "@angular/router";
|
||||
import { RouterTestingHarness } from "@angular/router/testing";
|
||||
import { MockProxy, mock } from "jest-mock-extended";
|
||||
import { of } from "rxjs";
|
||||
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { OrganizationUserType } 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 { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { FakeAccountService, mockAccountServiceWith } from "@bitwarden/common/spec";
|
||||
import { UserId } from "@bitwarden/common/types/guid";
|
||||
|
||||
import { organizationRedirectGuard } from "./org-redirect.guard";
|
||||
|
||||
@ -41,13 +46,17 @@ const orgFactory = (props: Partial<Organization> = {}) =>
|
||||
describe("Organization Redirect Guard", () => {
|
||||
let organizationService: MockProxy<OrganizationService>;
|
||||
let routerHarness: RouterTestingHarness;
|
||||
let accountService: FakeAccountService;
|
||||
const userId = Utils.newGuid() as UserId;
|
||||
|
||||
beforeEach(async () => {
|
||||
organizationService = mock<OrganizationService>();
|
||||
accountService = mockAccountServiceWith(userId);
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
providers: [
|
||||
{ provide: OrganizationService, useValue: organizationService },
|
||||
{ provide: AccountService, useValue: accountService },
|
||||
provideRouter([
|
||||
{
|
||||
path: "",
|
||||
@ -89,16 +98,16 @@ describe("Organization Redirect Guard", () => {
|
||||
|
||||
it("redirects to `/` if the organization id provided is not found", async () => {
|
||||
const org = orgFactory();
|
||||
organizationService.get.calledWith(org.id).mockResolvedValue(null);
|
||||
organizationService.organizations$.calledWith(userId).mockReturnValue(of([]));
|
||||
await routerHarness.navigateByUrl(`organizations/${org.id}/noCallback`);
|
||||
expect(routerHarness.routeNativeElement?.querySelector("h1")?.textContent?.trim() ?? "").toBe(
|
||||
"This is the home screen!",
|
||||
);
|
||||
});
|
||||
|
||||
it("redirects to `/organizations/{id}` if no custom redirect is supplied but the user can access the admin onsole", async () => {
|
||||
it("redirects to `/organizations/{id}` if no custom redirect is supplied but the user can access the admin console", async () => {
|
||||
const org = orgFactory();
|
||||
organizationService.get.calledWith(org.id).mockResolvedValue(org);
|
||||
organizationService.organizations$.calledWith(userId).mockReturnValue(of([org]));
|
||||
await routerHarness.navigateByUrl(`organizations/${org.id}/noCallback`);
|
||||
expect(routerHarness.routeNativeElement?.querySelector("h1")?.textContent?.trim() ?? "").toBe(
|
||||
"This is the admin console!",
|
||||
@ -107,7 +116,7 @@ describe("Organization Redirect Guard", () => {
|
||||
|
||||
it("redirects properly when the redirect callback returns a single string", async () => {
|
||||
const org = orgFactory();
|
||||
organizationService.get.calledWith(org.id).mockResolvedValue(org);
|
||||
organizationService.organizations$.calledWith(userId).mockReturnValue(of([org]));
|
||||
await routerHarness.navigateByUrl(`organizations/${org.id}/stringCallback`);
|
||||
expect(routerHarness.routeNativeElement?.querySelector("h1")?.textContent?.trim() ?? "").toBe(
|
||||
"This is a subroute of the admin console!",
|
||||
@ -116,7 +125,7 @@ describe("Organization Redirect Guard", () => {
|
||||
|
||||
it("redirects properly when the redirect callback returns an array of strings", async () => {
|
||||
const org = orgFactory();
|
||||
organizationService.get.calledWith(org.id).mockResolvedValue(org);
|
||||
organizationService.organizations$.calledWith(userId).mockReturnValue(of([org]));
|
||||
await routerHarness.navigateByUrl(`organizations/${org.id}/arrayCallback`);
|
||||
expect(routerHarness.routeNativeElement?.querySelector("h1")?.textContent?.trim() ?? "").toBe(
|
||||
"This is a subroute of the admin console!",
|
||||
|
@ -5,12 +5,14 @@ import {
|
||||
Router,
|
||||
RouterStateSnapshot,
|
||||
} from "@angular/router";
|
||||
import { firstValueFrom, map } from "rxjs";
|
||||
|
||||
import {
|
||||
canAccessOrgAdmin,
|
||||
OrganizationService,
|
||||
} from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
|
||||
/**
|
||||
*
|
||||
@ -25,8 +27,25 @@ export function organizationRedirectGuard(
|
||||
return async (route: ActivatedRouteSnapshot, state: RouterStateSnapshot) => {
|
||||
const router = inject(Router);
|
||||
const organizationService = inject(OrganizationService);
|
||||
const accountService = inject(AccountService);
|
||||
|
||||
const org = await organizationService.get(route.params.organizationId);
|
||||
const userId = await firstValueFrom(accountService.activeAccount$.pipe(map((a) => a?.id)));
|
||||
|
||||
if (!userId) {
|
||||
return router.createUrlTree(["/"]);
|
||||
}
|
||||
|
||||
const org = await firstValueFrom(
|
||||
organizationService
|
||||
.organizations$(userId)
|
||||
.pipe(
|
||||
map((organizations) => organizations.find((o) => o.id === route.params.organizationId)),
|
||||
),
|
||||
);
|
||||
|
||||
if (!org) {
|
||||
return router.createUrlTree(["/"]);
|
||||
}
|
||||
|
||||
if (customRedirect != null) {
|
||||
let redirectPath = customRedirect(org);
|
||||
|
@ -4,8 +4,12 @@ import { Component, OnInit } from "@angular/core";
|
||||
import { ActivatedRoute } from "@angular/router";
|
||||
import { Observable, switchMap } from "rxjs";
|
||||
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import {
|
||||
getOrganizationById,
|
||||
OrganizationService,
|
||||
} from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { IntegrationType } from "@bitwarden/common/enums";
|
||||
|
||||
import { HeaderModule } from "../../../layouts/header/header.module";
|
||||
@ -34,13 +38,22 @@ export class AdminConsoleIntegrationsComponent implements OnInit {
|
||||
|
||||
ngOnInit(): void {
|
||||
this.organization$ = this.route.params.pipe(
|
||||
switchMap((params) => this.organizationService.get$(params.organizationId)),
|
||||
switchMap((params) =>
|
||||
this.accountService.activeAccount$.pipe(
|
||||
switchMap((account) =>
|
||||
this.organizationService
|
||||
.organizations$(account?.id)
|
||||
.pipe(getOrganizationById(params.organizationId)),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
private organizationService: OrganizationService,
|
||||
private accountService: AccountService,
|
||||
) {
|
||||
this.integrationsList = [
|
||||
{
|
||||
|
@ -3,7 +3,7 @@
|
||||
import { CommonModule } from "@angular/common";
|
||||
import { Component, OnInit } from "@angular/core";
|
||||
import { ActivatedRoute, RouterModule } from "@angular/router";
|
||||
import { combineLatest, filter, map, Observable, switchMap } from "rxjs";
|
||||
import { combineLatest, filter, firstValueFrom, map, Observable, switchMap } from "rxjs";
|
||||
|
||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||
import {
|
||||
@ -20,6 +20,8 @@ import { PolicyService } from "@bitwarden/common/admin-console/abstractions/poli
|
||||
import { ProviderService } from "@bitwarden/common/admin-console/abstractions/provider.service";
|
||||
import { PolicyType, ProviderStatusType } 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 { getUserId } from "@bitwarden/common/auth/services/account.service";
|
||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
@ -66,14 +68,16 @@ export class OrganizationLayoutComponent implements OnInit {
|
||||
private configService: ConfigService,
|
||||
private policyService: PolicyService,
|
||||
private providerService: ProviderService,
|
||||
private accountService: AccountService,
|
||||
) {}
|
||||
|
||||
async ngOnInit() {
|
||||
document.body.classList.remove("layout_frontend");
|
||||
|
||||
const userId = await firstValueFrom(getUserId(this.accountService.activeAccount$));
|
||||
this.organization$ = this.route.params.pipe(
|
||||
map((p) => p.organizationId),
|
||||
switchMap((id) => this.organizationService.organizations$.pipe(getById(id))),
|
||||
switchMap((id) => this.organizationService.organizations$(userId).pipe(getById(id))),
|
||||
filter((org) => org != null),
|
||||
);
|
||||
|
||||
|
@ -2,14 +2,19 @@
|
||||
// @ts-strict-ignore
|
||||
import { Component, OnDestroy, OnInit } from "@angular/core";
|
||||
import { ActivatedRoute, Router } from "@angular/router";
|
||||
import { concatMap, Subject, takeUntil } from "rxjs";
|
||||
import { concatMap, firstValueFrom, Subject, takeUntil } from "rxjs";
|
||||
|
||||
import { OrganizationUserApiService } from "@bitwarden/admin-console/common";
|
||||
import { UserNamePipe } from "@bitwarden/angular/pipes/user-name.pipe";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import {
|
||||
getOrganizationById,
|
||||
OrganizationService,
|
||||
} from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { ProviderService } from "@bitwarden/common/admin-console/abstractions/provider.service";
|
||||
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 { EventSystemUser } from "@bitwarden/common/enums";
|
||||
import { EventResponse } from "@bitwarden/common/models/response/event.response";
|
||||
import { FileDownloadService } from "@bitwarden/common/platform/abstractions/file-download/file-download.service";
|
||||
@ -55,6 +60,7 @@ export class EventsComponent extends BaseEventsComponent implements OnInit, OnDe
|
||||
private providerService: ProviderService,
|
||||
fileDownloadService: FileDownloadService,
|
||||
toastService: ToastService,
|
||||
private accountService: AccountService,
|
||||
) {
|
||||
super(
|
||||
eventService,
|
||||
@ -68,11 +74,16 @@ export class EventsComponent extends BaseEventsComponent implements OnInit, OnDe
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
const userId = await firstValueFrom(getUserId(this.accountService.activeAccount$));
|
||||
this.route.params
|
||||
.pipe(
|
||||
concatMap(async (params) => {
|
||||
this.organizationId = params.organizationId;
|
||||
this.organization = await this.organizationService.get(this.organizationId);
|
||||
this.organization = await firstValueFrom(
|
||||
this.organizationService
|
||||
.organizations$(userId)
|
||||
.pipe(getOrganizationById(this.organizationId)),
|
||||
);
|
||||
if (this.organization == null || !this.organization.useEvents) {
|
||||
await this.router.navigate(["/organizations", this.organizationId]);
|
||||
return;
|
||||
|
@ -13,6 +13,7 @@ import {
|
||||
of,
|
||||
shareReplay,
|
||||
Subject,
|
||||
switchMap,
|
||||
takeUntil,
|
||||
} from "rxjs";
|
||||
|
||||
@ -22,7 +23,10 @@ import {
|
||||
OrganizationUserApiService,
|
||||
} from "@bitwarden/admin-console/common";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import {
|
||||
getOrganizationById,
|
||||
OrganizationService,
|
||||
} from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { ErrorResponse } from "@bitwarden/common/models/response/error.response";
|
||||
@ -97,9 +101,14 @@ export const openGroupAddEditDialog = (
|
||||
templateUrl: "group-add-edit.component.html",
|
||||
})
|
||||
export class GroupAddEditComponent implements OnInit, OnDestroy {
|
||||
private organization$ = this.organizationService
|
||||
.get$(this.organizationId)
|
||||
.pipe(shareReplay({ refCount: true }));
|
||||
private organization$ = this.accountService.activeAccount$.pipe(
|
||||
switchMap((account) =>
|
||||
this.organizationService
|
||||
.organizations$(account?.id)
|
||||
.pipe(getOrganizationById(this.organizationId))
|
||||
.pipe(shareReplay({ refCount: true })),
|
||||
),
|
||||
);
|
||||
|
||||
protected PermissionMode = PermissionMode;
|
||||
protected ResultType = GroupAddEditDialogResultType;
|
||||
|
@ -22,7 +22,10 @@ import {
|
||||
OrganizationUserApiService,
|
||||
CollectionView,
|
||||
} from "@bitwarden/admin-console/common";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import {
|
||||
getOrganizationById,
|
||||
OrganizationService,
|
||||
} from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import {
|
||||
OrganizationUserStatusType,
|
||||
OrganizationUserType,
|
||||
@ -156,9 +159,14 @@ export class MemberDialogComponent implements OnDestroy {
|
||||
private toastService: ToastService,
|
||||
private configService: ConfigService,
|
||||
) {
|
||||
this.organization$ = organizationService
|
||||
.get$(this.params.organizationId)
|
||||
.pipe(shareReplay({ refCount: true, bufferSize: 1 }));
|
||||
this.organization$ = accountService.activeAccount$.pipe(
|
||||
switchMap((account) =>
|
||||
organizationService
|
||||
.organizations$(account?.id)
|
||||
.pipe(getOrganizationById(this.params.organizationId))
|
||||
.pipe(shareReplay({ refCount: true, bufferSize: 1 })),
|
||||
),
|
||||
);
|
||||
|
||||
this.editMode = this.params.organizationUserId != null;
|
||||
this.tabIndex = this.params.initialTab ?? MemberDialogTab.Role;
|
||||
|
@ -28,7 +28,10 @@ import { UserNamePipe } from "@bitwarden/angular/pipes/user-name.pipe";
|
||||
import { ModalService } from "@bitwarden/angular/services/modal.service";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import {
|
||||
getOrganizationById,
|
||||
OrganizationService,
|
||||
} from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { OrganizationManagementPreferencesService } from "@bitwarden/common/admin-console/abstractions/organization-management-preferences/organization-management-preferences.service";
|
||||
import { PolicyApiServiceAbstraction as PolicyApiService } from "@bitwarden/common/admin-console/abstractions/policy/policy-api.service.abstraction";
|
||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||
@ -40,6 +43,7 @@ import {
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
import { Policy } from "@bitwarden/common/admin-console/models/domain/policy";
|
||||
import { OrganizationKeysRequest } from "@bitwarden/common/admin-console/models/request/organization-keys.request";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { BillingApiServiceAbstraction } from "@bitwarden/common/billing/abstractions/billing-api.service.abstraction";
|
||||
import { isNotSelfUpgradable, ProductTierType } from "@bitwarden/common/billing/enums";
|
||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||
@ -122,6 +126,7 @@ export class MembersComponent extends BaseMembersComponent<OrganizationUserView>
|
||||
private route: ActivatedRoute,
|
||||
private syncService: SyncService,
|
||||
private organizationService: OrganizationService,
|
||||
private accountService: AccountService,
|
||||
private organizationApiService: OrganizationApiServiceAbstraction,
|
||||
private organizationUserApiService: OrganizationUserApiService,
|
||||
private router: Router,
|
||||
@ -144,7 +149,15 @@ export class MembersComponent extends BaseMembersComponent<OrganizationUserView>
|
||||
);
|
||||
|
||||
const organization$ = this.route.params.pipe(
|
||||
concatMap((params) => this.organizationService.get$(params.organizationId)),
|
||||
concatMap((params) =>
|
||||
this.accountService.activeAccount$.pipe(
|
||||
switchMap((account) =>
|
||||
this.organizationService
|
||||
.organizations$(account?.id)
|
||||
.pipe(getOrganizationById(params.organizationId)),
|
||||
),
|
||||
),
|
||||
),
|
||||
shareReplay({ refCount: true, bufferSize: 1 }),
|
||||
);
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
// FIXME: Update this file to be type safe and remove this and next line
|
||||
// @ts-strict-ignore
|
||||
import { mock, MockProxy } from "jest-mock-extended";
|
||||
import { of } from "rxjs";
|
||||
|
||||
import {
|
||||
OrganizationUserApiService,
|
||||
@ -164,10 +165,9 @@ describe("OrganizationUserResetPasswordService", () => {
|
||||
|
||||
describe("getRotatedData", () => {
|
||||
beforeEach(() => {
|
||||
organizationService.getAll.mockResolvedValue([
|
||||
createOrganization("1", "org1"),
|
||||
createOrganization("2", "org2"),
|
||||
]);
|
||||
organizationService.organizations$.mockReturnValue(
|
||||
of([createOrganization("1", "org1"), createOrganization("2", "org2")]),
|
||||
);
|
||||
organizationApiService.getKeys.mockResolvedValue(
|
||||
new OrganizationKeysResponse({
|
||||
privateKey: "test-private-key",
|
||||
|
@ -1,6 +1,7 @@
|
||||
// FIXME: Update this file to be type safe and remove this and next line
|
||||
// @ts-strict-ignore
|
||||
import { Injectable } from "@angular/core";
|
||||
import { firstValueFrom } from "rxjs";
|
||||
|
||||
import {
|
||||
OrganizationUserApiService,
|
||||
@ -154,7 +155,7 @@ export class OrganizationUserResetPasswordService
|
||||
throw new Error("New user key is required for rotation.");
|
||||
}
|
||||
|
||||
const allOrgs = await this.organizationService.getAll();
|
||||
const allOrgs = await firstValueFrom(this.organizationService.organizations$(userId));
|
||||
|
||||
if (!allOrgs) {
|
||||
return;
|
||||
|
@ -2,11 +2,17 @@
|
||||
// @ts-strict-ignore
|
||||
import { Component, OnInit } from "@angular/core";
|
||||
import { FormBuilder, FormGroup, Validators } from "@angular/forms";
|
||||
import { firstValueFrom } from "rxjs";
|
||||
|
||||
import { ControlsOf } from "@bitwarden/angular/types/controls-of";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import {
|
||||
getOrganizationById,
|
||||
OrganizationService,
|
||||
} from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { PolicyType } from "@bitwarden/common/admin-console/enums";
|
||||
import { MasterPasswordPolicyOptions } from "@bitwarden/common/admin-console/models/domain/master-password-policy-options";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
|
||||
@ -43,6 +49,7 @@ export class MasterPasswordPolicyComponent extends BasePolicyComponent implement
|
||||
private formBuilder: FormBuilder,
|
||||
i18nService: I18nService,
|
||||
private organizationService: OrganizationService,
|
||||
private accountService: AccountService,
|
||||
) {
|
||||
super();
|
||||
|
||||
@ -58,7 +65,12 @@ export class MasterPasswordPolicyComponent extends BasePolicyComponent implement
|
||||
|
||||
async ngOnInit() {
|
||||
super.ngOnInit();
|
||||
const organization = await this.organizationService.get(this.policyResponse.organizationId);
|
||||
const userId = await firstValueFrom(getUserId(this.accountService.activeAccount$));
|
||||
const organization = await firstValueFrom(
|
||||
this.organizationService
|
||||
.organizations$(userId)
|
||||
.pipe(getOrganizationById(this.policyResponse.organizationId)),
|
||||
);
|
||||
this.showKeyConnectorInfo = organization.keyConnectorEnabled;
|
||||
}
|
||||
}
|
||||
|
@ -2,14 +2,18 @@
|
||||
// @ts-strict-ignore
|
||||
import { Component, OnInit, ViewChild, ViewContainerRef } from "@angular/core";
|
||||
import { ActivatedRoute } from "@angular/router";
|
||||
import { lastValueFrom } from "rxjs";
|
||||
import { first } from "rxjs/operators";
|
||||
import { firstValueFrom, lastValueFrom } from "rxjs";
|
||||
import { first, map } from "rxjs/operators";
|
||||
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import {
|
||||
getOrganizationById,
|
||||
OrganizationService,
|
||||
} from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { PolicyApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/policy/policy-api.service.abstraction";
|
||||
import { PolicyType } from "@bitwarden/common/admin-console/enums";
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
import { PolicyResponse } from "@bitwarden/common/admin-console/models/response/policy.response";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { DialogService } from "@bitwarden/components";
|
||||
|
||||
import { PolicyListService } from "../../core/policy-list.service";
|
||||
@ -37,6 +41,7 @@ export class PoliciesComponent implements OnInit {
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
private organizationService: OrganizationService,
|
||||
private accountService: AccountService,
|
||||
private policyApiService: PolicyApiServiceAbstraction,
|
||||
private policyListService: PolicyListService,
|
||||
private dialogService: DialogService,
|
||||
@ -46,7 +51,14 @@ export class PoliciesComponent implements OnInit {
|
||||
// eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe
|
||||
this.route.parent.parent.params.subscribe(async (params) => {
|
||||
this.organizationId = params.organizationId;
|
||||
this.organization = await this.organizationService.get(this.organizationId);
|
||||
const userId = await firstValueFrom(
|
||||
this.accountService.activeAccount$.pipe(map((a) => a?.id)),
|
||||
);
|
||||
this.organization = await firstValueFrom(
|
||||
this.organizationService
|
||||
.organizations$(userId)
|
||||
.pipe(getOrganizationById(this.organizationId)),
|
||||
);
|
||||
this.policies = this.policyListService.getPolicies();
|
||||
|
||||
await this.load();
|
||||
|
@ -1,9 +1,15 @@
|
||||
import { Component, OnInit } from "@angular/core";
|
||||
import { FormBuilder } from "@angular/forms";
|
||||
import { firstValueFrom } from "rxjs";
|
||||
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import {
|
||||
getOrganizationById,
|
||||
OrganizationService,
|
||||
} from "@bitwarden/common/admin-console/abstractions/organization/organization.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 { getUserId } from "@bitwarden/common/auth/services/account.service";
|
||||
|
||||
import { BasePolicy, BasePolicyComponent } from "./base-policy.component";
|
||||
|
||||
@ -31,13 +37,29 @@ export class ResetPasswordPolicyComponent extends BasePolicyComponent implements
|
||||
constructor(
|
||||
private formBuilder: FormBuilder,
|
||||
private organizationService: OrganizationService,
|
||||
private accountService: AccountService,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
super.ngOnInit();
|
||||
const organization = await this.organizationService.get(this.policyResponse.organizationId);
|
||||
|
||||
const userId = await firstValueFrom(getUserId(this.accountService.activeAccount$));
|
||||
|
||||
if (!userId) {
|
||||
throw new Error("No user found.");
|
||||
}
|
||||
|
||||
const organization = await firstValueFrom(
|
||||
this.organizationService
|
||||
.organizations$(userId)
|
||||
.pipe(getOrganizationById(this.policyResponse.organizationId)),
|
||||
);
|
||||
|
||||
if (!organization) {
|
||||
throw new Error("No organization found.");
|
||||
}
|
||||
this.showKeyConnectorInfo = organization.keyConnectorEnabled;
|
||||
}
|
||||
}
|
||||
|
@ -2,9 +2,14 @@
|
||||
// @ts-strict-ignore
|
||||
import { Component, OnInit } from "@angular/core";
|
||||
import { ActivatedRoute, NavigationEnd, Router } from "@angular/router";
|
||||
import { filter, map, Observable, startWith, concatMap } from "rxjs";
|
||||
import { filter, map, Observable, startWith, concatMap, firstValueFrom } from "rxjs";
|
||||
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import {
|
||||
getOrganizationById,
|
||||
OrganizationService,
|
||||
} from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
||||
import { ProductTierType } from "@bitwarden/common/billing/enums";
|
||||
|
||||
import { ReportVariant, reports, ReportType, ReportEntry } from "../../../tools/reports";
|
||||
@ -20,6 +25,7 @@ export class ReportsHomeComponent implements OnInit {
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
private organizationService: OrganizationService,
|
||||
private accountService: AccountService,
|
||||
private router: Router,
|
||||
) {}
|
||||
|
||||
@ -30,8 +36,14 @@ export class ReportsHomeComponent implements OnInit {
|
||||
startWith(this.isReportsHomepageRouteUrl(this.router.url)),
|
||||
);
|
||||
|
||||
const userId = await firstValueFrom(getUserId(this.accountService.activeAccount$));
|
||||
|
||||
this.reports$ = this.route.params.pipe(
|
||||
concatMap((params) => this.organizationService.get$(params.organizationId)),
|
||||
concatMap((params) =>
|
||||
this.organizationService
|
||||
.organizations$(userId)
|
||||
.pipe(getOrganizationById(params.organizationId)),
|
||||
),
|
||||
map((org) => this.buildReports(org.productTierType)),
|
||||
);
|
||||
}
|
||||
|
@ -3,15 +3,29 @@
|
||||
import { Component, OnDestroy, OnInit, ViewChild, ViewContainerRef } from "@angular/core";
|
||||
import { FormBuilder, Validators } from "@angular/forms";
|
||||
import { ActivatedRoute, Router } from "@angular/router";
|
||||
import { combineLatest, from, lastValueFrom, of, Subject, switchMap, takeUntil } from "rxjs";
|
||||
import {
|
||||
combineLatest,
|
||||
firstValueFrom,
|
||||
from,
|
||||
lastValueFrom,
|
||||
of,
|
||||
Subject,
|
||||
switchMap,
|
||||
takeUntil,
|
||||
} from "rxjs";
|
||||
|
||||
import { ModalService } from "@bitwarden/angular/services/modal.service";
|
||||
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import {
|
||||
getOrganizationById,
|
||||
OrganizationService,
|
||||
} from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { OrganizationCollectionManagementUpdateRequest } from "@bitwarden/common/admin-console/models/request/organization-collection-management-update.request";
|
||||
import { OrganizationKeysRequest } from "@bitwarden/common/admin-console/models/request/organization-keys.request";
|
||||
import { OrganizationUpdateRequest } from "@bitwarden/common/admin-console/models/request/organization-update.request";
|
||||
import { OrganizationResponse } from "@bitwarden/common/admin-console/models/response/organization.response";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
@ -77,6 +91,7 @@ export class AccountComponent implements OnInit, OnDestroy {
|
||||
private platformUtilsService: PlatformUtilsService,
|
||||
private keyService: KeyService,
|
||||
private router: Router,
|
||||
private accountService: AccountService,
|
||||
private organizationService: OrganizationService,
|
||||
private organizationApiService: OrganizationApiServiceAbstraction,
|
||||
private dialogService: DialogService,
|
||||
@ -88,9 +103,14 @@ export class AccountComponent implements OnInit, OnDestroy {
|
||||
async ngOnInit() {
|
||||
this.selfHosted = this.platformUtilsService.isSelfHost();
|
||||
|
||||
const userId = await firstValueFrom(getUserId(this.accountService.activeAccount$));
|
||||
this.route.params
|
||||
.pipe(
|
||||
switchMap((params) => this.organizationService.get$(params.organizationId)),
|
||||
switchMap((params) =>
|
||||
this.organizationService
|
||||
.organizations$(userId)
|
||||
.pipe(getOrganizationById(params.organizationId)),
|
||||
),
|
||||
switchMap((organization) => {
|
||||
return combineLatest([
|
||||
of(organization),
|
||||
|
@ -3,12 +3,17 @@
|
||||
import { DIALOG_DATA, DialogConfig, DialogRef } from "@angular/cdk/dialog";
|
||||
import { Component, Inject, OnDestroy, OnInit } from "@angular/core";
|
||||
import { FormBuilder, FormControl, Validators } from "@angular/forms";
|
||||
import { combineLatest, Subject, takeUntil } from "rxjs";
|
||||
import { combineLatest, firstValueFrom, Subject, takeUntil } from "rxjs";
|
||||
|
||||
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import {
|
||||
getOrganizationById,
|
||||
OrganizationService,
|
||||
} from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
||||
import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
||||
import { Verification } from "@bitwarden/common/auth/types/verification";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
@ -94,6 +99,7 @@ export class DeleteOrganizationDialogComponent implements OnInit, OnDestroy {
|
||||
private userVerificationService: UserVerificationService,
|
||||
private cipherService: CipherService,
|
||||
private organizationService: OrganizationService,
|
||||
private accountService: AccountService,
|
||||
private organizationApiService: OrganizationApiServiceAbstraction,
|
||||
private formBuilder: FormBuilder,
|
||||
private toastService: ToastService,
|
||||
@ -106,9 +112,12 @@ export class DeleteOrganizationDialogComponent implements OnInit, OnDestroy {
|
||||
|
||||
async ngOnInit(): Promise<void> {
|
||||
this.deleteOrganizationRequestType = this.params.requestType;
|
||||
const userId = await firstValueFrom(getUserId(this.accountService.activeAccount$));
|
||||
|
||||
combineLatest([
|
||||
this.organizationService.get$(this.params.organizationId),
|
||||
this.organizationService
|
||||
.organizations$(userId)
|
||||
.pipe(getOrganizationById(this.params.organizationId)),
|
||||
this.cipherService.getAllFromApiForOrganization(this.params.organizationId),
|
||||
])
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
|
@ -2,13 +2,15 @@
|
||||
// @ts-strict-ignore
|
||||
import { Component, OnInit } from "@angular/core";
|
||||
import { ActivatedRoute, Router } from "@angular/router";
|
||||
import { firstValueFrom } from "rxjs";
|
||||
import { firstValueFrom, map } from "rxjs";
|
||||
|
||||
import { CollectionAdminService } from "@bitwarden/admin-console/common";
|
||||
import {
|
||||
canAccessVaultTab,
|
||||
OrganizationService,
|
||||
} from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
||||
import { ImportCollectionServiceAbstraction } from "@bitwarden/importer/core";
|
||||
import { ImportComponent } from "@bitwarden/importer/ui";
|
||||
|
||||
@ -36,6 +38,7 @@ export class OrgImportComponent implements OnInit {
|
||||
private route: ActivatedRoute,
|
||||
private organizationService: OrganizationService,
|
||||
private router: Router,
|
||||
private accountService: AccountService,
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
@ -46,7 +49,12 @@ export class OrgImportComponent implements OnInit {
|
||||
* Callback that is called after a successful import.
|
||||
*/
|
||||
protected async onSuccessfulImport(organizationId: string): Promise<void> {
|
||||
const organization = await firstValueFrom(this.organizationService.get$(organizationId));
|
||||
const userId = await firstValueFrom(getUserId(this.accountService.activeAccount$));
|
||||
const organization = await firstValueFrom(
|
||||
this.organizationService
|
||||
.organizations$(userId)
|
||||
.pipe(map((organizations) => organizations.find((o) => o.id === organizationId))),
|
||||
);
|
||||
if (organization == null) {
|
||||
return;
|
||||
}
|
||||
|
@ -3,16 +3,20 @@
|
||||
import { DialogRef } from "@angular/cdk/dialog";
|
||||
import { Component, OnInit } from "@angular/core";
|
||||
import { ActivatedRoute } from "@angular/router";
|
||||
import { concatMap, takeUntil, map, lastValueFrom } from "rxjs";
|
||||
import { concatMap, takeUntil, map, lastValueFrom, firstValueFrom } from "rxjs";
|
||||
import { first, tap } from "rxjs/operators";
|
||||
|
||||
import { ModalService } from "@bitwarden/angular/services/modal.service";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import {
|
||||
getOrganizationById,
|
||||
OrganizationService,
|
||||
} from "@bitwarden/common/admin-console/abstractions/organization/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 { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type";
|
||||
import { TwoFactorDuoResponse } from "@bitwarden/common/auth/models/response/two-factor-duo.response";
|
||||
import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
||||
import { AuthResponse } from "@bitwarden/common/auth/types/auth-response";
|
||||
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
|
||||
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
|
||||
@ -38,7 +42,7 @@ export class TwoFactorSetupComponent extends BaseTwoFactorSetupComponent impleme
|
||||
private route: ActivatedRoute,
|
||||
private organizationService: OrganizationService,
|
||||
billingAccountProfileStateService: BillingAccountProfileStateService,
|
||||
accountService: AccountService,
|
||||
protected accountService: AccountService,
|
||||
) {
|
||||
super(
|
||||
dialogService,
|
||||
@ -52,11 +56,13 @@ export class TwoFactorSetupComponent extends BaseTwoFactorSetupComponent impleme
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
const userId = await firstValueFrom(getUserId(this.accountService.activeAccount$));
|
||||
this.route.params
|
||||
.pipe(
|
||||
concatMap((params) =>
|
||||
this.organizationService
|
||||
.get$(params.organizationId)
|
||||
.organizations$(userId)
|
||||
.pipe(getOrganizationById(params.organizationId))
|
||||
.pipe(map((organization) => ({ params, organization }))),
|
||||
),
|
||||
tap(async (mapResponse) => {
|
||||
|
@ -3,7 +3,7 @@
|
||||
import { Component, OnDestroy, OnInit, ViewChild } from "@angular/core";
|
||||
import { FormBuilder, Validators } from "@angular/forms";
|
||||
import { ActivatedRoute, Router } from "@angular/router";
|
||||
import { lastValueFrom, Observable, Subject } from "rxjs";
|
||||
import { firstValueFrom, lastValueFrom, Observable, Subject } from "rxjs";
|
||||
import { first, map, takeUntil } from "rxjs/operators";
|
||||
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
@ -12,6 +12,8 @@ import { OrganizationUserType } from "@bitwarden/common/admin-console/enums";
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
import { OrganizationSponsorshipRedeemRequest } from "@bitwarden/common/admin-console/models/request/organization/organization-sponsorship-redeem.request";
|
||||
import { PreValidateSponsorshipResponse } from "@bitwarden/common/admin-console/models/response/pre-validate-sponsorship.response";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
||||
import { PlanSponsorshipType, PlanType, ProductTierType } from "@bitwarden/common/billing/enums";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
@ -69,6 +71,7 @@ export class FamiliesForEnterpriseSetupComponent implements OnInit, OnDestroy {
|
||||
private syncService: SyncService,
|
||||
private validationService: ValidationService,
|
||||
private organizationService: OrganizationService,
|
||||
private accountService: AccountService,
|
||||
private dialogService: DialogService,
|
||||
private formBuilder: FormBuilder,
|
||||
private toastService: ToastService,
|
||||
@ -115,14 +118,18 @@ export class FamiliesForEnterpriseSetupComponent implements OnInit, OnDestroy {
|
||||
this.loading = false;
|
||||
});
|
||||
|
||||
this.existingFamilyOrganizations$ = this.organizationService.organizations$.pipe(
|
||||
map((orgs) =>
|
||||
orgs.filter(
|
||||
(o) =>
|
||||
o.productTierType === ProductTierType.Families && o.type === OrganizationUserType.Owner,
|
||||
const userId = await firstValueFrom(getUserId(this.accountService.activeAccount$));
|
||||
this.existingFamilyOrganizations$ = this.organizationService
|
||||
.organizations$(userId)
|
||||
.pipe(
|
||||
map((orgs) =>
|
||||
orgs.filter(
|
||||
(o) =>
|
||||
o.productTierType === ProductTierType.Families &&
|
||||
o.type === OrganizationUserType.Owner,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
);
|
||||
|
||||
this.existingFamilyOrganizations$.pipe(takeUntil(this._destroy)).subscribe((orgs) => {
|
||||
if (orgs.length === 0) {
|
||||
|
@ -2,10 +2,15 @@
|
||||
// @ts-strict-ignore
|
||||
import { Component, OnInit } from "@angular/core";
|
||||
import { ActivatedRoute } from "@angular/router";
|
||||
import { firstValueFrom, map } from "rxjs";
|
||||
|
||||
import { ModalService } from "@bitwarden/angular/services/modal.service";
|
||||
import { AuditService } from "@bitwarden/common/abstractions/audit.service";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import {
|
||||
getOrganizationById,
|
||||
OrganizationService,
|
||||
} from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
|
||||
@ -32,6 +37,7 @@ export class ExposedPasswordsReportComponent
|
||||
auditService: AuditService,
|
||||
modalService: ModalService,
|
||||
organizationService: OrganizationService,
|
||||
protected accountService: AccountService,
|
||||
private route: ActivatedRoute,
|
||||
passwordRepromptService: PasswordRepromptService,
|
||||
i18nService: I18nService,
|
||||
@ -41,6 +47,7 @@ export class ExposedPasswordsReportComponent
|
||||
cipherService,
|
||||
auditService,
|
||||
organizationService,
|
||||
accountService,
|
||||
modalService,
|
||||
passwordRepromptService,
|
||||
i18nService,
|
||||
@ -52,7 +59,14 @@ export class ExposedPasswordsReportComponent
|
||||
this.isAdminConsoleActive = true;
|
||||
// eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe
|
||||
this.route.parent.parent.params.subscribe(async (params) => {
|
||||
this.organization = await this.organizationService.get(params.organizationId);
|
||||
const userId = await firstValueFrom(
|
||||
this.accountService.activeAccount$.pipe(map((a) => a?.id)),
|
||||
);
|
||||
this.organization = await firstValueFrom(
|
||||
this.organizationService
|
||||
.organizations$(userId)
|
||||
.pipe(getOrganizationById(params.organizationId)),
|
||||
);
|
||||
this.manageableCiphers = await this.cipherService.getAll();
|
||||
});
|
||||
}
|
||||
|
@ -2,9 +2,14 @@
|
||||
// @ts-strict-ignore
|
||||
import { Component, OnInit } from "@angular/core";
|
||||
import { ActivatedRoute } from "@angular/router";
|
||||
import { firstValueFrom, map } from "rxjs";
|
||||
|
||||
import { ModalService } from "@bitwarden/angular/services/modal.service";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import {
|
||||
getOrganizationById,
|
||||
OrganizationService,
|
||||
} from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
@ -31,12 +36,14 @@ export class InactiveTwoFactorReportComponent
|
||||
logService: LogService,
|
||||
passwordRepromptService: PasswordRepromptService,
|
||||
organizationService: OrganizationService,
|
||||
accountService: AccountService,
|
||||
i18nService: I18nService,
|
||||
syncService: SyncService,
|
||||
) {
|
||||
super(
|
||||
cipherService,
|
||||
organizationService,
|
||||
accountService,
|
||||
modalService,
|
||||
logService,
|
||||
passwordRepromptService,
|
||||
@ -49,7 +56,14 @@ export class InactiveTwoFactorReportComponent
|
||||
this.isAdminConsoleActive = true;
|
||||
// eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe
|
||||
this.route.parent.parent.params.subscribe(async (params) => {
|
||||
this.organization = await this.organizationService.get(params.organizationId);
|
||||
const userId = await firstValueFrom(
|
||||
this.accountService.activeAccount$.pipe(map((a) => a?.id)),
|
||||
);
|
||||
this.organization = await firstValueFrom(
|
||||
this.organizationService
|
||||
.organizations$(userId)
|
||||
.pipe(getOrganizationById(params.organizationId)),
|
||||
);
|
||||
await super.ngOnInit();
|
||||
});
|
||||
}
|
||||
|
@ -2,9 +2,14 @@
|
||||
// @ts-strict-ignore
|
||||
import { Component, OnInit } from "@angular/core";
|
||||
import { ActivatedRoute } from "@angular/router";
|
||||
import { firstValueFrom, map } from "rxjs";
|
||||
|
||||
import { ModalService } from "@bitwarden/angular/services/modal.service";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import {
|
||||
getOrganizationById,
|
||||
OrganizationService,
|
||||
} from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
|
||||
@ -31,6 +36,7 @@ export class ReusedPasswordsReportComponent
|
||||
modalService: ModalService,
|
||||
private route: ActivatedRoute,
|
||||
organizationService: OrganizationService,
|
||||
protected accountService: AccountService,
|
||||
passwordRepromptService: PasswordRepromptService,
|
||||
i18nService: I18nService,
|
||||
syncService: SyncService,
|
||||
@ -38,6 +44,7 @@ export class ReusedPasswordsReportComponent
|
||||
super(
|
||||
cipherService,
|
||||
organizationService,
|
||||
accountService,
|
||||
modalService,
|
||||
passwordRepromptService,
|
||||
i18nService,
|
||||
@ -49,7 +56,14 @@ export class ReusedPasswordsReportComponent
|
||||
this.isAdminConsoleActive = true;
|
||||
// eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe
|
||||
this.route.parent.parent.params.subscribe(async (params) => {
|
||||
this.organization = await this.organizationService.get(params.organizationId);
|
||||
const userId = await firstValueFrom(
|
||||
this.accountService.activeAccount$.pipe(map((a) => a?.id)),
|
||||
);
|
||||
this.organization = await firstValueFrom(
|
||||
this.organizationService
|
||||
.organizations$(userId)
|
||||
.pipe(getOrganizationById(params.organizationId)),
|
||||
);
|
||||
this.manageableCiphers = await this.cipherService.getAll();
|
||||
await super.ngOnInit();
|
||||
});
|
||||
|
@ -2,10 +2,15 @@
|
||||
// @ts-strict-ignore
|
||||
import { Component, OnInit } from "@angular/core";
|
||||
import { ActivatedRoute } from "@angular/router";
|
||||
import { firstValueFrom, map } from "rxjs";
|
||||
|
||||
import { CollectionService } from "@bitwarden/admin-console/common";
|
||||
import { ModalService } from "@bitwarden/angular/services/modal.service";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import {
|
||||
getOrganizationById,
|
||||
OrganizationService,
|
||||
} from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
|
||||
@ -29,6 +34,7 @@ export class UnsecuredWebsitesReportComponent
|
||||
modalService: ModalService,
|
||||
private route: ActivatedRoute,
|
||||
organizationService: OrganizationService,
|
||||
protected accountService: AccountService,
|
||||
passwordRepromptService: PasswordRepromptService,
|
||||
i18nService: I18nService,
|
||||
syncService: SyncService,
|
||||
@ -37,6 +43,7 @@ export class UnsecuredWebsitesReportComponent
|
||||
super(
|
||||
cipherService,
|
||||
organizationService,
|
||||
accountService,
|
||||
modalService,
|
||||
passwordRepromptService,
|
||||
i18nService,
|
||||
@ -49,7 +56,14 @@ export class UnsecuredWebsitesReportComponent
|
||||
this.isAdminConsoleActive = true;
|
||||
// eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe
|
||||
this.route.parent.parent.params.subscribe(async (params) => {
|
||||
this.organization = await this.organizationService.get(params.organizationId);
|
||||
const userId = await firstValueFrom(
|
||||
this.accountService.activeAccount$.pipe(map((a) => a?.id)),
|
||||
);
|
||||
this.organization = await firstValueFrom(
|
||||
this.organizationService
|
||||
.organizations$(userId)
|
||||
.pipe(getOrganizationById(params.organizationId)),
|
||||
);
|
||||
await super.ngOnInit();
|
||||
});
|
||||
}
|
||||
|
@ -2,9 +2,14 @@
|
||||
// @ts-strict-ignore
|
||||
import { Component, OnInit } from "@angular/core";
|
||||
import { ActivatedRoute } from "@angular/router";
|
||||
import { firstValueFrom, map } from "rxjs";
|
||||
|
||||
import { ModalService } from "@bitwarden/angular/services/modal.service";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import {
|
||||
getOrganizationById,
|
||||
OrganizationService,
|
||||
} from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
@ -36,11 +41,13 @@ export class WeakPasswordsReportComponent
|
||||
passwordRepromptService: PasswordRepromptService,
|
||||
i18nService: I18nService,
|
||||
syncService: SyncService,
|
||||
protected accountService: AccountService,
|
||||
) {
|
||||
super(
|
||||
cipherService,
|
||||
passwordStrengthService,
|
||||
organizationService,
|
||||
accountService,
|
||||
modalService,
|
||||
passwordRepromptService,
|
||||
i18nService,
|
||||
@ -52,7 +59,14 @@ export class WeakPasswordsReportComponent
|
||||
this.isAdminConsoleActive = true;
|
||||
// eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe
|
||||
this.route.parent.parent.params.subscribe(async (params) => {
|
||||
this.organization = await this.organizationService.get(params.organizationId);
|
||||
const userId = await firstValueFrom(
|
||||
this.accountService.activeAccount$.pipe(map((a) => a?.id)),
|
||||
);
|
||||
this.organization = await firstValueFrom(
|
||||
this.organizationService
|
||||
.organizations$(userId)
|
||||
.pipe(getOrganizationById(params.organizationId)),
|
||||
);
|
||||
this.manageableCiphers = await this.cipherService.getAll();
|
||||
await super.ngOnInit();
|
||||
});
|
||||
|
@ -17,6 +17,7 @@ import { AccountService } from "@bitwarden/common/auth/abstractions/account.serv
|
||||
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
|
||||
import { KeyConnectorService } from "@bitwarden/common/auth/abstractions/key-connector.service";
|
||||
import { AuthenticationStatus } from "@bitwarden/common/auth/enums/authentication-status";
|
||||
import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
||||
import { ProcessReloadServiceAbstraction } from "@bitwarden/common/key-management/abstractions/process-reload.service";
|
||||
import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
@ -219,7 +220,10 @@ export class AppComponent implements OnDestroy, OnInit {
|
||||
break;
|
||||
case "syncOrganizationStatusChanged": {
|
||||
const { organizationId, enabled } = message;
|
||||
const organizations = await firstValueFrom(this.organizationService.organizations$);
|
||||
const userId = await firstValueFrom(getUserId(this.accountService.activeAccount$));
|
||||
const organizations = await firstValueFrom(
|
||||
this.organizationService.organizations$(userId),
|
||||
);
|
||||
const organization = organizations.find((org) => org.id === organizationId);
|
||||
|
||||
if (organization) {
|
||||
@ -227,21 +231,27 @@ export class AppComponent implements OnDestroy, OnInit {
|
||||
...organization,
|
||||
enabled: enabled,
|
||||
};
|
||||
await this.organizationService.upsert(updatedOrganization);
|
||||
await this.organizationService.upsert(updatedOrganization, userId);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "syncOrganizationCollectionSettingChanged": {
|
||||
const { organizationId, limitCollectionCreation, limitCollectionDeletion } = message;
|
||||
const organizations = await firstValueFrom(this.organizationService.organizations$);
|
||||
const userId = await firstValueFrom(getUserId(this.accountService.activeAccount$));
|
||||
const organizations = await firstValueFrom(
|
||||
this.organizationService.organizations$(userId),
|
||||
);
|
||||
const organization = organizations.find((org) => org.id === organizationId);
|
||||
|
||||
if (organization) {
|
||||
await this.organizationService.upsert({
|
||||
...organization,
|
||||
limitCollectionCreation: limitCollectionCreation,
|
||||
limitCollectionDeletion: limitCollectionDeletion,
|
||||
});
|
||||
await this.organizationService.upsert(
|
||||
{
|
||||
...organization,
|
||||
limitCollectionCreation: limitCollectionCreation,
|
||||
limitCollectionDeletion: limitCollectionDeletion,
|
||||
},
|
||||
userId,
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -291,7 +301,7 @@ export class AppComponent implements OnDestroy, OnInit {
|
||||
// will prevent any toasts from being displayed long enough to be read
|
||||
|
||||
await this.eventUploadService.uploadEvents();
|
||||
const userId = await firstValueFrom(this.accountService.activeAccount$.pipe(map((a) => a?.id)));
|
||||
const userId = await firstValueFrom(getUserId(this.accountService.activeAccount$));
|
||||
|
||||
const logoutPromise = firstValueFrom(
|
||||
this.authService.authStatusFor$(userId).pipe(
|
||||
|
@ -1,11 +1,13 @@
|
||||
// FIXME: Update this file to be type safe and remove this and next line
|
||||
// @ts-strict-ignore
|
||||
import { Component, OnInit, ViewChild, ViewContainerRef } from "@angular/core";
|
||||
import { combineLatest, from, lastValueFrom, map, Observable } from "rxjs";
|
||||
import { combineLatest, firstValueFrom, from, lastValueFrom, map, Observable } from "rxjs";
|
||||
|
||||
import { ModalService } from "@bitwarden/angular/services/modal.service";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
||||
import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
import { DialogService } from "@bitwarden/components";
|
||||
@ -33,16 +35,21 @@ export class AccountComponent implements OnInit {
|
||||
private userVerificationService: UserVerificationService,
|
||||
private configService: ConfigService,
|
||||
private organizationService: OrganizationService,
|
||||
private accountService: AccountService,
|
||||
) {}
|
||||
|
||||
async ngOnInit() {
|
||||
const userId = await firstValueFrom(getUserId(this.accountService.activeAccount$));
|
||||
|
||||
const isAccountDeprovisioningEnabled$ = this.configService.getFeatureFlag$(
|
||||
FeatureFlag.AccountDeprovisioning,
|
||||
);
|
||||
|
||||
const userIsManagedByOrganization$ = this.organizationService.organizations$.pipe(
|
||||
map((organizations) => organizations.some((o) => o.userIsManagedByOrganization === true)),
|
||||
);
|
||||
const userIsManagedByOrganization$ = this.organizationService
|
||||
.organizations$(userId)
|
||||
.pipe(
|
||||
map((organizations) => organizations.some((o) => o.userIsManagedByOrganization === true)),
|
||||
);
|
||||
|
||||
const hasMasterPassword$ = from(this.userVerificationService.hasMasterPassword());
|
||||
|
||||
|
@ -9,6 +9,7 @@ import { OrganizationService } from "@bitwarden/common/admin-console/abstraction
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { UpdateProfileRequest } from "@bitwarden/common/auth/models/request/update-profile.request";
|
||||
import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||
import { ProfileResponse } from "@bitwarden/common/models/response/profile.response";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
@ -49,16 +50,21 @@ export class ProfileComponent implements OnInit, OnDestroy {
|
||||
this.fingerprintMaterial = await firstValueFrom(
|
||||
this.accountService.activeAccount$.pipe(map((a) => a?.id)),
|
||||
);
|
||||
|
||||
const userId = await firstValueFrom(getUserId(this.accountService.activeAccount$));
|
||||
|
||||
this.managingOrganization$ = this.configService
|
||||
.getFeatureFlag$(FeatureFlag.AccountDeprovisioning)
|
||||
.pipe(
|
||||
switchMap((isAccountDeprovisioningEnabled) =>
|
||||
isAccountDeprovisioningEnabled
|
||||
? this.organizationService.organizations$.pipe(
|
||||
map((organizations) =>
|
||||
organizations.find((o) => o.userIsManagedByOrganization === true),
|
||||
),
|
||||
)
|
||||
? this.organizationService
|
||||
.organizations$(userId)
|
||||
.pipe(
|
||||
map((organizations) =>
|
||||
organizations.find((o) => o.userIsManagedByOrganization === true),
|
||||
),
|
||||
)
|
||||
: of(null),
|
||||
),
|
||||
);
|
||||
|
@ -12,6 +12,7 @@ import { AccountService } from "@bitwarden/common/auth/abstractions/account.serv
|
||||
import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/auth/abstractions/master-password.service.abstraction";
|
||||
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
||||
import { PasswordRequest } from "@bitwarden/common/auth/models/request/password.request";
|
||||
import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
@ -188,7 +189,7 @@ export class ChangePasswordComponent
|
||||
await this.kdfConfigService.getKdfConfig(),
|
||||
);
|
||||
|
||||
const userId = await firstValueFrom(this.accountService.activeAccount$.pipe(map((a) => a?.id)));
|
||||
const userId = await firstValueFrom(getUserId(this.accountService.activeAccount$));
|
||||
const newLocalKeyHash = await this.keyService.hashMasterKey(
|
||||
this.masterPassword,
|
||||
newMasterKey,
|
||||
|
@ -8,6 +8,7 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { OrganizationManagementPreferencesService } from "@bitwarden/common/admin-console/abstractions/organization-management-preferences/organization-management-preferences.service";
|
||||
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 { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
@ -83,7 +84,8 @@ export class EmergencyAccessComponent implements OnInit {
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
const orgs = await this.organizationService.getAll();
|
||||
const userId = await firstValueFrom(getUserId(this.accountService.activeAccount$));
|
||||
const orgs = await firstValueFrom(this.organizationService.organizations$(userId));
|
||||
this.isOrganizationOwner = orgs.some((o) => o.isOwner);
|
||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
|
@ -43,6 +43,7 @@ describe("EmergencyViewDialogComponent", () => {
|
||||
imports: [EmergencyViewDialogComponent, NoopAnimationsModule],
|
||||
providers: [
|
||||
{ provide: OrganizationService, useValue: mock<OrganizationService>() },
|
||||
{ provide: AccountService, useValue: accountService },
|
||||
{ provide: CollectionService, useValue: mock<CollectionService>() },
|
||||
{ provide: FolderService, useValue: mock<FolderService>() },
|
||||
{ provide: I18nService, useValue: { t: (...keys: string[]) => keys.join(" ") } },
|
||||
|
@ -71,7 +71,7 @@ export class TwoFactorSetupComponent implements OnInit, OnDestroy {
|
||||
protected messagingService: MessagingService,
|
||||
protected policyService: PolicyService,
|
||||
billingAccountProfileStateService: BillingAccountProfileStateService,
|
||||
private accountService: AccountService,
|
||||
protected accountService: AccountService,
|
||||
) {
|
||||
this.canAccessPremium$ = this.accountService.activeAccount$.pipe(
|
||||
switchMap((account) =>
|
||||
|
@ -1,15 +1,35 @@
|
||||
import { inject } from "@angular/core";
|
||||
import { ActivatedRouteSnapshot, CanActivateFn } from "@angular/router";
|
||||
import { firstValueFrom, map } from "rxjs";
|
||||
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import {
|
||||
getOrganizationById,
|
||||
OrganizationService,
|
||||
} from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { ProviderService } from "@bitwarden/common/admin-console/abstractions/provider.service";
|
||||
import { ProviderStatusType } from "@bitwarden/common/admin-console/enums";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
|
||||
export const organizationIsUnmanaged: CanActivateFn = async (route: ActivatedRouteSnapshot) => {
|
||||
const organizationService = inject(OrganizationService);
|
||||
const providerService = inject(ProviderService);
|
||||
const accountService = inject(AccountService);
|
||||
|
||||
const organization = await organizationService.get(route.params.organizationId);
|
||||
const userId = await firstValueFrom(accountService.activeAccount$.pipe(map((a) => a?.id)));
|
||||
|
||||
if (!userId) {
|
||||
throw new Error("No user found.");
|
||||
}
|
||||
|
||||
const organization = await firstValueFrom(
|
||||
organizationService
|
||||
.organizations$(userId)
|
||||
.pipe(getOrganizationById(route.params.organizationId)),
|
||||
);
|
||||
|
||||
if (!organization) {
|
||||
throw new Error("No organization found.");
|
||||
}
|
||||
|
||||
if (!organization.hasProvider) {
|
||||
return true;
|
||||
|
@ -2,11 +2,16 @@
|
||||
// @ts-strict-ignore
|
||||
import { Component, EventEmitter, Input, OnDestroy, OnInit, Output } from "@angular/core";
|
||||
import { FormBuilder, Validators } from "@angular/forms";
|
||||
import { Subject, takeUntil } from "rxjs";
|
||||
import { Subject, firstValueFrom, takeUntil } from "rxjs";
|
||||
|
||||
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction";
|
||||
import { InternalOrganizationServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import {
|
||||
getOrganizationById,
|
||||
InternalOrganizationServiceAbstraction,
|
||||
} from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { OrganizationData } from "@bitwarden/common/admin-console/models/data/organization.data";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
||||
import { OrganizationSubscriptionUpdateRequest } from "@bitwarden/common/billing/models/request/organization-subscription-update.request";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { ToastService } from "@bitwarden/components";
|
||||
@ -37,6 +42,7 @@ export class AdjustSubscription implements OnInit, OnDestroy {
|
||||
private formBuilder: FormBuilder,
|
||||
private toastService: ToastService,
|
||||
private internalOrganizationService: InternalOrganizationServiceAbstraction,
|
||||
private accountService: AccountService,
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
@ -73,14 +79,19 @@ export class AdjustSubscription implements OnInit, OnDestroy {
|
||||
request,
|
||||
);
|
||||
|
||||
const organization = await this.internalOrganizationService.get(this.organizationId);
|
||||
const userId = await firstValueFrom(getUserId(this.accountService.activeAccount$));
|
||||
const organization = await firstValueFrom(
|
||||
this.internalOrganizationService
|
||||
.organizations$(userId)
|
||||
.pipe(getOrganizationById(this.organizationId)),
|
||||
);
|
||||
|
||||
const organizationData = new OrganizationData(response, {
|
||||
isMember: organization.isMember,
|
||||
isProviderUser: organization.isProviderUser,
|
||||
});
|
||||
|
||||
await this.internalOrganizationService.upsert(organizationData);
|
||||
await this.internalOrganizationService.upsert(organizationData, userId);
|
||||
|
||||
this.toastService.showToast({
|
||||
variant: "success",
|
||||
|
@ -13,17 +13,21 @@ import {
|
||||
} from "@angular/core";
|
||||
import { FormBuilder, Validators } from "@angular/forms";
|
||||
import { Router } from "@angular/router";
|
||||
import { Subject, takeUntil } from "rxjs";
|
||||
import { Subject, firstValueFrom, map, takeUntil } from "rxjs";
|
||||
|
||||
import { ManageTaxInformationComponent } from "@bitwarden/angular/billing/components";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import {
|
||||
getOrganizationById,
|
||||
OrganizationService,
|
||||
} from "@bitwarden/common/admin-console/abstractions/organization/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 { OrganizationKeysRequest } from "@bitwarden/common/admin-console/models/request/organization-keys.request";
|
||||
import { OrganizationUpgradeRequest } from "@bitwarden/common/admin-console/models/request/organization-upgrade.request";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import {
|
||||
BillingApiServiceAbstraction,
|
||||
BillingInformation,
|
||||
@ -209,6 +213,7 @@ export class ChangePlanDialogComponent implements OnInit, OnDestroy {
|
||||
private configService: ConfigService,
|
||||
private billingApiService: BillingApiServiceAbstraction,
|
||||
private taxService: TaxServiceAbstraction,
|
||||
private accountService: AccountService,
|
||||
private organizationBillingService: OrganizationBillingService,
|
||||
) {}
|
||||
|
||||
@ -226,7 +231,14 @@ export class ChangePlanDialogComponent implements OnInit, OnDestroy {
|
||||
this.organizationId = this.dialogParams.organizationId;
|
||||
this.currentPlan = this.sub?.plan;
|
||||
this.selectedPlan = this.sub?.plan;
|
||||
this.organization = await this.organizationService.get(this.organizationId);
|
||||
const userId = await firstValueFrom(
|
||||
this.accountService.activeAccount$.pipe(map((a) => a?.id)),
|
||||
);
|
||||
this.organization = await firstValueFrom(
|
||||
this.organizationService
|
||||
.organizations$(userId)
|
||||
.pipe(getOrganizationById(this.organizationId)),
|
||||
);
|
||||
if (this.deprecateStripeSourcesAPI) {
|
||||
const { accountCredit, paymentSource } =
|
||||
await this.billingApiService.getOrganizationPaymentMethod(this.organizationId);
|
||||
|
@ -11,13 +11,16 @@ import {
|
||||
} from "@angular/core";
|
||||
import { FormBuilder, Validators } from "@angular/forms";
|
||||
import { Router } from "@angular/router";
|
||||
import { Subject, takeUntil } from "rxjs";
|
||||
import { debounceTime } from "rxjs/operators";
|
||||
import { Subject, firstValueFrom, takeUntil } from "rxjs";
|
||||
import { debounceTime, map } from "rxjs/operators";
|
||||
|
||||
import { ManageTaxInformationComponent } from "@bitwarden/angular/billing/components";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import {
|
||||
getOrganizationById,
|
||||
OrganizationService,
|
||||
} from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||
import { ProviderApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/provider/provider-api.service.abstraction";
|
||||
import { PolicyType } from "@bitwarden/common/admin-console/enums";
|
||||
@ -27,6 +30,7 @@ import { OrganizationKeysRequest } from "@bitwarden/common/admin-console/models/
|
||||
import { OrganizationUpgradeRequest } from "@bitwarden/common/admin-console/models/request/organization-upgrade.request";
|
||||
import { ProviderOrganizationCreateRequest } from "@bitwarden/common/admin-console/models/request/provider/provider-organization-create.request";
|
||||
import { ProviderResponse } from "@bitwarden/common/admin-console/models/response/provider/provider.response";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { BillingApiServiceAbstraction } from "@bitwarden/common/billing/abstractions";
|
||||
import { TaxServiceAbstraction } from "@bitwarden/common/billing/abstractions/tax.service.abstraction";
|
||||
import { PaymentMethodType, PlanType, ProductTierType } from "@bitwarden/common/billing/enums";
|
||||
@ -179,6 +183,7 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy {
|
||||
private configService: ConfigService,
|
||||
private billingApiService: BillingApiServiceAbstraction,
|
||||
private taxService: TaxServiceAbstraction,
|
||||
private accountService: AccountService,
|
||||
) {
|
||||
this.selfHosted = this.platformUtilsService.isSelfHost();
|
||||
}
|
||||
@ -189,7 +194,14 @@ export class OrganizationPlansComponent implements OnInit, OnDestroy {
|
||||
);
|
||||
|
||||
if (this.organizationId) {
|
||||
this.organization = await this.organizationService.get(this.organizationId);
|
||||
const userId = await firstValueFrom(
|
||||
this.accountService.activeAccount$.pipe(map((a) => a?.id)),
|
||||
);
|
||||
this.organization = await firstValueFrom(
|
||||
this.organizationService
|
||||
.organizations$(userId)
|
||||
.pipe(getOrganizationById(this.organizationId)),
|
||||
);
|
||||
this.billing = await this.organizationApiService.getBilling(this.organizationId);
|
||||
this.sub = await this.organizationApiService.getSubscription(this.organizationId);
|
||||
this.taxInformation = await this.organizationApiService.getTaxInfo(this.organizationId);
|
||||
|
@ -6,9 +6,14 @@ import { firstValueFrom, lastValueFrom, Observable, Subject } from "rxjs";
|
||||
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import {
|
||||
getOrganizationById,
|
||||
OrganizationService,
|
||||
} from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { OrganizationApiKeyType } 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 { getUserId } from "@bitwarden/common/auth/services/account.service";
|
||||
import { BillingApiServiceAbstraction } from "@bitwarden/common/billing/abstractions";
|
||||
import { PlanType, ProductTierType } from "@bitwarden/common/billing/enums";
|
||||
import { OrganizationSubscriptionResponse } from "@bitwarden/common/billing/models/response/organization-subscription.response";
|
||||
@ -76,6 +81,7 @@ export class OrganizationSubscriptionCloudComponent implements OnInit, OnDestroy
|
||||
private i18nService: I18nService,
|
||||
private logService: LogService,
|
||||
private organizationService: OrganizationService,
|
||||
private accountService: AccountService,
|
||||
private organizationApiService: OrganizationApiServiceAbstraction,
|
||||
private route: ActivatedRoute,
|
||||
private dialogService: DialogService,
|
||||
@ -117,7 +123,12 @@ export class OrganizationSubscriptionCloudComponent implements OnInit, OnDestroy
|
||||
async load() {
|
||||
this.loading = true;
|
||||
this.locale = await firstValueFrom(this.i18nService.locale$);
|
||||
this.userOrg = await this.organizationService.get(this.organizationId);
|
||||
const userId = await firstValueFrom(getUserId(this.accountService.activeAccount$));
|
||||
this.userOrg = await firstValueFrom(
|
||||
this.organizationService
|
||||
.organizations$(userId)
|
||||
.pipe(getOrganizationById(this.organizationId)),
|
||||
);
|
||||
|
||||
const isIndependentOrganizationOwner = !this.userOrg.hasProvider && this.userOrg.isOwner;
|
||||
const isResoldOrganizationOwner = this.userOrg.hasReseller && this.userOrg.isOwner;
|
||||
|
@ -7,10 +7,15 @@ import { concatMap, firstValueFrom, Subject, takeUntil } from "rxjs";
|
||||
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import {
|
||||
getOrganizationById,
|
||||
OrganizationService,
|
||||
} from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { OrganizationConnectionType } from "@bitwarden/common/admin-console/enums";
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
import { OrganizationConnectionResponse } from "@bitwarden/common/admin-console/models/response/organization-connection.response";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
||||
import { ProductTierType } from "@bitwarden/common/billing/enums";
|
||||
import { BillingSyncConfigApi } from "@bitwarden/common/billing/models/api/billing-sync-config.api";
|
||||
import { SelfHostedOrganizationSubscriptionView } from "@bitwarden/common/billing/models/view/self-hosted-organization-subscription.view";
|
||||
@ -80,6 +85,7 @@ export class OrganizationSubscriptionSelfhostComponent implements OnInit, OnDest
|
||||
private messagingService: MessagingService,
|
||||
private apiService: ApiService,
|
||||
private organizationService: OrganizationService,
|
||||
private accountService: AccountService,
|
||||
private route: ActivatedRoute,
|
||||
private organizationApiService: OrganizationApiServiceAbstraction,
|
||||
private platformUtilsService: PlatformUtilsService,
|
||||
@ -115,7 +121,12 @@ export class OrganizationSubscriptionSelfhostComponent implements OnInit, OnDest
|
||||
return;
|
||||
}
|
||||
this.loading = true;
|
||||
this.userOrg = await this.organizationService.get(this.organizationId);
|
||||
const userId = await firstValueFrom(getUserId(this.accountService.activeAccount$));
|
||||
this.userOrg = await firstValueFrom(
|
||||
this.organizationService
|
||||
.organizations$(userId)
|
||||
.pipe(getOrganizationById(this.organizationId)),
|
||||
);
|
||||
this.showAutomaticSyncAndManualUpload =
|
||||
this.userOrg.productTierType == ProductTierType.Families ? false : true;
|
||||
if (this.userOrg.canViewSubscription) {
|
||||
|
@ -4,11 +4,15 @@ import { Location } from "@angular/common";
|
||||
import { Component, OnDestroy } from "@angular/core";
|
||||
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
|
||||
import { ActivatedRoute, Router } from "@angular/router";
|
||||
import { from, lastValueFrom, switchMap } from "rxjs";
|
||||
import { firstValueFrom, from, lastValueFrom, map, switchMap } from "rxjs";
|
||||
|
||||
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import {
|
||||
getOrganizationById,
|
||||
OrganizationService,
|
||||
} from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { BillingApiServiceAbstraction } from "@bitwarden/common/billing/abstractions";
|
||||
import { PaymentMethodType } from "@bitwarden/common/billing/enums";
|
||||
import { VerifyBankAccountRequest } from "@bitwarden/common/billing/models/request/verify-bank-account.request";
|
||||
@ -60,6 +64,7 @@ export class OrganizationPaymentMethodComponent implements OnDestroy {
|
||||
private location: Location,
|
||||
private trialFlowService: TrialFlowService,
|
||||
private organizationService: OrganizationService,
|
||||
private accountService: AccountService,
|
||||
protected syncService: SyncService,
|
||||
) {
|
||||
this.activatedRoute.params
|
||||
@ -120,7 +125,14 @@ export class OrganizationPaymentMethodComponent implements OnDestroy {
|
||||
const organizationSubscriptionPromise = this.organizationApiService.getSubscription(
|
||||
this.organizationId,
|
||||
);
|
||||
const organizationPromise = this.organizationService.get(this.organizationId);
|
||||
const userId = await firstValueFrom(
|
||||
this.accountService.activeAccount$.pipe(map((a) => a?.id)),
|
||||
);
|
||||
const organizationPromise = await firstValueFrom(
|
||||
this.organizationService
|
||||
.organizations$(userId)
|
||||
.pipe(getOrganizationById(this.organizationId)),
|
||||
);
|
||||
|
||||
[this.organizationSubscriptionResponse, this.organization] = await Promise.all([
|
||||
organizationSubscriptionPromise,
|
||||
|
@ -2,11 +2,16 @@
|
||||
// @ts-strict-ignore
|
||||
import { Component, EventEmitter, Input, OnDestroy, OnInit, Output } from "@angular/core";
|
||||
import { FormBuilder, Validators } from "@angular/forms";
|
||||
import { Subject, takeUntil } from "rxjs";
|
||||
import { Subject, firstValueFrom, takeUntil } from "rxjs";
|
||||
|
||||
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction";
|
||||
import { InternalOrganizationServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import {
|
||||
getOrganizationById,
|
||||
InternalOrganizationServiceAbstraction,
|
||||
} from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { OrganizationData } from "@bitwarden/common/admin-console/models/data/organization.data";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
||||
import { OrganizationSmSubscriptionUpdateRequest } from "@bitwarden/common/billing/models/request/organization-sm-subscription-update.request";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
@ -107,6 +112,7 @@ export class SecretsManagerAdjustSubscriptionComponent implements OnInit, OnDest
|
||||
private platformUtilsService: PlatformUtilsService,
|
||||
private toastService: ToastService,
|
||||
private internalOrganizationService: InternalOrganizationServiceAbstraction,
|
||||
private accountService: AccountService,
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
@ -165,14 +171,19 @@ export class SecretsManagerAdjustSubscriptionComponent implements OnInit, OnDest
|
||||
request,
|
||||
);
|
||||
|
||||
const organization = await this.internalOrganizationService.get(this.organizationId);
|
||||
const userId = await firstValueFrom(getUserId(this.accountService.activeAccount$));
|
||||
const organization = await firstValueFrom(
|
||||
this.internalOrganizationService
|
||||
.organizations$(userId)
|
||||
.pipe(getOrganizationById(this.organizationId)),
|
||||
);
|
||||
|
||||
const organizationData = new OrganizationData(response, {
|
||||
isMember: organization.isMember,
|
||||
isProviderUser: organization.isProviderUser,
|
||||
});
|
||||
|
||||
await this.internalOrganizationService.upsert(organizationData);
|
||||
await this.internalOrganizationService.upsert(organizationData, userId);
|
||||
|
||||
this.toastService.showToast({
|
||||
variant: "success",
|
||||
|
@ -2,12 +2,15 @@
|
||||
// @ts-strict-ignore
|
||||
import { Component, EventEmitter, Input, Output } from "@angular/core";
|
||||
import { FormBuilder } from "@angular/forms";
|
||||
import { firstValueFrom } from "rxjs";
|
||||
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction";
|
||||
import { InternalOrganizationServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { OrganizationData } from "@bitwarden/common/admin-console/models/data/organization.data";
|
||||
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 { SecretsManagerSubscribeRequest } from "@bitwarden/common/billing/models/request/sm-subscribe.request";
|
||||
import { BillingCustomerDiscount } from "@bitwarden/common/billing/models/response/organization-subscription.response";
|
||||
import { PlanResponse } from "@bitwarden/common/billing/models/response/plan.response";
|
||||
@ -37,6 +40,7 @@ export class SecretsManagerSubscribeStandaloneComponent {
|
||||
private organizationApiService: OrganizationApiServiceAbstraction,
|
||||
private organizationService: InternalOrganizationServiceAbstraction,
|
||||
private toastService: ToastService,
|
||||
private accountService: AccountService,
|
||||
) {}
|
||||
|
||||
submit = async () => {
|
||||
@ -56,7 +60,8 @@ export class SecretsManagerSubscribeStandaloneComponent {
|
||||
isMember: this.organization.isMember,
|
||||
isProviderUser: this.organization.isProviderUser,
|
||||
});
|
||||
await this.organizationService.upsert(organizationData);
|
||||
const userId = await firstValueFrom(getUserId(this.accountService.activeAccount$));
|
||||
await this.organizationService.upsert(organizationData, userId);
|
||||
|
||||
/*
|
||||
Because subscribing to Secrets Manager automatically provides access to Secrets Manager for the
|
||||
|
@ -5,6 +5,7 @@ import { OrganizationService } from "@bitwarden/common/admin-console/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 { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
|
||||
@ -25,15 +26,34 @@ export class FreeFamiliesPolicyService {
|
||||
constructor(
|
||||
private policyService: PolicyService,
|
||||
private organizationService: OrganizationService,
|
||||
private accountService: AccountService,
|
||||
private configService: ConfigService,
|
||||
) {}
|
||||
|
||||
canManageSponsorships$ = this.accountService.activeAccount$.pipe(
|
||||
switchMap((account) => {
|
||||
if (account?.id) {
|
||||
return this.organizationService.canManageSponsorships$(account?.id);
|
||||
} else {
|
||||
return of();
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
organizations$ = this.accountService.activeAccount$.pipe(
|
||||
switchMap((account) => {
|
||||
if (account?.id) {
|
||||
return this.organizationService.organizations$(account?.id);
|
||||
} else {
|
||||
return of();
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
get showFreeFamilies$(): Observable<boolean> {
|
||||
return this.isFreeFamilyFlagEnabled$.pipe(
|
||||
switchMap((isFreeFamilyFlagEnabled) =>
|
||||
isFreeFamilyFlagEnabled
|
||||
? this.getFreeFamiliesVisibility$()
|
||||
: this.organizationService.canManageSponsorships$,
|
||||
isFreeFamilyFlagEnabled ? this.getFreeFamiliesVisibility$() : this.canManageSponsorships$,
|
||||
),
|
||||
);
|
||||
}
|
||||
@ -41,7 +61,7 @@ export class FreeFamiliesPolicyService {
|
||||
private getFreeFamiliesVisibility$(): Observable<boolean> {
|
||||
return combineLatest([
|
||||
this.checkEnterpriseOrganizationsAndFetchPolicy(),
|
||||
this.organizationService.canManageSponsorships$,
|
||||
this.canManageSponsorships$,
|
||||
]).pipe(
|
||||
map(([orgStatus, canManageSponsorships]) =>
|
||||
this.shouldShowFreeFamilyLink(orgStatus, canManageSponsorships),
|
||||
@ -61,7 +81,7 @@ export class FreeFamiliesPolicyService {
|
||||
}
|
||||
|
||||
checkEnterpriseOrganizationsAndFetchPolicy(): Observable<EnterpriseOrgStatus> {
|
||||
return this.organizationService.organizations$.pipe(
|
||||
return this.organizations$.pipe(
|
||||
filter((organizations) => Array.isArray(organizations) && organizations.length > 0),
|
||||
switchMap((organizations) => this.fetchEnterpriseOrganizationPolicy(organizations)),
|
||||
);
|
||||
|
@ -19,6 +19,7 @@ import { PolicyService } from "@bitwarden/common/admin-console/abstractions/poli
|
||||
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 { getUserId } from "@bitwarden/common/auth/services/account.service";
|
||||
import { PlanSponsorshipType } from "@bitwarden/common/billing/enums";
|
||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
@ -90,11 +91,13 @@ export class SponsoredFamiliesComponent implements OnInit, OnDestroy {
|
||||
FeatureFlag.DisableFreeFamiliesSponsorship,
|
||||
);
|
||||
|
||||
const userId = await firstValueFrom(getUserId(this.accountService.activeAccount$));
|
||||
|
||||
if (this.isFreeFamilyFlagEnabled) {
|
||||
await this.preventAccessToFreeFamiliesPage();
|
||||
|
||||
this.availableSponsorshipOrgs$ = combineLatest([
|
||||
this.organizationService.organizations$,
|
||||
this.organizationService.organizations$(userId),
|
||||
this.policyService.getAll$(PolicyType.FreeFamiliesSponsorshipPolicy),
|
||||
]).pipe(
|
||||
map(([organizations, policies]) =>
|
||||
@ -111,9 +114,9 @@ export class SponsoredFamiliesComponent implements OnInit, OnDestroy {
|
||||
),
|
||||
);
|
||||
} else {
|
||||
this.availableSponsorshipOrgs$ = this.organizationService.organizations$.pipe(
|
||||
map((orgs) => orgs.filter((o) => o.familySponsorshipAvailable)),
|
||||
);
|
||||
this.availableSponsorshipOrgs$ = this.organizationService
|
||||
.organizations$(userId)
|
||||
.pipe(map((orgs) => orgs.filter((o) => o.familySponsorshipAvailable)));
|
||||
}
|
||||
|
||||
this.availableSponsorshipOrgs$.pipe(takeUntil(this._destroy)).subscribe((orgs) => {
|
||||
@ -126,9 +129,9 @@ export class SponsoredFamiliesComponent implements OnInit, OnDestroy {
|
||||
|
||||
this.anyOrgsAvailable$ = this.availableSponsorshipOrgs$.pipe(map((orgs) => orgs.length > 0));
|
||||
|
||||
this.activeSponsorshipOrgs$ = this.organizationService.organizations$.pipe(
|
||||
map((orgs) => orgs.filter((o) => o.familySponsorshipFriendlyName !== null)),
|
||||
);
|
||||
this.activeSponsorshipOrgs$ = this.organizationService
|
||||
.organizations$(userId)
|
||||
.pipe(map((orgs) => orgs.filter((o) => o.familySponsorshipFriendlyName !== null)));
|
||||
|
||||
this.anyActiveSponsorships$ = this.activeSponsorshipOrgs$.pipe(map((orgs) => orgs.length > 0));
|
||||
|
||||
|
@ -6,7 +6,10 @@ import { FormControl, FormGroup, Validators } from "@angular/forms";
|
||||
import { firstValueFrom, map } from "rxjs";
|
||||
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import {
|
||||
getOrganizationById,
|
||||
OrganizationService,
|
||||
} from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { PaymentMethodType } from "@bitwarden/common/billing/enums";
|
||||
import { BitPayInvoiceRequest } from "@bitwarden/common/billing/models/request/bit-pay-invoice.request";
|
||||
@ -77,7 +80,14 @@ export class AddCreditDialogComponent implements OnInit {
|
||||
this.creditAmount = "20.00";
|
||||
}
|
||||
this.ppButtonCustomField = "organization_id:" + this.organizationId;
|
||||
const org = await this.organizationService.get(this.organizationId);
|
||||
const userId = await firstValueFrom(
|
||||
this.accountService.activeAccount$.pipe(map((a) => a?.id)),
|
||||
);
|
||||
const org = await firstValueFrom(
|
||||
this.organizationService
|
||||
.organizations$(userId)
|
||||
.pipe(getOrganizationById(this.organizationId)),
|
||||
);
|
||||
if (org != null) {
|
||||
this.subject = org.name;
|
||||
this.name = org.name;
|
||||
|
@ -4,12 +4,16 @@ import { Location } from "@angular/common";
|
||||
import { Component, OnDestroy, OnInit } from "@angular/core";
|
||||
import { FormBuilder, FormControl, Validators } from "@angular/forms";
|
||||
import { ActivatedRoute, Router } from "@angular/router";
|
||||
import { lastValueFrom } from "rxjs";
|
||||
import { firstValueFrom, lastValueFrom, map } from "rxjs";
|
||||
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import {
|
||||
getOrganizationById,
|
||||
OrganizationService,
|
||||
} from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { PaymentMethodType } from "@bitwarden/common/billing/enums";
|
||||
import { BillingPaymentResponse } from "@bitwarden/common/billing/models/response/billing-payment.response";
|
||||
import { OrganizationSubscriptionResponse } from "@bitwarden/common/billing/models/response/organization-subscription.response";
|
||||
@ -73,6 +77,7 @@ export class PaymentMethodComponent implements OnInit, OnDestroy {
|
||||
private toastService: ToastService,
|
||||
private trialFlowService: TrialFlowService,
|
||||
private organizationService: OrganizationService,
|
||||
private accountService: AccountService,
|
||||
protected syncService: SyncService,
|
||||
) {
|
||||
const state = this.router.getCurrentNavigation()?.extras?.state;
|
||||
@ -117,7 +122,14 @@ export class PaymentMethodComponent implements OnInit, OnDestroy {
|
||||
const organizationSubscriptionPromise = this.organizationApiService.getSubscription(
|
||||
this.organizationId,
|
||||
);
|
||||
const organizationPromise = this.organizationService.get(this.organizationId);
|
||||
const userId = await firstValueFrom(
|
||||
this.accountService.activeAccount$.pipe(map((a) => a?.id)),
|
||||
);
|
||||
const organizationPromise = await firstValueFrom(
|
||||
this.organizationService
|
||||
.organizations$(userId)
|
||||
.pipe(getOrganizationById(this.organizationId)),
|
||||
);
|
||||
|
||||
[this.billing, this.org, this.organization] = await Promise.all([
|
||||
billingPromise,
|
||||
|
@ -3,11 +3,12 @@
|
||||
import { CommonModule } from "@angular/common";
|
||||
import { Component, EventEmitter, Input, Output } from "@angular/core";
|
||||
import { ActivatedRoute } from "@angular/router";
|
||||
import { combineLatest, map, Observable } from "rxjs";
|
||||
import { combineLatest, map, Observable, switchMap } from "rxjs";
|
||||
|
||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import type { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { BillingApiServiceAbstraction } from "@bitwarden/common/billing/abstractions/billing-api.service.abstraction";
|
||||
import { DialogService, NavigationModule } from "@bitwarden/components";
|
||||
|
||||
@ -20,12 +21,17 @@ import { TrialFlowService } from "./../../billing/services/trial-flow.service";
|
||||
imports: [CommonModule, JslibModule, NavigationModule],
|
||||
})
|
||||
export class OrgSwitcherComponent {
|
||||
protected organizations$: Observable<Organization[]> =
|
||||
this.organizationService.organizations$.pipe(
|
||||
map((orgs) =>
|
||||
orgs.filter((org) => this.filter(org)).sort((a, b) => a.name.localeCompare(b.name)),
|
||||
),
|
||||
);
|
||||
protected organizations$: Observable<Organization[]> = this.accountService.activeAccount$.pipe(
|
||||
switchMap((account) =>
|
||||
this.organizationService
|
||||
.organizations$(account?.id)
|
||||
.pipe(
|
||||
map((orgs) =>
|
||||
orgs.filter((org) => this.filter(org)).sort((a, b) => a.name.localeCompare(b.name)),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
protected activeOrganization$: Observable<Organization> = combineLatest([
|
||||
this.route.paramMap,
|
||||
@ -61,6 +67,7 @@ export class OrgSwitcherComponent {
|
||||
private organizationService: OrganizationService,
|
||||
private trialFlowService: TrialFlowService,
|
||||
protected billingApiService: BillingApiServiceAbstraction,
|
||||
private accountService: AccountService,
|
||||
) {}
|
||||
|
||||
protected toggle(event?: MouseEvent) {
|
||||
|
@ -1,15 +1,17 @@
|
||||
import { Component, Directive, importProvidersFrom, Input } from "@angular/core";
|
||||
import { RouterModule } from "@angular/router";
|
||||
import { applicationConfig, Meta, moduleMetadata, StoryObj } from "@storybook/angular";
|
||||
import { BehaviorSubject, firstValueFrom } from "rxjs";
|
||||
import { BehaviorSubject, firstValueFrom, Observable, of } from "rxjs";
|
||||
|
||||
import { I18nPipe } from "@bitwarden/angular/platform/pipes/i18n.pipe";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { ProviderService } from "@bitwarden/common/admin-console/abstractions/provider.service";
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
import { Provider } from "@bitwarden/common/admin-console/models/domain/provider";
|
||||
import { AccountService, Account } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { SyncService } from "@bitwarden/common/platform/sync";
|
||||
import { UserId } from "@bitwarden/common/types/guid";
|
||||
import { LayoutComponent, NavigationModule } from "@bitwarden/components";
|
||||
import { I18nMockService } from "@bitwarden/components/src/utils/i18n-mock.service";
|
||||
|
||||
@ -22,11 +24,14 @@ import { NavigationProductSwitcherComponent } from "./navigation-switcher.compon
|
||||
})
|
||||
class MockOrganizationService implements Partial<OrganizationService> {
|
||||
private static _orgs = new BehaviorSubject<Organization[]>([]);
|
||||
organizations$ = MockOrganizationService._orgs; // eslint-disable-line rxjs/no-exposed-subjects
|
||||
|
||||
organizations$(): Observable<Organization[]> {
|
||||
return MockOrganizationService._orgs.asObservable();
|
||||
}
|
||||
|
||||
@Input()
|
||||
set mockOrgs(orgs: Organization[]) {
|
||||
this.organizations$.next(orgs);
|
||||
MockOrganizationService._orgs.next(orgs);
|
||||
}
|
||||
}
|
||||
|
||||
@ -52,6 +57,15 @@ class MockSyncService implements Partial<SyncService> {
|
||||
}
|
||||
}
|
||||
|
||||
class MockAccountService implements Partial<AccountService> {
|
||||
activeAccount$?: Observable<Account> = of({
|
||||
id: "test-user-id" as UserId,
|
||||
name: "Test User 1",
|
||||
email: "test@email.com",
|
||||
emailVerified: true,
|
||||
});
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: "story-layout",
|
||||
template: `<ng-content></ng-content>`,
|
||||
@ -86,6 +100,7 @@ export default {
|
||||
imports: [NavigationModule, RouterModule, LayoutComponent],
|
||||
providers: [
|
||||
{ provide: OrganizationService, useClass: MockOrganizationService },
|
||||
{ provide: AccountService, useClass: MockAccountService },
|
||||
{ provide: ProviderService, useClass: MockProviderService },
|
||||
{ provide: SyncService, useClass: MockSyncService },
|
||||
ProductSwitcherService,
|
||||
|
@ -1,15 +1,17 @@
|
||||
import { Component, Directive, importProvidersFrom, Input } from "@angular/core";
|
||||
import { RouterModule } from "@angular/router";
|
||||
import { applicationConfig, Meta, moduleMetadata, StoryObj } from "@storybook/angular";
|
||||
import { BehaviorSubject, firstValueFrom } from "rxjs";
|
||||
import { BehaviorSubject, firstValueFrom, Observable, of } from "rxjs";
|
||||
|
||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { ProviderService } from "@bitwarden/common/admin-console/abstractions/provider.service";
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
import { Provider } from "@bitwarden/common/admin-console/models/domain/provider";
|
||||
import { AccountService, Account } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { SyncService } from "@bitwarden/common/platform/sync";
|
||||
import { UserId } from "@bitwarden/common/types/guid";
|
||||
import { IconButtonModule, LinkModule, MenuModule } from "@bitwarden/components";
|
||||
import { I18nMockService } from "@bitwarden/components/src/utils/i18n-mock.service";
|
||||
|
||||
@ -22,11 +24,14 @@ import { ProductSwitcherService } from "./shared/product-switcher.service";
|
||||
})
|
||||
class MockOrganizationService implements Partial<OrganizationService> {
|
||||
private static _orgs = new BehaviorSubject<Organization[]>([]);
|
||||
organizations$ = MockOrganizationService._orgs; // eslint-disable-line rxjs/no-exposed-subjects
|
||||
|
||||
organizations$(): Observable<Organization[]> {
|
||||
return MockOrganizationService._orgs.asObservable();
|
||||
}
|
||||
|
||||
@Input()
|
||||
set mockOrgs(orgs: Organization[]) {
|
||||
this.organizations$.next(orgs);
|
||||
MockOrganizationService._orgs.next(orgs);
|
||||
}
|
||||
}
|
||||
|
||||
@ -52,6 +57,15 @@ class MockSyncService implements Partial<SyncService> {
|
||||
}
|
||||
}
|
||||
|
||||
class MockAccountService implements Partial<AccountService> {
|
||||
activeAccount$?: Observable<Account> = of({
|
||||
id: "test-user-id" as UserId,
|
||||
name: "Test User 1",
|
||||
email: "test@email.com",
|
||||
emailVerified: true,
|
||||
});
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: "story-layout",
|
||||
template: `<ng-content></ng-content>`,
|
||||
@ -78,6 +92,8 @@ export default {
|
||||
],
|
||||
imports: [JslibModule, MenuModule, IconButtonModule, LinkModule, RouterModule],
|
||||
providers: [
|
||||
{ provide: AccountService, useClass: MockAccountService },
|
||||
MockAccountService,
|
||||
{ provide: OrganizationService, useClass: MockOrganizationService },
|
||||
MockOrganizationService,
|
||||
{ provide: ProviderService, useClass: MockProviderService },
|
||||
@ -134,7 +150,9 @@ export default {
|
||||
],
|
||||
} as Meta<ProductSwitcherComponent>;
|
||||
|
||||
type Story = StoryObj<ProductSwitcherComponent & MockProviderService & MockOrganizationService>;
|
||||
type Story = StoryObj<
|
||||
ProductSwitcherComponent & MockProviderService & MockOrganizationService & MockAccountService
|
||||
>;
|
||||
|
||||
const Template: Story = {
|
||||
render: (args) => ({
|
||||
|
@ -10,7 +10,11 @@ import { OrganizationService } from "@bitwarden/common/admin-console/abstraction
|
||||
import { ProviderService } from "@bitwarden/common/admin-console/abstractions/provider.service";
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
import { Provider } from "@bitwarden/common/admin-console/models/domain/provider";
|
||||
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 { FakeAccountService, mockAccountServiceWith } from "@bitwarden/common/spec";
|
||||
import { UserId } from "@bitwarden/common/types/guid";
|
||||
|
||||
import { ProductSwitcherService } from "./product-switcher.service";
|
||||
|
||||
@ -19,8 +23,10 @@ describe("ProductSwitcherService", () => {
|
||||
let router: { url: string; events: Observable<unknown> };
|
||||
let organizationService: MockProxy<OrganizationService>;
|
||||
let providerService: MockProxy<ProviderService>;
|
||||
let accountService: FakeAccountService;
|
||||
let activeRouteParams = convertToParamMap({ organizationId: "1234" });
|
||||
const getLastSync = jest.fn().mockResolvedValue(new Date("2024-05-14"));
|
||||
const userId = Utils.newGuid() as UserId;
|
||||
|
||||
// The service is dependent on the SyncService, which is behind a `setTimeout`
|
||||
// Most of the tests don't need to test this aspect so `advanceTimersByTime`
|
||||
@ -36,10 +42,11 @@ describe("ProductSwitcherService", () => {
|
||||
router = mock<Router>();
|
||||
organizationService = mock<OrganizationService>();
|
||||
providerService = mock<ProviderService>();
|
||||
accountService = mockAccountServiceWith(userId);
|
||||
|
||||
router.url = "/";
|
||||
router.events = of({});
|
||||
organizationService.organizations$ = of([{}] as Organization[]);
|
||||
organizationService.organizations$.mockReturnValue(of([{}] as Organization[]));
|
||||
providerService.getAll.mockResolvedValue([] as Provider[]);
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
@ -47,6 +54,7 @@ describe("ProductSwitcherService", () => {
|
||||
{ provide: Router, useValue: router },
|
||||
{ provide: OrganizationService, useValue: organizationService },
|
||||
{ provide: ProviderService, useValue: providerService },
|
||||
{ provide: AccountService, useValue: accountService },
|
||||
{
|
||||
provide: ActivatedRoute,
|
||||
useValue: {
|
||||
@ -111,13 +119,15 @@ describe("ProductSwitcherService", () => {
|
||||
});
|
||||
|
||||
it("is included in bento when there is an organization with SM", async () => {
|
||||
organizationService.organizations$ = of([
|
||||
{
|
||||
id: "1234",
|
||||
canAccessSecretsManager: true,
|
||||
enabled: true,
|
||||
},
|
||||
] as Organization[]);
|
||||
organizationService.organizations$.mockReturnValue(
|
||||
of([
|
||||
{
|
||||
id: "1234",
|
||||
canAccessSecretsManager: true,
|
||||
enabled: true,
|
||||
},
|
||||
] as Organization[]),
|
||||
);
|
||||
|
||||
initiateService();
|
||||
|
||||
@ -138,7 +148,9 @@ describe("ProductSwitcherService", () => {
|
||||
});
|
||||
|
||||
it("includes Admin Console in bento when a user has access to it", async () => {
|
||||
organizationService.organizations$ = of([{ id: "1234", isOwner: true }] as Organization[]);
|
||||
organizationService.organizations$.mockReturnValue(
|
||||
of([{ id: "1234", isOwner: true }] as Organization[]),
|
||||
);
|
||||
|
||||
initiateService();
|
||||
|
||||
@ -194,7 +206,9 @@ describe("ProductSwitcherService", () => {
|
||||
});
|
||||
|
||||
it("marks Admin Console as active", async () => {
|
||||
organizationService.organizations$ = of([{ id: "1234", isOwner: true }] as Organization[]);
|
||||
organizationService.organizations$.mockReturnValue(
|
||||
of([{ id: "1234", isOwner: true }] as Organization[]),
|
||||
);
|
||||
activeRouteParams = convertToParamMap({ organizationId: "1" });
|
||||
router.url = "/organizations/";
|
||||
|
||||
@ -225,20 +239,22 @@ describe("ProductSwitcherService", () => {
|
||||
it("updates secrets manager path when the org id is found in the path", async () => {
|
||||
router.url = "/sm/4243";
|
||||
|
||||
organizationService.organizations$ = of([
|
||||
{
|
||||
id: "23443234",
|
||||
canAccessSecretsManager: true,
|
||||
enabled: true,
|
||||
name: "Org 2",
|
||||
},
|
||||
{
|
||||
id: "4243",
|
||||
canAccessSecretsManager: true,
|
||||
enabled: true,
|
||||
name: "Org 32",
|
||||
},
|
||||
] as Organization[]);
|
||||
organizationService.organizations$.mockReturnValue(
|
||||
of([
|
||||
{
|
||||
id: "23443234",
|
||||
canAccessSecretsManager: true,
|
||||
enabled: true,
|
||||
name: "Org 2",
|
||||
},
|
||||
{
|
||||
id: "4243",
|
||||
canAccessSecretsManager: true,
|
||||
enabled: true,
|
||||
name: "Org 32",
|
||||
},
|
||||
] as Organization[]),
|
||||
);
|
||||
|
||||
initiateService();
|
||||
|
||||
@ -253,10 +269,12 @@ describe("ProductSwitcherService", () => {
|
||||
it("updates admin console path when the org id is found in the path", async () => {
|
||||
router.url = "/organizations/111-22-33";
|
||||
|
||||
organizationService.organizations$ = of([
|
||||
{ id: "111-22-33", isOwner: true, name: "Test Org" },
|
||||
{ id: "4243", isOwner: true, name: "My Org" },
|
||||
] as Organization[]);
|
||||
organizationService.organizations$.mockReturnValue(
|
||||
of([
|
||||
{ id: "111-22-33", isOwner: true, name: "Test Org" },
|
||||
{ id: "4243", isOwner: true, name: "My Org" },
|
||||
] as Organization[]),
|
||||
);
|
||||
|
||||
initiateService();
|
||||
|
||||
|
@ -2,7 +2,16 @@
|
||||
// @ts-strict-ignore
|
||||
import { Injectable } from "@angular/core";
|
||||
import { ActivatedRoute, NavigationEnd, NavigationStart, ParamMap, Router } from "@angular/router";
|
||||
import { combineLatest, concatMap, filter, map, Observable, ReplaySubject, startWith } from "rxjs";
|
||||
import {
|
||||
combineLatest,
|
||||
concatMap,
|
||||
filter,
|
||||
map,
|
||||
Observable,
|
||||
ReplaySubject,
|
||||
startWith,
|
||||
switchMap,
|
||||
} from "rxjs";
|
||||
|
||||
import { I18nPipe } from "@bitwarden/angular/platform/pipes/i18n.pipe";
|
||||
import {
|
||||
@ -11,6 +20,7 @@ import {
|
||||
} from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { ProviderService } from "@bitwarden/common/admin-console/abstractions/provider.service";
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { SyncService } from "@bitwarden/common/platform/sync";
|
||||
|
||||
export type ProductSwitcherItem = {
|
||||
@ -90,18 +100,20 @@ export class ProductSwitcherService {
|
||||
private router: Router,
|
||||
private i18n: I18nPipe,
|
||||
private syncService: SyncService,
|
||||
private accountService: AccountService,
|
||||
) {
|
||||
this.pollUntilSynced();
|
||||
}
|
||||
|
||||
organizations$ = this.accountService.activeAccount$.pipe(
|
||||
map((a) => a?.id),
|
||||
switchMap((id) => this.organizationService.organizations$(id)),
|
||||
);
|
||||
|
||||
products$: Observable<{
|
||||
bento: ProductSwitcherItem[];
|
||||
other: ProductSwitcherItem[];
|
||||
}> = combineLatest([
|
||||
this.organizationService.organizations$,
|
||||
this.route.paramMap,
|
||||
this.triggerProductUpdate$,
|
||||
]).pipe(
|
||||
}> = combineLatest([this.organizations$, this.route.paramMap, this.triggerProductUpdate$]).pipe(
|
||||
map(([orgs, ...rest]): [Organization[], ParamMap, void] => {
|
||||
return [
|
||||
// Sort orgs by name to match the order within the sidebar
|
||||
|
@ -3,9 +3,12 @@
|
||||
import { Component, OnInit } from "@angular/core";
|
||||
import { FormControl, FormGroup, Validators } from "@angular/forms";
|
||||
import { Router } from "@angular/router";
|
||||
import { firstValueFrom } from "rxjs";
|
||||
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/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 { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { Guid } from "@bitwarden/common/types/guid";
|
||||
import { NoItemsModule, SearchModule, ToastService } from "@bitwarden/components";
|
||||
@ -39,10 +42,12 @@ export class RequestSMAccessComponent implements OnInit {
|
||||
private organizationService: OrganizationService,
|
||||
private smLandingApiService: SmLandingApiService,
|
||||
private toastService: ToastService,
|
||||
private accountService: AccountService,
|
||||
) {}
|
||||
|
||||
async ngOnInit() {
|
||||
this.organizations = (await this.organizationService.getAll())
|
||||
const userId = await firstValueFrom(getUserId(this.accountService.activeAccount$));
|
||||
this.organizations = (await firstValueFrom(this.organizationService.organizations$(userId)))
|
||||
.filter((e) => e.enabled)
|
||||
.sort((a, b) => a.name.localeCompare(b.name));
|
||||
|
||||
|
@ -1,9 +1,12 @@
|
||||
// FIXME: Update this file to be type safe and remove this and next line
|
||||
// @ts-strict-ignore
|
||||
import { Component, OnInit } from "@angular/core";
|
||||
import { firstValueFrom } from "rxjs";
|
||||
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/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 { NoItemsModule, SearchModule } from "@bitwarden/components";
|
||||
|
||||
import { HeaderModule } from "../../layouts/header/header.module";
|
||||
@ -22,10 +25,16 @@ export class SMLandingComponent implements OnInit {
|
||||
showSecretsManagerInformation: boolean = true;
|
||||
showGiveMembersAccessInstructions: boolean = false;
|
||||
|
||||
constructor(private organizationService: OrganizationService) {}
|
||||
constructor(
|
||||
private organizationService: OrganizationService,
|
||||
private accountService: AccountService,
|
||||
) {}
|
||||
|
||||
async ngOnInit() {
|
||||
const enabledOrganizations = (await this.organizationService.getAll()).filter((e) => e.enabled);
|
||||
const userId = await firstValueFrom(getUserId(this.accountService.activeAccount$));
|
||||
const enabledOrganizations = (
|
||||
await firstValueFrom(this.organizationService.organizations$(userId))
|
||||
).filter((e) => e.enabled);
|
||||
|
||||
if (enabledOrganizations.length > 0) {
|
||||
this.handleEnabledOrganizations(enabledOrganizations);
|
||||
|
@ -1,11 +1,12 @@
|
||||
// FIXME: Update this file to be type safe and remove this and next line
|
||||
// @ts-strict-ignore
|
||||
import { Directive, ViewChild, ViewContainerRef, OnDestroy } from "@angular/core";
|
||||
import { BehaviorSubject, Observable, Subject, takeUntil } from "rxjs";
|
||||
import { BehaviorSubject, Observable, Subject, switchMap, takeUntil } from "rxjs";
|
||||
|
||||
import { ModalService } from "@bitwarden/angular/services/modal.service";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { OrganizationId } from "@bitwarden/common/types/guid";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
@ -45,10 +46,13 @@ export class CipherReportComponent implements OnDestroy {
|
||||
private modalService: ModalService,
|
||||
protected passwordRepromptService: PasswordRepromptService,
|
||||
protected organizationService: OrganizationService,
|
||||
protected accountService: AccountService,
|
||||
protected i18nService: I18nService,
|
||||
private syncService: SyncService,
|
||||
) {
|
||||
this.organizations$ = this.organizationService.organizations$;
|
||||
this.organizations$ = this.accountService.activeAccount$.pipe(
|
||||
switchMap((account) => this.organizationService.organizations$(account?.id)),
|
||||
);
|
||||
this.organizations$.pipe(takeUntil(this.destroyed$)).subscribe((orgs) => {
|
||||
this.organizations = orgs;
|
||||
});
|
||||
|
@ -7,7 +7,11 @@ import { I18nPipe } from "@bitwarden/angular/platform/pipes/i18n.pipe";
|
||||
import { ModalService } from "@bitwarden/angular/services/modal.service";
|
||||
import { AuditService } from "@bitwarden/common/abstractions/audit.service";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { FakeAccountService, mockAccountServiceWith } from "@bitwarden/common/spec";
|
||||
import { UserId } from "@bitwarden/common/types/guid";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
|
||||
import { PasswordRepromptService } from "@bitwarden/vault";
|
||||
@ -21,12 +25,15 @@ describe("ExposedPasswordsReportComponent", () => {
|
||||
let auditService: MockProxy<AuditService>;
|
||||
let organizationService: MockProxy<OrganizationService>;
|
||||
let syncServiceMock: MockProxy<SyncService>;
|
||||
let accountService: FakeAccountService;
|
||||
const userId = Utils.newGuid() as UserId;
|
||||
|
||||
beforeEach(() => {
|
||||
syncServiceMock = mock<SyncService>();
|
||||
auditService = mock<AuditService>();
|
||||
organizationService = mock<OrganizationService>();
|
||||
organizationService.organizations$ = of([]);
|
||||
organizationService.organizations$.mockReturnValue(of([]));
|
||||
accountService = mockAccountServiceWith(userId);
|
||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
TestBed.configureTestingModule({
|
||||
@ -44,6 +51,10 @@ describe("ExposedPasswordsReportComponent", () => {
|
||||
provide: OrganizationService,
|
||||
useValue: organizationService,
|
||||
},
|
||||
{
|
||||
provide: AccountService,
|
||||
useValue: accountService,
|
||||
},
|
||||
{
|
||||
provide: ModalService,
|
||||
useValue: mock<ModalService>(),
|
||||
|
@ -3,6 +3,7 @@ import { Component, OnInit } from "@angular/core";
|
||||
import { ModalService } from "@bitwarden/angular/services/modal.service";
|
||||
import { AuditService } from "@bitwarden/common/abstractions/audit.service";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
|
||||
@ -25,6 +26,7 @@ export class ExposedPasswordsReportComponent extends CipherReportComponent imple
|
||||
protected cipherService: CipherService,
|
||||
protected auditService: AuditService,
|
||||
protected organizationService: OrganizationService,
|
||||
accountService: AccountService,
|
||||
modalService: ModalService,
|
||||
passwordRepromptService: PasswordRepromptService,
|
||||
i18nService: I18nService,
|
||||
@ -35,6 +37,7 @@ export class ExposedPasswordsReportComponent extends CipherReportComponent imple
|
||||
modalService,
|
||||
passwordRepromptService,
|
||||
organizationService,
|
||||
accountService,
|
||||
i18nService,
|
||||
syncService,
|
||||
);
|
||||
|
@ -6,8 +6,12 @@ import { of } from "rxjs";
|
||||
import { I18nPipe } from "@bitwarden/angular/platform/pipes/i18n.pipe";
|
||||
import { ModalService } from "@bitwarden/angular/services/modal.service";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { FakeAccountService, mockAccountServiceWith } from "@bitwarden/common/spec";
|
||||
import { UserId } from "@bitwarden/common/types/guid";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
|
||||
import { PasswordRepromptService } from "@bitwarden/vault";
|
||||
@ -20,11 +24,14 @@ describe("InactiveTwoFactorReportComponent", () => {
|
||||
let fixture: ComponentFixture<InactiveTwoFactorReportComponent>;
|
||||
let organizationService: MockProxy<OrganizationService>;
|
||||
let syncServiceMock: MockProxy<SyncService>;
|
||||
let accountService: FakeAccountService;
|
||||
const userId = Utils.newGuid() as UserId;
|
||||
|
||||
beforeEach(() => {
|
||||
organizationService = mock<OrganizationService>();
|
||||
organizationService.organizations$ = of([]);
|
||||
organizationService.organizations$.mockReturnValue(of([]));
|
||||
syncServiceMock = mock<SyncService>();
|
||||
accountService = mockAccountServiceWith(userId);
|
||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
TestBed.configureTestingModule({
|
||||
@ -38,6 +45,10 @@ describe("InactiveTwoFactorReportComponent", () => {
|
||||
provide: OrganizationService,
|
||||
useValue: organizationService,
|
||||
},
|
||||
{
|
||||
provide: AccountService,
|
||||
useValue: accountService,
|
||||
},
|
||||
{
|
||||
provide: ModalService,
|
||||
useValue: mock<ModalService>(),
|
||||
|
@ -4,6 +4,7 @@ import { Component, OnInit } from "@angular/core";
|
||||
|
||||
import { ModalService } from "@bitwarden/angular/services/modal.service";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
@ -27,6 +28,7 @@ export class InactiveTwoFactorReportComponent extends CipherReportComponent impl
|
||||
constructor(
|
||||
protected cipherService: CipherService,
|
||||
protected organizationService: OrganizationService,
|
||||
accountService: AccountService,
|
||||
modalService: ModalService,
|
||||
private logService: LogService,
|
||||
passwordRepromptService: PasswordRepromptService,
|
||||
@ -38,6 +40,7 @@ export class InactiveTwoFactorReportComponent extends CipherReportComponent impl
|
||||
modalService,
|
||||
passwordRepromptService,
|
||||
organizationService,
|
||||
accountService,
|
||||
i18nService,
|
||||
syncService,
|
||||
);
|
||||
|
@ -6,7 +6,11 @@ import { of } from "rxjs";
|
||||
import { I18nPipe } from "@bitwarden/angular/platform/pipes/i18n.pipe";
|
||||
import { ModalService } from "@bitwarden/angular/services/modal.service";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { FakeAccountService, mockAccountServiceWith } from "@bitwarden/common/spec";
|
||||
import { UserId } from "@bitwarden/common/types/guid";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
|
||||
import { PasswordRepromptService } from "@bitwarden/vault";
|
||||
@ -19,11 +23,15 @@ describe("ReusedPasswordsReportComponent", () => {
|
||||
let fixture: ComponentFixture<ReusedPasswordsReportComponent>;
|
||||
let organizationService: MockProxy<OrganizationService>;
|
||||
let syncServiceMock: MockProxy<SyncService>;
|
||||
let accountService: FakeAccountService;
|
||||
const userId = Utils.newGuid() as UserId;
|
||||
|
||||
beforeEach(() => {
|
||||
organizationService = mock<OrganizationService>();
|
||||
organizationService.organizations$ = of([]);
|
||||
organizationService.organizations$.mockReturnValue(of([]));
|
||||
syncServiceMock = mock<SyncService>();
|
||||
accountService = mockAccountServiceWith(userId);
|
||||
|
||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
TestBed.configureTestingModule({
|
||||
@ -37,6 +45,10 @@ describe("ReusedPasswordsReportComponent", () => {
|
||||
provide: OrganizationService,
|
||||
useValue: organizationService,
|
||||
},
|
||||
{
|
||||
provide: AccountService,
|
||||
useValue: accountService,
|
||||
},
|
||||
{
|
||||
provide: ModalService,
|
||||
useValue: mock<ModalService>(),
|
||||
|
@ -4,6 +4,7 @@ import { Component, OnInit } from "@angular/core";
|
||||
|
||||
import { ModalService } from "@bitwarden/angular/services/modal.service";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
|
||||
@ -24,6 +25,7 @@ export class ReusedPasswordsReportComponent extends CipherReportComponent implem
|
||||
constructor(
|
||||
protected cipherService: CipherService,
|
||||
protected organizationService: OrganizationService,
|
||||
accountService: AccountService,
|
||||
modalService: ModalService,
|
||||
passwordRepromptService: PasswordRepromptService,
|
||||
i18nService: I18nService,
|
||||
@ -34,6 +36,7 @@ export class ReusedPasswordsReportComponent extends CipherReportComponent implem
|
||||
modalService,
|
||||
passwordRepromptService,
|
||||
organizationService,
|
||||
accountService,
|
||||
i18nService,
|
||||
syncService,
|
||||
);
|
||||
|
@ -7,7 +7,11 @@ import { CollectionService } from "@bitwarden/admin-console/common";
|
||||
import { I18nPipe } from "@bitwarden/angular/platform/pipes/i18n.pipe";
|
||||
import { ModalService } from "@bitwarden/angular/services/modal.service";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { FakeAccountService, mockAccountServiceWith } from "@bitwarden/common/spec";
|
||||
import { UserId } from "@bitwarden/common/types/guid";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
|
||||
import { PasswordRepromptService } from "@bitwarden/vault";
|
||||
@ -21,12 +25,15 @@ describe("UnsecuredWebsitesReportComponent", () => {
|
||||
let organizationService: MockProxy<OrganizationService>;
|
||||
let syncServiceMock: MockProxy<SyncService>;
|
||||
let collectionService: MockProxy<CollectionService>;
|
||||
let accountService: FakeAccountService;
|
||||
const userId = Utils.newGuid() as UserId;
|
||||
|
||||
beforeEach(() => {
|
||||
organizationService = mock<OrganizationService>();
|
||||
organizationService.organizations$ = of([]);
|
||||
organizationService.organizations$.mockReturnValue(of([]));
|
||||
syncServiceMock = mock<SyncService>();
|
||||
collectionService = mock<CollectionService>();
|
||||
accountService = mockAccountServiceWith(userId);
|
||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
TestBed.configureTestingModule({
|
||||
@ -40,6 +47,10 @@ describe("UnsecuredWebsitesReportComponent", () => {
|
||||
provide: OrganizationService,
|
||||
useValue: organizationService,
|
||||
},
|
||||
{
|
||||
provide: AccountService,
|
||||
useValue: accountService,
|
||||
},
|
||||
{
|
||||
provide: ModalService,
|
||||
useValue: mock<ModalService>(),
|
||||
|
@ -3,6 +3,7 @@ import { Component, OnInit } from "@angular/core";
|
||||
import { CollectionService, Collection } from "@bitwarden/admin-console/common";
|
||||
import { ModalService } from "@bitwarden/angular/services/modal.service";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
|
||||
@ -22,6 +23,7 @@ export class UnsecuredWebsitesReportComponent extends CipherReportComponent impl
|
||||
constructor(
|
||||
protected cipherService: CipherService,
|
||||
protected organizationService: OrganizationService,
|
||||
accountService: AccountService,
|
||||
modalService: ModalService,
|
||||
passwordRepromptService: PasswordRepromptService,
|
||||
i18nService: I18nService,
|
||||
@ -33,6 +35,7 @@ export class UnsecuredWebsitesReportComponent extends CipherReportComponent impl
|
||||
modalService,
|
||||
passwordRepromptService,
|
||||
organizationService,
|
||||
accountService,
|
||||
i18nService,
|
||||
syncService,
|
||||
);
|
||||
|
@ -6,8 +6,12 @@ import { of } from "rxjs";
|
||||
import { I18nPipe } from "@bitwarden/angular/platform/pipes/i18n.pipe";
|
||||
import { ModalService } from "@bitwarden/angular/services/modal.service";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { FakeAccountService, mockAccountServiceWith } from "@bitwarden/common/spec";
|
||||
import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength";
|
||||
import { UserId } from "@bitwarden/common/types/guid";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
|
||||
import { PasswordRepromptService } from "@bitwarden/vault";
|
||||
@ -21,12 +25,15 @@ describe("WeakPasswordsReportComponent", () => {
|
||||
let passwordStrengthService: MockProxy<PasswordStrengthServiceAbstraction>;
|
||||
let organizationService: MockProxy<OrganizationService>;
|
||||
let syncServiceMock: MockProxy<SyncService>;
|
||||
let accountService: FakeAccountService;
|
||||
const userId = Utils.newGuid() as UserId;
|
||||
|
||||
beforeEach(() => {
|
||||
syncServiceMock = mock<SyncService>();
|
||||
passwordStrengthService = mock<PasswordStrengthServiceAbstraction>();
|
||||
organizationService = mock<OrganizationService>();
|
||||
organizationService.organizations$ = of([]);
|
||||
organizationService.organizations$.mockReturnValue(of([]));
|
||||
accountService = mockAccountServiceWith(userId);
|
||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
TestBed.configureTestingModule({
|
||||
@ -44,6 +51,10 @@ describe("WeakPasswordsReportComponent", () => {
|
||||
provide: OrganizationService,
|
||||
useValue: organizationService,
|
||||
},
|
||||
{
|
||||
provide: AccountService,
|
||||
useValue: accountService,
|
||||
},
|
||||
{
|
||||
provide: ModalService,
|
||||
useValue: mock<ModalService>(),
|
||||
|
@ -4,6 +4,7 @@ import { Component, OnInit } from "@angular/core";
|
||||
|
||||
import { ModalService } from "@bitwarden/angular/services/modal.service";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength";
|
||||
@ -32,6 +33,7 @@ export class WeakPasswordsReportComponent extends CipherReportComponent implemen
|
||||
protected cipherService: CipherService,
|
||||
protected passwordStrengthService: PasswordStrengthServiceAbstraction,
|
||||
protected organizationService: OrganizationService,
|
||||
protected accountService: AccountService,
|
||||
modalService: ModalService,
|
||||
passwordRepromptService: PasswordRepromptService,
|
||||
i18nService: I18nService,
|
||||
@ -42,6 +44,7 @@ export class WeakPasswordsReportComponent extends CipherReportComponent implemen
|
||||
modalService,
|
||||
passwordRepromptService,
|
||||
organizationService,
|
||||
accountService,
|
||||
i18nService,
|
||||
syncService,
|
||||
);
|
||||
|
@ -5,6 +5,7 @@ import { ChangeDetectorRef, Component, Inject, OnDestroy, OnInit } from "@angula
|
||||
import { AbstractControl, FormBuilder, Validators } from "@angular/forms";
|
||||
import {
|
||||
combineLatest,
|
||||
firstValueFrom,
|
||||
map,
|
||||
Observable,
|
||||
of,
|
||||
@ -24,8 +25,13 @@ import {
|
||||
CollectionResponse,
|
||||
CollectionView,
|
||||
} from "@bitwarden/admin-console/common";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import {
|
||||
getOrganizationById,
|
||||
OrganizationService,
|
||||
} from "@bitwarden/common/admin-console/abstractions/organization/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 { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
@ -110,6 +116,7 @@ export class CollectionDialogComponent implements OnInit, OnDestroy {
|
||||
private organizationUserApiService: OrganizationUserApiService,
|
||||
private dialogService: DialogService,
|
||||
private changeDetectorRef: ChangeDetectorRef,
|
||||
private accountService: AccountService,
|
||||
private toastService: ToastService,
|
||||
) {
|
||||
this.tabIndex = params.initialTab ?? CollectionDialogTabType.Info;
|
||||
@ -122,7 +129,10 @@ export class CollectionDialogComponent implements OnInit, OnDestroy {
|
||||
this.formGroup.controls.selectedOrg.valueChanges
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe((id) => this.loadOrg(id));
|
||||
this.organizations$ = this.organizationService.organizations$.pipe(
|
||||
const userId = await firstValueFrom(
|
||||
this.accountService.activeAccount$.pipe(map((a) => a?.id)),
|
||||
);
|
||||
this.organizations$ = this.organizationService.organizations$(userId).pipe(
|
||||
first(),
|
||||
map((orgs) =>
|
||||
orgs
|
||||
@ -140,8 +150,10 @@ export class CollectionDialogComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
async loadOrg(orgId: string) {
|
||||
const userId = await firstValueFrom(getUserId(this.accountService.activeAccount$));
|
||||
const organization$ = this.organizationService
|
||||
.get$(orgId)
|
||||
.organizations$(userId)
|
||||
.pipe(getOrganizationById(orgId))
|
||||
.pipe(shareReplay({ refCount: true, bufferSize: 1 }));
|
||||
const groups$ = organization$.pipe(
|
||||
switchMap((organization) => {
|
||||
|
@ -49,7 +49,7 @@ describe("AddEditComponentV2", () => {
|
||||
} as Organization;
|
||||
|
||||
organizationService = mock<OrganizationService>();
|
||||
organizationService.organizations$ = of([mockOrganization]);
|
||||
organizationService.organizations$.mockReturnValue(of([mockOrganization]));
|
||||
|
||||
policyService = mock<PolicyService>();
|
||||
policyService.policyAppliesToActiveUser$.mockImplementation((policyType: PolicyType) =>
|
||||
|
@ -8,6 +8,7 @@ import { CollectionService, CollectionView } from "@bitwarden/admin-console/comm
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/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 { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import { Checkable, isChecked } from "@bitwarden/common/types/checkable";
|
||||
@ -76,7 +77,8 @@ export class BulkShareDialogComponent implements OnInit, OnDestroy {
|
||||
this.nonShareableCount = this.ciphers.length - this.shareableCiphers.length;
|
||||
const allCollections = await this.collectionService.getAllDecrypted();
|
||||
this.writeableCollections = allCollections.filter((c) => !c.readOnly);
|
||||
this.organizations = await this.organizationService.getAll();
|
||||
const userId = await firstValueFrom(getUserId(this.accountService.activeAccount$));
|
||||
this.organizations = await firstValueFrom(this.organizationService.organizations$(userId));
|
||||
if (this.organizationId == null && this.organizations.length > 0) {
|
||||
this.organizationId = this.organizations[0].id;
|
||||
}
|
||||
|
@ -1,7 +1,16 @@
|
||||
// FIXME: Update this file to be type safe and remove this and next line
|
||||
// @ts-strict-ignore
|
||||
import { Component, Inject, OnDestroy, OnInit } from "@angular/core";
|
||||
import { combineLatest, map, Observable, of, Subject, switchMap, takeUntil } from "rxjs";
|
||||
import {
|
||||
combineLatest,
|
||||
firstValueFrom,
|
||||
map,
|
||||
Observable,
|
||||
of,
|
||||
Subject,
|
||||
switchMap,
|
||||
takeUntil,
|
||||
} from "rxjs";
|
||||
|
||||
import {
|
||||
OrganizationUserApiService,
|
||||
@ -15,7 +24,9 @@ import { PolicyService } from "@bitwarden/common/admin-console/abstractions/poli
|
||||
import { PolicyType } from "@bitwarden/common/admin-console/enums";
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
import { Policy } from "@bitwarden/common/admin-console/models/domain/policy";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { UserVerificationService } from "@bitwarden/common/auth/abstractions/user-verification/user-verification.service.abstraction";
|
||||
import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
@ -60,6 +71,7 @@ export class OrganizationOptionsComponent implements OnInit, OnDestroy {
|
||||
private toastService: ToastService,
|
||||
private configService: ConfigService,
|
||||
private organizationService: OrganizationService,
|
||||
private accountService: AccountService,
|
||||
) {}
|
||||
|
||||
async ngOnInit() {
|
||||
@ -67,16 +79,19 @@ export class OrganizationOptionsComponent implements OnInit, OnDestroy {
|
||||
map((policies) => policies.filter((policy) => policy.type === PolicyType.ResetPassword)),
|
||||
);
|
||||
|
||||
const userId = await firstValueFrom(getUserId(this.accountService.activeAccount$));
|
||||
const managingOrg$ = this.configService
|
||||
.getFeatureFlag$(FeatureFlag.AccountDeprovisioning)
|
||||
.pipe(
|
||||
switchMap((isAccountDeprovisioningEnabled) =>
|
||||
isAccountDeprovisioningEnabled
|
||||
? this.organizationService.organizations$.pipe(
|
||||
map((organizations) =>
|
||||
organizations.find((o) => o.userIsManagedByOrganization === true),
|
||||
),
|
||||
)
|
||||
? this.organizationService
|
||||
.organizations$(userId)
|
||||
.pipe(
|
||||
map((organizations) =>
|
||||
organizations.find((o) => o.userIsManagedByOrganization === true),
|
||||
),
|
||||
)
|
||||
: of(null),
|
||||
),
|
||||
);
|
||||
|
@ -62,7 +62,7 @@ describe("vault filter service", () => {
|
||||
personalOwnershipPolicy = new ReplaySubject<boolean>(1);
|
||||
singleOrgPolicy = new ReplaySubject<boolean>(1);
|
||||
|
||||
organizationService.memberOrganizations$ = organizations;
|
||||
organizationService.memberOrganizations$.mockReturnValue(organizations);
|
||||
folderService.folderViews$.mockReturnValue(folderViews);
|
||||
collectionService.decryptedCollections$ = collectionViews;
|
||||
policyService.policyAppliesToActiveUser$
|
||||
|
@ -48,8 +48,12 @@ const NestingDelimiter = "/";
|
||||
export class VaultFilterService implements VaultFilterServiceAbstraction {
|
||||
private activeUserId$ = this.accountService.activeAccount$.pipe(map((a) => a?.id));
|
||||
|
||||
memberOrganizations$ = this.activeUserId$.pipe(
|
||||
switchMap((id) => this.organizationService.memberOrganizations$(id)),
|
||||
);
|
||||
|
||||
organizationTree$: Observable<TreeNode<OrganizationFilter>> = combineLatest([
|
||||
this.organizationService.memberOrganizations$,
|
||||
this.memberOrganizations$,
|
||||
this.policyService.policyAppliesToActiveUser$(PolicyType.SingleOrg),
|
||||
this.policyService.policyAppliesToActiveUser$(PolicyType.PersonalOwnership),
|
||||
]).pipe(
|
||||
|
@ -47,7 +47,10 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
|
||||
import { SearchService } from "@bitwarden/common/abstractions/search.service";
|
||||
import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-console/abstractions/organization/organization-api.service.abstraction";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import {
|
||||
getOrganizationById,
|
||||
OrganizationService,
|
||||
} from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { OrganizationBillingServiceAbstraction } from "@bitwarden/common/billing/abstractions";
|
||||
@ -193,7 +196,11 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
private hasSubscription$ = new BehaviorSubject<boolean>(false);
|
||||
|
||||
private vaultItemDialogRef?: DialogRef<VaultItemDialogResult> | undefined;
|
||||
private readonly unpaidSubscriptionDialog$ = this.organizationService.organizations$.pipe(
|
||||
private organizations$ = this.accountService.activeAccount$
|
||||
.pipe(map((a) => a?.id))
|
||||
.pipe(switchMap((id) => this.organizationService.organizations$(id)));
|
||||
|
||||
private readonly unpaidSubscriptionDialog$ = this.organizations$.pipe(
|
||||
filter((organizations) => organizations.length === 1),
|
||||
map(([organization]) => organization),
|
||||
switchMap((organization) =>
|
||||
@ -212,9 +219,8 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
protected organizationsPaymentStatus$: Observable<FreeTrial[]> = combineLatest([
|
||||
this.organizationService.organizations$.pipe(
|
||||
this.organizations$.pipe(
|
||||
map(
|
||||
(organizations) =>
|
||||
organizations?.filter((org) => org.isOwner && org.canViewBillingHistory) ?? [],
|
||||
@ -501,7 +507,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
filter$,
|
||||
this.billingAccountProfileStateService.hasPremiumFromAnySource$(this.activeUserId),
|
||||
allCollections$,
|
||||
this.organizationService.organizations$,
|
||||
this.organizations$,
|
||||
ciphers$,
|
||||
collections$,
|
||||
selectedCollection$,
|
||||
@ -646,7 +652,9 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
this.messagingService.send("premiumRequired");
|
||||
return;
|
||||
} else if (cipher.organizationId != null) {
|
||||
const org = await this.organizationService.get(cipher.organizationId);
|
||||
const org = await firstValueFrom(
|
||||
this.organizations$.pipe(getOrganizationById(cipher.organizationId)),
|
||||
);
|
||||
if (org != null && (org.maxStorageGb == null || org.maxStorageGb === 0)) {
|
||||
this.messagingService.send("upgradeOrganization", {
|
||||
organizationId: cipher.organizationId,
|
||||
@ -971,7 +979,9 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
async deleteCollection(collection: CollectionView): Promise<void> {
|
||||
const organization = await this.organizationService.get(collection.organizationId);
|
||||
const organization = await firstValueFrom(
|
||||
this.organizations$.pipe(getOrganizationById(collection.organizationId)),
|
||||
);
|
||||
if (!collection.canDelete(organization)) {
|
||||
this.showMissingPermissionsError();
|
||||
return;
|
||||
@ -1136,9 +1146,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
.filter((i) => i.cipher === undefined)
|
||||
.map((i) => i.collection.organizationId);
|
||||
const orgs = await firstValueFrom(
|
||||
this.organizationService.organizations$.pipe(
|
||||
map((orgs) => orgs.filter((o) => orgIds.includes(o.id))),
|
||||
),
|
||||
this.organizations$.pipe(map((orgs) => orgs.filter((o) => orgIds.includes(o.id)))),
|
||||
);
|
||||
await this.bulkDelete(ciphers, collections, orgs);
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { DIALOG_DATA, DialogRef } from "@angular/cdk/dialog";
|
||||
import { ComponentFixture, TestBed } from "@angular/core/testing";
|
||||
import { mock } from "jest-mock-extended";
|
||||
import { of } from "rxjs";
|
||||
|
||||
import { CollectionService } from "@bitwarden/admin-console/common";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
@ -11,7 +12,8 @@ import { ConfigService } from "@bitwarden/common/platform/abstractions/config/co
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
|
||||
import { mockAccountServiceWith } from "@bitwarden/common/spec";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { FakeAccountService, 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";
|
||||
@ -41,6 +43,8 @@ describe("ViewComponent", () => {
|
||||
const mockParams: ViewCipherDialogParams = {
|
||||
cipher: mockCipher,
|
||||
};
|
||||
const userId = Utils.newGuid() as UserId;
|
||||
const accountService: FakeAccountService = mockAccountServiceWith(userId);
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
@ -53,10 +57,14 @@ describe("ViewComponent", () => {
|
||||
{ provide: CipherService, useValue: mock<CipherService>() },
|
||||
{ provide: ToastService, useValue: mock<ToastService>() },
|
||||
{ provide: MessagingService, useValue: mock<MessagingService>() },
|
||||
{
|
||||
provide: AccountService,
|
||||
useValue: accountService,
|
||||
},
|
||||
{ provide: LogService, useValue: mock<LogService>() },
|
||||
{
|
||||
provide: OrganizationService,
|
||||
useValue: { get: jest.fn().mockResolvedValue(mockOrganization) },
|
||||
useValue: { organizations$: jest.fn().mockReturnValue(of([mockOrganization])) },
|
||||
},
|
||||
{ provide: CollectionService, useValue: mock<CollectionService>() },
|
||||
{ provide: FolderService, useValue: mock<FolderService>() },
|
||||
|
@ -3,11 +3,13 @@
|
||||
import { DIALOG_DATA, DialogConfig, DialogRef } from "@angular/cdk/dialog";
|
||||
import { CommonModule } from "@angular/common";
|
||||
import { Component, EventEmitter, Inject, OnInit } from "@angular/core";
|
||||
import { Observable } from "rxjs";
|
||||
import { Observable, firstValueFrom, map } from "rxjs";
|
||||
|
||||
import { 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 { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
|
||||
@ -94,6 +96,7 @@ export class ViewComponent implements OnInit {
|
||||
private toastService: ToastService,
|
||||
private organizationService: OrganizationService,
|
||||
private cipherAuthorizationService: CipherAuthorizationService,
|
||||
private accountService: AccountService,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@ -103,8 +106,17 @@ export class ViewComponent implements OnInit {
|
||||
this.cipher = this.params.cipher;
|
||||
this.collections = this.params.collections;
|
||||
this.cipherTypeString = this.getCipherViewTypeString();
|
||||
|
||||
const userId = await firstValueFrom(getUserId(this.accountService.activeAccount$));
|
||||
|
||||
if (this.cipher.organizationId) {
|
||||
this.organization = await this.organizationService.get(this.cipher.organizationId);
|
||||
this.organization = await firstValueFrom(
|
||||
this.organizationService
|
||||
.organizations$(userId)
|
||||
.pipe(
|
||||
map((organizations) => organizations.find((o) => o.id === this.cipher.organizationId)),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
this.canDeleteCipher$ = this.cipherAuthorizationService.canDeleteCipher$(this.cipher, [
|
||||
|
@ -10,8 +10,12 @@ import {
|
||||
OrganizationUserApiService,
|
||||
CollectionView,
|
||||
} from "@bitwarden/admin-console/common";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import {
|
||||
getOrganizationById,
|
||||
OrganizationService,
|
||||
} from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { DialogService, ToastService } from "@bitwarden/components";
|
||||
@ -63,6 +67,7 @@ export class BulkCollectionsDialogComponent implements OnDestroy {
|
||||
private dialogRef: DialogRef<BulkCollectionsDialogResult>,
|
||||
private formBuilder: FormBuilder,
|
||||
private organizationService: OrganizationService,
|
||||
private accountService: AccountService,
|
||||
private groupService: GroupApiService,
|
||||
private organizationUserApiService: OrganizationUserApiService,
|
||||
private platformUtilsService: PlatformUtilsService,
|
||||
@ -71,7 +76,13 @@ export class BulkCollectionsDialogComponent implements OnDestroy {
|
||||
private toastService: ToastService,
|
||||
) {
|
||||
this.numCollections = this.params.collections.length;
|
||||
const organization$ = this.organizationService.get$(this.params.organizationId);
|
||||
const organization$ = this.accountService.activeAccount$.pipe(
|
||||
switchMap((account) =>
|
||||
this.organizationService
|
||||
.organizations$(account?.id)
|
||||
.pipe(getOrganizationById(this.params.organizationId)),
|
||||
),
|
||||
);
|
||||
const groups$ = organization$.pipe(
|
||||
switchMap((organization) => {
|
||||
if (!organization.useGroups) {
|
||||
|
@ -7,9 +7,11 @@ import { OrganizationService } from "@bitwarden/common/admin-console/abstraction
|
||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||
import { OrganizationUserStatusType } 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 { CipherId } from "@bitwarden/common/types/guid";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
|
||||
import { Account } from "../../../../../../../libs/importer/src/importers/lastpass/access/models";
|
||||
import { RoutedVaultFilterService } from "../../individual-vault/vault-filter/services/routed-vault-filter.service";
|
||||
|
||||
import { AdminConsoleCipherFormConfigService } from "./admin-console-cipher-form-config.service";
|
||||
@ -50,8 +52,7 @@ describe("AdminConsoleCipherFormConfigService", () => {
|
||||
readOnly: false,
|
||||
} as CollectionAdminView;
|
||||
|
||||
const organization$ = new BehaviorSubject<Organization>(testOrg as Organization);
|
||||
const organizations$ = new BehaviorSubject<Organization[]>([testOrg, testOrg2] as Organization[]);
|
||||
const orgs$ = new BehaviorSubject<Organization[]>([testOrg, testOrg2] as Organization[]);
|
||||
const getCipherAdmin = jest.fn().mockResolvedValue(null);
|
||||
const getCipher = jest.fn().mockResolvedValue(null);
|
||||
|
||||
@ -65,7 +66,7 @@ describe("AdminConsoleCipherFormConfigService", () => {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [
|
||||
AdminConsoleCipherFormConfigService,
|
||||
{ provide: OrganizationService, useValue: { get$: () => organization$, organizations$ } },
|
||||
{ provide: OrganizationService, useValue: { organizations$: () => orgs$ } },
|
||||
{
|
||||
provide: CollectionAdminService,
|
||||
useValue: { getAll: () => Promise.resolve([collection, collection2]) },
|
||||
@ -80,6 +81,10 @@ describe("AdminConsoleCipherFormConfigService", () => {
|
||||
},
|
||||
{ provide: ApiService, useValue: { getCipherAdmin } },
|
||||
{ provide: CipherService, useValue: { get: getCipher } },
|
||||
{
|
||||
provide: AccountService,
|
||||
useValue: { activeAccount$: new BehaviorSubject<Account>(new Account()) },
|
||||
},
|
||||
],
|
||||
});
|
||||
adminConsoleConfigService = TestBed.inject(AdminConsoleCipherFormConfigService);
|
||||
|
@ -9,6 +9,7 @@ import { OrganizationService } from "@bitwarden/common/admin-console/abstraction
|
||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||
import { OrganizationUserStatusType, 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 { CipherId } from "@bitwarden/common/types/guid";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { CipherType } from "@bitwarden/common/vault/enums";
|
||||
@ -31,6 +32,7 @@ export class AdminConsoleCipherFormConfigService implements CipherFormConfigServ
|
||||
private collectionAdminService: CollectionAdminService = inject(CollectionAdminService);
|
||||
private cipherService: CipherService = inject(CipherService);
|
||||
private apiService: ApiService = inject(ApiService);
|
||||
private accountService: AccountService = inject(AccountService);
|
||||
|
||||
private allowPersonalOwnership$ = this.policyService
|
||||
.policyAppliesToActiveUser$(PolicyType.PersonalOwnership)
|
||||
@ -41,12 +43,16 @@ export class AdminConsoleCipherFormConfigService implements CipherFormConfigServ
|
||||
filter((filter) => filter !== undefined),
|
||||
);
|
||||
|
||||
private allOrganizations$ = this.organizationService.organizations$.pipe(
|
||||
map((orgs) => {
|
||||
return orgs.filter(
|
||||
(o) => o.isMember && o.enabled && o.status === OrganizationUserStatusType.Confirmed,
|
||||
);
|
||||
}),
|
||||
private allOrganizations$ = this.accountService.activeAccount$.pipe(
|
||||
switchMap((account) =>
|
||||
this.organizationService.organizations$(account?.id).pipe(
|
||||
map((orgs) => {
|
||||
return orgs.filter(
|
||||
(o) => o.isMember && o.enabled && o.status === OrganizationUserStatusType.Confirmed,
|
||||
);
|
||||
}),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
private organization$ = combineLatest([this.allOrganizations$, this.organizationId$]).pipe(
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user