diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/helpers/process-nested-relations-v2.helper.ts b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/helpers/process-nested-relations-v2.helper.ts index 5f87664a0..75e73a1f7 100644 --- a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/helpers/process-nested-relations-v2.helper.ts +++ b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/helpers/process-nested-relations-v2.helper.ts @@ -37,7 +37,7 @@ export class ProcessNestedRelationsV2Helper { aggregate = {}, limit, authContext, - dataSource, + workspaceDataSource, roleId, shouldBypassPermissionChecks, }: { @@ -50,7 +50,7 @@ export class ProcessNestedRelationsV2Helper { aggregate?: Record; limit: number; authContext: AuthContext; - dataSource: WorkspaceDataSource; + workspaceDataSource: WorkspaceDataSource; shouldBypassPermissionChecks: boolean; roleId?: string; }): Promise { @@ -66,7 +66,7 @@ export class ProcessNestedRelationsV2Helper { aggregate, limit, authContext, - dataSource, + workspaceDataSource, shouldBypassPermissionChecks, roleId, }), @@ -85,7 +85,7 @@ export class ProcessNestedRelationsV2Helper { aggregate, limit, authContext, - dataSource, + workspaceDataSource, shouldBypassPermissionChecks, roleId, }: { @@ -99,7 +99,7 @@ export class ProcessNestedRelationsV2Helper { aggregate: Record; limit: number; authContext: AuthContext; - dataSource: WorkspaceDataSource; + workspaceDataSource: WorkspaceDataSource; shouldBypassPermissionChecks: boolean; roleId?: string; }): Promise { @@ -131,7 +131,7 @@ export class ProcessNestedRelationsV2Helper { sourceFieldName, }); - const targetObjectRepository = dataSource.getRepository( + const targetObjectRepository = workspaceDataSource.getRepository( targetObjectMetadata.nameSingular, shouldBypassPermissionChecks, roleId, @@ -203,7 +203,7 @@ export class ProcessNestedRelationsV2Helper { aggregate, limit, authContext, - dataSource, + workspaceDataSource, shouldBypassPermissionChecks, roleId, }); diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/helpers/process-nested-relations.helper.ts b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/helpers/process-nested-relations.helper.ts index 66e8f30a1..080630a60 100644 --- a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/helpers/process-nested-relations.helper.ts +++ b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/helpers/process-nested-relations.helper.ts @@ -4,7 +4,6 @@ import { FindOptionsRelations, ObjectLiteral } from 'typeorm'; import { ObjectRecord } from 'src/engine/api/graphql/workspace-query-builder/interfaces/object-record.interface'; -import { ProcessAggregateHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/process-aggregate.helper'; import { ProcessNestedRelationsV2Helper } from 'src/engine/api/graphql/graphql-query-runner/helpers/process-nested-relations-v2.helper'; import { AggregationField } from 'src/engine/api/graphql/workspace-schema-builder/utils/get-available-aggregations-from-object-fields.util'; import { AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type'; @@ -16,7 +15,6 @@ import { WorkspaceDataSource } from 'src/engine/twenty-orm/datasource/workspace. export class ProcessNestedRelationsHelper { constructor( private readonly processNestedRelationsV2Helper: ProcessNestedRelationsV2Helper, - private readonly processAggregateHelper: ProcessAggregateHelper, ) {} public async processNestedRelations({ @@ -28,7 +26,7 @@ export class ProcessNestedRelationsHelper { aggregate = {}, limit, authContext, - dataSource, + workspaceDataSource, shouldBypassPermissionChecks, roleId, }: { @@ -41,7 +39,7 @@ export class ProcessNestedRelationsHelper { aggregate?: Record; limit: number; authContext: AuthContext; - dataSource: WorkspaceDataSource; + workspaceDataSource: WorkspaceDataSource; shouldBypassPermissionChecks: boolean; roleId?: string; }): Promise { @@ -54,7 +52,7 @@ export class ProcessNestedRelationsHelper { aggregate, limit, authContext, - dataSource, + workspaceDataSource, shouldBypassPermissionChecks, roleId, }); diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/interfaces/base-resolver-service.ts b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/interfaces/base-resolver-service.ts index 80ad60dda..5236f4f2a 100644 --- a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/interfaces/base-resolver-service.ts +++ b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/interfaces/base-resolver-service.ts @@ -41,7 +41,7 @@ import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global. export type GraphqlQueryResolverExecutionArgs = { args: Input; options: WorkspaceQueryRunnerOptions; - dataSource: WorkspaceDataSource; + workspaceDataSource: WorkspaceDataSource; repository: WorkspaceRepository; graphqlQueryParser: GraphqlQueryParser; graphqlQuerySelectedFieldsResult: GraphqlQuerySelectedFieldsResult; @@ -152,7 +152,7 @@ export abstract class GraphqlQueryBaseResolverService< const graphqlQueryResolverExecutionArgs = { args: computedArgs, options, - dataSource: workspaceDataSource, + workspaceDataSource, repository, graphqlQueryParser, graphqlQuerySelectedFieldsResult, diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-create-many-resolver.service.ts b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-create-many-resolver.service.ts index 921d15fe7..1ff8a1184 100644 --- a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-create-many-resolver.service.ts +++ b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-create-many-resolver.service.ts @@ -415,7 +415,7 @@ export class GraphqlQueryCreateManyResolverService extends GraphqlQueryBaseResol relations: executionArgs.graphqlQuerySelectedFieldsResult.relations, limit: QUERY_MAX_RECORDS, authContext: executionArgs.options.authContext, - dataSource: executionArgs.dataSource, + workspaceDataSource: executionArgs.workspaceDataSource, roleId, shouldBypassPermissionChecks, }); diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-create-one-resolver.service.ts b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-create-one-resolver.service.ts index a31a0d49a..e9afc18af 100644 --- a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-create-one-resolver.service.ts +++ b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-create-one-resolver.service.ts @@ -67,7 +67,7 @@ export class GraphqlQueryCreateOneResolverService extends GraphqlQueryBaseResolv relations: executionArgs.graphqlQuerySelectedFieldsResult.relations, limit: QUERY_MAX_RECORDS, authContext, - dataSource: executionArgs.dataSource, + workspaceDataSource: executionArgs.workspaceDataSource, roleId, shouldBypassPermissionChecks: executionArgs.isExecutedByApiKey, }); diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-delete-many-resolver.service.ts b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-delete-many-resolver.service.ts index 100007d42..ba918a78c 100644 --- a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-delete-many-resolver.service.ts +++ b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-delete-many-resolver.service.ts @@ -69,7 +69,7 @@ export class GraphqlQueryDeleteManyResolverService extends GraphqlQueryBaseResol relations: executionArgs.graphqlQuerySelectedFieldsResult.relations, limit: QUERY_MAX_RECORDS, authContext, - dataSource: executionArgs.dataSource, + workspaceDataSource: executionArgs.workspaceDataSource, roleId, shouldBypassPermissionChecks: executionArgs.isExecutedByApiKey, }); diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-delete-one-resolver.service.ts b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-delete-one-resolver.service.ts index 8538b3ca6..5f26b44c3 100644 --- a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-delete-one-resolver.service.ts +++ b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-delete-one-resolver.service.ts @@ -71,7 +71,7 @@ export class GraphqlQueryDeleteOneResolverService extends GraphqlQueryBaseResolv relations: executionArgs.graphqlQuerySelectedFieldsResult.relations, limit: QUERY_MAX_RECORDS, authContext, - dataSource: executionArgs.dataSource, + workspaceDataSource: executionArgs.workspaceDataSource, roleId, shouldBypassPermissionChecks: executionArgs.isExecutedByApiKey, }); diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-destroy-many-resolver.service.ts b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-destroy-many-resolver.service.ts index 0145ed9a2..d6f44bdfc 100644 --- a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-destroy-many-resolver.service.ts +++ b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-destroy-many-resolver.service.ts @@ -67,7 +67,7 @@ export class GraphqlQueryDestroyManyResolverService extends GraphqlQueryBaseReso relations: executionArgs.graphqlQuerySelectedFieldsResult.relations, limit: QUERY_MAX_RECORDS, authContext, - dataSource: executionArgs.dataSource, + workspaceDataSource: executionArgs.workspaceDataSource, roleId, shouldBypassPermissionChecks: executionArgs.isExecutedByApiKey, }); diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-destroy-one-resolver.service.ts b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-destroy-one-resolver.service.ts index 1bd44395a..9e86daaaa 100644 --- a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-destroy-one-resolver.service.ts +++ b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-destroy-one-resolver.service.ts @@ -67,7 +67,7 @@ export class GraphqlQueryDestroyOneResolverService extends GraphqlQueryBaseResol relations: executionArgs.graphqlQuerySelectedFieldsResult.relations, limit: QUERY_MAX_RECORDS, authContext, - dataSource: executionArgs.dataSource, + workspaceDataSource: executionArgs.workspaceDataSource, roleId, shouldBypassPermissionChecks: executionArgs.isExecutedByApiKey, }); diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-find-many-resolver.service.ts b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-find-many-resolver.service.ts index ca6d0bf95..85fc489ba 100644 --- a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-find-many-resolver.service.ts +++ b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-find-many-resolver.service.ts @@ -153,7 +153,7 @@ export class GraphqlQueryFindManyResolverService extends GraphqlQueryBaseResolve aggregate: executionArgs.graphqlQuerySelectedFieldsResult.aggregate, limit: QUERY_MAX_RECORDS, authContext, - dataSource: executionArgs.dataSource, + workspaceDataSource: executionArgs.workspaceDataSource, roleId, shouldBypassPermissionChecks: executionArgs.isExecutedByApiKey, }); diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-find-one-resolver.service.ts b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-find-one-resolver.service.ts index adeb27ef6..860148f38 100644 --- a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-find-one-resolver.service.ts +++ b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-find-one-resolver.service.ts @@ -77,7 +77,7 @@ export class GraphqlQueryFindOneResolverService extends GraphqlQueryBaseResolver relations: executionArgs.graphqlQuerySelectedFieldsResult.relations, limit: QUERY_MAX_RECORDS, authContext, - dataSource: executionArgs.dataSource, + workspaceDataSource: executionArgs.workspaceDataSource, roleId, shouldBypassPermissionChecks: executionArgs.isExecutedByApiKey, }); diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-restore-many-resolver.service.ts b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-restore-many-resolver.service.ts index 33280b482..45c521d78 100644 --- a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-restore-many-resolver.service.ts +++ b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-restore-many-resolver.service.ts @@ -69,7 +69,7 @@ export class GraphqlQueryRestoreManyResolverService extends GraphqlQueryBaseReso relations: executionArgs.graphqlQuerySelectedFieldsResult.relations, limit: QUERY_MAX_RECORDS, authContext, - dataSource: executionArgs.dataSource, + workspaceDataSource: executionArgs.workspaceDataSource, roleId, shouldBypassPermissionChecks: executionArgs.isExecutedByApiKey, }); diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-restore-one-resolver.service.ts b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-restore-one-resolver.service.ts index 5875b441e..c4c123695 100644 --- a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-restore-one-resolver.service.ts +++ b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-restore-one-resolver.service.ts @@ -71,7 +71,7 @@ export class GraphqlQueryRestoreOneResolverService extends GraphqlQueryBaseResol relations: executionArgs.graphqlQuerySelectedFieldsResult.relations, limit: QUERY_MAX_RECORDS, authContext, - dataSource: executionArgs.dataSource, + workspaceDataSource: executionArgs.workspaceDataSource, roleId, shouldBypassPermissionChecks: executionArgs.isExecutedByApiKey, }); diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-update-many-resolver.service.ts b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-update-many-resolver.service.ts index 261aa1195..f66d5b518 100644 --- a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-update-many-resolver.service.ts +++ b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-update-many-resolver.service.ts @@ -108,7 +108,7 @@ export class GraphqlQueryUpdateManyResolverService extends GraphqlQueryBaseResol relations: executionArgs.graphqlQuerySelectedFieldsResult.relations, limit: QUERY_MAX_RECORDS, authContext, - dataSource: executionArgs.dataSource, + workspaceDataSource: executionArgs.workspaceDataSource, roleId, shouldBypassPermissionChecks: executionArgs.isExecutedByApiKey, }); diff --git a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-update-one-resolver.service.ts b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-update-one-resolver.service.ts index 47b4d0923..5a5775119 100644 --- a/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-update-one-resolver.service.ts +++ b/packages/twenty-server/src/engine/api/graphql/graphql-query-runner/resolvers/graphql-query-update-one-resolver.service.ts @@ -100,7 +100,7 @@ export class GraphqlQueryUpdateOneResolverService extends GraphqlQueryBaseResolv relations: executionArgs.graphqlQuerySelectedFieldsResult.relations, limit: QUERY_MAX_RECORDS, authContext, - dataSource: executionArgs.dataSource, + workspaceDataSource: executionArgs.workspaceDataSource, roleId, shouldBypassPermissionChecks: executionArgs.isExecutedByApiKey, }); diff --git a/packages/twenty-server/src/engine/api/rest/core/interfaces/rest-api-base.handler.ts b/packages/twenty-server/src/engine/api/rest/core/interfaces/rest-api-base.handler.ts index 7ba6b4537..34d289efa 100644 --- a/packages/twenty-server/src/engine/api/rest/core/interfaces/rest-api-base.handler.ts +++ b/packages/twenty-server/src/engine/api/rest/core/interfaces/rest-api-base.handler.ts @@ -104,7 +104,7 @@ export abstract class RestApiBaseHandler { throw new BadRequestException('Workspace not found'); } - const dataSource = + const workspaceDataSource = await this.twentyORMGlobalManager.getDataSourceForWorkspace({ workspaceId: workspace.id, shouldFailIfMetadataNotFound: false, @@ -125,7 +125,7 @@ export abstract class RestApiBaseHandler { ); } - const shouldBypassPermissionChecks = !!apiKey; + const shouldBypassPermissionChecks = isDefined(apiKey); const roleId = await this.workspacePermissionsCacheService.getRoleIdFromUserWorkspaceId({ @@ -133,7 +133,7 @@ export abstract class RestApiBaseHandler { userWorkspaceId, }); - const repository = dataSource.getRepository( + const repository = workspaceDataSource.getRepository( objectMetadataNameSingular, shouldBypassPermissionChecks, roleId, @@ -142,7 +142,7 @@ export abstract class RestApiBaseHandler { return { objectMetadata, repository, - dataSource, + workspaceDataSource, objectMetadataItemWithFieldsMaps, }; } diff --git a/packages/twenty-server/src/engine/twenty-orm/datasource/workspace.datasource.ts b/packages/twenty-server/src/engine/twenty-orm/datasource/workspace.datasource.ts index f88e0df9c..fbcdd4948 100644 --- a/packages/twenty-server/src/engine/twenty-orm/datasource/workspace.datasource.ts +++ b/packages/twenty-server/src/engine/twenty-orm/datasource/workspace.datasource.ts @@ -1,3 +1,4 @@ +import { isDefined } from 'class-validator'; import { ObjectRecordsPermissionsByRoleId } from 'twenty-shared/types'; import { DataSource, @@ -6,11 +7,13 @@ import { ObjectLiteral, QueryRunner, ReplicationMode, + SelectQueryBuilder, } from 'typeorm'; import { FeatureFlagMap } from 'src/engine/core-modules/feature-flag/interfaces/feature-flag-map.interface'; import { WorkspaceInternalContext } from 'src/engine/twenty-orm/interfaces/workspace-internal-context.interface'; +import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum'; import { PermissionsException, PermissionsExceptionCode, @@ -19,6 +22,10 @@ import { WorkspaceEntityManager } from 'src/engine/twenty-orm/entity-manager/wor import { WorkspaceQueryRunner } from 'src/engine/twenty-orm/query-runner/workspace-query-runner'; import { WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.repository'; +type CreateQueryBuilderOptions = { + calledByWorkspaceEntityManager?: boolean; +}; + export class WorkspaceDataSource extends DataSource { readonly internalContext: WorkspaceInternalContext; readonly manager: WorkspaceEntityManager; @@ -83,6 +90,69 @@ export class WorkspaceDataSource extends DataSource { return queryRunner as any as WorkspaceQueryRunner; } + override createQueryBuilder( + entityClass: EntityTarget, + alias: string, + queryRunner?: QueryRunner, + options?: CreateQueryBuilderOptions, + ): SelectQueryBuilder; + + override createQueryBuilder( + queryRunner?: QueryRunner, + options?: CreateQueryBuilderOptions, // eslint-disable-next-line @typescript-eslint/no-explicit-any + ): SelectQueryBuilder; + + // Only callable from workspaceEntityManager to guarantee a permission check was run + override createQueryBuilder( + // eslint-disable-next-line @typescript-eslint/no-explicit-any + queryRunnerOrEntityClass?: QueryRunner | EntityTarget, + aliasOrOptions?: string | CreateQueryBuilderOptions, + queryRunner?: QueryRunner, + options?: CreateQueryBuilderOptions, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + ): SelectQueryBuilder { + let calledByWorkspaceEntityManager; + + const isPermissionsV2Enabled = + this.featureFlagMap[FeatureFlagKey.IS_PERMISSIONS_V2_ENABLED]; + + const isCalledWithEntityTarget = + isDefined(aliasOrOptions) && typeof aliasOrOptions === 'string'; + + if (isPermissionsV2Enabled) { + if (isCalledWithEntityTarget) { + calledByWorkspaceEntityManager = + options?.calledByWorkspaceEntityManager; + } else { + calledByWorkspaceEntityManager = ( + aliasOrOptions as CreateQueryBuilderOptions + )?.calledByWorkspaceEntityManager; + } + + if (!(calledByWorkspaceEntityManager === true)) { + throw new PermissionsException( + 'Method not allowed because permissions are not implemented at datasource level.', + PermissionsExceptionCode.METHOD_NOT_ALLOWED, + ); + } + } + + if (isCalledWithEntityTarget) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const entityClass = queryRunnerOrEntityClass as EntityTarget; + + return super.createQueryBuilder( + entityClass, + aliasOrOptions as string, + queryRunner, + ); + } else { + const queryRunner = queryRunnerOrEntityClass as QueryRunner; + + return super.createQueryBuilder(queryRunner); + } + } + // eslint-disable-next-line @typescript-eslint/no-explicit-any override query( query: string, 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 d0d446c31..0ae340fc7 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 @@ -145,14 +145,20 @@ export class WorkspaceEntityManager extends EntityManager { let queryBuilder: SelectQueryBuilder; if (alias) { - queryBuilder = super.createQueryBuilder( + queryBuilder = this.connection.createQueryBuilder( entityClassOrQueryRunner as EntityTarget, alias as string, queryRunner as QueryRunner | undefined, + { + calledByWorkspaceEntityManager: true, + }, ); } else { - queryBuilder = super.createQueryBuilder( + queryBuilder = this.connection.createQueryBuilder( entityClassOrQueryRunner as QueryRunner, + { + calledByWorkspaceEntityManager: true, + }, ); } @@ -912,7 +918,10 @@ export class WorkspaceEntityManager extends EntityManager { permissionOptions, ) .setFindOptions(options || {}) - .getExists(); + .select('1') + .limit(1) + .getRawOne() + .then((result) => isDefined(result)); } override existsBy( @@ -929,7 +938,10 @@ export class WorkspaceEntityManager extends EntityManager { permissionOptions, ) .setFindOptions({ where }) - .getExists(); + .select('1') + .limit(1) + .getRawOne() + .then((result) => isDefined(result)); } override count( diff --git a/packages/twenty-server/src/engine/twenty-orm/repository/workspace-select-query-builder.ts b/packages/twenty-server/src/engine/twenty-orm/repository/workspace-select-query-builder.ts index 093499398..9ee79aa5f 100644 --- a/packages/twenty-server/src/engine/twenty-orm/repository/workspace-select-query-builder.ts +++ b/packages/twenty-server/src/engine/twenty-orm/repository/workspace-select-query-builder.ts @@ -4,6 +4,10 @@ import { QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity import { WorkspaceInternalContext } from 'src/engine/twenty-orm/interfaces/workspace-internal-context.interface'; +import { + PermissionsException, + PermissionsExceptionCode, +} from 'src/engine/metadata-modules/permissions/permissions.exception'; import { validateQueryIsPermittedOrThrow } from 'src/engine/twenty-orm/repository/permissions.utils'; import { WorkspaceDeleteQueryBuilder } from 'src/engine/twenty-orm/repository/workspace-delete-query-builder'; import { WorkspaceSoftDeleteQueryBuilder } from 'src/engine/twenty-orm/repository/workspace-soft-delete-query-builder'; @@ -83,9 +87,10 @@ export class WorkspaceSelectQueryBuilder< } override getExists(): Promise { - this.validatePermissions(); - - return super.getExists(); + throw new PermissionsException( + 'getExists is not supported because it calls dataSource.createQueryBuilder()', + PermissionsExceptionCode.METHOD_NOT_ALLOWED, + ); } override getManyAndCount(): Promise<[T[], number]> { @@ -148,6 +153,13 @@ export class WorkspaceSelectQueryBuilder< ); } + override executeExistsQuery(): Promise { + throw new PermissionsException( + 'executeExistsQuery is not supported because it calls dataSource.createQueryBuilder()', + PermissionsExceptionCode.METHOD_NOT_ALLOWED, + ); + } + private validatePermissions(): void { validateQueryIsPermittedOrThrow( this.expressionMap,