From 72b4b26e2c5578c66eaeca5a84b9f426054c67db Mon Sep 17 00:00:00 2001 From: Marie <51697796+ijreilly@users.noreply.github.com> Date: Wed, 26 Mar 2025 13:51:34 +0100 Subject: [PATCH] [permissions] Enable permissions V1 for all workspaces (#11172) Closes https://github.com/twentyhq/core-team-issues/issues/526 (for reminder: 1. Make defaultRoleId non-nullable for an active workspace 2. Remove permissions V1 feature flag 3. Set member role as default role for new workspaces About 1.: An active workspace's defaultRoleId should never be null. We can't rely on a simple postgres NOT NULL constraint as defaultRoleId will always be initially null when the workspace is first created since the roles do not exist at that time. Let's add a more complex rule to ensure that About 3.: In the first phase of our deploy of permissions, we chose to assign admin role to all existing users, not to break any existing behavior with the introduction of the feature (= existing users have less rights than before). As we deploy permissions to all existing and future workspaces, let's set the member role as default role for future workspaces. ) --- .../modules/app/components/SettingsRoutes.tsx | 2 - .../SettingsProtectedRouteWrapper.tsx | 8 +- .../useSettingsNavigationItems.test.tsx | 7 - .../hooks/useSettingsNavigationItems.tsx | 7 +- .../hooks/useHasObjectReadOnlyPermission.ts | 11 +- .../roles/hooks/useSettingsPermissionMap.ts | 8 +- .../database/typeorm-seeds/core/workspaces.ts | 6 +- .../interfaces/base-resolver-service.ts | 12 +- .../core-modules/billing/billing.resolver.ts | 10 -- .../constants/public-feature-flag.const.ts | 13 +- .../enums/feature-flag-key.enum.ts | 1 - .../user/services/user.service.ts | 10 +- .../engine/core-modules/user/user.resolver.ts | 158 ++++++++---------- .../workspace/services/workspace.service.ts | 32 ++-- .../workspace/workspace.entity.ts | 2 +- .../guards/settings-permissions.guard.ts | 17 +- .../workspace-manager.service.ts | 12 +- ...workspace-member-pre-query-hook.service.ts | 11 -- ...ct-records-permissions.integration-spec.ts | 22 --- ...ct-records-permissions.integration-spec.ts | 22 --- ...ct-records-permissions.integration-spec.ts | 22 --- ...ct-records-permissions.integration-spec.ts | 24 +-- ...ct-records-permissions.integration-spec.ts | 22 --- ...ct-records-permissions.integration-spec.ts | 20 --- ...ct-records-permissions.integration-spec.ts | 20 --- ...ct-records-permissions.integration-spec.ts | 20 --- ...ct-records-permissions.integration-spec.ts | 20 --- ...ct-records-permissions.integration-spec.ts | 20 --- .../api-key-webhooks.integration-spec.ts | 22 --- .../data-model.integration-spec.ts | 21 +-- .../security.integration-spec.ts | 8 - .../workspace-invitation.integration-spec.ts | 23 --- .../workspace-members.integration-spec.ts | 21 --- .../workspace.integration-spec.ts | 8 - .../graphql/suites/user.integration-spec.ts | 23 --- 35 files changed, 103 insertions(+), 562 deletions(-) diff --git a/packages/twenty-front/src/modules/app/components/SettingsRoutes.tsx b/packages/twenty-front/src/modules/app/components/SettingsRoutes.tsx index 924635cee..5cf8aa4a6 100644 --- a/packages/twenty-front/src/modules/app/components/SettingsRoutes.tsx +++ b/packages/twenty-front/src/modules/app/components/SettingsRoutes.tsx @@ -4,7 +4,6 @@ import { Route, Routes } from 'react-router-dom'; import { SettingsProtectedRouteWrapper } from '@/settings/components/SettingsProtectedRouteWrapper'; import { SettingsSkeletonLoader } from '@/settings/components/SettingsSkeletonLoader'; import { SettingsPath } from '@/types/SettingsPath'; -import { FeatureFlagKey } from '~/generated-metadata/graphql'; import { SettingPermissionType } from '~/generated/graphql'; const SettingsApiKeys = lazy(() => @@ -388,7 +387,6 @@ export const SettingsRoutes = ({ element={ } > diff --git a/packages/twenty-front/src/modules/settings/components/SettingsProtectedRouteWrapper.tsx b/packages/twenty-front/src/modules/settings/components/SettingsProtectedRouteWrapper.tsx index 8c187b5d6..21f5e2676 100644 --- a/packages/twenty-front/src/modules/settings/components/SettingsProtectedRouteWrapper.tsx +++ b/packages/twenty-front/src/modules/settings/components/SettingsProtectedRouteWrapper.tsx @@ -17,18 +17,12 @@ export const SettingsProtectedRouteWrapper = ({ settingsPermission, requiredFeatureFlag, }: SettingsProtectedRouteWrapperProps) => { - const isPermissionsEnabled = useIsFeatureEnabled( - FeatureFlagKey.IsPermissionsEnabled, - ); const hasPermission = useHasSettingsPermission(settingsPermission); const requiredFeatureFlagEnabled = useIsFeatureEnabled( requiredFeatureFlag || null, ); - if ( - (requiredFeatureFlag && !requiredFeatureFlagEnabled) || - (!hasPermission && isPermissionsEnabled) - ) { + if ((requiredFeatureFlag && !requiredFeatureFlagEnabled) || !hasPermission) { return ; } diff --git a/packages/twenty-front/src/modules/settings/hooks/__tests__/useSettingsNavigationItems.test.tsx b/packages/twenty-front/src/modules/settings/hooks/__tests__/useSettingsNavigationItems.test.tsx index 1ad9a1e2f..db2bb9faf 100644 --- a/packages/twenty-front/src/modules/settings/hooks/__tests__/useSettingsNavigationItems.test.tsx +++ b/packages/twenty-front/src/modules/settings/hooks/__tests__/useSettingsNavigationItems.test.tsx @@ -6,7 +6,6 @@ import { MemoryRouter } from 'react-router-dom'; import { MutableSnapshot, RecoilRoot } from 'recoil'; import { Billing, - FeatureFlagKey, OnboardingStatus, SettingPermissionType, } from '~/generated/graphql'; @@ -52,12 +51,6 @@ jest.mock('@/settings/roles/hooks/useSettingsPermissionMap', () => ({ useSettingsPermissionMap: jest.fn(), })); -jest.mock('@/workspace/hooks/useFeatureFlagsMap', () => ({ - useFeatureFlagsMap: () => ({ - [FeatureFlagKey.IsPermissionsEnabled]: true, - }), -})); - describe('useSettingsNavigationItems', () => { it('should hide workspace settings when no permissions', () => { (useSettingsPermissionMap as jest.Mock).mockImplementation(() => ({ diff --git a/packages/twenty-front/src/modules/settings/hooks/useSettingsNavigationItems.tsx b/packages/twenty-front/src/modules/settings/hooks/useSettingsNavigationItems.tsx index ae868467d..36e091035 100644 --- a/packages/twenty-front/src/modules/settings/hooks/useSettingsNavigationItems.tsx +++ b/packages/twenty-front/src/modules/settings/hooks/useSettingsNavigationItems.tsx @@ -21,14 +21,12 @@ import { } from 'twenty-ui'; import { SettingsPath } from '@/types/SettingsPath'; -import { FeatureFlagKey } from '~/generated-metadata/graphql'; import { currentUserState } from '@/auth/states/currentUserState'; import { billingState } from '@/client-config/states/billingState'; import { labPublicFeatureFlagsState } from '@/client-config/states/labPublicFeatureFlagsState'; import { useSettingsPermissionMap } from '@/settings/roles/hooks/useSettingsPermissionMap'; import { NavigationDrawerItemIndentationLevel } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerItem'; -import { useFeatureFlagsMap } from '@/workspace/hooks/useFeatureFlagsMap'; import { t } from '@lingui/core/macro'; import { useRecoilValue } from 'recoil'; import { SettingPermissionType } from '~/generated/graphql'; @@ -63,7 +61,6 @@ const useSettingsNavigationItems = (): SettingsNavigationSection[] => { false; const labPublicFeatureFlags = useRecoilValue(labPublicFeatureFlagsState); - const featureFlags = useFeatureFlagsMap(); const permissionMap = useSettingsPermissionMap(); return [ { @@ -120,9 +117,7 @@ const useSettingsNavigationItems = (): SettingsNavigationSection[] => { label: t`Roles`, path: SettingsPath.Roles, Icon: IconLock, - isHidden: - !featureFlags[FeatureFlagKey.IsPermissionsEnabled] || - !permissionMap[SettingPermissionType.ROLES], + isHidden: !permissionMap[SettingPermissionType.ROLES], }, { label: t`Billing`, diff --git a/packages/twenty-front/src/modules/settings/roles/hooks/useHasObjectReadOnlyPermission.ts b/packages/twenty-front/src/modules/settings/roles/hooks/useHasObjectReadOnlyPermission.ts index fc81010cd..785e444d5 100644 --- a/packages/twenty-front/src/modules/settings/roles/hooks/useHasObjectReadOnlyPermission.ts +++ b/packages/twenty-front/src/modules/settings/roles/hooks/useHasObjectReadOnlyPermission.ts @@ -1,19 +1,10 @@ import { currentUserWorkspaceState } from '@/auth/states/currentUserWorkspaceState'; -import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled'; import { useRecoilValue } from 'recoil'; -import { FeatureFlagKey } from '~/generated-metadata/graphql'; -import { isDefined } from 'twenty-shared/utils'; import { PermissionsOnAllObjectRecords } from 'twenty-shared/constants'; +import { isDefined } from 'twenty-shared/utils'; export const useHasObjectReadOnlyPermission = () => { const currentUserWorkspace = useRecoilValue(currentUserWorkspaceState); - const isPermissionEnabled = useIsFeatureEnabled( - FeatureFlagKey.IsPermissionsEnabled, - ); - - if (!isPermissionEnabled) { - return false; - } if (!isDefined(currentUserWorkspace?.objectRecordsPermissions)) { return false; diff --git a/packages/twenty-front/src/modules/settings/roles/hooks/useSettingsPermissionMap.ts b/packages/twenty-front/src/modules/settings/roles/hooks/useSettingsPermissionMap.ts index 35bea8576..50e2bd804 100644 --- a/packages/twenty-front/src/modules/settings/roles/hooks/useSettingsPermissionMap.ts +++ b/packages/twenty-front/src/modules/settings/roles/hooks/useSettingsPermissionMap.ts @@ -1,7 +1,5 @@ import { currentUserWorkspaceState } from '@/auth/states/currentUserWorkspaceState'; -import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled'; import { useRecoilValue } from 'recoil'; -import { FeatureFlagKey } from '~/generated-metadata/graphql'; import { SettingPermissionType } from '~/generated/graphql'; import { buildRecordFromKeysWithSameValue } from '~/utils/array/buildRecordFromKeysWithSameValue'; @@ -11,16 +9,12 @@ export const useSettingsPermissionMap = (): Record< > => { const currentUserWorkspace = useRecoilValue(currentUserWorkspaceState); - const isPermissionEnabled = useIsFeatureEnabled( - FeatureFlagKey.IsPermissionsEnabled, - ); - const currentUserWorkspaceSettingsPermissions = currentUserWorkspace?.settingsPermissions; const initialPermissions = buildRecordFromKeysWithSameValue( Object.values(SettingPermissionType), - !isPermissionEnabled, + false, ); if (!currentUserWorkspaceSettingsPermissions) { diff --git a/packages/twenty-server/src/database/typeorm-seeds/core/workspaces.ts b/packages/twenty-server/src/database/typeorm-seeds/core/workspaces.ts index 8eeaac469..80b15ed59 100644 --- a/packages/twenty-server/src/database/typeorm-seeds/core/workspaces.ts +++ b/packages/twenty-server/src/database/typeorm-seeds/core/workspaces.ts @@ -1,5 +1,5 @@ -import { DataSource } from 'typeorm'; import { WorkspaceActivationStatus } from 'twenty-shared/workspace'; +import { DataSource } from 'typeorm'; import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; import { extractVersionMajorMinorPatch } from 'src/utils/version/extract-version-major-minor-patch'; @@ -46,7 +46,7 @@ export const seedWorkspaces = async ({ subdomain: 'apple', inviteHash: 'apple.dev-invite-hash', logo: 'https://twentyhq.github.io/placeholder-images/workspaces/apple-logo.png', - activationStatus: WorkspaceActivationStatus.ACTIVE, + activationStatus: WorkspaceActivationStatus.PENDING_CREATION, // will be set to active after default role creation version: version, }, [SEED_ACME_WORKSPACE_ID]: { @@ -55,7 +55,7 @@ export const seedWorkspaces = async ({ subdomain: 'acme', inviteHash: 'acme.dev-invite-hash', logo: 'https://logos-world.net/wp-content/uploads/2022/05/Acme-Logo-700x394.png', - activationStatus: WorkspaceActivationStatus.ACTIVE, + activationStatus: WorkspaceActivationStatus.PENDING_CREATION, // will be set to active after default role creation version: version, }, }; diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/interfaces/base-resolver-service.ts b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/interfaces/base-resolver-service.ts index 58416a50a..b21b7f243 100644 --- a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/interfaces/base-resolver-service.ts +++ b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/interfaces/base-resolver-service.ts @@ -87,17 +87,9 @@ export abstract class GraphqlQueryBaseResolverService< authContext.workspace.id, ); - if ( - featureFlagsMap[FeatureFlagKey.IsPermissionsEnabled] && - objectMetadataItemWithFieldMaps.isSystem === true - ) { + if (objectMetadataItemWithFieldMaps.isSystem === true) { await this.validateSystemObjectPermissionsOrThrow(options); - } - - if ( - featureFlagsMap[FeatureFlagKey.IsPermissionsEnabled] && - !objectMetadataItemWithFieldMaps.isSystem - ) { + } else { await this.validateObjectRecordPermissionsOrThrow({ operationName, options, diff --git a/packages/twenty-server/src/engine/core-modules/billing/billing.resolver.ts b/packages/twenty-server/src/engine/core-modules/billing/billing.resolver.ts index 7fc721050..411ec039a 100644 --- a/packages/twenty-server/src/engine/core-modules/billing/billing.resolver.ts +++ b/packages/twenty-server/src/engine/core-modules/billing/billing.resolver.ts @@ -17,7 +17,6 @@ import { BillingSubscriptionService } from 'src/engine/core-modules/billing/serv import { BillingService } from 'src/engine/core-modules/billing/services/billing.service'; import { BillingPortalCheckoutSessionParameters } from 'src/engine/core-modules/billing/types/billing-portal-checkout-session-parameters.type'; import { formatBillingDatabaseProductToGraphqlDTO } from 'src/engine/core-modules/billing/utils/format-database-product-to-graphql-dto.util'; -import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum'; import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service'; import { User } from 'src/engine/core-modules/user/user.entity'; import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; @@ -140,15 +139,6 @@ export class BillingResolver { userWorkspaceId: string; isExecutedByApiKey: boolean; }) { - const isPermissionsEnabled = await this.featureFlagService.isFeatureEnabled( - FeatureFlagKey.IsPermissionsEnabled, - workspaceId, - ); - - if (!isPermissionsEnabled) { - return; - } - if ( await this.billingService.isSubscriptionIncompleteOnboardingStatus( workspaceId, diff --git a/packages/twenty-server/src/engine/core-modules/feature-flag/constants/public-feature-flag.const.ts b/packages/twenty-server/src/engine/core-modules/feature-flag/constants/public-feature-flag.const.ts index 309b054f9..8d231c5f3 100644 --- a/packages/twenty-server/src/engine/core-modules/feature-flag/constants/public-feature-flag.const.ts +++ b/packages/twenty-server/src/engine/core-modules/feature-flag/constants/public-feature-flag.const.ts @@ -9,9 +9,7 @@ type FeatureFlagMetadata = { export type PublicFeatureFlag = { key: Extract< FeatureFlagKey, - | FeatureFlagKey.IsWorkflowEnabled - | FeatureFlagKey.IsPermissionsEnabled - | FeatureFlagKey.IsCustomDomainEnabled + FeatureFlagKey.IsWorkflowEnabled | FeatureFlagKey.IsCustomDomainEnabled >; metadata: FeatureFlagMetadata; }; @@ -25,15 +23,6 @@ export const PUBLIC_FEATURE_FLAGS: PublicFeatureFlag[] = [ imagePath: 'https://twenty.com/images/lab/is-workflow-enabled.png', }, }, - { - key: FeatureFlagKey.IsPermissionsEnabled, - metadata: { - label: 'Permissions V1', - description: - 'Role-based access control system for workspace security management (Admin/Member)', - imagePath: 'https://twenty.com/images/lab/is-permissions-enabled.png', - }, - }, ...(process.env.CLOUDFLARE_API_KEY ? [ { diff --git a/packages/twenty-server/src/engine/core-modules/feature-flag/enums/feature-flag-key.enum.ts b/packages/twenty-server/src/engine/core-modules/feature-flag/enums/feature-flag-key.enum.ts index e0ee7f15f..86fb628b7 100644 --- a/packages/twenty-server/src/engine/core-modules/feature-flag/enums/feature-flag-key.enum.ts +++ b/packages/twenty-server/src/engine/core-modules/feature-flag/enums/feature-flag-key.enum.ts @@ -12,7 +12,6 @@ export enum FeatureFlagKey { IsCustomDomainEnabled = 'IS_CUSTOM_DOMAIN_ENABLED', IsApprovedAccessDomainsEnabled = 'IS_APPROVED_ACCESS_DOMAINS_ENABLED', IsNewRelationEnabled = 'IS_NEW_RELATION_ENABLED', - IsPermissionsEnabled = 'IS_PERMISSIONS_ENABLED', IsWorkflowFormActionEnabled = 'IS_WORKFLOW_FORM_ACTION_ENABLED', IsPermissionsV2Enabled = 'IS_PERMISSIONS_V2_ENABLED', } diff --git a/packages/twenty-server/src/engine/core-modules/user/services/user.service.ts b/packages/twenty-server/src/engine/core-modules/user/services/user.service.ts index 323ce29bc..cae4ba870 100644 --- a/packages/twenty-server/src/engine/core-modules/user/services/user.service.ts +++ b/packages/twenty-server/src/engine/core-modules/user/services/user.service.ts @@ -3,8 +3,8 @@ import { InjectRepository } from '@nestjs/typeorm'; import assert from 'assert'; import { TypeOrmQueryService } from '@ptc-org/nestjs-query-typeorm'; -import { Repository } from 'typeorm'; import { isWorkspaceActiveOrSuspended } from 'twenty-shared/workspace'; +import { Repository } from 'typeorm'; import { TypeORMService } from 'src/database/typeorm/typeorm.service'; import { DatabaseEventAction } from 'src/engine/api/graphql/graphql-query-runner/enums/database-event-action'; @@ -12,7 +12,6 @@ import { AuthException, AuthExceptionCode, } from 'src/engine/core-modules/auth/auth.exception'; -import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum'; import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service'; import { UserWorkspaceService } from 'src/engine/core-modules/user-workspace/user-workspace.service'; import { User } from 'src/engine/core-modules/user/user.entity'; @@ -97,16 +96,11 @@ export class UserService extends TypeOrmQueryService { const workspaceDataSource = await this.typeORMService.connectToDataSource(dataSourceMetadata); - const isPermissionsEnabled = await this.featureFlagService.isFeatureEnabled( - FeatureFlagKey.IsPermissionsEnabled, - workspaceId, - ); - const workspaceMembers = await workspaceDataSource?.query( `SELECT * FROM ${dataSourceMetadata.schema}."workspaceMember"`, ); - if (isPermissionsEnabled && workspaceMembers.length > 1) { + if (workspaceMembers.length > 1) { const userWorkspace = await this.userWorkspaceService.getUserWorkspaceForUserOrThrow({ userId, diff --git a/packages/twenty-server/src/engine/core-modules/user/user.resolver.ts b/packages/twenty-server/src/engine/core-modules/user/user.resolver.ts index 10fe0b22a..3dc25324b 100644 --- a/packages/twenty-server/src/engine/core-modules/user/user.resolver.ts +++ b/packages/twenty-server/src/engine/core-modules/user/user.resolver.ts @@ -27,8 +27,6 @@ import { } from 'src/engine/core-modules/auth/auth.exception'; import { DomainManagerService } from 'src/engine/core-modules/domain-manager/services/domain-manager.service'; import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service'; -import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum'; -import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service'; import { FileUploadService } from 'src/engine/core-modules/file/file-upload/services/file-upload.service'; import { FileService } from 'src/engine/core-modules/file/services/file.service'; import { OnboardingStatus } from 'src/engine/core-modules/onboarding/enums/onboarding-status.enum'; @@ -83,7 +81,6 @@ export class UserResolver { private readonly userWorkspaceRepository: Repository, private readonly userRoleService: UserRoleService, private readonly permissionsService: PermissionsService, - private readonly featureFlagService: FeatureFlagService, ) {} @Query(() => User) @@ -103,38 +100,31 @@ export class UserResolver { new AuthException('User not found', AuthExceptionCode.USER_NOT_FOUND), ); - const permissionsEnabled = await this.featureFlagService.isFeatureEnabled( - FeatureFlagKey.IsPermissionsEnabled, - workspace.id, + const currentUserWorkspace = user.workspaces.find( + (userWorkspace) => userWorkspace.workspace.id === workspace.id, ); - if (permissionsEnabled === true) { - const currentUserWorkspace = user.workspaces.find( - (userWorkspace) => userWorkspace.workspace.id === workspace.id, - ); - - if (!currentUserWorkspace) { - throw new Error('Current user workspace not found'); - } - const { settingsPermissions, objectRecordsPermissions } = - await this.permissionsService.getUserWorkspacePermissions({ - userWorkspaceId: currentUserWorkspace.id, - workspaceId: workspace.id, - }); - - const grantedSettingsPermissions: SettingPermissionType[] = ( - Object.keys(settingsPermissions) as SettingPermissionType[] - ).filter((feature) => settingsPermissions[feature] === true); - - const grantedObjectRecordsPermissions = ( - Object.keys(objectRecordsPermissions) as PermissionsOnAllObjectRecords[] - ).filter((permission) => objectRecordsPermissions[permission] === true); - - currentUserWorkspace.settingsPermissions = grantedSettingsPermissions; - currentUserWorkspace.objectRecordsPermissions = - grantedObjectRecordsPermissions; - user.currentUserWorkspace = currentUserWorkspace; + if (!currentUserWorkspace) { + throw new Error('Current user workspace not found'); } + const { settingsPermissions, objectRecordsPermissions } = + await this.permissionsService.getUserWorkspacePermissions({ + userWorkspaceId: currentUserWorkspace.id, + workspaceId: workspace.id, + }); + + const grantedSettingsPermissions: SettingPermissionType[] = ( + Object.keys(settingsPermissions) as SettingPermissionType[] + ).filter((feature) => settingsPermissions[feature] === true); + + const grantedObjectRecordsPermissions = ( + Object.keys(objectRecordsPermissions) as PermissionsOnAllObjectRecords[] + ).filter((permission) => objectRecordsPermissions[permission] === true); + + currentUserWorkspace.settingsPermissions = grantedSettingsPermissions; + currentUserWorkspace.objectRecordsPermissions = + grantedObjectRecordsPermissions; + user.currentUserWorkspace = currentUserWorkspace; return { ...user, @@ -202,37 +192,31 @@ export class UserResolver { const workspaceMembers: WorkspaceMember[] = []; - const permissionsEnabled = await this.featureFlagService.isFeatureEnabled( - FeatureFlagKey.IsPermissionsEnabled, - workspace.id, - ); - let userWorkspacesByUserId = new Map(); let rolesByUserWorkspaces = new Map(); - if (permissionsEnabled === true) { - const userWorkspaces = await this.userWorkspaceRepository.find({ - where: { - userId: In(workspaceMemberEntities.map((entity) => entity.userId)), - workspaceId: workspace.id, - }, - }); + const userWorkspaces = await this.userWorkspaceRepository.find({ + where: { + userId: In(workspaceMemberEntities.map((entity) => entity.userId)), + workspaceId: workspace.id, + }, + }); - userWorkspacesByUserId = new Map( - userWorkspaces.map((userWorkspace) => [ - userWorkspace.userId, - userWorkspace, - ]), - ); + userWorkspacesByUserId = new Map( + userWorkspaces.map((userWorkspace) => [ + userWorkspace.userId, + userWorkspace, + ]), + ); - rolesByUserWorkspaces = - await this.userRoleService.getRolesByUserWorkspaces({ - userWorkspaceIds: userWorkspaces.map( - (userWorkspace) => userWorkspace.id, - ), - workspaceId: workspace.id, - }); - } + rolesByUserWorkspaces = await this.userRoleService.getRolesByUserWorkspaces( + { + userWorkspaceIds: userWorkspaces.map( + (userWorkspace) => userWorkspace.id, + ), + workspaceId: workspace.id, + }, + ); for (const workspaceMemberEntity of workspaceMemberEntities) { if (workspaceMemberEntity.avatarUrl) { @@ -246,39 +230,37 @@ export class UserResolver { const workspaceMember = workspaceMemberEntity as WorkspaceMember; - if (permissionsEnabled === true) { - const userWorkspace = userWorkspacesByUserId.get( - workspaceMemberEntity.userId, - ); + const userWorkspace = userWorkspacesByUserId.get( + workspaceMemberEntity.userId, + ); - if (!userWorkspace) { - throw new Error('User workspace not found'); - } - - workspaceMember.userWorkspaceId = userWorkspace.id; - - const workspaceMemberRoles = ( - rolesByUserWorkspaces.get(userWorkspace.id) ?? [] - ).map((roleEntity) => { - return { - id: roleEntity.id, - label: roleEntity.label, - canUpdateAllSettings: roleEntity.canUpdateAllSettings, - description: roleEntity.description, - icon: roleEntity.icon, - isEditable: roleEntity.isEditable, - userWorkspaceRoles: roleEntity.userWorkspaceRoles, - canReadAllObjectRecords: roleEntity.canReadAllObjectRecords, - canUpdateAllObjectRecords: roleEntity.canUpdateAllObjectRecords, - canSoftDeleteAllObjectRecords: - roleEntity.canSoftDeleteAllObjectRecords, - canDestroyAllObjectRecords: roleEntity.canDestroyAllObjectRecords, - }; - }); - - workspaceMember.roles = workspaceMemberRoles; + if (!userWorkspace) { + throw new Error('User workspace not found'); } + workspaceMember.userWorkspaceId = userWorkspace.id; + + const workspaceMemberRoles = ( + rolesByUserWorkspaces.get(userWorkspace.id) ?? [] + ).map((roleEntity) => { + return { + id: roleEntity.id, + label: roleEntity.label, + canUpdateAllSettings: roleEntity.canUpdateAllSettings, + description: roleEntity.description, + icon: roleEntity.icon, + isEditable: roleEntity.isEditable, + userWorkspaceRoles: roleEntity.userWorkspaceRoles, + canReadAllObjectRecords: roleEntity.canReadAllObjectRecords, + canUpdateAllObjectRecords: roleEntity.canUpdateAllObjectRecords, + canSoftDeleteAllObjectRecords: + roleEntity.canSoftDeleteAllObjectRecords, + canDestroyAllObjectRecords: roleEntity.canDestroyAllObjectRecords, + }; + }); + + workspaceMember.roles = workspaceMemberRoles; + workspaceMembers.push(workspaceMember); } diff --git a/packages/twenty-server/src/engine/core-modules/workspace/services/workspace.service.ts b/packages/twenty-server/src/engine/core-modules/workspace/services/workspace.service.ts index b46c39e15..5fcf3f2b5 100644 --- a/packages/twenty-server/src/engine/core-modules/workspace/services/workspace.service.ts +++ b/packages/twenty-server/src/engine/core-modules/workspace/services/workspace.service.ts @@ -15,7 +15,6 @@ import { CustomDomainService } from 'src/engine/core-modules/domain-manager/serv import { DomainManagerService } from 'src/engine/core-modules/domain-manager/services/domain-manager.service'; import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service'; import { ExceptionHandlerService } from 'src/engine/core-modules/exception-handler/exception-handler.service'; -import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum'; import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service'; import { FileWorkspaceFolderDeletionJob, @@ -154,26 +153,19 @@ export class WorkspaceService extends TypeOrmQueryService { workspaceValidator.assertIsDefinedOrThrow(workspace); - const permissionsEnabled = await this.featureFlagService.isFeatureEnabled( - FeatureFlagKey.IsPermissionsEnabled, - workspace.id, - ); + await this.validateSecurityPermissions({ + payload, + userWorkspaceId, + workspaceId: workspace.id, + apiKey, + }); - if (permissionsEnabled) { - await this.validateSecurityPermissions({ - payload, - userWorkspaceId, - workspaceId: workspace.id, - apiKey, - }); - - await this.validateWorkspacePermissions({ - payload, - userWorkspaceId, - workspaceId: workspace.id, - apiKey, - }); - } + await this.validateWorkspacePermissions({ + payload, + userWorkspaceId, + workspaceId: workspace.id, + apiKey, + }); if (payload.subdomain && workspace.subdomain !== payload.subdomain) { await this.validateSubdomainUpdate(payload.subdomain); diff --git a/packages/twenty-server/src/engine/core-modules/workspace/workspace.entity.ts b/packages/twenty-server/src/engine/core-modules/workspace/workspace.entity.ts index 0b411d4b6..7b6c969f4 100644 --- a/packages/twenty-server/src/engine/core-modules/workspace/workspace.entity.ts +++ b/packages/twenty-server/src/engine/core-modules/workspace/workspace.entity.ts @@ -1,6 +1,7 @@ import { Field, ObjectType, registerEnumType } from '@nestjs/graphql'; import { IDField } from '@ptc-org/nestjs-query-graphql'; +import { WorkspaceActivationStatus } from 'twenty-shared/workspace'; import { Column, CreateDateColumn, @@ -11,7 +12,6 @@ import { Relation, UpdateDateColumn, } from 'typeorm'; -import { WorkspaceActivationStatus } from 'twenty-shared/workspace'; import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars'; import { AppToken } from 'src/engine/core-modules/app-token/app-token.entity'; diff --git a/packages/twenty-server/src/engine/guards/settings-permissions.guard.ts b/packages/twenty-server/src/engine/guards/settings-permissions.guard.ts index add96582a..9169e5a9b 100644 --- a/packages/twenty-server/src/engine/guards/settings-permissions.guard.ts +++ b/packages/twenty-server/src/engine/guards/settings-permissions.guard.ts @@ -9,8 +9,6 @@ import { GqlExecutionContext } from '@nestjs/graphql'; import { isDefined } from 'twenty-shared/utils'; -import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum'; -import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service'; import { SettingPermissionType } from 'src/engine/metadata-modules/permissions/constants/setting-permission-type.constants'; import { PermissionsException, @@ -24,24 +22,11 @@ export const SettingsPermissionsGuard = ( ): Type => { @Injectable() class SettingsPermissionsMixin implements CanActivate { - constructor( - private readonly featureFlagService: FeatureFlagService, - private readonly permissionsService: PermissionsService, - ) {} + constructor(private readonly permissionsService: PermissionsService) {} async canActivate(context: ExecutionContext): Promise { const ctx = GqlExecutionContext.create(context); const workspaceId = ctx.getContext().req.workspace.id; - - const permissionsEnabled = await this.featureFlagService.isFeatureEnabled( - FeatureFlagKey.IsPermissionsEnabled, - workspaceId, - ); - - if (!permissionsEnabled) { - return true; - } - const userWorkspaceId = ctx.getContext().req.userWorkspaceId; const hasPermission = diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-manager.service.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-manager.service.ts index 5ba9a46af..83253b78c 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-manager.service.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-manager.service.ts @@ -1,6 +1,7 @@ import { Injectable, Logger } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; +import { WorkspaceActivationStatus } from 'twenty-shared/workspace'; import { Repository } from 'typeorm'; import { DEV_SEED_USER_WORKSPACE_IDS } from 'src/database/typeorm-seeds/core/user-workspaces'; @@ -8,7 +9,6 @@ import { SEED_ACME_WORKSPACE_ID, SEED_APPLE_WORKSPACE_ID, } from 'src/database/typeorm-seeds/core/workspaces'; -import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum'; import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service'; import { UserWorkspace } from 'src/engine/core-modules/user-workspace/user-workspace.entity'; import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; @@ -315,21 +315,16 @@ export class WorkspaceManagerService { roleId: adminRole.id, }); - await this.roleService.createMemberRole({ + const memberRole = await this.roleService.createMemberRole({ workspaceId, }); - // Temporary - after permissions are rolled-out we will set member role as the default role await this.workspaceRepository.update(workspaceId, { - defaultRoleId: adminRole.id, + defaultRoleId: memberRole.id, }); } private async initPermissionsDev(workspaceId: string) { - await this.featureFlagService.enableFeatureFlags( - [FeatureFlagKey.IsPermissionsEnabled], - workspaceId, - ); const adminRole = await this.roleService.createAdminRole({ workspaceId, }); @@ -369,6 +364,7 @@ export class WorkspaceManagerService { await this.workspaceRepository.update(workspaceId, { defaultRoleId: memberRole.id, + activationStatus: WorkspaceActivationStatus.ACTIVE, }); if (memberUserWorkspaceId) { diff --git a/packages/twenty-server/src/modules/workspace-member/query-hooks/workspace-member-pre-query-hook.service.ts b/packages/twenty-server/src/modules/workspace-member/query-hooks/workspace-member-pre-query-hook.service.ts index 6f9e3ab94..2ea2631e5 100644 --- a/packages/twenty-server/src/modules/workspace-member/query-hooks/workspace-member-pre-query-hook.service.ts +++ b/packages/twenty-server/src/modules/workspace-member/query-hooks/workspace-member-pre-query-hook.service.ts @@ -2,7 +2,6 @@ import { Injectable } from '@nestjs/common'; import { isDefined } from 'twenty-shared/utils'; -import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum'; import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service'; import { SettingPermissionType } from 'src/engine/metadata-modules/permissions/constants/setting-permission-type.constants'; import { @@ -33,16 +32,6 @@ export class WorkspaceMemberPreQueryHookService { workspaceId: string; apiKey?: ApiKeyWorkspaceEntity | null; }) { - const featureFlagsMap = - await this.featureFlagService.getWorkspaceFeatureFlagsMap(workspaceId); - - const isPermissionsEnabled = - featureFlagsMap[FeatureFlagKey.IsPermissionsEnabled]; - - if (!isPermissionsEnabled) { - return; - } - if (isDefined(apiKey)) { return; } diff --git a/packages/twenty-server/test/integration/graphql/suites/object-records-permissions/create-many-object-records-permissions.integration-spec.ts b/packages/twenty-server/test/integration/graphql/suites/object-records-permissions/create-many-object-records-permissions.integration-spec.ts index e6d65ad0e..26ebffc76 100644 --- a/packages/twenty-server/test/integration/graphql/suites/object-records-permissions/create-many-object-records-permissions.integration-spec.ts +++ b/packages/twenty-server/test/integration/graphql/suites/object-records-permissions/create-many-object-records-permissions.integration-spec.ts @@ -4,33 +4,11 @@ import { PERSON_GQL_FIELDS } from 'test/integration/constants/person-gql-fields. import { createManyOperationFactory } from 'test/integration/graphql/utils/create-many-operation-factory.util'; import { makeGraphqlAPIRequestWithGuestRole } from 'test/integration/graphql/utils/make-graphql-api-request-with-guest-role.util'; import { makeGraphqlAPIRequest } from 'test/integration/graphql/utils/make-graphql-api-request.util'; -import { updateFeatureFlagFactory } from 'test/integration/graphql/utils/update-feature-flag-factory.util'; -import { SEED_APPLE_WORKSPACE_ID } from 'src/database/typeorm-seeds/core/workspaces'; import { ErrorCode } from 'src/engine/core-modules/graphql/utils/graphql-errors.util'; import { PermissionsExceptionMessage } from 'src/engine/metadata-modules/permissions/permissions.exception'; describe('createManyObjectRecordsPermissions', () => { - beforeAll(async () => { - const enablePermissionsQuery = updateFeatureFlagFactory( - SEED_APPLE_WORKSPACE_ID, - 'IsPermissionsEnabled', - true, - ); - - await makeGraphqlAPIRequest(enablePermissionsQuery); - }); - - afterAll(async () => { - const disablePermissionsQuery = updateFeatureFlagFactory( - SEED_APPLE_WORKSPACE_ID, - 'IsPermissionsEnabled', - false, - ); - - await makeGraphqlAPIRequest(disablePermissionsQuery); - }); - it('should throw a permission error when user does not have permission (guest role)', async () => { const graphqlOperation = createManyOperationFactory({ objectMetadataSingularName: 'person', diff --git a/packages/twenty-server/test/integration/graphql/suites/object-records-permissions/create-one-object-records-permissions.integration-spec.ts b/packages/twenty-server/test/integration/graphql/suites/object-records-permissions/create-one-object-records-permissions.integration-spec.ts index 0da7ae11c..40256f027 100644 --- a/packages/twenty-server/test/integration/graphql/suites/object-records-permissions/create-one-object-records-permissions.integration-spec.ts +++ b/packages/twenty-server/test/integration/graphql/suites/object-records-permissions/create-one-object-records-permissions.integration-spec.ts @@ -4,33 +4,11 @@ import { PERSON_GQL_FIELDS } from 'test/integration/constants/person-gql-fields. import { createOneOperationFactory } from 'test/integration/graphql/utils/create-one-operation-factory.util'; import { makeGraphqlAPIRequestWithGuestRole } from 'test/integration/graphql/utils/make-graphql-api-request-with-guest-role.util'; import { makeGraphqlAPIRequest } from 'test/integration/graphql/utils/make-graphql-api-request.util'; -import { updateFeatureFlagFactory } from 'test/integration/graphql/utils/update-feature-flag-factory.util'; -import { SEED_APPLE_WORKSPACE_ID } from 'src/database/typeorm-seeds/core/workspaces'; import { ErrorCode } from 'src/engine/core-modules/graphql/utils/graphql-errors.util'; import { PermissionsExceptionMessage } from 'src/engine/metadata-modules/permissions/permissions.exception'; describe('createOneObjectRecordsPermissions', () => { - beforeAll(async () => { - const enablePermissionsQuery = updateFeatureFlagFactory( - SEED_APPLE_WORKSPACE_ID, - 'IsPermissionsEnabled', - true, - ); - - await makeGraphqlAPIRequest(enablePermissionsQuery); - }); - - afterAll(async () => { - const disablePermissionsQuery = updateFeatureFlagFactory( - SEED_APPLE_WORKSPACE_ID, - 'IsPermissionsEnabled', - false, - ); - - await makeGraphqlAPIRequest(disablePermissionsQuery); - }); - it('should throw a permission error when user does not have permission (guest role)', async () => { const graphqlOperation = createOneOperationFactory({ objectMetadataSingularName: 'person', diff --git a/packages/twenty-server/test/integration/graphql/suites/object-records-permissions/delete-many-object-records-permissions.integration-spec.ts b/packages/twenty-server/test/integration/graphql/suites/object-records-permissions/delete-many-object-records-permissions.integration-spec.ts index 834dddfe7..d37f2066b 100644 --- a/packages/twenty-server/test/integration/graphql/suites/object-records-permissions/delete-many-object-records-permissions.integration-spec.ts +++ b/packages/twenty-server/test/integration/graphql/suites/object-records-permissions/delete-many-object-records-permissions.integration-spec.ts @@ -5,33 +5,11 @@ import { createManyOperationFactory } from 'test/integration/graphql/utils/creat import { deleteManyOperationFactory } from 'test/integration/graphql/utils/delete-many-operation-factory.util'; import { makeGraphqlAPIRequestWithGuestRole } from 'test/integration/graphql/utils/make-graphql-api-request-with-guest-role.util'; import { makeGraphqlAPIRequest } from 'test/integration/graphql/utils/make-graphql-api-request.util'; -import { updateFeatureFlagFactory } from 'test/integration/graphql/utils/update-feature-flag-factory.util'; -import { SEED_APPLE_WORKSPACE_ID } from 'src/database/typeorm-seeds/core/workspaces'; import { ErrorCode } from 'src/engine/core-modules/graphql/utils/graphql-errors.util'; import { PermissionsExceptionMessage } from 'src/engine/metadata-modules/permissions/permissions.exception'; describe('deleteManyObjectRecordsPermissions', () => { - beforeAll(async () => { - const enablePermissionsQuery = updateFeatureFlagFactory( - SEED_APPLE_WORKSPACE_ID, - 'IsPermissionsEnabled', - true, - ); - - await makeGraphqlAPIRequest(enablePermissionsQuery); - }); - - afterAll(async () => { - const disablePermissionsQuery = updateFeatureFlagFactory( - SEED_APPLE_WORKSPACE_ID, - 'IsPermissionsEnabled', - false, - ); - - await makeGraphqlAPIRequest(disablePermissionsQuery); - }); - it('should throw a permission error when user does not have permission (guest role)', async () => { const graphqlOperation = deleteManyOperationFactory({ objectMetadataSingularName: 'person', diff --git a/packages/twenty-server/test/integration/graphql/suites/object-records-permissions/delete-one-object-records-permissions.integration-spec.ts b/packages/twenty-server/test/integration/graphql/suites/object-records-permissions/delete-one-object-records-permissions.integration-spec.ts index b004dc5b0..c2ffee0d5 100644 --- a/packages/twenty-server/test/integration/graphql/suites/object-records-permissions/delete-one-object-records-permissions.integration-spec.ts +++ b/packages/twenty-server/test/integration/graphql/suites/object-records-permissions/delete-one-object-records-permissions.integration-spec.ts @@ -5,9 +5,7 @@ import { createOneOperationFactory } from 'test/integration/graphql/utils/create import { deleteOneOperationFactory } from 'test/integration/graphql/utils/delete-one-operation-factory.util'; import { makeGraphqlAPIRequestWithGuestRole } from 'test/integration/graphql/utils/make-graphql-api-request-with-guest-role.util'; import { makeGraphqlAPIRequest } from 'test/integration/graphql/utils/make-graphql-api-request.util'; -import { updateFeatureFlagFactory } from 'test/integration/graphql/utils/update-feature-flag-factory.util'; -import { SEED_APPLE_WORKSPACE_ID } from 'src/database/typeorm-seeds/core/workspaces'; import { ErrorCode } from 'src/engine/core-modules/graphql/utils/graphql-errors.util'; import { PermissionsExceptionMessage } from 'src/engine/metadata-modules/permissions/permissions.exception'; @@ -15,15 +13,7 @@ describe('deleteOneObjectRecordsPermissions', () => { const personId = randomUUID(); beforeAll(async () => { - const enablePermissionsQuery = updateFeatureFlagFactory( - SEED_APPLE_WORKSPACE_ID, - 'IsPermissionsEnabled', - true, - ); - - await makeGraphqlAPIRequest(enablePermissionsQuery); - - const createGraphqlOperation = createOneOperationFactory({ + const createOnePersonRecordOperation = createOneOperationFactory({ objectMetadataSingularName: 'person', gqlFields: PERSON_GQL_FIELDS, data: { @@ -31,17 +21,7 @@ describe('deleteOneObjectRecordsPermissions', () => { }, }); - await makeGraphqlAPIRequest(createGraphqlOperation); - }); - - afterAll(async () => { - const disablePermissionsQuery = updateFeatureFlagFactory( - SEED_APPLE_WORKSPACE_ID, - 'IsPermissionsEnabled', - false, - ); - - await makeGraphqlAPIRequest(disablePermissionsQuery); + await makeGraphqlAPIRequest(createOnePersonRecordOperation); }); it('should throw a permission error when user does not have permission (guest role)', async () => { diff --git a/packages/twenty-server/test/integration/graphql/suites/object-records-permissions/destroy-many-object-records-permissions.integration-spec.ts b/packages/twenty-server/test/integration/graphql/suites/object-records-permissions/destroy-many-object-records-permissions.integration-spec.ts index 36ae403e2..089b7403d 100644 --- a/packages/twenty-server/test/integration/graphql/suites/object-records-permissions/destroy-many-object-records-permissions.integration-spec.ts +++ b/packages/twenty-server/test/integration/graphql/suites/object-records-permissions/destroy-many-object-records-permissions.integration-spec.ts @@ -5,33 +5,11 @@ import { createManyOperationFactory } from 'test/integration/graphql/utils/creat import { destroyManyOperationFactory } from 'test/integration/graphql/utils/destroy-many-operation-factory.util'; import { makeGraphqlAPIRequestWithGuestRole } from 'test/integration/graphql/utils/make-graphql-api-request-with-guest-role.util'; import { makeGraphqlAPIRequest } from 'test/integration/graphql/utils/make-graphql-api-request.util'; -import { updateFeatureFlagFactory } from 'test/integration/graphql/utils/update-feature-flag-factory.util'; -import { SEED_APPLE_WORKSPACE_ID } from 'src/database/typeorm-seeds/core/workspaces'; import { ErrorCode } from 'src/engine/core-modules/graphql/utils/graphql-errors.util'; import { PermissionsExceptionMessage } from 'src/engine/metadata-modules/permissions/permissions.exception'; describe('destroyManyObjectRecordsPermissions', () => { - beforeAll(async () => { - const enablePermissionsQuery = updateFeatureFlagFactory( - SEED_APPLE_WORKSPACE_ID, - 'IsPermissionsEnabled', - true, - ); - - await makeGraphqlAPIRequest(enablePermissionsQuery); - }); - - afterAll(async () => { - const disablePermissionsQuery = updateFeatureFlagFactory( - SEED_APPLE_WORKSPACE_ID, - 'IsPermissionsEnabled', - false, - ); - - await makeGraphqlAPIRequest(disablePermissionsQuery); - }); - it('should throw a permission error when user does not have permission (guest role)', async () => { const graphqlOperation = destroyManyOperationFactory({ objectMetadataSingularName: 'person', diff --git a/packages/twenty-server/test/integration/graphql/suites/object-records-permissions/destroy-one-object-records-permissions.integration-spec.ts b/packages/twenty-server/test/integration/graphql/suites/object-records-permissions/destroy-one-object-records-permissions.integration-spec.ts index 18932e15e..06139c959 100644 --- a/packages/twenty-server/test/integration/graphql/suites/object-records-permissions/destroy-one-object-records-permissions.integration-spec.ts +++ b/packages/twenty-server/test/integration/graphql/suites/object-records-permissions/destroy-one-object-records-permissions.integration-spec.ts @@ -5,9 +5,7 @@ import { createOneOperationFactory } from 'test/integration/graphql/utils/create import { destroyOneOperationFactory } from 'test/integration/graphql/utils/destroy-one-operation-factory.util'; import { makeGraphqlAPIRequestWithGuestRole } from 'test/integration/graphql/utils/make-graphql-api-request-with-guest-role.util'; import { makeGraphqlAPIRequest } from 'test/integration/graphql/utils/make-graphql-api-request.util'; -import { updateFeatureFlagFactory } from 'test/integration/graphql/utils/update-feature-flag-factory.util'; -import { SEED_APPLE_WORKSPACE_ID } from 'src/database/typeorm-seeds/core/workspaces'; import { ErrorCode } from 'src/engine/core-modules/graphql/utils/graphql-errors.util'; import { PermissionsExceptionMessage } from 'src/engine/metadata-modules/permissions/permissions.exception'; @@ -15,14 +13,6 @@ describe('destroyOneObjectRecordsPermissions', () => { const personId = randomUUID(); beforeAll(async () => { - const enablePermissionsQuery = updateFeatureFlagFactory( - SEED_APPLE_WORKSPACE_ID, - 'IsPermissionsEnabled', - true, - ); - - await makeGraphqlAPIRequest(enablePermissionsQuery); - const createGraphqlOperation = createOneOperationFactory({ objectMetadataSingularName: 'person', gqlFields: PERSON_GQL_FIELDS, @@ -34,16 +24,6 @@ describe('destroyOneObjectRecordsPermissions', () => { await makeGraphqlAPIRequest(createGraphqlOperation); }); - afterAll(async () => { - const disablePermissionsQuery = updateFeatureFlagFactory( - SEED_APPLE_WORKSPACE_ID, - 'IsPermissionsEnabled', - false, - ); - - await makeGraphqlAPIRequest(disablePermissionsQuery); - }); - it('should throw a permission error when user does not have permission (guest role)', async () => { const personId = randomUUID(); const graphqlOperation = destroyOneOperationFactory({ diff --git a/packages/twenty-server/test/integration/graphql/suites/object-records-permissions/restore-many-object-records-permissions.integration-spec.ts b/packages/twenty-server/test/integration/graphql/suites/object-records-permissions/restore-many-object-records-permissions.integration-spec.ts index 72abd7223..d4cccbcf6 100644 --- a/packages/twenty-server/test/integration/graphql/suites/object-records-permissions/restore-many-object-records-permissions.integration-spec.ts +++ b/packages/twenty-server/test/integration/graphql/suites/object-records-permissions/restore-many-object-records-permissions.integration-spec.ts @@ -6,9 +6,7 @@ import { deleteManyOperationFactory } from 'test/integration/graphql/utils/delet import { makeGraphqlAPIRequestWithGuestRole } from 'test/integration/graphql/utils/make-graphql-api-request-with-guest-role.util'; import { makeGraphqlAPIRequest } from 'test/integration/graphql/utils/make-graphql-api-request.util'; import { restoreManyOperationFactory } from 'test/integration/graphql/utils/restore-many-operation-factory.util'; -import { updateFeatureFlagFactory } from 'test/integration/graphql/utils/update-feature-flag-factory.util'; -import { SEED_APPLE_WORKSPACE_ID } from 'src/database/typeorm-seeds/core/workspaces'; import { ErrorCode } from 'src/engine/core-modules/graphql/utils/graphql-errors.util'; import { PermissionsExceptionMessage } from 'src/engine/metadata-modules/permissions/permissions.exception'; @@ -17,14 +15,6 @@ describe('restoreManyObjectRecordsPermissions', () => { const personId2 = randomUUID(); beforeAll(async () => { - const enablePermissionsQuery = updateFeatureFlagFactory( - SEED_APPLE_WORKSPACE_ID, - 'IsPermissionsEnabled', - true, - ); - - await makeGraphqlAPIRequest(enablePermissionsQuery); - // Create people const createGraphqlOperation = createManyOperationFactory({ objectMetadataSingularName: 'person', @@ -57,16 +47,6 @@ describe('restoreManyObjectRecordsPermissions', () => { await makeGraphqlAPIRequest(deleteGraphqlOperation); }); - afterAll(async () => { - const disablePermissionsQuery = updateFeatureFlagFactory( - SEED_APPLE_WORKSPACE_ID, - 'IsPermissionsEnabled', - false, - ); - - await makeGraphqlAPIRequest(disablePermissionsQuery); - }); - it('should throw a permission error when user does not have permission (guest role)', async () => { const graphqlOperation = restoreManyOperationFactory({ objectMetadataSingularName: 'person', diff --git a/packages/twenty-server/test/integration/graphql/suites/object-records-permissions/restore-one-object-records-permissions.integration-spec.ts b/packages/twenty-server/test/integration/graphql/suites/object-records-permissions/restore-one-object-records-permissions.integration-spec.ts index 75ee6c588..915b68992 100644 --- a/packages/twenty-server/test/integration/graphql/suites/object-records-permissions/restore-one-object-records-permissions.integration-spec.ts +++ b/packages/twenty-server/test/integration/graphql/suites/object-records-permissions/restore-one-object-records-permissions.integration-spec.ts @@ -6,9 +6,7 @@ import { deleteOneOperationFactory } from 'test/integration/graphql/utils/delete import { makeGraphqlAPIRequestWithGuestRole } from 'test/integration/graphql/utils/make-graphql-api-request-with-guest-role.util'; import { makeGraphqlAPIRequest } from 'test/integration/graphql/utils/make-graphql-api-request.util'; import { restoreOneOperationFactory } from 'test/integration/graphql/utils/restore-one-operation-factory.util'; -import { updateFeatureFlagFactory } from 'test/integration/graphql/utils/update-feature-flag-factory.util'; -import { SEED_APPLE_WORKSPACE_ID } from 'src/database/typeorm-seeds/core/workspaces'; import { ErrorCode } from 'src/engine/core-modules/graphql/utils/graphql-errors.util'; import { PermissionsExceptionMessage } from 'src/engine/metadata-modules/permissions/permissions.exception'; @@ -16,14 +14,6 @@ describe('restoreOneObjectRecordsPermissions', () => { const personId = randomUUID(); beforeAll(async () => { - const enablePermissionsQuery = updateFeatureFlagFactory( - SEED_APPLE_WORKSPACE_ID, - 'IsPermissionsEnabled', - true, - ); - - await makeGraphqlAPIRequest(enablePermissionsQuery); - // Create a person const createGraphqlOperation = createOneOperationFactory({ objectMetadataSingularName: 'person', @@ -45,16 +35,6 @@ describe('restoreOneObjectRecordsPermissions', () => { await makeGraphqlAPIRequest(deleteGraphqlOperation); }); - afterAll(async () => { - const disablePermissionsQuery = updateFeatureFlagFactory( - SEED_APPLE_WORKSPACE_ID, - 'IsPermissionsEnabled', - false, - ); - - await makeGraphqlAPIRequest(disablePermissionsQuery); - }); - it('should throw a permission error when user does not have permission (guest role)', async () => { const graphqlOperation = restoreOneOperationFactory({ objectMetadataSingularName: 'person', diff --git a/packages/twenty-server/test/integration/graphql/suites/object-records-permissions/update-many-object-records-permissions.integration-spec.ts b/packages/twenty-server/test/integration/graphql/suites/object-records-permissions/update-many-object-records-permissions.integration-spec.ts index 3500dd82c..a42831da8 100644 --- a/packages/twenty-server/test/integration/graphql/suites/object-records-permissions/update-many-object-records-permissions.integration-spec.ts +++ b/packages/twenty-server/test/integration/graphql/suites/object-records-permissions/update-many-object-records-permissions.integration-spec.ts @@ -4,10 +4,8 @@ import { PERSON_GQL_FIELDS } from 'test/integration/constants/person-gql-fields. import { createManyOperationFactory } from 'test/integration/graphql/utils/create-many-operation-factory.util'; import { makeGraphqlAPIRequestWithGuestRole } from 'test/integration/graphql/utils/make-graphql-api-request-with-guest-role.util'; import { makeGraphqlAPIRequest } from 'test/integration/graphql/utils/make-graphql-api-request.util'; -import { updateFeatureFlagFactory } from 'test/integration/graphql/utils/update-feature-flag-factory.util'; import { updateManyOperationFactory } from 'test/integration/graphql/utils/update-many-operation-factory.util'; -import { SEED_APPLE_WORKSPACE_ID } from 'src/database/typeorm-seeds/core/workspaces'; import { ErrorCode } from 'src/engine/core-modules/graphql/utils/graphql-errors.util'; import { PermissionsExceptionMessage } from 'src/engine/metadata-modules/permissions/permissions.exception'; @@ -16,14 +14,6 @@ describe('updateManyObjectRecordsPermissions', () => { const personId2 = randomUUID(); beforeAll(async () => { - const enablePermissionsQuery = updateFeatureFlagFactory( - SEED_APPLE_WORKSPACE_ID, - 'IsPermissionsEnabled', - true, - ); - - await makeGraphqlAPIRequest(enablePermissionsQuery); - const createGraphqlOperation = createManyOperationFactory({ objectMetadataSingularName: 'person', objectMetadataPluralName: 'people', @@ -41,16 +31,6 @@ describe('updateManyObjectRecordsPermissions', () => { await makeGraphqlAPIRequest(createGraphqlOperation); }); - afterAll(async () => { - const disablePermissionsQuery = updateFeatureFlagFactory( - SEED_APPLE_WORKSPACE_ID, - 'IsPermissionsEnabled', - false, - ); - - await makeGraphqlAPIRequest(disablePermissionsQuery); - }); - it('should throw a permission error when user does not have permission (guest role)', async () => { const graphqlOperation = updateManyOperationFactory({ objectMetadataSingularName: 'person', diff --git a/packages/twenty-server/test/integration/graphql/suites/object-records-permissions/update-one-object-records-permissions.integration-spec.ts b/packages/twenty-server/test/integration/graphql/suites/object-records-permissions/update-one-object-records-permissions.integration-spec.ts index bb6c6ff00..31bd91bbb 100644 --- a/packages/twenty-server/test/integration/graphql/suites/object-records-permissions/update-one-object-records-permissions.integration-spec.ts +++ b/packages/twenty-server/test/integration/graphql/suites/object-records-permissions/update-one-object-records-permissions.integration-spec.ts @@ -4,10 +4,8 @@ import { PERSON_GQL_FIELDS } from 'test/integration/constants/person-gql-fields. import { createOneOperationFactory } from 'test/integration/graphql/utils/create-one-operation-factory.util'; import { makeGraphqlAPIRequestWithGuestRole } from 'test/integration/graphql/utils/make-graphql-api-request-with-guest-role.util'; import { makeGraphqlAPIRequest } from 'test/integration/graphql/utils/make-graphql-api-request.util'; -import { updateFeatureFlagFactory } from 'test/integration/graphql/utils/update-feature-flag-factory.util'; import { updateOneOperationFactory } from 'test/integration/graphql/utils/update-one-operation-factory.util'; -import { SEED_APPLE_WORKSPACE_ID } from 'src/database/typeorm-seeds/core/workspaces'; import { ErrorCode } from 'src/engine/core-modules/graphql/utils/graphql-errors.util'; import { PermissionsExceptionMessage } from 'src/engine/metadata-modules/permissions/permissions.exception'; @@ -15,14 +13,6 @@ describe('updateOneObjectRecordsPermissions', () => { const personId = randomUUID(); beforeAll(async () => { - const enablePermissionsQuery = updateFeatureFlagFactory( - SEED_APPLE_WORKSPACE_ID, - 'IsPermissionsEnabled', - true, - ); - - await makeGraphqlAPIRequest(enablePermissionsQuery); - const createPersonOperation = createOneOperationFactory({ objectMetadataSingularName: 'person', gqlFields: PERSON_GQL_FIELDS, @@ -35,16 +25,6 @@ describe('updateOneObjectRecordsPermissions', () => { await makeGraphqlAPIRequest(createPersonOperation); }); - afterAll(async () => { - const disablePermissionsQuery = updateFeatureFlagFactory( - SEED_APPLE_WORKSPACE_ID, - 'IsPermissionsEnabled', - false, - ); - - await makeGraphqlAPIRequest(disablePermissionsQuery); - }); - it('should throw a permission error when user does not have permission (guest role)', async () => { const personId = randomUUID(); const graphqlOperation = updateOneOperationFactory({ diff --git a/packages/twenty-server/test/integration/graphql/suites/settings-permissions/api-key-webhooks.integration-spec.ts b/packages/twenty-server/test/integration/graphql/suites/settings-permissions/api-key-webhooks.integration-spec.ts index c38d4dc04..fe876fb38 100644 --- a/packages/twenty-server/test/integration/graphql/suites/settings-permissions/api-key-webhooks.integration-spec.ts +++ b/packages/twenty-server/test/integration/graphql/suites/settings-permissions/api-key-webhooks.integration-spec.ts @@ -1,33 +1,11 @@ import request from 'supertest'; -import { makeGraphqlAPIRequest } from 'test/integration/graphql/utils/make-graphql-api-request.util'; -import { updateFeatureFlagFactory } from 'test/integration/graphql/utils/update-feature-flag-factory.util'; -import { SEED_APPLE_WORKSPACE_ID } from 'src/database/typeorm-seeds/core/workspaces'; import { ErrorCode } from 'src/engine/core-modules/graphql/utils/graphql-errors.util'; import { PermissionsExceptionMessage } from 'src/engine/metadata-modules/permissions/permissions.exception'; const client = request(`http://localhost:${APP_PORT}`); describe('api key and webhooks permissions', () => { - beforeAll(async () => { - const enablePermissionsQuery = updateFeatureFlagFactory( - SEED_APPLE_WORKSPACE_ID, - 'IsPermissionsEnabled', - true, - ); - - await makeGraphqlAPIRequest(enablePermissionsQuery); - }); - - afterAll(async () => { - const disablePermissionsQuery = updateFeatureFlagFactory( - SEED_APPLE_WORKSPACE_ID, - 'IsPermissionsEnabled', - false, - ); - - await makeGraphqlAPIRequest(disablePermissionsQuery); - }); describe('generateApiKeyToken', () => { it('should throw a permission error when user does not have permission (member role)', async () => { const queryData = { diff --git a/packages/twenty-server/test/integration/graphql/suites/settings-permissions/data-model.integration-spec.ts b/packages/twenty-server/test/integration/graphql/suites/settings-permissions/data-model.integration-spec.ts index 3387b6faf..fc500ccca 100644 --- a/packages/twenty-server/test/integration/graphql/suites/settings-permissions/data-model.integration-spec.ts +++ b/packages/twenty-server/test/integration/graphql/suites/settings-permissions/data-model.integration-spec.ts @@ -1,5 +1,3 @@ -import { makeGraphqlAPIRequest } from 'test/integration/graphql/utils/make-graphql-api-request.util'; -import { updateFeatureFlagFactory } from 'test/integration/graphql/utils/update-feature-flag-factory.util'; import { createCustomTextFieldMetadata } from 'test/integration/metadata/suites/field-metadata/utils/create-custom-text-field-metadata.util'; import { createOneFieldMetadataFactory } from 'test/integration/metadata/suites/field-metadata/utils/create-one-field-metadata-factory.util'; import { deleteOneFieldMetadataItemFactory } from 'test/integration/metadata/suites/field-metadata/utils/delete-one-field-metadata-factory.util'; @@ -12,29 +10,12 @@ import { updateOneObjectMetadataItemFactory } from 'test/integration/metadata/su import { makeMetadataAPIRequestWithMemberRole } from 'test/integration/metadata/suites/utils/make-metadata-api-request-with-member-role.util'; import { FieldMetadataType } from 'twenty-shared/types'; -import { SEED_APPLE_WORKSPACE_ID } from 'src/database/typeorm-seeds/core/workspaces'; import { ErrorCode } from 'src/engine/core-modules/graphql/utils/graphql-errors.util'; import { PermissionsExceptionMessage } from 'src/engine/metadata-modules/permissions/permissions.exception'; describe('datamodel permissions', () => { - beforeAll(async () => { - const enablePermissionsQuery = updateFeatureFlagFactory( - SEED_APPLE_WORKSPACE_ID, - 'IsPermissionsEnabled', - true, - ); + beforeAll(async () => {}); - await makeGraphqlAPIRequest(enablePermissionsQuery); - }); - afterAll(async () => { - const disablePermissionsQuery = updateFeatureFlagFactory( - SEED_APPLE_WORKSPACE_ID, - 'IsPermissionsEnabled', - false, - ); - - await makeGraphqlAPIRequest(disablePermissionsQuery); - }); describe('fieldMetadata', () => { let listingObjectId = ''; let testFieldId = ''; diff --git a/packages/twenty-server/test/integration/graphql/suites/settings-permissions/security.integration-spec.ts b/packages/twenty-server/test/integration/graphql/suites/settings-permissions/security.integration-spec.ts index 44b36bff6..d5ac7028c 100644 --- a/packages/twenty-server/test/integration/graphql/suites/settings-permissions/security.integration-spec.ts +++ b/packages/twenty-server/test/integration/graphql/suites/settings-permissions/security.integration-spec.ts @@ -32,14 +32,6 @@ describe('Security permissions', () => { const response = await makeGraphqlAPIRequest({ query }); originalWorkspaceState = response.body.data.currentWorkspace; - - const enablePermissionsQuery = updateFeatureFlagFactory( - SEED_APPLE_WORKSPACE_ID, - 'IsPermissionsEnabled', - true, - ); - - await makeGraphqlAPIRequest(enablePermissionsQuery); }); afterAll(async () => { diff --git a/packages/twenty-server/test/integration/graphql/suites/settings-permissions/workspace-invitation.integration-spec.ts b/packages/twenty-server/test/integration/graphql/suites/settings-permissions/workspace-invitation.integration-spec.ts index 8a18a22a6..0eb56f3be 100644 --- a/packages/twenty-server/test/integration/graphql/suites/settings-permissions/workspace-invitation.integration-spec.ts +++ b/packages/twenty-server/test/integration/graphql/suites/settings-permissions/workspace-invitation.integration-spec.ts @@ -1,34 +1,11 @@ import request from 'supertest'; -import { makeGraphqlAPIRequest } from 'test/integration/graphql/utils/make-graphql-api-request.util'; -import { updateFeatureFlagFactory } from 'test/integration/graphql/utils/update-feature-flag-factory.util'; -import { SEED_APPLE_WORKSPACE_ID } from 'src/database/typeorm-seeds/core/workspaces'; import { ErrorCode } from 'src/engine/core-modules/graphql/utils/graphql-errors.util'; import { PermissionsExceptionMessage } from 'src/engine/metadata-modules/permissions/permissions.exception'; const client = request(`http://localhost:${APP_PORT}`); describe('workspace invitation permissions', () => { - beforeAll(async () => { - const enablePermissionsQuery = updateFeatureFlagFactory( - SEED_APPLE_WORKSPACE_ID, - 'IsPermissionsEnabled', - true, - ); - - await makeGraphqlAPIRequest(enablePermissionsQuery); - }); - - afterAll(async () => { - const disablePermissionsQuery = updateFeatureFlagFactory( - SEED_APPLE_WORKSPACE_ID, - 'IsPermissionsEnabled', - false, - ); - - await makeGraphqlAPIRequest(disablePermissionsQuery); - }); - it('should throw a permission error when user does not have permission to send invitation', async () => { const queryData = { query: ` diff --git a/packages/twenty-server/test/integration/graphql/suites/settings-permissions/workspace-members.integration-spec.ts b/packages/twenty-server/test/integration/graphql/suites/settings-permissions/workspace-members.integration-spec.ts index a08f16d45..ef848a4c3 100644 --- a/packages/twenty-server/test/integration/graphql/suites/settings-permissions/workspace-members.integration-spec.ts +++ b/packages/twenty-server/test/integration/graphql/suites/settings-permissions/workspace-members.integration-spec.ts @@ -3,10 +3,8 @@ import { deleteOneOperationFactory } from 'test/integration/graphql/utils/delete import { makeGraphqlAPIRequestWithMemberRole } from 'test/integration/graphql/utils/make-graphql-api-request-with-member-role.util'; import { makeGraphqlAPIRequest } from 'test/integration/graphql/utils/make-graphql-api-request.util'; import { restoreOneOperationFactory } from 'test/integration/graphql/utils/restore-one-operation-factory.util'; -import { updateFeatureFlagFactory } from 'test/integration/graphql/utils/update-feature-flag-factory.util'; import { updateOneOperationFactory } from 'test/integration/graphql/utils/update-one-operation-factory.util'; -import { SEED_APPLE_WORKSPACE_ID } from 'src/database/typeorm-seeds/core/workspaces'; import { DEV_SEED_WORKSPACE_MEMBER_IDS } from 'src/database/typeorm-seeds/workspace/workspace-members'; import { ErrorCode } from 'src/engine/core-modules/graphql/utils/graphql-errors.util'; import { PermissionsExceptionMessage } from 'src/engine/metadata-modules/permissions/permissions.exception'; @@ -19,25 +17,6 @@ const WORKSPACE_MEMBER_GQL_FIELDS = ` `; describe('workspace members permissions', () => { - beforeAll(async () => { - const enablePermissionsQuery = updateFeatureFlagFactory( - SEED_APPLE_WORKSPACE_ID, - 'IsPermissionsEnabled', - true, - ); - - await makeGraphqlAPIRequest(enablePermissionsQuery); - }); - - afterAll(async () => { - const disablePermissionsQuery = updateFeatureFlagFactory( - SEED_APPLE_WORKSPACE_ID, - 'IsPermissionsEnabled', - false, - ); - - await makeGraphqlAPIRequest(disablePermissionsQuery); - }); describe('updateOne', () => { it('should allow update when user is updating themself (member role)', async () => { const graphqlOperation = updateOneOperationFactory({ diff --git a/packages/twenty-server/test/integration/graphql/suites/settings-permissions/workspace.integration-spec.ts b/packages/twenty-server/test/integration/graphql/suites/settings-permissions/workspace.integration-spec.ts index addd0fcc1..2574bd914 100644 --- a/packages/twenty-server/test/integration/graphql/suites/settings-permissions/workspace.integration-spec.ts +++ b/packages/twenty-server/test/integration/graphql/suites/settings-permissions/workspace.integration-spec.ts @@ -33,14 +33,6 @@ describe('workspace permissions', () => { const response = await makeGraphqlAPIRequest({ query }); originalWorkspaceState = response.body.data.currentWorkspace; - - const enablePermissionsQuery = updateFeatureFlagFactory( - SEED_APPLE_WORKSPACE_ID, - 'IsPermissionsEnabled', - true, - ); - - await makeGraphqlAPIRequest(enablePermissionsQuery); }); afterAll(async () => { diff --git a/packages/twenty-server/test/integration/graphql/suites/user.integration-spec.ts b/packages/twenty-server/test/integration/graphql/suites/user.integration-spec.ts index 6fb6b88c5..a1ee14569 100644 --- a/packages/twenty-server/test/integration/graphql/suites/user.integration-spec.ts +++ b/packages/twenty-server/test/integration/graphql/suites/user.integration-spec.ts @@ -1,33 +1,10 @@ import request from 'supertest'; -import { makeGraphqlAPIRequest } from 'test/integration/graphql/utils/make-graphql-api-request.util'; -import { updateFeatureFlagFactory } from 'test/integration/graphql/utils/update-feature-flag-factory.util'; -import { SEED_APPLE_WORKSPACE_ID } from 'src/database/typeorm-seeds/core/workspaces'; import { ErrorCode } from 'src/engine/core-modules/graphql/utils/graphql-errors.util'; const client = request(`http://localhost:${APP_PORT}`); describe('deleteUser', () => { - beforeAll(async () => { - const enablePermissionsQuery = updateFeatureFlagFactory( - SEED_APPLE_WORKSPACE_ID, - 'IsPermissionsEnabled', - true, - ); - - await makeGraphqlAPIRequest(enablePermissionsQuery); - }); - - afterAll(async () => { - const disablePermissionsQuery = updateFeatureFlagFactory( - SEED_APPLE_WORKSPACE_ID, - 'IsPermissionsEnabled', - false, - ); - - await makeGraphqlAPIRequest(disablePermissionsQuery); - }); - it('should not allow to delete user if they are the unique admin of a workspace', async () => { const query = { query: `