diff --git a/packages/twenty-server/src/engine/twenty-orm/entity-manager/workspace-entity-manager.ts b/packages/twenty-server/src/engine/twenty-orm/entity-manager/workspace-entity-manager.ts index 31f24a8ecb..26136f0c68 100644 --- a/packages/twenty-server/src/engine/twenty-orm/entity-manager/workspace-entity-manager.ts +++ b/packages/twenty-server/src/engine/twenty-orm/entity-manager/workspace-entity-manager.ts @@ -170,7 +170,7 @@ export class WorkspaceEntityManager extends EntityManager { entity: | QueryDeepPartialEntityWithNestedRelationFields | QueryDeepPartialEntityWithNestedRelationFields[], - selectedColumns: string[] = [], + selectedColumns: string[] | '*' = '*', permissionOptions?: PermissionOptions, ): Promise { const metadata = this.connection.getMetadata(target); @@ -197,7 +197,7 @@ export class WorkspaceEntityManager extends EntityManager { shouldBypassPermissionChecks?: boolean; objectRecordsPermissions?: ObjectRecordsPermissions; }, - selectedColumns: string[] = [], + selectedColumns: string[] | '*' = '*', ): Promise { const metadata = this.connection.getMetadata(target); let options; @@ -269,7 +269,7 @@ export class WorkspaceEntityManager extends EntityManager { | unknown, partialEntity: QueryDeepPartialEntity, permissionOptions?: PermissionOptions, - selectedColumns: string[] = [], + selectedColumns: string[] | '*' = '*', ): Promise { const metadata = this.connection.getMetadata(target); @@ -324,7 +324,7 @@ export class WorkspaceEntityManager extends EntityManager { partialEntity: QueryDeepPartialEntity; }[], permissionOptions?: PermissionOptions, - selectedColumns?: string[], + selectedColumns: string[] | '*' = '*', ): Promise { const metadata = this.connection.getMetadata(target); @@ -346,7 +346,7 @@ export class WorkspaceEntityManager extends EntityManager { propertyPath: string, value: number | string, permissionOptions?: PermissionOptions, - selectedColumns: string[] = [], + selectedColumns: string[] | '*' = '*', ): Promise { const metadata = this.connection.getMetadata(target); const column = metadata.findColumnWithPropertyPath(propertyPath); @@ -947,7 +947,7 @@ export class WorkspaceEntityManager extends EntityManager { propertyPath: string, value: number | string, permissionOptions?: PermissionOptions, - selectedColumns: string[] = [], + selectedColumns: string[] | '*' = '*', ): Promise { const metadata = this.connection.getMetadata(target); const column = metadata.findColumnWithPropertyPath(propertyPath); 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 9b63056ad8..63b5419dec 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 @@ -49,7 +49,7 @@ export const validateOperationIsPermittedOrThrow = ({ operationType: OperationType; objectRecordsPermissions: ObjectRecordsPermissions; objectMetadataMaps: ObjectMetadataMaps; - selectedColumns: string[]; + selectedColumns: string[] | '*'; isFieldPermissionsEnabled?: boolean; allFieldsSelected: boolean; updatedColumns: string[]; @@ -198,7 +198,7 @@ export const validateQueryIsPermittedOrThrow = ({ (select) => select.selection === mainEntity, ); - let selectedColumns: string[] = []; + let selectedColumns: string[] | '*' = []; let updatedColumns: string[] = []; if (isFieldPermissionsEnabled) { @@ -248,15 +248,19 @@ const validateReadFieldPermissionOrThrow = ({ allFieldsSelected, }: { restrictedFields: RestrictedFields; - selectedColumns: string[]; + selectedColumns: string[] | '*'; columnNameToFieldMetadataIdMap: Record; allFieldsSelected?: boolean; }) => { - if (isEmpty(restrictedFields)) { + const noReadRestrictions = + isEmpty(restrictedFields) || + Object.values(restrictedFields).every((field) => field.canRead !== false); + + if (noReadRestrictions) { return; } - if (allFieldsSelected) { + if (allFieldsSelected || selectedColumns === '*') { throw new PermissionsException( PermissionsExceptionMessage.PERMISSION_DENIED, PermissionsExceptionCode.PERMISSION_DENIED, @@ -321,7 +325,7 @@ const getSelectedColumnsFromExpressionMap = ({ expressionMap: QueryExpressionMap; allFieldsSelected: boolean; }) => { - let selectedColumns: string[] = []; + let selectedColumns: string[] | '*' = []; if ( ['update', 'insert', 'delete', 'soft-delete', 'restore'].includes( @@ -333,7 +337,8 @@ const getSelectedColumnsFromExpressionMap = ({ 'Returning columns are not set for update query', ); } - selectedColumns = [expressionMap.returning].flat(); + selectedColumns = + expressionMap.returning === '*' ? '*' : [expressionMap.returning].flat(); } else if (!allFieldsSelected) { selectedColumns = getSelectedColumnsFromExpressionMapSelects( expressionMap.selects, diff --git a/packages/twenty-server/src/engine/twenty-orm/repository/workspace-insert-query-builder.ts b/packages/twenty-server/src/engine/twenty-orm/repository/workspace-insert-query-builder.ts index 0ec313a08e..5a15c40e10 100644 --- a/packages/twenty-server/src/engine/twenty-orm/repository/workspace-insert-query-builder.ts +++ b/packages/twenty-server/src/engine/twenty-orm/repository/workspace-insert-query-builder.ts @@ -16,6 +16,7 @@ import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/featu import { QueryDeepPartialEntityWithNestedRelationFields } from 'src/engine/twenty-orm/entity-manager/types/query-deep-partial-entity-with-nested-relation-fields.type'; import { RelationConnectQueryConfig } from 'src/engine/twenty-orm/entity-manager/types/relation-connect-query-config.type'; import { RelationDisconnectQueryFieldsByEntityIndex } from 'src/engine/twenty-orm/entity-manager/types/relation-nested-query-fields-by-entity-index.type'; +import { WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager'; import { TwentyORMException, TwentyORMExceptionCode, @@ -29,7 +30,6 @@ import { WorkspaceUpdateQueryBuilder } from 'src/engine/twenty-orm/repository/wo import { formatData } from 'src/engine/twenty-orm/utils/format-data.util'; import { formatResult } from 'src/engine/twenty-orm/utils/format-result.util'; import { getObjectMetadataFromEntityTarget } from 'src/engine/twenty-orm/utils/get-object-metadata-from-entity-target.util'; -import { WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/workspace-entity-manager'; export class WorkspaceInsertQueryBuilder< T extends ObjectLiteral, @@ -155,7 +155,7 @@ export class WorkspaceInsertQueryBuilder< const afterResult = await eventSelectQueryBuilder.getMany(); - const formattedResult = formatResult( + const formattedResultForEvent = formatResult( afterResult, objectMetadata, this.internalContext.objectMetadataMaps, @@ -165,12 +165,30 @@ export class WorkspaceInsertQueryBuilder< action: DatabaseEventAction.CREATED, objectMetadataItem: objectMetadata, workspaceId: this.internalContext.workspaceId, - entities: formattedResult, + entities: formattedResultForEvent, authContext: this.authContext, }); + // TypeORM returns all entity columns for insertions + const resultWithoutInsertionExtraColumns = result.raw.map( + (rawResult: Record) => + Object.keys(rawResult) + .filter((key) => this.expressionMap.returning.includes(key)) + .reduce((filtered: Record, key) => { + filtered[key] = rawResult[key]; + + return filtered; + }, {}), + ); + + const formattedResult = formatResult( + resultWithoutInsertionExtraColumns, + objectMetadata, + this.internalContext.objectMetadataMaps, + ); + return { - raw: afterResult, + raw: resultWithoutInsertionExtraColumns, generatedMaps: formattedResult, identifiers: result.identifiers, };