From 66375831abdf862ea780dd87ffb38b06679c5ca3 Mon Sep 17 00:00:00 2001 From: Thomas Rittson Date: Tue, 19 Nov 2024 12:49:04 +1000 Subject: [PATCH 1/8] Split organization.canAccessImportExport --- .../organization-layout.component.html | 4 +-- .../organization-settings-routing.module.ts | 6 ++-- .../organization.service.abstraction.ts | 31 ++----------------- .../vnext.organization.service.ts | 19 ++---------- .../models/domain/organization.ts | 6 +++- .../src/components/import.component.ts | 15 ++++----- 6 files changed, 20 insertions(+), 61 deletions(-) diff --git a/apps/web/src/app/admin-console/organizations/layouts/organization-layout.component.html b/apps/web/src/app/admin-console/organizations/layouts/organization-layout.component.html index aaba492dff80..fee674225499 100644 --- a/apps/web/src/app/admin-console/organizations/layouts/organization-layout.component.html +++ b/apps/web/src/app/admin-console/organizations/layouts/organization-layout.component.html @@ -84,12 +84,12 @@ import("./org-import.component").then((mod) => mod.OrgImportComponent), - canActivate: [organizationPermissionsGuard((org) => org.canAccessImportExport)], + canActivate: [organizationPermissionsGuard((org) => org.canAccessImport)], data: { titleId: "importData", }, @@ -64,7 +64,7 @@ const routes: Routes = [ import("../tools/vault-export/org-vault-export.component").then( (mod) => mod.OrganizationVaultExportComponent, ), - canActivate: [organizationPermissionsGuard((org) => org.canAccessImportExport)], + canActivate: [organizationPermissionsGuard((org) => org.canAccessExport)], data: { titleId: "exportVault", }, @@ -82,7 +82,7 @@ function getSettingsRoute(organization: Organization) { if (organization.canManagePolicies) { return "policies"; } - if (organization.canAccessImportExport) { + if (organization.canAccessImport) { return ["tools", "import"]; } if (organization.canManageSso) { diff --git a/libs/common/src/admin-console/abstractions/organization/organization.service.abstraction.ts b/libs/common/src/admin-console/abstractions/organization/organization.service.abstraction.ts index a2ea6aa88610..0c9d0501ead2 100644 --- a/libs/common/src/admin-console/abstractions/organization/organization.service.abstraction.ts +++ b/libs/common/src/admin-console/abstractions/organization/organization.service.abstraction.ts @@ -1,7 +1,5 @@ import { map, Observable } from "rxjs"; -import { I18nService } from "../../../platform/abstractions/i18n.service"; -import { Utils } from "../../../platform/misc/utils"; import { UserId } from "../../../types/guid"; import { OrganizationData } from "../../models/data/organization.data"; import { Organization } from "../../models/domain/organization"; @@ -16,7 +14,8 @@ export function canAccessSettingsTab(org: Organization): boolean { org.canManagePolicies || org.canManageSso || org.canManageScim || - org.canAccessImportExport || + org.canAccessImport || + org.canAccessExport || org.canManageDeviceApprovals ); } @@ -56,32 +55,6 @@ export function getOrganizationById(id: string) { return map((orgs) => orgs.find((o) => o.id === id)); } -export function canAccessAdmin(i18nService: I18nService) { - return map((orgs) => - orgs.filter(canAccessOrgAdmin).sort(Utils.getSortFunction(i18nService, "name")), - ); -} - -/** - * @deprecated - * To be removed after Flexible Collections. - **/ -export function canAccessImportExport(i18nService: I18nService) { - return map((orgs) => - orgs - .filter((org) => org.canAccessImportExport) - .sort(Utils.getSortFunction(i18nService, "name")), - ); -} - -export function canAccessImport(i18nService: I18nService) { - return map((orgs) => - orgs - .filter((org) => org.canAccessImportExport || org.canCreateNewCollections) - .sort(Utils.getSortFunction(i18nService, "name")), - ); -} - /** * Returns `true` if a user is a member of an organization (rather than only being a ProviderUser) * @deprecated Use organizationService.organizations$ with a filter instead diff --git a/libs/common/src/admin-console/abstractions/organization/vnext.organization.service.ts b/libs/common/src/admin-console/abstractions/organization/vnext.organization.service.ts index 45c00e3fd4a2..869d255be264 100644 --- a/libs/common/src/admin-console/abstractions/organization/vnext.organization.service.ts +++ b/libs/common/src/admin-console/abstractions/organization/vnext.organization.service.ts @@ -1,7 +1,5 @@ import { map, Observable } from "rxjs"; -import { I18nService } from "../../../platform/abstractions/i18n.service"; -import { Utils } from "../../../platform/misc/utils"; import { UserId } from "../../../types/guid"; import { OrganizationData } from "../../models/data/organization.data"; import { Organization } from "../../models/domain/organization"; @@ -16,7 +14,8 @@ export function canAccessSettingsTab(org: Organization): boolean { org.canManagePolicies || org.canManageSso || org.canManageScim || - org.canAccessImportExport || + org.canAccessImport || + org.canAccessExport || org.canManageDeviceApprovals ); } @@ -56,20 +55,6 @@ export function getOrganizationById(id: string) { return map((orgs) => orgs.find((o) => o.id === id)); } -export function canAccessAdmin(i18nService: I18nService) { - return map((orgs) => - orgs.filter(canAccessOrgAdmin).sort(Utils.getSortFunction(i18nService, "name")), - ); -} - -export function canAccessImport(i18nService: I18nService) { - return map((orgs) => - orgs - .filter((org) => org.canAccessImportExport || org.canCreateNewCollections) - .sort(Utils.getSortFunction(i18nService, "name")), - ); -} - /** * Publishes an observable stream of organizations. This service is meant to * be used widely across Bitwarden as the primary way of fetching organizations. diff --git a/libs/common/src/admin-console/models/domain/organization.ts b/libs/common/src/admin-console/models/domain/organization.ts index 070617b9e5fe..acd870715420 100644 --- a/libs/common/src/admin-console/models/domain/organization.ts +++ b/libs/common/src/admin-console/models/domain/organization.ts @@ -168,7 +168,11 @@ export class Organization { return (this.isAdmin || this.permissions.accessEventLogs) && this.useEvents; } - get canAccessImportExport() { + get canAccessImport() { + return this.isAdmin || this.permissions.accessImportExport || this.canCreateNewCollections; + } + + get canAccessExport() { return this.isAdmin || this.permissions.accessImportExport; } diff --git a/libs/importer/src/components/import.component.ts b/libs/importer/src/components/import.component.ts index 1ffe2728b058..1ab300fc378d 100644 --- a/libs/importer/src/components/import.component.ts +++ b/libs/importer/src/components/import.component.ts @@ -21,10 +21,7 @@ import { JslibModule } from "@bitwarden/angular/jslib.module"; import { safeProvider, SafeProvider } from "@bitwarden/angular/platform/utils/safe-provider"; import { PinServiceAbstraction } from "@bitwarden/auth/common"; import { ApiService } from "@bitwarden/common/abstractions/api.service"; -import { - canAccessImport, - OrganizationService, -} from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; +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 { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; @@ -226,7 +223,7 @@ export class ImportComponent implements OnInit, OnDestroy, AfterViewInit { this.setImportOptions(); await this.initializeOrganizations(); - if (this.organizationId && (await this.canAccessImportExport(this.organizationId))) { + if (this.organizationId && (await this.canAccessImport(this.organizationId))) { this.handleOrganizationImportInit(); } else { this.handleImportInit(); @@ -289,7 +286,7 @@ export class ImportComponent implements OnInit, OnDestroy, AfterViewInit { private async initializeOrganizations() { this.organizations$ = concat( this.organizationService.memberOrganizations$.pipe( - canAccessImport(this.i18nService), + map((orgs) => orgs.filter((org) => org.canAccessImport)), map((orgs) => orgs.sort(Utils.getSortFunction(this.i18nService, "name"))), ), ); @@ -375,7 +372,7 @@ export class ImportComponent implements OnInit, OnDestroy, AfterViewInit { importContents, this.organizationId, this.formGroup.controls.targetSelector.value, - (await this.canAccessImportExport(this.organizationId)) && this.isFromAC, + (await this.canAccessImport(this.organizationId)) && this.isFromAC, ); //No errors, display success message @@ -395,11 +392,11 @@ export class ImportComponent implements OnInit, OnDestroy, AfterViewInit { } } - private async canAccessImportExport(organizationId?: string): Promise { + private async canAccessImport(organizationId?: string): Promise { if (!organizationId) { return false; } - return (await this.organizationService.get(this.organizationId))?.canAccessImportExport; + return (await this.organizationService.get(this.organizationId))?.canAccessImport; } getFormatInstructionTitle() { From 0cf1f232b623c31629c88625501dc1cfd5b6d5bf Mon Sep 17 00:00:00 2001 From: Thomas Rittson Date: Wed, 20 Nov 2024 12:33:29 +1000 Subject: [PATCH 2/8] Add org authz service --- ...ault-organization-authorization.service.ts | 40 +++++++++++++++++++ .../organization-authorization.service.ts | 8 ++++ 2 files changed, 48 insertions(+) create mode 100644 libs/common/src/admin-console/services/organization-authorization/default-organization-authorization.service.ts create mode 100644 libs/common/src/admin-console/services/organization-authorization/organization-authorization.service.ts diff --git a/libs/common/src/admin-console/services/organization-authorization/default-organization-authorization.service.ts b/libs/common/src/admin-console/services/organization-authorization/default-organization-authorization.service.ts new file mode 100644 index 000000000000..c59e66ccd72d --- /dev/null +++ b/libs/common/src/admin-console/services/organization-authorization/default-organization-authorization.service.ts @@ -0,0 +1,40 @@ +import { map, Observable } from "rxjs"; + +import { OrganizationUserType } from "@bitwarden/common/admin-console/enums"; +import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; +import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; +import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; + +import { OrganizationAuthorizationService } from "./organization-authorization.service"; + +export class DefaultOrganizationAuthorizationService implements OrganizationAuthorizationService { + constructor(private configService: ConfigService) {} + + canExport(org: Organization): Observable { + return this.configService + .getFeatureFlag$(FeatureFlag.PM11360RemoveProviderExportPermission) + .pipe( + map((featureFlag) => { + if (!featureFlag && org.isProviderUser) { + return true; + } + + return ( + org.type === OrganizationUserType.Owner || + org.type === OrganizationUserType.Admin || + org.permissions.accessImportExport + ); + }), + ); + } + + canImport(org: Organization) { + return ( + org.isProviderUser || + org.type === OrganizationUserType.Owner || + org.type === OrganizationUserType.Admin || + org.permissions.accessImportExport || + org.canCreateNewCollections // To allow users to create collections and then import items into them + ); + } +} diff --git a/libs/common/src/admin-console/services/organization-authorization/organization-authorization.service.ts b/libs/common/src/admin-console/services/organization-authorization/organization-authorization.service.ts new file mode 100644 index 000000000000..82e05b20d458 --- /dev/null +++ b/libs/common/src/admin-console/services/organization-authorization/organization-authorization.service.ts @@ -0,0 +1,8 @@ +import { Observable } from "rxjs"; + +import { Organization } from "../../models/domain/organization"; + +export abstract class OrganizationAuthorizationService { + canExport: (org: Organization) => Observable; + canImport: (org: Organization) => boolean; +} From 942c8d340088ea1d9d7c4735f9f28799d07cd25e Mon Sep 17 00:00:00 2001 From: Thomas Rittson Date: Wed, 20 Nov 2024 13:51:00 +1000 Subject: [PATCH 3/8] Revert "Add org authz service" This reverts commit 0cf1f232b623c31629c88625501dc1cfd5b6d5bf. --- ...ault-organization-authorization.service.ts | 40 ------------------- .../organization-authorization.service.ts | 8 ---- 2 files changed, 48 deletions(-) delete mode 100644 libs/common/src/admin-console/services/organization-authorization/default-organization-authorization.service.ts delete mode 100644 libs/common/src/admin-console/services/organization-authorization/organization-authorization.service.ts diff --git a/libs/common/src/admin-console/services/organization-authorization/default-organization-authorization.service.ts b/libs/common/src/admin-console/services/organization-authorization/default-organization-authorization.service.ts deleted file mode 100644 index c59e66ccd72d..000000000000 --- a/libs/common/src/admin-console/services/organization-authorization/default-organization-authorization.service.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { map, Observable } from "rxjs"; - -import { OrganizationUserType } from "@bitwarden/common/admin-console/enums"; -import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; -import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; -import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; - -import { OrganizationAuthorizationService } from "./organization-authorization.service"; - -export class DefaultOrganizationAuthorizationService implements OrganizationAuthorizationService { - constructor(private configService: ConfigService) {} - - canExport(org: Organization): Observable { - return this.configService - .getFeatureFlag$(FeatureFlag.PM11360RemoveProviderExportPermission) - .pipe( - map((featureFlag) => { - if (!featureFlag && org.isProviderUser) { - return true; - } - - return ( - org.type === OrganizationUserType.Owner || - org.type === OrganizationUserType.Admin || - org.permissions.accessImportExport - ); - }), - ); - } - - canImport(org: Organization) { - return ( - org.isProviderUser || - org.type === OrganizationUserType.Owner || - org.type === OrganizationUserType.Admin || - org.permissions.accessImportExport || - org.canCreateNewCollections // To allow users to create collections and then import items into them - ); - } -} diff --git a/libs/common/src/admin-console/services/organization-authorization/organization-authorization.service.ts b/libs/common/src/admin-console/services/organization-authorization/organization-authorization.service.ts deleted file mode 100644 index 82e05b20d458..000000000000 --- a/libs/common/src/admin-console/services/organization-authorization/organization-authorization.service.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Observable } from "rxjs"; - -import { Organization } from "../../models/domain/organization"; - -export abstract class OrganizationAuthorizationService { - canExport: (org: Organization) => Observable; - canImport: (org: Organization) => boolean; -} From 03c56cf5a8f6c40ca5c065629a11c2858b9207f2 Mon Sep 17 00:00:00 2001 From: Thomas Rittson Date: Wed, 20 Nov 2024 13:52:26 +1000 Subject: [PATCH 4/8] Remove provider export --- .../organization-layout.component.html | 2 +- .../layouts/organization-layout.component.ts | 21 +++++++------- .../organization-settings-routing.module.ts | 29 +++++++++++++++++-- .../organization.service.abstraction.ts | 2 +- .../models/domain/organization.ts | 21 ++++++++++++-- libs/common/src/enums/feature-flag.enum.ts | 2 ++ 6 files changed, 58 insertions(+), 19 deletions(-) diff --git a/apps/web/src/app/admin-console/organizations/layouts/organization-layout.component.html b/apps/web/src/app/admin-console/organizations/layouts/organization-layout.component.html index fee674225499..1e811b6c29d1 100644 --- a/apps/web/src/app/admin-console/organizations/layouts/organization-layout.component.html +++ b/apps/web/src/app/admin-console/organizations/layouts/organization-layout.component.html @@ -89,7 +89,7 @@ canAccessOrgAdmin(org); organization$: Observable; + canAccessExport$: Observable; showPaymentAndHistory$: Observable; hideNewOrgButton$: Observable; organizationIsUnmanaged$: Observable; @@ -72,15 +73,13 @@ export class OrganizationLayoutComponent implements OnInit, OnDestroy { ); this.organization$ = this.route.params - .pipe(takeUntil(this._destroy)) - .pipe(map((p) => p.organizationId)) - .pipe( - mergeMap((id) => { - return this.organizationService.organizations$ - .pipe(takeUntil(this._destroy)) - .pipe(getOrganizationById(id)); - }), - ); + .pipe(map((p) => p.organizationId)) + .pipe(switchMap((id) => this.organizationService.organizations$.pipe(getById(id)))); + + this.canAccessExport$ = combineLatest([ + this.organization$, + this.configService.getFeatureFlag$(FeatureFlag.PM11360RemoveProviderExportPermission), + ]).pipe(map(([org, removeProviderExport]) => org.canAccessExport(removeProviderExport))); this.showPaymentAndHistory$ = this.organization$.pipe( map( diff --git a/apps/web/src/app/admin-console/organizations/settings/organization-settings-routing.module.ts b/apps/web/src/app/admin-console/organizations/settings/organization-settings-routing.module.ts index 8cb1a30d6a6d..8c3f6da9354f 100644 --- a/apps/web/src/app/admin-console/organizations/settings/organization-settings-routing.module.ts +++ b/apps/web/src/app/admin-console/organizations/settings/organization-settings-routing.module.ts @@ -1,8 +1,11 @@ -import { NgModule } from "@angular/core"; -import { RouterModule, Routes } from "@angular/router"; +import { inject, NgModule } from "@angular/core"; +import { CanMatchFn, RouterModule, Routes } from "@angular/router"; +import { map } from "rxjs"; import { canAccessSettingsTab } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; +import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; +import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { organizationPermissionsGuard } from "../../organizations/guards/org-permissions.guard"; import { organizationRedirectGuard } from "../../organizations/guards/org-redirect.guard"; @@ -11,6 +14,12 @@ import { PoliciesComponent } from "../../organizations/policies"; import { AccountComponent } from "./account.component"; import { TwoFactorSetupComponent } from "./two-factor-setup.component"; + +const removeProviderExportPermission$: CanMatchFn = () => + inject(ConfigService) + .getFeatureFlag$(FeatureFlag.PM11360RemoveProviderExportPermission) + .pipe(map((removeProviderExport) => removeProviderExport === true)); + const routes: Routes = [ { path: "", @@ -58,13 +67,27 @@ const routes: Routes = [ titleId: "importData", }, }, + + // Export routing is temporarily duplicated to set the flag value passed into org.canAccessExport + { + path: "export", + loadComponent: () => + import("../tools/vault-export/org-vault-export.component").then( + (mod) => mod.OrganizationVaultExportComponent, + ), + canMatch: [removeProviderExportPermission$], // if this matches, the flag is ON + canActivate: [organizationPermissionsGuard((org) => org.canAccessExport(true))], + data: { + titleId: "exportVault", + }, + }, { path: "export", loadComponent: () => import("../tools/vault-export/org-vault-export.component").then( (mod) => mod.OrganizationVaultExportComponent, ), - canActivate: [organizationPermissionsGuard((org) => org.canAccessExport)], + canActivate: [organizationPermissionsGuard((org) => org.canAccessExport(false))], data: { titleId: "exportVault", }, diff --git a/libs/common/src/admin-console/abstractions/organization/organization.service.abstraction.ts b/libs/common/src/admin-console/abstractions/organization/organization.service.abstraction.ts index 0c9d0501ead2..e687c0a34a70 100644 --- a/libs/common/src/admin-console/abstractions/organization/organization.service.abstraction.ts +++ b/libs/common/src/admin-console/abstractions/organization/organization.service.abstraction.ts @@ -15,7 +15,7 @@ export function canAccessSettingsTab(org: Organization): boolean { org.canManageSso || org.canManageScim || org.canAccessImport || - org.canAccessExport || + org.canAccessExport(false) || // Feature flag value doesn't matter here, providers will have access to this group anyway org.canManageDeviceApprovals ); } diff --git a/libs/common/src/admin-console/models/domain/organization.ts b/libs/common/src/admin-console/models/domain/organization.ts index acd870715420..2ff17ca119cb 100644 --- a/libs/common/src/admin-console/models/domain/organization.ts +++ b/libs/common/src/admin-console/models/domain/organization.ts @@ -169,11 +169,26 @@ export class Organization { } get canAccessImport() { - return this.isAdmin || this.permissions.accessImportExport || this.canCreateNewCollections; + return ( + this.isProviderUser || + this.type === OrganizationUserType.Owner || + this.type === OrganizationUserType.Admin || + this.permissions.accessImportExport || + this.canCreateNewCollections // To allow users to create collections and then import into them + ); } - get canAccessExport() { - return this.isAdmin || this.permissions.accessImportExport; + canAccessExport(removeProviderExport: boolean) { + if (!removeProviderExport && this.isProviderUser) { + return true; + } + + return ( + this.isMember && + (this.type === OrganizationUserType.Owner || + this.type === OrganizationUserType.Admin || + this.permissions.accessImportExport) + ); } get canAccessReports() { diff --git a/libs/common/src/enums/feature-flag.enum.ts b/libs/common/src/enums/feature-flag.enum.ts index ec5a8e47d736..6dafe8fc7fec 100644 --- a/libs/common/src/enums/feature-flag.enum.ts +++ b/libs/common/src/enums/feature-flag.enum.ts @@ -40,6 +40,7 @@ export enum FeatureFlag { NewDeviceVerificationTemporaryDismiss = "new-device-temporary-dismiss", NewDeviceVerificationPermanentDismiss = "new-device-permanent-dismiss", DisableFreeFamiliesSponsorship = "PM-12274-disable-free-families-sponsorship", + PM11360RemoveProviderExportPermission = "pm-11360-remove-provider-export-permission", } export type AllowedFeatureFlagTypes = boolean | number | string; @@ -90,6 +91,7 @@ export const DefaultFeatureFlagValue = { [FeatureFlag.NewDeviceVerificationTemporaryDismiss]: FALSE, [FeatureFlag.NewDeviceVerificationPermanentDismiss]: FALSE, [FeatureFlag.DisableFreeFamiliesSponsorship]: FALSE, + [FeatureFlag.PM11360RemoveProviderExportPermission]: FALSE, } satisfies Record; export type DefaultFeatureFlagValueType = typeof DefaultFeatureFlagValue; From 3aff3a8d2bb45f1647b6356eaf88c7255782a2bf Mon Sep 17 00:00:00 2001 From: Thomas Rittson Date: Wed, 20 Nov 2024 13:57:31 +1000 Subject: [PATCH 5/8] Tweak layout rxjs logic --- .../layouts/organization-layout.component.ts | 25 ++++++++----------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/apps/web/src/app/admin-console/organizations/layouts/organization-layout.component.ts b/apps/web/src/app/admin-console/organizations/layouts/organization-layout.component.ts index 198474d2e700..a15882f42de4 100644 --- a/apps/web/src/app/admin-console/organizations/layouts/organization-layout.component.ts +++ b/apps/web/src/app/admin-console/organizations/layouts/organization-layout.component.ts @@ -1,7 +1,7 @@ import { CommonModule } from "@angular/common"; -import { Component, OnDestroy, OnInit } from "@angular/core"; +import { Component, OnInit } from "@angular/core"; import { ActivatedRoute, RouterModule } from "@angular/router"; -import { combineLatest, map, Observable, Subject, switchMap } from "rxjs"; +import { combineLatest, filter, map, Observable, switchMap } from "rxjs"; import { JslibModule } from "@bitwarden/angular/jslib.module"; import { @@ -42,7 +42,7 @@ import { AdminConsoleLogo } from "../../icons/admin-console-logo"; BannerModule, ], }) -export class OrganizationLayoutComponent implements OnInit, OnDestroy { +export class OrganizationLayoutComponent implements OnInit { protected readonly logo = AdminConsoleLogo; protected orgFilter = (org: Organization) => canAccessOrgAdmin(org); @@ -54,8 +54,6 @@ export class OrganizationLayoutComponent implements OnInit, OnDestroy { organizationIsUnmanaged$: Observable; isAccessIntelligenceFeatureEnabled = false; - private _destroy = new Subject(); - constructor( private route: ActivatedRoute, private organizationService: OrganizationService, @@ -72,9 +70,11 @@ export class OrganizationLayoutComponent implements OnInit, OnDestroy { FeatureFlag.AccessIntelligence, ); - this.organization$ = this.route.params - .pipe(map((p) => p.organizationId)) - .pipe(switchMap((id) => this.organizationService.organizations$.pipe(getById(id)))); + this.organization$ = this.route.params.pipe( + map((p) => p.organizationId), + switchMap((id) => this.organizationService.organizations$.pipe(getById(id))), + filter((org) => org != null), + ); this.canAccessExport$ = combineLatest([ this.organization$, @@ -85,8 +85,8 @@ export class OrganizationLayoutComponent implements OnInit, OnDestroy { map( (org) => !this.platformUtilsService.isSelfHost() && - org?.canViewBillingHistory && - org?.canEditPaymentMethods, + org.canViewBillingHistory && + org.canEditPaymentMethods, ), ); @@ -106,11 +106,6 @@ export class OrganizationLayoutComponent implements OnInit, OnDestroy { ); } - ngOnDestroy() { - this._destroy.next(); - this._destroy.complete(); - } - canShowVaultTab(organization: Organization): boolean { return canAccessVaultTab(organization); } From 4b4c4e9c7f55e12e4f4779e9f615c280a8829dfe Mon Sep 17 00:00:00 2001 From: Thomas Rittson Date: Wed, 20 Nov 2024 13:58:08 +1000 Subject: [PATCH 6/8] Duplicate changes into org service vnext --- .../abstractions/organization/vnext.organization.service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/common/src/admin-console/abstractions/organization/vnext.organization.service.ts b/libs/common/src/admin-console/abstractions/organization/vnext.organization.service.ts index 869d255be264..68c61e298ae8 100644 --- a/libs/common/src/admin-console/abstractions/organization/vnext.organization.service.ts +++ b/libs/common/src/admin-console/abstractions/organization/vnext.organization.service.ts @@ -15,7 +15,7 @@ export function canAccessSettingsTab(org: Organization): boolean { org.canManageSso || org.canManageScim || org.canAccessImport || - org.canAccessExport || + org.canAccessExport(false) || // Feature flag value doesn't matter here, providers will have access to this group anyway org.canManageDeviceApprovals ); } From 48a0e4d1596b594a44d8caf9a410128faaf0d599 Mon Sep 17 00:00:00 2001 From: Thomas Rittson Date: Wed, 20 Nov 2024 14:01:16 +1000 Subject: [PATCH 7/8] prettier --- .../settings/organization-settings-routing.module.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/web/src/app/admin-console/organizations/settings/organization-settings-routing.module.ts b/apps/web/src/app/admin-console/organizations/settings/organization-settings-routing.module.ts index 8c3f6da9354f..d7fad9fded24 100644 --- a/apps/web/src/app/admin-console/organizations/settings/organization-settings-routing.module.ts +++ b/apps/web/src/app/admin-console/organizations/settings/organization-settings-routing.module.ts @@ -14,7 +14,6 @@ import { PoliciesComponent } from "../../organizations/policies"; import { AccountComponent } from "./account.component"; import { TwoFactorSetupComponent } from "./two-factor-setup.component"; - const removeProviderExportPermission$: CanMatchFn = () => inject(ConfigService) .getFeatureFlag$(FeatureFlag.PM11360RemoveProviderExportPermission) From 7ca6244546bed34bd8aab2b49f213d3e789758a2 Mon Sep 17 00:00:00 2001 From: Thomas Rittson Date: Wed, 20 Nov 2024 15:38:12 +1000 Subject: [PATCH 8/8] Fix CI failures --- apps/cli/src/tools/import.command.ts | 2 +- .../shared/product-switcher.service.spec.ts | 23 ++++++++++++++++--- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/apps/cli/src/tools/import.command.ts b/apps/cli/src/tools/import.command.ts index 1cb3ac19f6bd..879b2313bafc 100644 --- a/apps/cli/src/tools/import.command.ts +++ b/apps/cli/src/tools/import.command.ts @@ -27,7 +27,7 @@ export class ImportCommand { ); } - if (!organization.canAccessImportExport) { + if (!organization.canAccessImport) { return Response.badRequest( "You are not authorized to import into the provided organization.", ); diff --git a/apps/web/src/app/layouts/product-switcher/shared/product-switcher.service.spec.ts b/apps/web/src/app/layouts/product-switcher/shared/product-switcher.service.spec.ts index 07a41e7c94c8..7c53cd86d3b9 100644 --- a/apps/web/src/app/layouts/product-switcher/shared/product-switcher.service.spec.ts +++ b/apps/web/src/app/layouts/product-switcher/shared/product-switcher.service.spec.ts @@ -110,7 +110,12 @@ describe("ProductSwitcherService", () => { it("is included in bento when there is an organization with SM", async () => { organizationService.organizations$ = of([ - { id: "1234", canAccessSecretsManager: true, enabled: true }, + { + id: "1234", + canAccessSecretsManager: true, + enabled: true, + canAccessExport: (_) => true, + }, ] as Organization[]); initiateService(); @@ -220,8 +225,20 @@ describe("ProductSwitcherService", () => { 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" }, + { + id: "23443234", + canAccessSecretsManager: true, + enabled: true, + name: "Org 2", + canAccessExport: (_) => true, + }, + { + id: "4243", + canAccessSecretsManager: true, + enabled: true, + name: "Org 32", + canAccessExport: (_) => true, + }, ] as Organization[]); initiateService();