diff --git a/packages/twenty-front/src/generated-metadata/graphql.ts b/packages/twenty-front/src/generated-metadata/graphql.ts index bc8e36aa0..b7b8ec8f5 100644 --- a/packages/twenty-front/src/generated-metadata/graphql.ts +++ b/packages/twenty-front/src/generated-metadata/graphql.ts @@ -1525,9 +1525,7 @@ export type ObjectPermission = { canReadObjectRecords?: Maybe; canSoftDeleteObjectRecords?: Maybe; canUpdateObjectRecords?: Maybe; - id: Scalars['String']['output']; objectMetadataId: Scalars['String']['output']; - roleId: Scalars['String']['output']; }; export type ObjectPermissionInput = { @@ -2543,6 +2541,8 @@ export type UserWorkspace = { createdAt: Scalars['DateTime']['output']; deletedAt?: Maybe; id: Scalars['UUID']['output']; + objectPermissions?: Maybe>; + /** @deprecated Use objectPermissions instead */ objectRecordsPermissions?: Maybe>; settingsPermissions?: Maybe>; updatedAt: Scalars['DateTime']['output']; diff --git a/packages/twenty-front/src/generated/graphql.tsx b/packages/twenty-front/src/generated/graphql.tsx index 96bfd725c..2fb30518d 100644 --- a/packages/twenty-front/src/generated/graphql.tsx +++ b/packages/twenty-front/src/generated/graphql.tsx @@ -1391,9 +1391,7 @@ export type ObjectPermission = { canReadObjectRecords?: Maybe; canSoftDeleteObjectRecords?: Maybe; canUpdateObjectRecords?: Maybe; - id: Scalars['String']; objectMetadataId: Scalars['String']; - roleId: Scalars['String']; }; export type ObjectPermissionInput = { @@ -2320,6 +2318,8 @@ export type UserWorkspace = { createdAt: Scalars['DateTime']; deletedAt?: Maybe; id: Scalars['UUID']; + objectPermissions?: Maybe>; + /** @deprecated Use objectPermissions instead */ objectRecordsPermissions?: Maybe>; settingsPermissions?: Maybe>; updatedAt: Scalars['DateTime']; @@ -2854,7 +2854,7 @@ export type UpdateLabPublicFeatureFlagMutationVariables = Exact<{ export type UpdateLabPublicFeatureFlagMutation = { __typename?: 'Mutation', updateLabPublicFeatureFlag: { __typename?: 'FeatureFlagDTO', key: FeatureFlagKey, value: boolean } }; -export type ObjectPermissionFragmentFragment = { __typename?: 'ObjectPermission', id: string, objectMetadataId: string, roleId: string, canReadObjectRecords?: boolean | null, canUpdateObjectRecords?: boolean | null, canSoftDeleteObjectRecords?: boolean | null, canDestroyObjectRecords?: boolean | null }; +export type ObjectPermissionFragmentFragment = { __typename?: 'ObjectPermission', objectMetadataId: string, canReadObjectRecords?: boolean | null, canUpdateObjectRecords?: boolean | null, canSoftDeleteObjectRecords?: boolean | null, canDestroyObjectRecords?: boolean | null }; export type RoleFragmentFragment = { __typename?: 'Role', id: string, label: string, description?: string | null, icon?: string | null, canUpdateAllSettings: boolean, isEditable: boolean, canReadAllObjectRecords: boolean, canUpdateAllObjectRecords: boolean, canSoftDeleteAllObjectRecords: boolean, canDestroyAllObjectRecords: boolean }; @@ -2887,7 +2887,7 @@ export type UpsertObjectPermissionsMutationVariables = Exact<{ }>; -export type UpsertObjectPermissionsMutation = { __typename?: 'Mutation', upsertObjectPermissions: Array<{ __typename?: 'ObjectPermission', id: string, objectMetadataId: string, roleId: string, canReadObjectRecords?: boolean | null, canUpdateObjectRecords?: boolean | null, canSoftDeleteObjectRecords?: boolean | null, canDestroyObjectRecords?: boolean | null }> }; +export type UpsertObjectPermissionsMutation = { __typename?: 'Mutation', upsertObjectPermissions: Array<{ __typename?: 'ObjectPermission', objectMetadataId: string, canReadObjectRecords?: boolean | null, canUpdateObjectRecords?: boolean | null, canSoftDeleteObjectRecords?: boolean | null, canDestroyObjectRecords?: boolean | null }> }; export type UpsertSettingPermissionsMutationVariables = Exact<{ upsertSettingPermissionsInput: UpsertSettingPermissionsInput; @@ -2899,7 +2899,7 @@ export type UpsertSettingPermissionsMutation = { __typename?: 'Mutation', upsert export type GetRolesQueryVariables = Exact<{ [key: string]: never; }>; -export type GetRolesQuery = { __typename?: 'Query', getRoles: Array<{ __typename?: 'Role', id: string, label: string, description?: string | null, icon?: string | null, canUpdateAllSettings: boolean, isEditable: boolean, canReadAllObjectRecords: boolean, canUpdateAllObjectRecords: boolean, canSoftDeleteAllObjectRecords: boolean, canDestroyAllObjectRecords: boolean, workspaceMembers: Array<{ __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale?: string | null, userEmail: string, timeZone?: string | null, dateFormat?: WorkspaceMemberDateFormatEnum | null, timeFormat?: WorkspaceMemberTimeFormatEnum | null, name: { __typename?: 'FullName', firstName: string, lastName: string } }>, settingPermissions?: Array<{ __typename?: 'SettingPermission', id: string, setting: SettingPermissionType, roleId: string }> | null, objectPermissions?: Array<{ __typename?: 'ObjectPermission', id: string, objectMetadataId: string, roleId: string, canReadObjectRecords?: boolean | null, canUpdateObjectRecords?: boolean | null, canSoftDeleteObjectRecords?: boolean | null, canDestroyObjectRecords?: boolean | null }> | null }> }; +export type GetRolesQuery = { __typename?: 'Query', getRoles: Array<{ __typename?: 'Role', id: string, label: string, description?: string | null, icon?: string | null, canUpdateAllSettings: boolean, isEditable: boolean, canReadAllObjectRecords: boolean, canUpdateAllObjectRecords: boolean, canSoftDeleteAllObjectRecords: boolean, canDestroyAllObjectRecords: boolean, workspaceMembers: Array<{ __typename?: 'WorkspaceMember', id: any, colorScheme: string, avatarUrl?: string | null, locale?: string | null, userEmail: string, timeZone?: string | null, dateFormat?: WorkspaceMemberDateFormatEnum | null, timeFormat?: WorkspaceMemberTimeFormatEnum | null, name: { __typename?: 'FullName', firstName: string, lastName: string } }>, settingPermissions?: Array<{ __typename?: 'SettingPermission', id: string, setting: SettingPermissionType, roleId: string }> | null, objectPermissions?: Array<{ __typename?: 'ObjectPermission', objectMetadataId: string, canReadObjectRecords?: boolean | null, canUpdateObjectRecords?: boolean | null, canSoftDeleteObjectRecords?: boolean | null, canDestroyObjectRecords?: boolean | null }> | null }> }; export type CreateApprovedAccessDomainMutationVariables = Exact<{ input: CreateApprovedAccessDomainInput; @@ -3225,9 +3225,7 @@ export const AvailableSsoIdentityProvidersFragmentFragmentDoc = gql` `; export const ObjectPermissionFragmentFragmentDoc = gql` fragment ObjectPermissionFragment on ObjectPermission { - id objectMetadataId - roleId canReadObjectRecords canUpdateObjectRecords canSoftDeleteObjectRecords diff --git a/packages/twenty-front/src/modules/settings/roles/graphql/fragments/objectPermissionFragment.ts b/packages/twenty-front/src/modules/settings/roles/graphql/fragments/objectPermissionFragment.ts index 8abbc4826..a1fb6dc25 100644 --- a/packages/twenty-front/src/modules/settings/roles/graphql/fragments/objectPermissionFragment.ts +++ b/packages/twenty-front/src/modules/settings/roles/graphql/fragments/objectPermissionFragment.ts @@ -2,9 +2,7 @@ import { gql } from '@apollo/client'; export const OBJECT_PERMISSION_FRAGMENT = gql` fragment ObjectPermissionFragment on ObjectPermission { - id objectMetadataId - roleId canReadObjectRecords canUpdateObjectRecords canSoftDeleteObjectRecords diff --git a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/components/SettingsRolePermissionsObjectLevelOverrideCell.tsx b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/components/SettingsRolePermissionsObjectLevelOverrideCell.tsx index c1b3d8688..258498bcd 100644 --- a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/components/SettingsRolePermissionsObjectLevelOverrideCell.tsx +++ b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/components/SettingsRolePermissionsObjectLevelOverrideCell.tsx @@ -36,15 +36,17 @@ const StyledSettingsRolePermissionsObjectLevelOverrideCell = styled.div` type SettingsRolePermissionsObjectLevelOverrideCellProps = { objectPermission: ObjectPermission; + roleId: string; }; export const SettingsRolePermissionsObjectLevelOverrideCell = ({ objectPermission, + roleId, }: SettingsRolePermissionsObjectLevelOverrideCellProps) => { const theme = useTheme(); const settingsDraftRole = useRecoilValue( - settingsDraftRoleFamilyState(objectPermission.roleId), + settingsDraftRoleFamilyState(roleId), ); const permissionMappings = diff --git a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/components/SettingsRolePermissionsObjectLevelSection.tsx b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/components/SettingsRolePermissionsObjectLevelSection.tsx index 2a4c6c3ed..bc9969598 100644 --- a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/components/SettingsRolePermissionsObjectLevelSection.tsx +++ b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/components/SettingsRolePermissionsObjectLevelSection.tsx @@ -15,7 +15,6 @@ import { isDefined } from 'twenty-shared/utils'; import { H2Title, IconPlus } from 'twenty-ui/display'; import { Button } from 'twenty-ui/input'; import { Section } from 'twenty-ui/layout'; -import { v4 } from 'uuid'; import { useNavigateSettings } from '~/hooks/useNavigateSettings'; const StyledCreateObjectOverrideSection = styled(Section)` @@ -81,11 +80,9 @@ export const SettingsRolePermissionsObjectLevelSection = ({ ...draftRole, objectPermissions: [ ...(draftRole.objectPermissions ?? []).filter( - (permission) => - permission.objectMetadataId !== objectMetadataId || - permission.roleId !== roleId, + (permission) => permission.objectMetadataId !== objectMetadataId, ), - { objectMetadataId, roleId, id: v4() }, + { objectMetadataId, roleId }, ], })); navigate(SettingsPath.RoleObjectLevel, { @@ -107,11 +104,12 @@ export const SettingsRolePermissionsObjectLevelSection = ({ filteredObjectPermissions?.length > 0 ? ( filteredObjectPermissions?.map((objectPermission) => ( )) ) : ( diff --git a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/components/SettingsRolePermissionsObjectLevelTableRow.tsx b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/components/SettingsRolePermissionsObjectLevelTableRow.tsx index 42d6c57bb..bcc3c383e 100644 --- a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/components/SettingsRolePermissionsObjectLevelTableRow.tsx +++ b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/components/SettingsRolePermissionsObjectLevelTableRow.tsx @@ -27,11 +27,13 @@ const StyledNameLabel = styled.div` type SettingsRolePermissionsObjectLevelTableRowProps = { objectPermission: ObjectPermission; objectMetadataItem: ObjectMetadataItem; + roleId: string; }; export const SettingsRolePermissionsObjectLevelTableRow = ({ objectPermission, objectMetadataItem, + roleId, }: SettingsRolePermissionsObjectLevelTableRowProps) => { const { getIcon } = useIcons(); const theme = useTheme(); @@ -45,7 +47,7 @@ export const SettingsRolePermissionsObjectLevelTableRow = ({ return ( 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 e0ead5bee..9be7b9882 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 @@ -20,6 +20,7 @@ import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/ import { TwoFactorMethod } from 'src/engine/core-modules/two-factor-method/two-factor-method.entity'; import { User } from 'src/engine/core-modules/user/user.entity'; import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; +import { ObjectPermissionDTO } from 'src/engine/metadata-modules/object-permission/dtos/object-permission.dto'; import { SettingPermissionType } from 'src/engine/metadata-modules/permissions/constants/setting-permission-type.constants'; registerEnumType(SettingPermissionType, { @@ -84,6 +85,12 @@ export class UserWorkspace { @Field(() => [SettingPermissionType], { nullable: true }) settingsPermissions?: SettingPermissionType[]; - @Field(() => [PermissionsOnAllObjectRecords], { nullable: true }) + @Field(() => [PermissionsOnAllObjectRecords], { + nullable: true, + deprecationReason: 'Use objectPermissions instead', + }) objectRecordsPermissions?: PermissionsOnAllObjectRecords[]; + + @Field(() => [ObjectPermissionDTO], { nullable: true }) + objectPermissions?: ObjectPermissionDTO[]; } 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 9f3d65760..b28c282f6 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 @@ -26,8 +26,12 @@ import { AuthExceptionCode, } from 'src/engine/core-modules/auth/auth.exception'; import { DomainManagerService } from 'src/engine/core-modules/domain-manager/services/domain-manager.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 { SignedFileDTO } from 'src/engine/core-modules/file/file-upload/dtos/signed-file.dto'; 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 { extractFilenameFromPath } from 'src/engine/core-modules/file/utils/extract-file-id-from-path.utils'; import { OnboardingStatus } from 'src/engine/core-modules/onboarding/enums/onboarding-status.enum'; import { OnboardingService, @@ -46,6 +50,7 @@ import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; import { AuthUser } from 'src/engine/decorators/auth/auth-user.decorator'; import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorator'; import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard'; +import { ObjectPermissionDTO } from 'src/engine/metadata-modules/object-permission/dtos/object-permission.dto'; import { SettingPermissionType } from 'src/engine/metadata-modules/permissions/constants/setting-permission-type.constants'; import { PermissionsService } from 'src/engine/metadata-modules/permissions/permissions.service'; import { PermissionsGraphqlApiExceptionFilter } from 'src/engine/metadata-modules/permissions/utils/permissions-graphql-api-exception.filter'; @@ -53,8 +58,6 @@ import { RoleDTO } from 'src/engine/metadata-modules/role/dtos/role.dto'; import { UserRoleService } from 'src/engine/metadata-modules/user-role/user-role.service'; import { AccountsToReconnectKeys } from 'src/modules/connected-account/types/accounts-to-reconnect-key-value.type'; import { streamToBuffer } from 'src/utils/stream-to-buffer'; -import { SignedFileDTO } from 'src/engine/core-modules/file/file-upload/dtos/signed-file.dto'; -import { extractFilenameFromPath } from 'src/engine/core-modules/file/utils/extract-file-id-from-path.utils'; const getHMACKey = (email?: string, key?: string | null) => { if (!email || !key) return null; @@ -83,6 +86,7 @@ export class UserResolver { private readonly userRoleService: UserRoleService, private readonly permissionsService: PermissionsService, private readonly deletedWorkspaceMemberTranspiler: DeletedWorkspaceMemberTranspiler, + private readonly featureFlagService: FeatureFlagService, ) {} @Query(() => User) @@ -111,6 +115,7 @@ export class UserResolver { } let settingsPermissions = {}; let objectRecordsPermissions = {}; + let objectPermissions: ObjectPermissionDTO[] = []; if ( ![ @@ -118,14 +123,40 @@ export class UserResolver { WorkspaceActivationStatus.ONGOING_CREATION, ].includes(workspace.activationStatus) ) { - const permissions = - await this.permissionsService.getUserWorkspacePermissions({ - userWorkspaceId: currentUserWorkspace.id, - workspaceId: workspace.id, - }); + const isPermissionsV2Enabled = + await this.featureFlagService.isFeatureEnabled( + FeatureFlagKey.IsPermissionsV2Enabled, + workspace.id, + ); - settingsPermissions = permissions.settingsPermissions; - objectRecordsPermissions = permissions.objectRecordsPermissions; + if (isPermissionsV2Enabled) { + const permissions = + await this.permissionsService.getUserWorkspacePermissionsV2({ + userWorkspaceId: currentUserWorkspace.id, + workspaceId: workspace.id, + }); + + settingsPermissions = permissions.settingsPermissions; + objectPermissions = Object.entries( + permissions.objectRecordsPermissions, + ).map(([objectMetadataId, permissions]) => ({ + objectMetadataId, + canReadObjectRecords: permissions.canRead, + canUpdateObjectRecords: permissions.canUpdate, + canSoftDeleteObjectRecords: permissions.canSoftDelete, + canDestroyObjectRecords: permissions.canDestroy, + })); + objectRecordsPermissions = permissions.objectRecordsPermissions; + } else { + const permissions = + await this.permissionsService.getUserWorkspacePermissions({ + userWorkspaceId: currentUserWorkspace.id, + workspaceId: workspace.id, + }); + + settingsPermissions = permissions.settingsPermissions; + objectRecordsPermissions = permissions.objectRecordsPermissions; + } } const grantedSettingsPermissions: SettingPermissionType[] = ( @@ -143,6 +174,7 @@ export class UserResolver { currentUserWorkspace.settingsPermissions = grantedSettingsPermissions; currentUserWorkspace.objectRecordsPermissions = grantedObjectRecordsPermissions; + currentUserWorkspace.objectPermissions = objectPermissions; user.currentUserWorkspace = currentUserWorkspace; return { diff --git a/packages/twenty-server/src/engine/metadata-modules/object-permission/dtos/object-permission.dto.ts b/packages/twenty-server/src/engine/metadata-modules/object-permission/dtos/object-permission.dto.ts index 4f02edb54..30456a30a 100644 --- a/packages/twenty-server/src/engine/metadata-modules/object-permission/dtos/object-permission.dto.ts +++ b/packages/twenty-server/src/engine/metadata-modules/object-permission/dtos/object-permission.dto.ts @@ -2,12 +2,6 @@ import { Field, ObjectType } from '@nestjs/graphql'; @ObjectType('ObjectPermission') export class ObjectPermissionDTO { - @Field({ nullable: false }) - id: string; - - @Field({ nullable: false }) - roleId: string; - @Field({ nullable: false }) objectMetadataId: string; 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 ec9aacf0c..7c27d1471 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,6 +1,7 @@ import { Injectable } from '@nestjs/common'; import { PermissionsOnAllObjectRecords } from 'twenty-shared/constants'; +import { ObjectRecordsPermissions } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; import { @@ -26,6 +27,64 @@ export class PermissionsService { private readonly featureFlagService: FeatureFlagService, ) {} + public async getUserWorkspacePermissionsV2({ + userWorkspaceId, + workspaceId, + }: { + userWorkspaceId: string; + workspaceId: string; + }): Promise<{ + settingsPermissions: Record; + objectRecordsPermissions: ObjectRecordsPermissions; + }> { + const [roleOfUserWorkspace] = await this.userRoleService + .getRolesByUserWorkspaces({ + userWorkspaceIds: [userWorkspaceId], + workspaceId, + }) + .then((roles) => roles?.get(userWorkspaceId) ?? []); + + let hasPermissionOnSettingFeature = false; + + if (!isDefined(roleOfUserWorkspace)) { + throw new PermissionsException( + PermissionsExceptionMessage.NO_ROLE_FOUND_FOR_USER_WORKSPACE, + PermissionsExceptionCode.NO_ROLE_FOUND_FOR_USER_WORKSPACE, + ); + } + + if (roleOfUserWorkspace.canUpdateAllSettings === true) { + hasPermissionOnSettingFeature = true; + } + + const settingPermissions = roleOfUserWorkspace.settingPermissions ?? []; + + const settingsPermissionsMap = Object.keys(SettingPermissionType).reduce( + (acc, feature) => ({ + ...acc, + [feature]: + hasPermissionOnSettingFeature || + settingPermissions.some( + (settingPermission) => settingPermission.setting === feature, + ), + }), + {} as Record, + ); + + const { data: rolesPermissions } = + await this.workspacePermissionsCacheService.getRolesPermissionsFromCache({ + workspaceId, + }); + + const objectRecordsPermissions = + rolesPermissions[roleOfUserWorkspace.id] ?? {}; + + return { + settingsPermissions: settingsPermissionsMap, + objectRecordsPermissions: objectRecordsPermissions, + }; + } + public async getUserWorkspacePermissions({ userWorkspaceId, workspaceId, diff --git a/packages/twenty-server/src/engine/metadata-modules/workspace-permissions-cache/workspace-permissions-cache.service.ts b/packages/twenty-server/src/engine/metadata-modules/workspace-permissions-cache/workspace-permissions-cache.service.ts index 5a409792a..0241a1dc3 100644 --- a/packages/twenty-server/src/engine/metadata-modules/workspace-permissions-cache/workspace-permissions-cache.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/workspace-permissions-cache/workspace-permissions-cache.service.ts @@ -247,17 +247,15 @@ export class WorkspacePermissionsCacheService { relations: ['objectPermissions'], }); - const workspaceObjectMetadataNameIdMap = - await this.getWorkspaceObjectMetadataNameIdMap(workspaceId); + const workspaceObjectMetadataIds = + await this.getWorkspaceObjectMetadataIds(workspaceId); const permissionsByRoleId: ObjectRecordsPermissionsByRoleId = {}; for (const role of roles) { const objectRecordsPermissions: ObjectRecordsPermissions = {}; - for (const objectMetadataNameSingular of Object.keys( - workspaceObjectMetadataNameIdMap, - )) { + for (const objectMetadataId of workspaceObjectMetadataIds) { let canRead = role.canReadAllObjectRecords; let canUpdate = role.canUpdateAllObjectRecords; let canSoftDelete = role.canSoftDeleteAllObjectRecords; @@ -266,8 +264,7 @@ export class WorkspacePermissionsCacheService { if (isPermissionsV2Enabled) { const objectRecordPermissionsOverride = role.objectPermissions.find( (objectPermission) => - objectPermission.objectMetadataId === - workspaceObjectMetadataNameIdMap[objectMetadataNameSingular], + objectPermission.objectMetadataId === objectMetadataId, ); canRead = @@ -283,7 +280,7 @@ export class WorkspacePermissionsCacheService { canDestroy; } - objectRecordsPermissions[objectMetadataNameSingular] = { + objectRecordsPermissions[objectMetadataId] = { canRead, canUpdate, canSoftDelete, @@ -297,53 +294,17 @@ export class WorkspacePermissionsCacheService { return permissionsByRoleId; } - private async getWorkspaceObjectMetadataNameIdMap( + private async getWorkspaceObjectMetadataIds( workspaceId: string, - ): Promise> { - let workspaceObjectMetadataMap: Record = {}; - const metadataVersion = - await this.workspaceCacheStorageService.getMetadataVersion(workspaceId); + ): Promise { + const workspaceObjectMetadata = await this.objectMetadataRepository.find({ + where: { + workspaceId, + }, + select: ['id'], + }); - if (metadataVersion) { - const objectMetadataMaps = - await this.workspaceCacheStorageService.getObjectMetadataMaps( - workspaceId, - metadataVersion, - ); - - workspaceObjectMetadataMap = Object.values( - objectMetadataMaps?.byId ?? {}, - ).reduce( - (acc, objectMetadata) => { - acc[objectMetadata.nameSingular] = objectMetadata.id; - - return acc; - }, - {} as Record, - ); - } - - if ( - !metadataVersion || - Object.keys(workspaceObjectMetadataMap).length === 0 - ) { - const workspaceObjectMetadata = await this.objectMetadataRepository.find({ - where: { - workspaceId, - }, - }); - - workspaceObjectMetadataMap = workspaceObjectMetadata.reduce( - (acc, objectMetadata) => { - acc[objectMetadata.nameSingular] = objectMetadata.id; - - return acc; - }, - {} as Record, - ); - } - - return workspaceObjectMetadataMap; + return workspaceObjectMetadata.map((objectMetadata) => objectMetadata.id); } private async getUserWorkspaceRoleMapFromDatabase({ diff --git a/packages/twenty-server/src/engine/twenty-orm/repository/permissions.utils.ts b/packages/twenty-server/src/engine/twenty-orm/repository/permissions.utils.ts index b2ec3a64c..05c72648d 100644 --- a/packages/twenty-server/src/engine/twenty-orm/repository/permissions.utils.ts +++ b/packages/twenty-server/src/engine/twenty-orm/repository/permissions.utils.ts @@ -47,7 +47,8 @@ export const validateOperationIsPermittedOrThrow = ({ return; } - const permissionsForEntity = objectRecordsPermissions[entityName]; + const permissionsForEntity = + objectRecordsPermissions[objectMetadataIdForEntity]; switch (operationType) { case 'select': diff --git a/packages/twenty-server/test/integration/graphql/suites/settings-permissions/roles.integration-spec.ts b/packages/twenty-server/test/integration/graphql/suites/settings-permissions/roles.integration-spec.ts index 022fb2789..e59e7c79c 100644 --- a/packages/twenty-server/test/integration/graphql/suites/settings-permissions/roles.integration-spec.ts +++ b/packages/twenty-server/test/integration/graphql/suites/settings-permissions/roles.integration-spec.ts @@ -478,8 +478,6 @@ describe('roles permissions', () => { }) => ` mutation UpsertObjectPermissions { upsertObjectPermissions(upsertObjectPermissionsInput: { roleId: "${roleId}", objectPermissions: [{objectMetadataId: "${objectMetadataId}", canUpdateObjectRecords: true}]}) { - id - roleId objectMetadataId canUpdateObjectRecords } @@ -541,7 +539,6 @@ describe('roles permissions', () => { expect(res.body.data.upsertObjectPermissions).toEqual( expect.arrayContaining([ expect.objectContaining({ - roleId: createdEditableRoleId, objectMetadataId: listingObjectId, canUpdateObjectRecords: true, }), diff --git a/packages/twenty-shared/src/types/ObjectRecordsPermissions.ts b/packages/twenty-shared/src/types/ObjectRecordsPermissions.ts index 0fc63f1e0..637965976 100644 --- a/packages/twenty-shared/src/types/ObjectRecordsPermissions.ts +++ b/packages/twenty-shared/src/types/ObjectRecordsPermissions.ts @@ -1,5 +1,5 @@ export type ObjectRecordsPermissions = { - [objectName: string]: { + [objectMetadataId: string]: { canRead: boolean; canUpdate: boolean; canSoftDelete: boolean;