From 052f91cff12aec393d4177249ca323830c6e49d7 Mon Sep 17 00:00:00 2001 From: Marie <51697796+ijreilly@users.noreply.github.com> Date: Wed, 3 Sep 2025 19:37:06 +0200 Subject: [PATCH] Adapt field permissions to label identifier (#14287) Closes https://github.com/twentyhq/core-team-issues/issues/1316 As discussed with @Bonapara, the behaviour is the following: 1 if there is a read restriction on a field that is or becomes the label identifier, this restriction is actually overriden to allow any user who has read rights on the object to also be able to read the values on the label identifier field. This restriction is overriden in the values stored in the cache but not in the db. 2 in the UI it is not possible to add a field permission to restrict read rights on the field that is the label identifier. It is still possible to update the label identifier for it to be a field that previously had a restrictive field permission on a role though, but then 1. has our back. --- ...onsObjectLevelObjectFieldPermissionTable.tsx | 4 ++++ ...ObjectLevelObjectFieldPermissionTableRow.tsx | 9 +++++++-- .../object-metadata-v2.service.ts | 10 ++++++++++ .../workspace-permissions-cache.service.ts | 17 +++++++++++++---- 4 files changed, 34 insertions(+), 6 deletions(-) diff --git a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/field-permissions/components/SettingsRolePermissionsObjectLevelObjectFieldPermissionTable.tsx b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/field-permissions/components/SettingsRolePermissionsObjectLevelObjectFieldPermissionTable.tsx index e3348664bf..6588448cfe 100644 --- a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/field-permissions/components/SettingsRolePermissionsObjectLevelObjectFieldPermissionTable.tsx +++ b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/field-permissions/components/SettingsRolePermissionsObjectLevelObjectFieldPermissionTable.tsx @@ -145,6 +145,10 @@ export const SettingsRolePermissionsObjectLevelObjectFieldPermissionTable = ({ fieldPermissions={fieldPermissions} objectMetadataItem={objectMetadataItem} roleId={roleId} + isLabelIdentifier={ + objectMetadataItem.labelIdentifierFieldMetadataId === + fieldMetadataItem.id + } /> ))} diff --git a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/field-permissions/components/SettingsRolePermissionsObjectLevelObjectFieldPermissionTableRow.tsx b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/field-permissions/components/SettingsRolePermissionsObjectLevelObjectFieldPermissionTableRow.tsx index e192362879..9236bc19f1 100644 --- a/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/field-permissions/components/SettingsRolePermissionsObjectLevelObjectFieldPermissionTableRow.tsx +++ b/packages/twenty-front/src/modules/settings/roles/role-permissions/object-level-permissions/field-permissions/components/SettingsRolePermissionsObjectLevelObjectFieldPermissionTableRow.tsx @@ -39,6 +39,7 @@ type SettingsRolePermissionsObjectLevelObjectFieldPermissionTableRowProps = { objectMetadataItem: ObjectMetadataItem; fieldPermissions: FieldPermission[]; roleId: string; + isLabelIdentifier: boolean; }; export const SettingsRolePermissionsObjectLevelObjectFieldPermissionTableRow = @@ -47,6 +48,7 @@ export const SettingsRolePermissionsObjectLevelObjectFieldPermissionTableRow = fieldPermissions, objectMetadataItem, roleId, + isLabelIdentifier, }: SettingsRolePermissionsObjectLevelObjectFieldPermissionTableRowProps) => { const theme = useTheme(); const { getIcon } = useIcons(); @@ -132,7 +134,8 @@ export const SettingsRolePermissionsObjectLevelObjectFieldPermissionTableRow = const isReadRestricted = hasRestriction && - fieldPermissionForThisFieldMetadataItem?.canReadFieldValue === false; + fieldPermissionForThisFieldMetadataItem?.canReadFieldValue === false && + !isLabelIdentifier; const isUpdateRestricted = hasRestriction && @@ -184,7 +187,9 @@ export const SettingsRolePermissionsObjectLevelObjectFieldPermissionTableRow = {shouldShowSeeTableHeader && ( , ) {} @@ -126,6 +128,14 @@ export class ObjectMetadataServiceV2 { ); } + if (isDefined(updateObjectInput.update.labelIdentifierFieldMetadataId)) { + await this.workspacePermissionsCacheService.recomputeRolesPermissionsCache( + { + workspaceId, + }, + ); + } + return fromFlatObjectMetadataToObjectMetadataDto(updatedFlatObjectMetadata); } 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 45f347260f..f0a01348ff 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 @@ -13,7 +13,6 @@ import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadat import { PermissionFlagType } from 'src/engine/metadata-modules/permissions/constants/permission-flag-type.constants'; import { RoleTargetsEntity } from 'src/engine/metadata-modules/role/role-targets.entity'; import { RoleEntity } from 'src/engine/metadata-modules/role/role.entity'; -import { WorkspaceFeatureFlagsMapCacheService } from 'src/engine/metadata-modules/workspace-feature-flags-map-cache/workspace-feature-flags-map-cache.service'; import { type UserWorkspaceRoleMap } from 'src/engine/metadata-modules/workspace-permissions-cache/types/user-workspace-role-map.type'; import { WorkspacePermissionsCacheStorageService } from 'src/engine/metadata-modules/workspace-permissions-cache/workspace-permissions-cache-storage.service'; import { TwentyORMExceptionCode } from 'src/engine/twenty-orm/exceptions/twenty-orm.exception'; @@ -45,7 +44,6 @@ export class WorkspacePermissionsCacheService { @InjectRepository(RoleTargetsEntity) private readonly roleTargetsRepository: Repository, private readonly workspacePermissionsCacheStorageService: WorkspacePermissionsCacheStorageService, - private readonly workspaceFeatureFlagsMapCacheService: WorkspaceFeatureFlagsMapCacheService, ) {} async recomputeRolesPermissionsCache({ @@ -249,12 +247,18 @@ export class WorkspacePermissionsCacheService { ); for (const fieldPermission of fieldPermissions) { + const isFieldLabelIdentifier = + fieldPermission.fieldMetadataId === + objectMetadata.labelIdentifierFieldMetadataId; + if ( isDefined(fieldPermission.canReadFieldValue) || isDefined(fieldPermission.canUpdateFieldValue) ) { restrictedFields[fieldPermission.fieldMetadataId] = { - canRead: fieldPermission.canReadFieldValue, + canRead: isFieldLabelIdentifier + ? true + : fieldPermission.canReadFieldValue, canUpdate: fieldPermission.canUpdateFieldValue, }; } @@ -283,7 +287,12 @@ export class WorkspacePermissionsCacheService { where: { workspaceId, }, - select: ['id', 'isSystem', 'standardId'], + select: [ + 'id', + 'isSystem', + 'standardId', + 'labelIdentifierFieldMetadataId', + ], }); return workspaceObjectMetadata;