[permissions] QA fixes (#13698)

In this PR

- Introduction of readableFields and updatableFields in
objectMetadataItem selector to ease filtering from a developer
experience perspective ( + to help developers think to do it). In
discussion @lucasbordeau @charlesBochet
- Remove non-updatable field from CSV import process (@etiennejouan)
- QA fix / Non-readable fields should not show on show page
- QA fix / It should not be offered to create a kanban view on a
non-readable field
- QA fix / It should not be offered to create view groups on a
non-readable field
- QA fix / Rating field should have a readonly mode

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
Marie
2025-08-07 18:21:59 +02:00
committed by GitHub
parent 258f21a4be
commit ee19ee5119
120 changed files with 1211 additions and 943 deletions
@@ -1,4 +1,4 @@
import { ObjectRecordsPermissions } from 'twenty-shared/types';
import { ObjectsPermissionsDeprecated } from 'twenty-shared/types';
import { EntityManager } from 'typeorm';
import { EntityPersistExecutor } from 'typeorm/persistence/EntityPersistExecutor';
import { PlainObjectToDatabaseEntityTransformer } from 'typeorm/query-builder/transformer/PlainObjectToDatabaseEntityTransformer';
@@ -75,7 +75,7 @@ describe('WorkspaceEntityManager', () => {
let mockDataSource: WorkspaceDataSource;
let mockPermissionOptions: {
shouldBypassPermissionChecks: boolean;
objectRecordsPermissions?: ObjectRecordsPermissions;
objectRecordsPermissions?: ObjectsPermissionsDeprecated;
};
beforeEach(() => {
@@ -331,8 +331,7 @@ describe('WorkspaceEntityManager', () => {
isFieldPermissionsEnabled: true,
operationType: 'update',
objectMetadataMaps: mockInternalContext.objectMetadataMaps,
objectRecordsPermissions:
mockPermissionOptions.objectRecordsPermissions,
objectsPermissions: mockPermissionOptions.objectRecordsPermissions,
selectedColumns: [],
allFieldsSelected: false,
updatedColumns: [],
@@ -366,8 +365,7 @@ describe('WorkspaceEntityManager', () => {
operationType: 'delete',
isFieldPermissionsEnabled: true,
objectMetadataMaps: mockInternalContext.objectMetadataMaps,
objectRecordsPermissions:
mockPermissionOptions.objectRecordsPermissions,
objectsPermissions: mockPermissionOptions.objectRecordsPermissions,
selectedColumns: [],
allFieldsSelected: false,
updatedColumns: [],
@@ -1,5 +1,5 @@
import isEmpty from 'lodash.isempty';
import { ObjectRecordsPermissions } from 'twenty-shared/types';
import { ObjectsPermissionsDeprecated } from 'twenty-shared/types';
import { isDefined } from 'twenty-shared/utils';
import {
DeleteResult,
@@ -58,7 +58,7 @@ import { getObjectMetadataFromEntityTarget } from 'src/engine/twenty-orm/utils/g
type PermissionOptions = {
shouldBypassPermissionChecks?: boolean;
objectRecordsPermissions?: ObjectRecordsPermissions;
objectRecordsPermissions?: ObjectsPermissionsDeprecated;
};
export class WorkspaceEntityManager extends EntityManager {
@@ -130,7 +130,7 @@ export class WorkspaceEntityManager extends EntityManager {
queryRunner?: QueryRunner,
options: {
shouldBypassPermissionChecks?: boolean;
objectRecordsPermissions?: ObjectRecordsPermissions;
objectRecordsPermissions?: ObjectsPermissionsDeprecated;
} = {
shouldBypassPermissionChecks: false,
objectRecordsPermissions: {},
@@ -198,7 +198,7 @@ export class WorkspaceEntityManager extends EntityManager {
conflictPathsOrOptions: string[] | UpsertOptions<Entity>,
permissionOptions?: {
shouldBypassPermissionChecks?: boolean;
objectRecordsPermissions?: ObjectRecordsPermissions;
objectRecordsPermissions?: ObjectsPermissionsDeprecated;
},
selectedColumns: string[] | '*' = '*',
): Promise<InsertResult> {
@@ -387,7 +387,7 @@ export class WorkspaceEntityManager extends EntityManager {
operationType: OperationType;
permissionOptions?: {
shouldBypassPermissionChecks?: boolean;
objectRecordsPermissions?: ObjectRecordsPermissions;
objectRecordsPermissions?: ObjectsPermissionsDeprecated;
};
selectedColumns: string[];
updatedColumns?: string[];
@@ -404,8 +404,7 @@ export class WorkspaceEntityManager extends EntityManager {
validateOperationIsPermittedOrThrow({
entityName,
operationType,
objectRecordsPermissions:
permissionOptions?.objectRecordsPermissions ?? {},
objectsPermissions: permissionOptions?.objectRecordsPermissions ?? {},
objectMetadataMaps: this.internalContext.objectMetadataMaps,
selectedColumns,
allFieldsSelected: false,