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.
This commit is contained in:
Marie
2025-09-03 19:37:06 +02:00
committed by GitHub
parent 4fa114b3ec
commit 052f91cff1
4 changed files with 34 additions and 6 deletions
@@ -145,6 +145,10 @@ export const SettingsRolePermissionsObjectLevelObjectFieldPermissionTable = ({
fieldPermissions={fieldPermissions}
objectMetadataItem={objectMetadataItem}
roleId={roleId}
isLabelIdentifier={
objectMetadataItem.labelIdentifierFieldMetadataId ===
fieldMetadataItem.id
}
/>
))}
</Table>
@@ -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 && (
<TableCell>
<OverridableCheckbox
disabled={fieldMetadataItem.isUIReadOnly ?? false}
disabled={
(fieldMetadataItem.isUIReadOnly || isLabelIdentifier) ?? false
}
checked={true}
onChange={handleSeeChange}
type={isReadRestricted ? 'override' : 'default'}
@@ -29,6 +29,7 @@ import {
} from 'src/engine/metadata-modules/object-metadata/object-metadata.exception';
import { ObjectMetadataRelatedRecordsService } from 'src/engine/metadata-modules/object-metadata/services/object-metadata-related-records.service';
import { WorkspaceMetadataCacheService } from 'src/engine/metadata-modules/workspace-metadata-cache/services/workspace-metadata-cache.service';
import { WorkspacePermissionsCacheService } from 'src/engine/metadata-modules/workspace-permissions-cache/workspace-permissions-cache.service';
import { WorkspaceMigrationBuilderExceptionV2 } from 'src/engine/workspace-manager/workspace-migration-v2/exceptions/workspace-migration-builder-exception-v2';
import { WorkspaceMigrationValidateBuildAndRunService } from 'src/engine/workspace-manager/workspace-migration-v2/services/workspace-migration-validate-build-and-run-service';
@@ -38,6 +39,7 @@ export class ObjectMetadataServiceV2 {
private readonly workspaceMetadataCacheService: WorkspaceMetadataCacheService,
private readonly workspaceMigrationValidateBuildAndRunService: WorkspaceMigrationValidateBuildAndRunService,
private readonly objectMetadataRelatedRecordsService: ObjectMetadataRelatedRecordsService,
private readonly workspacePermissionsCacheService: WorkspacePermissionsCacheService,
@InjectRepository(ViewEntity)
private readonly viewRepository: Repository<ViewEntity>,
) {}
@@ -126,6 +128,14 @@ export class ObjectMetadataServiceV2 {
);
}
if (isDefined(updateObjectInput.update.labelIdentifierFieldMetadataId)) {
await this.workspacePermissionsCacheService.recomputeRolesPermissionsCache(
{
workspaceId,
},
);
}
return fromFlatObjectMetadataToObjectMetadataDto(updatedFlatObjectMetadata);
}
@@ -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<RoleTargetsEntity>,
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;