From 3270c64a96fe4c871916a5816dfbc72416e8d288 Mon Sep 17 00:00:00 2001 From: Marie <51697796+ijreilly@users.noreply.github.com> Date: Fri, 12 Sep 2025 16:02:42 +0200 Subject: [PATCH] [permissions] Deprecate ObjectsPermissionsDeprecated (2/3) (#14450) Following https://github.com/twentyhq/twenty/pull/14306 , working on the deprecation of objectRecordsPermissions + renaming of objectPermissions -> objectsPermissions In this PR - Removal of objectRecordsPermissions (was not used in the FE any longer) - Addition of objectsPermissions, same as objectPermission but renamed. objectPermission is no longer used in the FE. Next step - Remove unused objectPermissions --- .../src/generated-metadata/graphql.ts | 17 ++++---------- .../twenty-front/src/generated/graphql.ts | 10 +------- .../auth/states/currentUserWorkspaceState.ts | 2 +- .../states/objectPermissionsFamilySelector.ts | 2 +- .../hooks/__mocks__/useFieldMetadataItem.ts | 8 +------ .../hooks/useRefreshObjectMetadataItems.ts | 2 +- .../hooks/useObjectPermissions.ts | 6 ++--- .../users/components/UserProviderEffect.tsx | 4 ++-- .../graphql/fragments/userQueryFragment.ts | 3 +-- .../modules/users/hooks/useLoadCurrentUser.ts | 4 ++-- .../src/testing/mock-data/users.ts | 4 ++-- .../user-workspace/user-workspace.entity.ts | 9 +++----- .../permissions/permissions.service.ts | 23 ------------------- .../types/user-workspace-permissions.ts | 10 ++------ .../dtos/user-workspace-permissions.dto.ts | 2 +- ...ermissionsToUserWorkspacePermissionsDto.ts | 23 ++++++++----------- 16 files changed, 34 insertions(+), 95 deletions(-) diff --git a/packages/twenty-front/src/generated-metadata/graphql.ts b/packages/twenty-front/src/generated-metadata/graphql.ts index 614af25a27..10dc470d11 100644 --- a/packages/twenty-front/src/generated-metadata/graphql.ts +++ b/packages/twenty-front/src/generated-metadata/graphql.ts @@ -2593,13 +2593,6 @@ export enum PermissionFlagType { WORKSPACE_MEMBERS = 'WORKSPACE_MEMBERS' } -export enum PermissionsOnAllObjectRecords { - DESTROY_ALL_OBJECT_RECORDS = 'DESTROY_ALL_OBJECT_RECORDS', - READ_ALL_OBJECT_RECORDS = 'READ_ALL_OBJECT_RECORDS', - SOFT_DELETE_ALL_OBJECT_RECORDS = 'SOFT_DELETE_ALL_OBJECT_RECORDS', - UPDATE_ALL_OBJECT_RECORDS = 'UPDATE_ALL_OBJECT_RECORDS' -} - export type PlaceDetailsResultDto = { __typename?: 'PlaceDetailsResultDto'; city?: Maybe; @@ -3811,8 +3804,7 @@ export type UserWorkspace = { id: Scalars['UUID']; locale: Scalars['String']; objectPermissions?: Maybe>; - /** @deprecated Use objectPermissions instead */ - objectRecordsPermissions?: Maybe>; + objectsPermissions?: Maybe>; permissionFlags?: Maybe>; twoFactorAuthenticationMethodSummary?: Maybe>; updatedAt: Scalars['DateTime']; @@ -4992,7 +4984,7 @@ export type VerifyTwoFactorAuthenticationMethodForAuthenticatedUserMutationVaria export type VerifyTwoFactorAuthenticationMethodForAuthenticatedUserMutation = { __typename?: 'Mutation', verifyTwoFactorAuthenticationMethodForAuthenticatedUser: { __typename?: 'VerifyTwoFactorAuthenticationMethodOutput', success: boolean } }; -export type UserQueryFragmentFragment = { __typename?: 'User', id: string, firstName: string, lastName: string, email: string, canAccessFullAdminPanel: boolean, canImpersonate: boolean, supportUserHash?: string | null, onboardingStatus?: OnboardingStatus | null, userVars?: any | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: string, colorScheme: string, avatarUrl?: string | null, locale?: string | null, userEmail: string, timeZone?: string | null, dateFormat?: WorkspaceMemberDateFormatEnum | null, timeFormat?: WorkspaceMemberTimeFormatEnum | null, calendarStartDay?: number | null, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, workspaceMembers?: Array<{ __typename?: 'WorkspaceMember', id: string, avatarUrl?: string | null, userEmail: string, name: { __typename?: 'FullName', firstName: string, lastName: string } }> | null, deletedWorkspaceMembers?: Array<{ __typename?: 'DeletedWorkspaceMember', id: string, avatarUrl?: string | null, userEmail: string, name: { __typename?: 'FullName', firstName: string, lastName: string } }> | null, currentUserWorkspace?: { __typename?: 'UserWorkspace', permissionFlags?: Array | null, objectRecordsPermissions?: Array | null, objectPermissions?: Array<{ __typename?: 'ObjectPermission', objectMetadataId: string, canReadObjectRecords?: boolean | null, canUpdateObjectRecords?: boolean | null, canSoftDeleteObjectRecords?: boolean | null, canDestroyObjectRecords?: boolean | null, restrictedFields?: any | null }> | null, twoFactorAuthenticationMethodSummary?: Array<{ __typename?: 'TwoFactorAuthenticationMethodDTO', twoFactorAuthenticationMethodId: string, status: string, strategy: string }> | null } | null, currentWorkspace?: { __typename?: 'Workspace', id: string, displayName?: string | null, logo?: string | null, inviteHash?: string | null, allowImpersonation: boolean, activationStatus: WorkspaceActivationStatus, isPublicInviteLinkEnabled: boolean, isGoogleAuthEnabled: boolean, isMicrosoftAuthEnabled: boolean, isPasswordAuthEnabled: boolean, subdomain: string, hasValidEnterpriseKey: boolean, customDomain?: string | null, isCustomDomainEnabled: boolean, metadataVersion: number, workspaceMembersCount?: number | null, isTwoFactorAuthenticationEnforced: boolean, workspaceUrls: { __typename?: 'WorkspaceUrls', subdomainUrl: string, customUrl?: string | null }, featureFlags?: Array<{ __typename?: 'FeatureFlagDTO', key: FeatureFlagKey, value: boolean }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: string, status: SubscriptionStatus, interval?: SubscriptionInterval | null, metadata: any, currentPeriodEnd?: string | null, billingSubscriptionItems?: Array<{ __typename?: 'BillingSubscriptionItem', id: string, hasReachedCurrentPeriodCap: boolean, quantity?: number | null, stripePriceId?: string | null, billingProduct?: { __typename?: 'BillingProduct', name: string, description: string, metadata: { __typename?: 'BillingProductMetadata', planKey: BillingPlanKey, priceUsageBased: BillingUsageType, productKey: BillingProductKey } } | null }> | null } | null, billingSubscriptions: Array<{ __typename?: 'BillingSubscription', id: string, status: SubscriptionStatus, metadata: any }>, defaultRole?: { __typename?: 'Role', id: string, label: string, description?: string | null, icon?: string | null, canUpdateAllSettings: boolean, canAccessAllTools: boolean, isEditable: boolean, canReadAllObjectRecords: boolean, canUpdateAllObjectRecords: boolean, canSoftDeleteAllObjectRecords: boolean, canDestroyAllObjectRecords: boolean, canBeAssignedToUsers: boolean, canBeAssignedToAgents: boolean, canBeAssignedToApiKeys: boolean } | null, defaultAgent?: { __typename?: 'Agent', id: string } | null, views?: Array<{ __typename?: 'CoreView', id: string, name: string, objectMetadataId: string, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: string | null, anyFieldFilterValue?: string | null, viewFields: Array<{ __typename?: 'CoreViewField', id: string, fieldMetadataId: string, viewId: string, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: string, fieldMetadataId: string, operand: ViewFilterOperand, value: any, viewFilterGroupId?: string | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: string }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: string, parentViewFilterGroupId?: string | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: string }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: string, fieldMetadataId: string, direction: ViewSortDirection, viewId: string }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: string, fieldMetadataId: string, isVisible: boolean, fieldValue: string, position: number, viewId: string }> }> | null } | null, availableWorkspaces: { __typename?: 'AvailableWorkspaces', availableWorkspacesForSignIn: Array<{ __typename?: 'AvailableWorkspace', id: string, displayName?: string | null, loginToken?: string | null, inviteHash?: string | null, personalInviteToken?: string | null, logo?: string | null, workspaceUrls: { __typename?: 'WorkspaceUrls', subdomainUrl: string, customUrl?: string | null }, sso: Array<{ __typename?: 'SSOConnection', type: IdentityProviderType, id: string, issuer: string, name: string, status: SsoIdentityProviderStatus }> }>, availableWorkspacesForSignUp: Array<{ __typename?: 'AvailableWorkspace', id: string, displayName?: string | null, loginToken?: string | null, inviteHash?: string | null, personalInviteToken?: string | null, logo?: string | null, workspaceUrls: { __typename?: 'WorkspaceUrls', subdomainUrl: string, customUrl?: string | null }, sso: Array<{ __typename?: 'SSOConnection', type: IdentityProviderType, id: string, issuer: string, name: string, status: SsoIdentityProviderStatus }> }> } }; +export type UserQueryFragmentFragment = { __typename?: 'User', id: string, firstName: string, lastName: string, email: string, canAccessFullAdminPanel: boolean, canImpersonate: boolean, supportUserHash?: string | null, onboardingStatus?: OnboardingStatus | null, userVars?: any | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: string, colorScheme: string, avatarUrl?: string | null, locale?: string | null, userEmail: string, timeZone?: string | null, dateFormat?: WorkspaceMemberDateFormatEnum | null, timeFormat?: WorkspaceMemberTimeFormatEnum | null, calendarStartDay?: number | null, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, workspaceMembers?: Array<{ __typename?: 'WorkspaceMember', id: string, avatarUrl?: string | null, userEmail: string, name: { __typename?: 'FullName', firstName: string, lastName: string } }> | null, deletedWorkspaceMembers?: Array<{ __typename?: 'DeletedWorkspaceMember', id: string, avatarUrl?: string | null, userEmail: string, name: { __typename?: 'FullName', firstName: string, lastName: string } }> | null, currentUserWorkspace?: { __typename?: 'UserWorkspace', permissionFlags?: Array | null, objectsPermissions?: Array<{ __typename?: 'ObjectPermission', objectMetadataId: string, canReadObjectRecords?: boolean | null, canUpdateObjectRecords?: boolean | null, canSoftDeleteObjectRecords?: boolean | null, canDestroyObjectRecords?: boolean | null, restrictedFields?: any | null }> | null, twoFactorAuthenticationMethodSummary?: Array<{ __typename?: 'TwoFactorAuthenticationMethodDTO', twoFactorAuthenticationMethodId: string, status: string, strategy: string }> | null } | null, currentWorkspace?: { __typename?: 'Workspace', id: string, displayName?: string | null, logo?: string | null, inviteHash?: string | null, allowImpersonation: boolean, activationStatus: WorkspaceActivationStatus, isPublicInviteLinkEnabled: boolean, isGoogleAuthEnabled: boolean, isMicrosoftAuthEnabled: boolean, isPasswordAuthEnabled: boolean, subdomain: string, hasValidEnterpriseKey: boolean, customDomain?: string | null, isCustomDomainEnabled: boolean, metadataVersion: number, workspaceMembersCount?: number | null, isTwoFactorAuthenticationEnforced: boolean, workspaceUrls: { __typename?: 'WorkspaceUrls', subdomainUrl: string, customUrl?: string | null }, featureFlags?: Array<{ __typename?: 'FeatureFlagDTO', key: FeatureFlagKey, value: boolean }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: string, status: SubscriptionStatus, interval?: SubscriptionInterval | null, metadata: any, currentPeriodEnd?: string | null, billingSubscriptionItems?: Array<{ __typename?: 'BillingSubscriptionItem', id: string, hasReachedCurrentPeriodCap: boolean, quantity?: number | null, stripePriceId?: string | null, billingProduct?: { __typename?: 'BillingProduct', name: string, description: string, metadata: { __typename?: 'BillingProductMetadata', planKey: BillingPlanKey, priceUsageBased: BillingUsageType, productKey: BillingProductKey } } | null }> | null } | null, billingSubscriptions: Array<{ __typename?: 'BillingSubscription', id: string, status: SubscriptionStatus, metadata: any }>, defaultRole?: { __typename?: 'Role', id: string, label: string, description?: string | null, icon?: string | null, canUpdateAllSettings: boolean, canAccessAllTools: boolean, isEditable: boolean, canReadAllObjectRecords: boolean, canUpdateAllObjectRecords: boolean, canSoftDeleteAllObjectRecords: boolean, canDestroyAllObjectRecords: boolean, canBeAssignedToUsers: boolean, canBeAssignedToAgents: boolean, canBeAssignedToApiKeys: boolean } | null, defaultAgent?: { __typename?: 'Agent', id: string } | null, views?: Array<{ __typename?: 'CoreView', id: string, name: string, objectMetadataId: string, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: string | null, anyFieldFilterValue?: string | null, viewFields: Array<{ __typename?: 'CoreViewField', id: string, fieldMetadataId: string, viewId: string, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: string, fieldMetadataId: string, operand: ViewFilterOperand, value: any, viewFilterGroupId?: string | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: string }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: string, parentViewFilterGroupId?: string | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: string }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: string, fieldMetadataId: string, direction: ViewSortDirection, viewId: string }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: string, fieldMetadataId: string, isVisible: boolean, fieldValue: string, position: number, viewId: string }> }> | null } | null, availableWorkspaces: { __typename?: 'AvailableWorkspaces', availableWorkspacesForSignIn: Array<{ __typename?: 'AvailableWorkspace', id: string, displayName?: string | null, loginToken?: string | null, inviteHash?: string | null, personalInviteToken?: string | null, logo?: string | null, workspaceUrls: { __typename?: 'WorkspaceUrls', subdomainUrl: string, customUrl?: string | null }, sso: Array<{ __typename?: 'SSOConnection', type: IdentityProviderType, id: string, issuer: string, name: string, status: SsoIdentityProviderStatus }> }>, availableWorkspacesForSignUp: Array<{ __typename?: 'AvailableWorkspace', id: string, displayName?: string | null, loginToken?: string | null, inviteHash?: string | null, personalInviteToken?: string | null, logo?: string | null, workspaceUrls: { __typename?: 'WorkspaceUrls', subdomainUrl: string, customUrl?: string | null }, sso: Array<{ __typename?: 'SSOConnection', type: IdentityProviderType, id: string, issuer: string, name: string, status: SsoIdentityProviderStatus }> }> } }; export type WorkspaceUrlsFragmentFragment = { __typename?: 'WorkspaceUrls', subdomainUrl: string, customUrl?: string | null }; @@ -5011,7 +5003,7 @@ export type UploadProfilePictureMutation = { __typename?: 'Mutation', uploadProf export type GetCurrentUserQueryVariables = Exact<{ [key: string]: never; }>; -export type GetCurrentUserQuery = { __typename?: 'Query', currentUser: { __typename?: 'User', id: string, firstName: string, lastName: string, email: string, canAccessFullAdminPanel: boolean, canImpersonate: boolean, supportUserHash?: string | null, onboardingStatus?: OnboardingStatus | null, userVars?: any | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: string, colorScheme: string, avatarUrl?: string | null, locale?: string | null, userEmail: string, timeZone?: string | null, dateFormat?: WorkspaceMemberDateFormatEnum | null, timeFormat?: WorkspaceMemberTimeFormatEnum | null, calendarStartDay?: number | null, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, workspaceMembers?: Array<{ __typename?: 'WorkspaceMember', id: string, avatarUrl?: string | null, userEmail: string, name: { __typename?: 'FullName', firstName: string, lastName: string } }> | null, deletedWorkspaceMembers?: Array<{ __typename?: 'DeletedWorkspaceMember', id: string, avatarUrl?: string | null, userEmail: string, name: { __typename?: 'FullName', firstName: string, lastName: string } }> | null, currentUserWorkspace?: { __typename?: 'UserWorkspace', permissionFlags?: Array | null, objectRecordsPermissions?: Array | null, objectPermissions?: Array<{ __typename?: 'ObjectPermission', objectMetadataId: string, canReadObjectRecords?: boolean | null, canUpdateObjectRecords?: boolean | null, canSoftDeleteObjectRecords?: boolean | null, canDestroyObjectRecords?: boolean | null, restrictedFields?: any | null }> | null, twoFactorAuthenticationMethodSummary?: Array<{ __typename?: 'TwoFactorAuthenticationMethodDTO', twoFactorAuthenticationMethodId: string, status: string, strategy: string }> | null } | null, currentWorkspace?: { __typename?: 'Workspace', id: string, displayName?: string | null, logo?: string | null, inviteHash?: string | null, allowImpersonation: boolean, activationStatus: WorkspaceActivationStatus, isPublicInviteLinkEnabled: boolean, isGoogleAuthEnabled: boolean, isMicrosoftAuthEnabled: boolean, isPasswordAuthEnabled: boolean, subdomain: string, hasValidEnterpriseKey: boolean, customDomain?: string | null, isCustomDomainEnabled: boolean, metadataVersion: number, workspaceMembersCount?: number | null, isTwoFactorAuthenticationEnforced: boolean, workspaceUrls: { __typename?: 'WorkspaceUrls', subdomainUrl: string, customUrl?: string | null }, featureFlags?: Array<{ __typename?: 'FeatureFlagDTO', key: FeatureFlagKey, value: boolean }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: string, status: SubscriptionStatus, interval?: SubscriptionInterval | null, metadata: any, currentPeriodEnd?: string | null, billingSubscriptionItems?: Array<{ __typename?: 'BillingSubscriptionItem', id: string, hasReachedCurrentPeriodCap: boolean, quantity?: number | null, stripePriceId?: string | null, billingProduct?: { __typename?: 'BillingProduct', name: string, description: string, metadata: { __typename?: 'BillingProductMetadata', planKey: BillingPlanKey, priceUsageBased: BillingUsageType, productKey: BillingProductKey } } | null }> | null } | null, billingSubscriptions: Array<{ __typename?: 'BillingSubscription', id: string, status: SubscriptionStatus, metadata: any }>, defaultRole?: { __typename?: 'Role', id: string, label: string, description?: string | null, icon?: string | null, canUpdateAllSettings: boolean, canAccessAllTools: boolean, isEditable: boolean, canReadAllObjectRecords: boolean, canUpdateAllObjectRecords: boolean, canSoftDeleteAllObjectRecords: boolean, canDestroyAllObjectRecords: boolean, canBeAssignedToUsers: boolean, canBeAssignedToAgents: boolean, canBeAssignedToApiKeys: boolean } | null, defaultAgent?: { __typename?: 'Agent', id: string } | null, views?: Array<{ __typename?: 'CoreView', id: string, name: string, objectMetadataId: string, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: string | null, anyFieldFilterValue?: string | null, viewFields: Array<{ __typename?: 'CoreViewField', id: string, fieldMetadataId: string, viewId: string, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: string, fieldMetadataId: string, operand: ViewFilterOperand, value: any, viewFilterGroupId?: string | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: string }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: string, parentViewFilterGroupId?: string | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: string }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: string, fieldMetadataId: string, direction: ViewSortDirection, viewId: string }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: string, fieldMetadataId: string, isVisible: boolean, fieldValue: string, position: number, viewId: string }> }> | null } | null, availableWorkspaces: { __typename?: 'AvailableWorkspaces', availableWorkspacesForSignIn: Array<{ __typename?: 'AvailableWorkspace', id: string, displayName?: string | null, loginToken?: string | null, inviteHash?: string | null, personalInviteToken?: string | null, logo?: string | null, workspaceUrls: { __typename?: 'WorkspaceUrls', subdomainUrl: string, customUrl?: string | null }, sso: Array<{ __typename?: 'SSOConnection', type: IdentityProviderType, id: string, issuer: string, name: string, status: SsoIdentityProviderStatus }> }>, availableWorkspacesForSignUp: Array<{ __typename?: 'AvailableWorkspace', id: string, displayName?: string | null, loginToken?: string | null, inviteHash?: string | null, personalInviteToken?: string | null, logo?: string | null, workspaceUrls: { __typename?: 'WorkspaceUrls', subdomainUrl: string, customUrl?: string | null }, sso: Array<{ __typename?: 'SSOConnection', type: IdentityProviderType, id: string, issuer: string, name: string, status: SsoIdentityProviderStatus }> }> } } }; +export type GetCurrentUserQuery = { __typename?: 'Query', currentUser: { __typename?: 'User', id: string, firstName: string, lastName: string, email: string, canAccessFullAdminPanel: boolean, canImpersonate: boolean, supportUserHash?: string | null, onboardingStatus?: OnboardingStatus | null, userVars?: any | null, workspaceMember?: { __typename?: 'WorkspaceMember', id: string, colorScheme: string, avatarUrl?: string | null, locale?: string | null, userEmail: string, timeZone?: string | null, dateFormat?: WorkspaceMemberDateFormatEnum | null, timeFormat?: WorkspaceMemberTimeFormatEnum | null, calendarStartDay?: number | null, name: { __typename?: 'FullName', firstName: string, lastName: string } } | null, workspaceMembers?: Array<{ __typename?: 'WorkspaceMember', id: string, avatarUrl?: string | null, userEmail: string, name: { __typename?: 'FullName', firstName: string, lastName: string } }> | null, deletedWorkspaceMembers?: Array<{ __typename?: 'DeletedWorkspaceMember', id: string, avatarUrl?: string | null, userEmail: string, name: { __typename?: 'FullName', firstName: string, lastName: string } }> | null, currentUserWorkspace?: { __typename?: 'UserWorkspace', permissionFlags?: Array | null, objectsPermissions?: Array<{ __typename?: 'ObjectPermission', objectMetadataId: string, canReadObjectRecords?: boolean | null, canUpdateObjectRecords?: boolean | null, canSoftDeleteObjectRecords?: boolean | null, canDestroyObjectRecords?: boolean | null, restrictedFields?: any | null }> | null, twoFactorAuthenticationMethodSummary?: Array<{ __typename?: 'TwoFactorAuthenticationMethodDTO', twoFactorAuthenticationMethodId: string, status: string, strategy: string }> | null } | null, currentWorkspace?: { __typename?: 'Workspace', id: string, displayName?: string | null, logo?: string | null, inviteHash?: string | null, allowImpersonation: boolean, activationStatus: WorkspaceActivationStatus, isPublicInviteLinkEnabled: boolean, isGoogleAuthEnabled: boolean, isMicrosoftAuthEnabled: boolean, isPasswordAuthEnabled: boolean, subdomain: string, hasValidEnterpriseKey: boolean, customDomain?: string | null, isCustomDomainEnabled: boolean, metadataVersion: number, workspaceMembersCount?: number | null, isTwoFactorAuthenticationEnforced: boolean, workspaceUrls: { __typename?: 'WorkspaceUrls', subdomainUrl: string, customUrl?: string | null }, featureFlags?: Array<{ __typename?: 'FeatureFlagDTO', key: FeatureFlagKey, value: boolean }> | null, currentBillingSubscription?: { __typename?: 'BillingSubscription', id: string, status: SubscriptionStatus, interval?: SubscriptionInterval | null, metadata: any, currentPeriodEnd?: string | null, billingSubscriptionItems?: Array<{ __typename?: 'BillingSubscriptionItem', id: string, hasReachedCurrentPeriodCap: boolean, quantity?: number | null, stripePriceId?: string | null, billingProduct?: { __typename?: 'BillingProduct', name: string, description: string, metadata: { __typename?: 'BillingProductMetadata', planKey: BillingPlanKey, priceUsageBased: BillingUsageType, productKey: BillingProductKey } } | null }> | null } | null, billingSubscriptions: Array<{ __typename?: 'BillingSubscription', id: string, status: SubscriptionStatus, metadata: any }>, defaultRole?: { __typename?: 'Role', id: string, label: string, description?: string | null, icon?: string | null, canUpdateAllSettings: boolean, canAccessAllTools: boolean, isEditable: boolean, canReadAllObjectRecords: boolean, canUpdateAllObjectRecords: boolean, canSoftDeleteAllObjectRecords: boolean, canDestroyAllObjectRecords: boolean, canBeAssignedToUsers: boolean, canBeAssignedToAgents: boolean, canBeAssignedToApiKeys: boolean } | null, defaultAgent?: { __typename?: 'Agent', id: string } | null, views?: Array<{ __typename?: 'CoreView', id: string, name: string, objectMetadataId: string, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: string | null, anyFieldFilterValue?: string | null, viewFields: Array<{ __typename?: 'CoreViewField', id: string, fieldMetadataId: string, viewId: string, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: string, fieldMetadataId: string, operand: ViewFilterOperand, value: any, viewFilterGroupId?: string | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: string }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: string, parentViewFilterGroupId?: string | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: string }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: string, fieldMetadataId: string, direction: ViewSortDirection, viewId: string }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: string, fieldMetadataId: string, isVisible: boolean, fieldValue: string, position: number, viewId: string }> }> | null } | null, availableWorkspaces: { __typename?: 'AvailableWorkspaces', availableWorkspacesForSignIn: Array<{ __typename?: 'AvailableWorkspace', id: string, displayName?: string | null, loginToken?: string | null, inviteHash?: string | null, personalInviteToken?: string | null, logo?: string | null, workspaceUrls: { __typename?: 'WorkspaceUrls', subdomainUrl: string, customUrl?: string | null }, sso: Array<{ __typename?: 'SSOConnection', type: IdentityProviderType, id: string, issuer: string, name: string, status: SsoIdentityProviderStatus }> }>, availableWorkspacesForSignUp: Array<{ __typename?: 'AvailableWorkspace', id: string, displayName?: string | null, loginToken?: string | null, inviteHash?: string | null, personalInviteToken?: string | null, logo?: string | null, workspaceUrls: { __typename?: 'WorkspaceUrls', subdomainUrl: string, customUrl?: string | null }, sso: Array<{ __typename?: 'SSOConnection', type: IdentityProviderType, id: string, issuer: string, name: string, status: SsoIdentityProviderStatus }> }> } } }; export type ViewFieldFragmentFragment = { __typename?: 'CoreViewField', id: string, fieldMetadataId: string, viewId: string, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string, deletedAt?: string | null }; @@ -5792,8 +5784,7 @@ export const UserQueryFragmentFragmentDoc = gql` } currentUserWorkspace { permissionFlags - objectRecordsPermissions - objectPermissions { + objectsPermissions { ...ObjectPermissionFragment } twoFactorAuthenticationMethodSummary { diff --git a/packages/twenty-front/src/generated/graphql.ts b/packages/twenty-front/src/generated/graphql.ts index 2f1db2e7a3..b83e7578fa 100644 --- a/packages/twenty-front/src/generated/graphql.ts +++ b/packages/twenty-front/src/generated/graphql.ts @@ -2504,13 +2504,6 @@ export enum PermissionFlagType { WORKSPACE_MEMBERS = 'WORKSPACE_MEMBERS' } -export enum PermissionsOnAllObjectRecords { - DESTROY_ALL_OBJECT_RECORDS = 'DESTROY_ALL_OBJECT_RECORDS', - READ_ALL_OBJECT_RECORDS = 'READ_ALL_OBJECT_RECORDS', - SOFT_DELETE_ALL_OBJECT_RECORDS = 'SOFT_DELETE_ALL_OBJECT_RECORDS', - UPDATE_ALL_OBJECT_RECORDS = 'UPDATE_ALL_OBJECT_RECORDS' -} - export type PlaceDetailsResultDto = { __typename?: 'PlaceDetailsResultDto'; city?: Maybe; @@ -3639,8 +3632,7 @@ export type UserWorkspace = { id: Scalars['UUID']; locale: Scalars['String']; objectPermissions?: Maybe>; - /** @deprecated Use objectPermissions instead */ - objectRecordsPermissions?: Maybe>; + objectsPermissions?: Maybe>; permissionFlags?: Maybe>; twoFactorAuthenticationMethodSummary?: Maybe>; updatedAt: Scalars['DateTime']; diff --git a/packages/twenty-front/src/modules/auth/states/currentUserWorkspaceState.ts b/packages/twenty-front/src/modules/auth/states/currentUserWorkspaceState.ts index 341485659e..d3c1375529 100644 --- a/packages/twenty-front/src/modules/auth/states/currentUserWorkspaceState.ts +++ b/packages/twenty-front/src/modules/auth/states/currentUserWorkspaceState.ts @@ -6,7 +6,7 @@ export type CurrentUserWorkspace = Pick< UserWorkspace, 'permissionFlags' | 'twoFactorAuthenticationMethodSummary' > & { - objectPermissions: Array; + objectsPermissions: Array; }; export const currentUserWorkspaceState = diff --git a/packages/twenty-front/src/modules/auth/states/objectPermissionsFamilySelector.ts b/packages/twenty-front/src/modules/auth/states/objectPermissionsFamilySelector.ts index a87a9aa245..cb921b2365 100644 --- a/packages/twenty-front/src/modules/auth/states/objectPermissionsFamilySelector.ts +++ b/packages/twenty-front/src/modules/auth/states/objectPermissionsFamilySelector.ts @@ -27,7 +27,7 @@ export const objectPermissionsFamilySelector = selectorFamily< }; } - const objectPermissions = currentUserWorkspace?.objectPermissions?.find( + const objectPermissions = currentUserWorkspace?.objectsPermissions?.find( (permission) => permission.objectMetadataId === objectMetadataItem.id, ); diff --git a/packages/twenty-front/src/modules/object-metadata/hooks/__mocks__/useFieldMetadataItem.ts b/packages/twenty-front/src/modules/object-metadata/hooks/__mocks__/useFieldMetadataItem.ts index edb521dcc8..dffde5a6b3 100644 --- a/packages/twenty-front/src/modules/object-metadata/hooks/__mocks__/useFieldMetadataItem.ts +++ b/packages/twenty-front/src/modules/object-metadata/hooks/__mocks__/useFieldMetadataItem.ts @@ -1,5 +1,5 @@ import { gql } from '@apollo/client'; -import { FieldMetadataType, PermissionsOnAllObjectRecords } from '~/generated/graphql'; +import { FieldMetadataType } from '~/generated/graphql'; export const FIELD_METADATA_ID = '2c43466a-fe9e-4005-8d08-c5836067aa6c'; export const FIELD_RELATION_METADATA_ID = @@ -167,12 +167,6 @@ export const responseData = { workspaceMembers: [], currentUserWorkspace: { permissionFlags: ['DATA_MODEL'], - objectRecordsPermissions: [ - PermissionsOnAllObjectRecords.READ_ALL_OBJECT_RECORDS, - PermissionsOnAllObjectRecords.UPDATE_ALL_OBJECT_RECORDS, - PermissionsOnAllObjectRecords.SOFT_DELETE_ALL_OBJECT_RECORDS, - PermissionsOnAllObjectRecords.DESTROY_ALL_OBJECT_RECORDS, - ], }, currentWorkspace: { id: 'test-workspace-id', diff --git a/packages/twenty-front/src/modules/object-metadata/hooks/useRefreshObjectMetadataItems.ts b/packages/twenty-front/src/modules/object-metadata/hooks/useRefreshObjectMetadataItems.ts index 9f7576eec3..0301a311c2 100644 --- a/packages/twenty-front/src/modules/object-metadata/hooks/useRefreshObjectMetadataItems.ts +++ b/packages/twenty-front/src/modules/object-metadata/hooks/useRefreshObjectMetadataItems.ts @@ -49,7 +49,7 @@ export const useRefreshObjectMetadataItems = ( } const objectPermissionsByObjectMetadataId = - currentUserWorkspace.objectPermissions.reduce( + currentUserWorkspace.objectsPermissions.reduce( (acc, objectPermission) => { acc[objectPermission.objectMetadataId] = objectPermission; return acc; diff --git a/packages/twenty-front/src/modules/object-record/hooks/useObjectPermissions.ts b/packages/twenty-front/src/modules/object-record/hooks/useObjectPermissions.ts index 5f0d9e8a70..79fa5bc032 100644 --- a/packages/twenty-front/src/modules/object-record/hooks/useObjectPermissions.ts +++ b/packages/twenty-front/src/modules/object-record/hooks/useObjectPermissions.ts @@ -13,15 +13,15 @@ type useObjectPermissionsReturnType = { export const useObjectPermissions = (): useObjectPermissionsReturnType => { const currentUserWorkspace = useRecoilValue(currentUserWorkspaceState); - const objectPermissions = currentUserWorkspace?.objectPermissions; + const objectsPermissions = currentUserWorkspace?.objectsPermissions; - if (!isDefined(objectPermissions)) { + if (!isDefined(objectsPermissions)) { return { objectPermissionsByObjectMetadataId: {}, }; } - const objectPermissionsByObjectMetadataId = objectPermissions?.reduce( + const objectPermissionsByObjectMetadataId = objectsPermissions?.reduce( ( acc: Record, objectPermission, diff --git a/packages/twenty-front/src/modules/users/components/UserProviderEffect.tsx b/packages/twenty-front/src/modules/users/components/UserProviderEffect.tsx index 33a6d0e879..cbda42015f 100644 --- a/packages/twenty-front/src/modules/users/components/UserProviderEffect.tsx +++ b/packages/twenty-front/src/modules/users/components/UserProviderEffect.tsx @@ -118,9 +118,9 @@ export const UserProviderEffect = () => { if (isDefined(queryData.currentUser.currentUserWorkspace)) { setCurrentUserWorkspace({ ...queryData.currentUser.currentUserWorkspace, - objectPermissions: + objectsPermissions: (queryData.currentUser.currentUserWorkspace - .objectPermissions as Array< + .objectsPermissions as Array< ObjectPermissions & { objectMetadataId: string } >) ?? [], }); diff --git a/packages/twenty-front/src/modules/users/graphql/fragments/userQueryFragment.ts b/packages/twenty-front/src/modules/users/graphql/fragments/userQueryFragment.ts index c060d58a7c..4ff4dad5b4 100644 --- a/packages/twenty-front/src/modules/users/graphql/fragments/userQueryFragment.ts +++ b/packages/twenty-front/src/modules/users/graphql/fragments/userQueryFragment.ts @@ -32,8 +32,7 @@ export const USER_QUERY_FRAGMENT = gql` } currentUserWorkspace { permissionFlags - objectRecordsPermissions - objectPermissions { + objectsPermissions { ...ObjectPermissionFragment } twoFactorAuthenticationMethodSummary { diff --git a/packages/twenty-front/src/modules/users/hooks/useLoadCurrentUser.ts b/packages/twenty-front/src/modules/users/hooks/useLoadCurrentUser.ts index 7e8cdcf16f..1a6beb07f4 100644 --- a/packages/twenty-front/src/modules/users/hooks/useLoadCurrentUser.ts +++ b/packages/twenty-front/src/modules/users/hooks/useLoadCurrentUser.ts @@ -75,8 +75,8 @@ export const useLoadCurrentUser = () => { if (isDefined(user.currentUserWorkspace)) { setCurrentUserWorkspace({ ...user.currentUserWorkspace, - objectPermissions: - (user.currentUserWorkspace.objectPermissions as Array< + objectsPermissions: + (user.currentUserWorkspace.objectsPermissions as Array< ObjectPermissions & { objectMetadataId: string } >) ?? [], }); diff --git a/packages/twenty-front/src/testing/mock-data/users.ts b/packages/twenty-front/src/testing/mock-data/users.ts index 57b65f28b8..86f5f8213d 100644 --- a/packages/twenty-front/src/testing/mock-data/users.ts +++ b/packages/twenty-front/src/testing/mock-data/users.ts @@ -126,7 +126,7 @@ export const mockedUserData: MockedUser = { currentWorkspace: mockCurrentWorkspace, currentUserWorkspace: { permissionFlags: [PermissionFlagType.WORKSPACE_MEMBERS], - objectPermissions: generatedMockObjectMetadataItems.map((item) => ({ + objectsPermissions: generatedMockObjectMetadataItems.map((item) => ({ objectMetadataId: item.id, canReadObjectRecords: true, canUpdateObjectRecords: true, @@ -150,7 +150,7 @@ export const mockedLimitedPermissionsUserData: MockedUser = { ...mockedUserData, currentUserWorkspace: { ...mockedUserData.currentUserWorkspace, - objectPermissions: generatedMockObjectMetadataItems + objectsPermissions: generatedMockObjectMetadataItems .filter( (objectMetadata) => objectMetadata.nameSingular !== 'task' && diff --git a/packages/twenty-server/src/engine/core-modules/user-workspace/user-workspace.entity.ts b/packages/twenty-server/src/engine/core-modules/user-workspace/user-workspace.entity.ts index fa695b1ec7..883ef97890 100644 --- a/packages/twenty-server/src/engine/core-modules/user-workspace/user-workspace.entity.ts +++ b/packages/twenty-server/src/engine/core-modules/user-workspace/user-workspace.entity.ts @@ -102,15 +102,12 @@ export class UserWorkspace { @Field(() => [PermissionFlagType], { nullable: true }) permissionFlags?: PermissionFlagType[]; - @Field(() => [PermissionsOnAllObjectRecords], { - nullable: true, - deprecationReason: 'Use objectPermissions instead', - }) - objectRecordsPermissions?: PermissionsOnAllObjectRecords[]; - @Field(() => [ObjectPermissionDTO], { nullable: true }) objectPermissions?: ObjectPermissionDTO[]; + @Field(() => [ObjectPermissionDTO], { nullable: true }) + objectsPermissions?: ObjectPermissionDTO[]; + @Field(() => [TwoFactorAuthenticationMethodSummaryDto], { nullable: true }) twoFactorAuthenticationMethodSummary?: TwoFactorAuthenticationMethodSummaryDto[]; } diff --git a/packages/twenty-server/src/engine/metadata-modules/permissions/permissions.service.ts b/packages/twenty-server/src/engine/metadata-modules/permissions/permissions.service.ts index d19bda7c09..5cc5b7ca33 100644 --- a/packages/twenty-server/src/engine/metadata-modules/permissions/permissions.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/permissions/permissions.service.ts @@ -1,7 +1,6 @@ import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; -import { PermissionsOnAllObjectRecords } from 'twenty-shared/constants'; import { isDefined } from 'twenty-shared/utils'; import { Repository } from 'typeorm'; @@ -82,37 +81,16 @@ export class PermissionsService { workspaceId, }); - const objectPermissions = rolesPermissions[roleOfUserWorkspace.id] ?? {}; const objectsPermissions = rolesPermissions[roleOfUserWorkspace.id] ?? {}; - const objectRecordsPermissions: UserWorkspacePermissions['objectRecordsPermissions'] = - { - [PermissionsOnAllObjectRecords.READ_ALL_OBJECT_RECORDS]: - roleOfUserWorkspace.canReadAllObjectRecords ?? false, - [PermissionsOnAllObjectRecords.UPDATE_ALL_OBJECT_RECORDS]: - roleOfUserWorkspace.canUpdateAllObjectRecords ?? false, - [PermissionsOnAllObjectRecords.SOFT_DELETE_ALL_OBJECT_RECORDS]: - roleOfUserWorkspace.canSoftDeleteAllObjectRecords ?? false, - [PermissionsOnAllObjectRecords.DESTROY_ALL_OBJECT_RECORDS]: - roleOfUserWorkspace.canDestroyAllObjectRecords ?? false, - }; - return { permissionFlags, - objectRecordsPermissions, - objectPermissions, objectsPermissions, }; } public getDefaultUserWorkspacePermissions = () => ({ - objectRecordsPermissions: { - [PermissionsOnAllObjectRecords.READ_ALL_OBJECT_RECORDS]: false, - [PermissionsOnAllObjectRecords.UPDATE_ALL_OBJECT_RECORDS]: false, - [PermissionsOnAllObjectRecords.SOFT_DELETE_ALL_OBJECT_RECORDS]: false, - [PermissionsOnAllObjectRecords.DESTROY_ALL_OBJECT_RECORDS]: false, - }, permissionFlags: { [PermissionFlagType.API_KEYS_AND_WEBHOOKS]: false, [PermissionFlagType.WORKSPACE]: false, @@ -126,7 +104,6 @@ export class PermissionsService { [PermissionFlagType.IMPORT_CSV]: false, [PermissionFlagType.EXPORT_CSV]: false, }, - objectPermissions: {}, objectsPermissions: {}, }) as const satisfies UserWorkspacePermissions; diff --git a/packages/twenty-server/src/engine/metadata-modules/permissions/types/user-workspace-permissions.ts b/packages/twenty-server/src/engine/metadata-modules/permissions/types/user-workspace-permissions.ts index 7366c9ce08..afc6189041 100644 --- a/packages/twenty-server/src/engine/metadata-modules/permissions/types/user-workspace-permissions.ts +++ b/packages/twenty-server/src/engine/metadata-modules/permissions/types/user-workspace-permissions.ts @@ -1,14 +1,8 @@ -import { type PermissionsOnAllObjectRecords } from 'twenty-shared/constants'; -import { - type ObjectsPermissions, - type ObjectsPermissionsDeprecated, -} from 'twenty-shared/types'; +import { type ObjectsPermissions } from 'twenty-shared/types'; import { type PermissionFlagType } from 'src/engine/metadata-modules/permissions/constants/permission-flag-type.constants'; export type UserWorkspacePermissions = { permissionFlags: Record; - objectRecordsPermissions: Record; - objectPermissions: ObjectsPermissionsDeprecated; - objectsPermissions: ObjectsPermissions; // replaces ObjectsPermissionsDeprecated - deprecation ongoing + objectsPermissions: ObjectsPermissions; }; diff --git a/packages/twenty-server/src/engine/metadata-modules/role/dtos/user-workspace-permissions.dto.ts b/packages/twenty-server/src/engine/metadata-modules/role/dtos/user-workspace-permissions.dto.ts index 4efe01534e..7eb78a66a6 100644 --- a/packages/twenty-server/src/engine/metadata-modules/role/dtos/user-workspace-permissions.dto.ts +++ b/packages/twenty-server/src/engine/metadata-modules/role/dtos/user-workspace-permissions.dto.ts @@ -2,5 +2,5 @@ import { type UserWorkspace } from 'src/engine/core-modules/user-workspace/user- export type UserWorkspacePermissionsDto = Pick< UserWorkspace, - 'objectPermissions' | 'permissionFlags' | 'objectRecordsPermissions' + 'objectPermissions' | 'permissionFlags' | 'objectsPermissions' >; diff --git a/packages/twenty-server/src/engine/metadata-modules/role/utils/fromUserWorkspacePermissionsToUserWorkspacePermissionsDto.ts b/packages/twenty-server/src/engine/metadata-modules/role/utils/fromUserWorkspacePermissionsToUserWorkspacePermissionsDto.ts index 44a0105ca0..e0b477367b 100644 --- a/packages/twenty-server/src/engine/metadata-modules/role/utils/fromUserWorkspacePermissionsToUserWorkspacePermissionsDto.ts +++ b/packages/twenty-server/src/engine/metadata-modules/role/utils/fromUserWorkspacePermissionsToUserWorkspacePermissionsDto.ts @@ -1,36 +1,31 @@ -import { type PermissionsOnAllObjectRecords } from 'twenty-shared/constants'; - import { type PermissionFlagType } from 'src/engine/metadata-modules/permissions/constants/permission-flag-type.constants'; import { type UserWorkspacePermissions } from 'src/engine/metadata-modules/permissions/types/user-workspace-permissions'; import { type UserWorkspacePermissionsDto } from 'src/engine/metadata-modules/role/dtos/user-workspace-permissions.dto'; export const fromUserWorkspacePermissionsToUserWorkspacePermissionsDto = ({ - objectPermissions: rawObjectPermissions, - objectRecordsPermissions: rawObjectRecordsPermissions, + objectsPermissions: rawObjectsPermissions, permissionFlags: rawSettingsPermissions, }: UserWorkspacePermissions): UserWorkspacePermissionsDto => { - const objectPermissions = Object.entries(rawObjectPermissions).map( + const objectPermissions = Object.entries(rawObjectsPermissions).map( ([objectMetadataId, permissions]) => ({ objectMetadataId, - canReadObjectRecords: permissions.canRead, - canUpdateObjectRecords: permissions.canUpdate, - canSoftDeleteObjectRecords: permissions.canSoftDelete, - canDestroyObjectRecords: permissions.canDestroy, + canReadObjectRecords: permissions.canReadObjectRecords, + canUpdateObjectRecords: permissions.canUpdateObjectRecords, + canSoftDeleteObjectRecords: permissions.canSoftDeleteObjectRecords, + canDestroyObjectRecords: permissions.canDestroyObjectRecords, restrictedFields: permissions.restrictedFields, }), ); + const objectsPermissions = objectPermissions; + const permissionFlags = ( Object.keys(rawSettingsPermissions) as PermissionFlagType[] ).filter((feature) => rawSettingsPermissions[feature] === true); - const objectRecordsPermissions = ( - Object.keys(rawObjectRecordsPermissions) as PermissionsOnAllObjectRecords[] - ).filter((feature) => rawObjectRecordsPermissions[feature] === true); - return { objectPermissions, - objectRecordsPermissions, + objectsPermissions, permissionFlags, }; };