diff --git a/packages/twenty-server/src/engine/api/common/common-query-runners/common-base-query-runner.service.ts b/packages/twenty-server/src/engine/api/common/common-query-runners/common-base-query-runner.service.ts index f4259404c82..f1f12b09339 100644 --- a/packages/twenty-server/src/engine/api/common/common-query-runners/common-base-query-runner.service.ts +++ b/packages/twenty-server/src/engine/api/common/common-query-runners/common-base-query-runner.service.ts @@ -3,7 +3,6 @@ import { Inject, Injectable } from '@nestjs/common'; import { type PermissionFlagType } from 'twenty-shared/constants'; import { isDefined } from 'twenty-shared/utils'; -import { WorkspaceAuthContext } from 'src/engine/api/common/interfaces/workspace-auth-context.interface'; import { QueryResultFieldValue } from 'src/engine/api/graphql/workspace-query-runner/factories/query-result-getters/interfaces/query-result-field-value'; import { DataArgProcessor } from 'src/engine/api/common/common-args-processors/data-arg-processor/data-arg.processor'; @@ -24,14 +23,17 @@ import { } from 'src/engine/api/common/types/common-query-args.type'; import { CommonQueryResult } from 'src/engine/api/common/types/common-query-result.type'; import { CommonSelectedFieldsResult } from 'src/engine/api/common/types/common-selected-fields-result.type'; -import { isWorkspaceAuthContext } from 'src/engine/api/common/utils/is-workspace-auth-context.util'; import { OBJECTS_WITH_SETTINGS_PERMISSIONS_REQUIREMENTS } from 'src/engine/api/graphql/graphql-query-runner/constants/objects-with-settings-permissions-requirements'; import { GraphqlQueryParser } from 'src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query.parser'; import { ProcessNestedRelationsHelper } from 'src/engine/api/graphql/graphql-query-runner/helpers/process-nested-relations.helper'; import { WorkspacePreQueryHookPayload } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/types/workspace-query-hook.type'; import { WorkspaceQueryHookService } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/workspace-query-hook.service'; import { ApiKeyRoleService } from 'src/engine/core-modules/api-key/services/api-key-role.service'; +import { isApiKeyAuthContext } from 'src/engine/core-modules/auth/guards/is-api-key-auth-context.guard'; +import { isUserAuthContext } from 'src/engine/core-modules/auth/guards/is-user-auth-context.guard'; +import { isWorkspaceAuthContext } from 'src/engine/core-modules/auth/guards/is-workspace-auth-context.guard'; import { AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type'; +import { WorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type'; import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service'; import { MetricsService } from 'src/engine/core-modules/metrics/metrics.service'; import { MetricsKeys } from 'src/engine/core-modules/metrics/types/metrics-keys.type'; @@ -287,10 +289,14 @@ export abstract class CommonBaseQueryRunnerService< const userHasPermission = await this.permissionsService.userHasWorkspaceSettingPermission({ - userWorkspaceId: authContext.userWorkspaceId, + userWorkspaceId: isUserAuthContext(authContext) + ? authContext.userWorkspaceId + : undefined, setting: permissionRequired, workspaceId: workspace.id, - apiKeyId: authContext.apiKey?.id, + apiKeyId: isApiKeyAuthContext(authContext) + ? authContext.apiKey.id + : undefined, }); if (!userHasPermission) { @@ -363,7 +369,7 @@ export abstract class CommonBaseQueryRunnerService< private async throttleQueryExecution(authContext: WorkspaceAuthContext) { try { - if (!isDefined(authContext.apiKey)) return; + if (!isApiKeyAuthContext(authContext)) return; const workspaceId = authContext.workspace.id; diff --git a/packages/twenty-server/src/engine/api/common/common-query-runners/common-create-many-query-runner/common-create-many-query-runner.service.ts b/packages/twenty-server/src/engine/api/common/common-query-runners/common-create-many-query-runner/common-create-many-query-runner.service.ts index 726ae136dc1..bbea2e92035 100644 --- a/packages/twenty-server/src/engine/api/common/common-query-runners/common-create-many-query-runner/common-create-many-query-runner.service.ts +++ b/packages/twenty-server/src/engine/api/common/common-query-runners/common-create-many-query-runner/common-create-many-query-runner.service.ts @@ -6,8 +6,7 @@ import { ObjectRecord } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; import { FindOptionsRelations, In, InsertResult, ObjectLiteral } from 'typeorm'; -import { WorkspaceAuthContext } from 'src/engine/api/common/interfaces/workspace-auth-context.interface'; - +import { WorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type'; import { CommonBaseQueryRunnerService } from 'src/engine/api/common/common-query-runners/common-base-query-runner.service'; import { PartialObjectRecordWithId } from 'src/engine/api/common/common-query-runners/common-create-many-query-runner/types/partial-object-record-with-id.type'; import { buildWhereConditions } from 'src/engine/api/common/common-query-runners/common-create-many-query-runner/utils/build-where-conditions.util'; diff --git a/packages/twenty-server/src/engine/api/common/common-query-runners/common-create-one-query-runner.service.ts b/packages/twenty-server/src/engine/api/common/common-query-runners/common-create-one-query-runner.service.ts index ad30ae45720..ae4eb48342e 100644 --- a/packages/twenty-server/src/engine/api/common/common-query-runners/common-create-one-query-runner.service.ts +++ b/packages/twenty-server/src/engine/api/common/common-query-runners/common-create-one-query-runner.service.ts @@ -2,8 +2,7 @@ import { Injectable } from '@nestjs/common'; import { type ObjectRecord } from 'twenty-shared/types'; -import { WorkspaceAuthContext } from 'src/engine/api/common/interfaces/workspace-auth-context.interface'; - +import { WorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type'; import { CommonBaseQueryRunnerService } from 'src/engine/api/common/common-query-runners/common-base-query-runner.service'; import { CommonCreateManyQueryRunnerService } from 'src/engine/api/common/common-query-runners/common-create-many-query-runner/common-create-many-query-runner.service'; import { CommonBaseQueryRunnerContext } from 'src/engine/api/common/types/common-base-query-runner-context.type'; diff --git a/packages/twenty-server/src/engine/api/common/common-query-runners/common-delete-many-query-runner.service.ts b/packages/twenty-server/src/engine/api/common/common-query-runners/common-delete-many-query-runner.service.ts index 88773f89888..b8d266ab377 100644 --- a/packages/twenty-server/src/engine/api/common/common-query-runners/common-delete-many-query-runner.service.ts +++ b/packages/twenty-server/src/engine/api/common/common-query-runners/common-delete-many-query-runner.service.ts @@ -5,8 +5,7 @@ import { ObjectRecord } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; import { FindOptionsRelations, ObjectLiteral } from 'typeorm'; -import { WorkspaceAuthContext } from 'src/engine/api/common/interfaces/workspace-auth-context.interface'; - +import { WorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type'; import { CommonBaseQueryRunnerService } from 'src/engine/api/common/common-query-runners/common-base-query-runner.service'; import { CommonQueryRunnerException, diff --git a/packages/twenty-server/src/engine/api/common/common-query-runners/common-delete-one-query-runner.service.ts b/packages/twenty-server/src/engine/api/common/common-query-runners/common-delete-one-query-runner.service.ts index f5f76363967..db241baa4f5 100644 --- a/packages/twenty-server/src/engine/api/common/common-query-runners/common-delete-one-query-runner.service.ts +++ b/packages/twenty-server/src/engine/api/common/common-query-runners/common-delete-one-query-runner.service.ts @@ -4,8 +4,7 @@ import { msg } from '@lingui/core/macro'; import { type ObjectRecord } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; -import { WorkspaceAuthContext } from 'src/engine/api/common/interfaces/workspace-auth-context.interface'; - +import { WorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type'; import { CommonBaseQueryRunnerService } from 'src/engine/api/common/common-query-runners/common-base-query-runner.service'; import { CommonDeleteManyQueryRunnerService } from 'src/engine/api/common/common-query-runners/common-delete-many-query-runner.service'; import { diff --git a/packages/twenty-server/src/engine/api/common/common-query-runners/common-destroy-many-query-runner.service.ts b/packages/twenty-server/src/engine/api/common/common-query-runners/common-destroy-many-query-runner.service.ts index 0cbc56f2f4b..ca28d217a64 100644 --- a/packages/twenty-server/src/engine/api/common/common-query-runners/common-destroy-many-query-runner.service.ts +++ b/packages/twenty-server/src/engine/api/common/common-query-runners/common-destroy-many-query-runner.service.ts @@ -5,8 +5,7 @@ import { ObjectRecord } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; import { FindOptionsRelations, ObjectLiteral } from 'typeorm'; -import { WorkspaceAuthContext } from 'src/engine/api/common/interfaces/workspace-auth-context.interface'; - +import { WorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type'; import { CommonBaseQueryRunnerService } from 'src/engine/api/common/common-query-runners/common-base-query-runner.service'; import { CommonQueryRunnerException, diff --git a/packages/twenty-server/src/engine/api/common/common-query-runners/common-destroy-one-query-runner.service.ts b/packages/twenty-server/src/engine/api/common/common-query-runners/common-destroy-one-query-runner.service.ts index a23fecd759e..dcb53064271 100644 --- a/packages/twenty-server/src/engine/api/common/common-query-runners/common-destroy-one-query-runner.service.ts +++ b/packages/twenty-server/src/engine/api/common/common-query-runners/common-destroy-one-query-runner.service.ts @@ -4,8 +4,7 @@ import { msg } from '@lingui/core/macro'; import { type ObjectRecord } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; -import { WorkspaceAuthContext } from 'src/engine/api/common/interfaces/workspace-auth-context.interface'; - +import { WorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type'; import { CommonBaseQueryRunnerService } from 'src/engine/api/common/common-query-runners/common-base-query-runner.service'; import { CommonDestroyManyQueryRunnerService } from 'src/engine/api/common/common-query-runners/common-destroy-many-query-runner.service'; import { diff --git a/packages/twenty-server/src/engine/api/common/common-query-runners/common-find-duplicates-query-runner.service.ts b/packages/twenty-server/src/engine/api/common/common-query-runners/common-find-duplicates-query-runner.service.ts index 79249e0035f..75aac10ada4 100644 --- a/packages/twenty-server/src/engine/api/common/common-query-runners/common-find-duplicates-query-runner.service.ts +++ b/packages/twenty-server/src/engine/api/common/common-query-runners/common-find-duplicates-query-runner.service.ts @@ -9,8 +9,7 @@ import { ObjectRecord, OrderByDirection } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; import { FindOptionsRelations, In, ObjectLiteral } from 'typeorm'; -import { WorkspaceAuthContext } from 'src/engine/api/common/interfaces/workspace-auth-context.interface'; - +import { WorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type'; import { CommonBaseQueryRunnerService } from 'src/engine/api/common/common-query-runners/common-base-query-runner.service'; import { CommonQueryRunnerException, diff --git a/packages/twenty-server/src/engine/api/common/common-query-runners/common-find-many-query-runner.service.ts b/packages/twenty-server/src/engine/api/common/common-query-runners/common-find-many-query-runner.service.ts index cd7e61812f0..b0c38ac4f75 100644 --- a/packages/twenty-server/src/engine/api/common/common-query-runners/common-find-many-query-runner.service.ts +++ b/packages/twenty-server/src/engine/api/common/common-query-runners/common-find-many-query-runner.service.ts @@ -8,12 +8,12 @@ import { import { ObjectRecord, OrderByDirection } from 'twenty-shared/types'; import { FindOptionsRelations, ObjectLiteral } from 'typeorm'; -import { WorkspaceAuthContext } from 'src/engine/api/common/interfaces/workspace-auth-context.interface'; import { ObjectRecordFilter, ObjectRecordOrderBy, } from 'src/engine/api/graphql/workspace-query-builder/interfaces/object-record.interface'; +import { WorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type'; import { CommonBaseQueryRunnerService } from 'src/engine/api/common/common-query-runners/common-base-query-runner.service'; import { CommonQueryRunnerException, diff --git a/packages/twenty-server/src/engine/api/common/common-query-runners/common-find-one-query-runner.service.ts b/packages/twenty-server/src/engine/api/common/common-query-runners/common-find-one-query-runner.service.ts index d7fdce15a10..be3289162cf 100644 --- a/packages/twenty-server/src/engine/api/common/common-query-runners/common-find-one-query-runner.service.ts +++ b/packages/twenty-server/src/engine/api/common/common-query-runners/common-find-one-query-runner.service.ts @@ -6,9 +6,9 @@ import { ObjectRecord } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; import { FindOptionsRelations, ObjectLiteral } from 'typeorm'; -import { WorkspaceAuthContext } from 'src/engine/api/common/interfaces/workspace-auth-context.interface'; import { ObjectRecordFilter } from 'src/engine/api/graphql/workspace-query-builder/interfaces/object-record.interface'; +import { WorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type'; import { CommonBaseQueryRunnerService } from 'src/engine/api/common/common-query-runners/common-base-query-runner.service'; import { CommonQueryRunnerException, diff --git a/packages/twenty-server/src/engine/api/common/common-query-runners/common-group-by-query-runner.service.ts b/packages/twenty-server/src/engine/api/common/common-query-runners/common-group-by-query-runner.service.ts index 19baa8ded29..20ecfcdd849 100644 --- a/packages/twenty-server/src/engine/api/common/common-query-runners/common-group-by-query-runner.service.ts +++ b/packages/twenty-server/src/engine/api/common/common-query-runners/common-group-by-query-runner.service.ts @@ -15,9 +15,9 @@ import { } from 'twenty-shared/utils'; import { ObjectLiteral } from 'typeorm'; -import { WorkspaceAuthContext } from 'src/engine/api/common/interfaces/workspace-auth-context.interface'; import { ObjectRecordFilter } from 'src/engine/api/graphql/workspace-query-builder/interfaces/object-record.interface'; +import { WorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type'; import { CommonBaseQueryRunnerService } from 'src/engine/api/common/common-query-runners/common-base-query-runner.service'; import { CommonQueryRunnerException, diff --git a/packages/twenty-server/src/engine/api/common/common-query-runners/common-merge-many-query-runner.service.ts b/packages/twenty-server/src/engine/api/common/common-query-runners/common-merge-many-query-runner.service.ts index a9199fb9fbc..b82e5ea3b8c 100644 --- a/packages/twenty-server/src/engine/api/common/common-query-runners/common-merge-many-query-runner.service.ts +++ b/packages/twenty-server/src/engine/api/common/common-query-runners/common-merge-many-query-runner.service.ts @@ -15,8 +15,7 @@ import { isDefined } from 'twenty-shared/utils'; import { FindOptionsRelations, In, ObjectLiteral } from 'typeorm'; import { v4 as uuidv4 } from 'uuid'; -import { WorkspaceAuthContext } from 'src/engine/api/common/interfaces/workspace-auth-context.interface'; - +import { WorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type'; import { CommonBaseQueryRunnerService } from 'src/engine/api/common/common-query-runners/common-base-query-runner.service'; import { CommonQueryRunnerException, diff --git a/packages/twenty-server/src/engine/api/common/common-query-runners/common-restore-many-query-runner.service.ts b/packages/twenty-server/src/engine/api/common/common-query-runners/common-restore-many-query-runner.service.ts index c789c178fb6..b6d580644d2 100644 --- a/packages/twenty-server/src/engine/api/common/common-query-runners/common-restore-many-query-runner.service.ts +++ b/packages/twenty-server/src/engine/api/common/common-query-runners/common-restore-many-query-runner.service.ts @@ -5,8 +5,7 @@ import { ObjectRecord } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; import { FindOptionsRelations, ObjectLiteral } from 'typeorm'; -import { WorkspaceAuthContext } from 'src/engine/api/common/interfaces/workspace-auth-context.interface'; - +import { WorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type'; import { CommonBaseQueryRunnerService } from 'src/engine/api/common/common-query-runners/common-base-query-runner.service'; import { CommonQueryRunnerException, diff --git a/packages/twenty-server/src/engine/api/common/common-query-runners/common-restore-one-query-runner.service.ts b/packages/twenty-server/src/engine/api/common/common-query-runners/common-restore-one-query-runner.service.ts index 141f0246022..92dda2807b1 100644 --- a/packages/twenty-server/src/engine/api/common/common-query-runners/common-restore-one-query-runner.service.ts +++ b/packages/twenty-server/src/engine/api/common/common-query-runners/common-restore-one-query-runner.service.ts @@ -4,8 +4,7 @@ import { msg } from '@lingui/core/macro'; import { type ObjectRecord } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; -import { WorkspaceAuthContext } from 'src/engine/api/common/interfaces/workspace-auth-context.interface'; - +import { WorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type'; import { CommonBaseQueryRunnerService } from 'src/engine/api/common/common-query-runners/common-base-query-runner.service'; import { CommonRestoreManyQueryRunnerService } from 'src/engine/api/common/common-query-runners/common-restore-many-query-runner.service'; import { diff --git a/packages/twenty-server/src/engine/api/common/common-query-runners/common-update-many-query-runner.service.ts b/packages/twenty-server/src/engine/api/common/common-query-runners/common-update-many-query-runner.service.ts index 10bcb187335..29d51490004 100644 --- a/packages/twenty-server/src/engine/api/common/common-query-runners/common-update-many-query-runner.service.ts +++ b/packages/twenty-server/src/engine/api/common/common-query-runners/common-update-many-query-runner.service.ts @@ -5,8 +5,7 @@ import { QUERY_MAX_RECORDS_FROM_RELATION } from 'twenty-shared/constants'; import { ObjectRecord } from 'twenty-shared/types'; import { FindOptionsRelations, ObjectLiteral } from 'typeorm'; -import { WorkspaceAuthContext } from 'src/engine/api/common/interfaces/workspace-auth-context.interface'; - +import { WorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type'; import { CommonBaseQueryRunnerService } from 'src/engine/api/common/common-query-runners/common-base-query-runner.service'; import { CommonQueryRunnerException, diff --git a/packages/twenty-server/src/engine/api/common/common-query-runners/common-update-one-query-runner.service.ts b/packages/twenty-server/src/engine/api/common/common-query-runners/common-update-one-query-runner.service.ts index b7a077fd3fa..78d19e57f6b 100644 --- a/packages/twenty-server/src/engine/api/common/common-query-runners/common-update-one-query-runner.service.ts +++ b/packages/twenty-server/src/engine/api/common/common-query-runners/common-update-one-query-runner.service.ts @@ -3,8 +3,7 @@ import { Injectable } from '@nestjs/common'; import { msg } from '@lingui/core/macro'; import { type ObjectRecord } from 'twenty-shared/types'; -import { WorkspaceAuthContext } from 'src/engine/api/common/interfaces/workspace-auth-context.interface'; - +import { WorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type'; import { CommonBaseQueryRunnerService } from 'src/engine/api/common/common-query-runners/common-base-query-runner.service'; import { CommonUpdateManyQueryRunnerService } from 'src/engine/api/common/common-query-runners/common-update-many-query-runner.service'; import { diff --git a/packages/twenty-server/src/engine/api/common/interfaces/workspace-auth-context.interface.ts b/packages/twenty-server/src/engine/api/common/interfaces/workspace-auth-context.interface.ts deleted file mode 100644 index a83ee148dd2..00000000000 --- a/packages/twenty-server/src/engine/api/common/interfaces/workspace-auth-context.interface.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { type AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type'; - -interface AuthContextWithDefinedWorkspaceProperties { - user: AuthContext['user']; - application: AuthContext['application']; - workspace: NonNullable; - workspaceMetadataVersion?: string; - workspaceMemberId: AuthContext['workspaceMemberId']; - workspaceMember: AuthContext['workspaceMember']; - userWorkspaceId: AuthContext['userWorkspaceId']; - apiKey: AuthContext['apiKey']; -} - -interface ApiKeyAuthContext extends Request { - apiKey: NonNullable; -} - -interface UserWorkspaceAuthContext extends Request { - userWorkspaceId: NonNullable; -} - -interface ApplicationAuthContext extends Request { - application: NonNullable; -} - -export type WorkspaceAuthContext = AuthContextWithDefinedWorkspaceProperties & - (ApiKeyAuthContext | UserWorkspaceAuthContext | ApplicationAuthContext); diff --git a/packages/twenty-server/src/engine/api/common/types/common-extended-query-runner-context.type.ts b/packages/twenty-server/src/engine/api/common/types/common-extended-query-runner-context.type.ts index b1765695df9..af9bd8b2394 100644 --- a/packages/twenty-server/src/engine/api/common/types/common-extended-query-runner-context.type.ts +++ b/packages/twenty-server/src/engine/api/common/types/common-extended-query-runner-context.type.ts @@ -1,7 +1,6 @@ import { type ObjectLiteral } from 'typeorm'; -import { type WorkspaceAuthContext } from 'src/engine/api/common/interfaces/workspace-auth-context.interface'; - +import { type WorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type'; import { type CommonBaseQueryRunnerContext } from 'src/engine/api/common/types/common-base-query-runner-context.type'; import { type GraphqlQueryParser } from 'src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query.parser'; import { type GlobalWorkspaceDataSource } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-datasource'; diff --git a/packages/twenty-server/src/engine/api/mcp/mcp.module.ts b/packages/twenty-server/src/engine/api/mcp/mcp.module.ts index 5cfa611d9c5..8f2463c47a1 100644 --- a/packages/twenty-server/src/engine/api/mcp/mcp.module.ts +++ b/packages/twenty-server/src/engine/api/mcp/mcp.module.ts @@ -1,4 +1,5 @@ import { Module } from '@nestjs/common'; +import { TypeOrmModule } from '@nestjs/typeorm'; import { McpCoreController } from 'src/engine/api/mcp/controllers/mcp-core.controller'; import { McpMetadataController } from 'src/engine/api/mcp/controllers/mcp-metadata.controller'; @@ -10,8 +11,11 @@ import { TokenModule } from 'src/engine/core-modules/auth/token/token.module'; import { FeatureFlagModule } from 'src/engine/core-modules/feature-flag/feature-flag.module'; import { MetricsModule } from 'src/engine/core-modules/metrics/metrics.module'; import { ToolProviderModule } from 'src/engine/core-modules/tool-provider/tool-provider.module'; +import { UserWorkspaceEntity } from 'src/engine/core-modules/user-workspace/user-workspace.entity'; +import { UserEntity } from 'src/engine/core-modules/user/user.entity'; import { UserRoleModule } from 'src/engine/metadata-modules/user-role/user-role.module'; import { WorkspaceCacheStorageModule } from 'src/engine/workspace-cache-storage/workspace-cache-storage.module'; +import { WorkspaceCacheModule } from 'src/engine/workspace-cache/workspace-cache.module'; @Module({ imports: [ @@ -22,6 +26,8 @@ import { WorkspaceCacheStorageModule } from 'src/engine/workspace-cache-storage/ MetricsModule, UserRoleModule, ToolProviderModule, + TypeOrmModule.forFeature([UserEntity, UserWorkspaceEntity]), + WorkspaceCacheModule, ], controllers: [McpCoreController, McpMetadataController], exports: [McpProtocolService], diff --git a/packages/twenty-server/src/engine/api/mcp/services/__tests__/mcp-protocol.service.spec.ts b/packages/twenty-server/src/engine/api/mcp/services/__tests__/mcp-protocol.service.spec.ts index 0dfcf063bbf..37cd9dad8ef 100644 --- a/packages/twenty-server/src/engine/api/mcp/services/__tests__/mcp-protocol.service.spec.ts +++ b/packages/twenty-server/src/engine/api/mcp/services/__tests__/mcp-protocol.service.spec.ts @@ -1,5 +1,6 @@ import { HttpException, HttpStatus } from '@nestjs/common'; import { Test, type TestingModule } from '@nestjs/testing'; +import { getRepositoryToken } from '@nestjs/typeorm'; import { jsonSchema } from 'ai'; @@ -12,8 +13,10 @@ import { ApiKeyRoleService } from 'src/engine/core-modules/api-key/services/api- import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum'; import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service'; import { ToolRegistryService } from 'src/engine/core-modules/tool-provider/services/tool-registry.service'; +import { UserWorkspaceEntity } from 'src/engine/core-modules/user-workspace/user-workspace.entity'; import { type WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; import { UserRoleService } from 'src/engine/metadata-modules/user-role/user-role.service'; +import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service'; describe('McpProtocolService', () => { let service: McpProtocolService; @@ -22,15 +25,32 @@ describe('McpProtocolService', () => { let userRoleService: jest.Mocked; let mcpToolExecutorService: jest.Mocked; let apiKeyRoleService: jest.Mocked; + let userWorkspaceRepository: jest.Mocked<{ findOne: jest.Mock }>; + let workspaceCacheService: jest.Mocked<{ getOrRecompute: jest.Mock }>; const mockWorkspace = { id: 'workspace-1' } as WorkspaceEntity; const mockUserWorkspaceId = 'user-workspace-1'; + const mockUserId = 'user-1'; + const mockWorkspaceMemberId = 'workspace-member-1'; const mockRoleId = 'role-1'; const mockAdminRoleId = 'admin-role-1'; const mockApiKey = { id: 'api-key-1', workspaceId: mockWorkspace.id, } as ApiKeyEntity; + const mockUser = { id: mockUserId }; + const mockUserWorkspace = { + id: mockUserWorkspaceId, + user: mockUser, + }; + const mockWorkspaceMember = { + id: mockWorkspaceMemberId, + userId: mockUserId, + }; + const mockFlatWorkspaceMemberMaps = { + idByUserId: { [mockUserId]: mockWorkspaceMemberId }, + byId: { [mockWorkspaceMemberId]: mockWorkspaceMember }, + }; beforeEach(async () => { const mockFeatureFlagService = { @@ -54,6 +74,15 @@ describe('McpProtocolService', () => { getRoleIdForApiKeyId: jest.fn().mockResolvedValue(mockAdminRoleId), }; + const mockWorkspaceCacheService = { + getOrRecompute: jest.fn(), + invalidateAndRecompute: jest.fn(), + }; + + const mockUserWorkspaceRepository = { + findOne: jest.fn(), + }; + const module: TestingModule = await Test.createTestingModule({ providers: [ McpProtocolService, @@ -77,6 +106,14 @@ describe('McpProtocolService', () => { provide: ApiKeyRoleService, useValue: mockApiKeyRoleService, }, + { + provide: WorkspaceCacheService, + useValue: mockWorkspaceCacheService, + }, + { + provide: getRepositoryToken(UserWorkspaceEntity), + useValue: mockUserWorkspaceRepository, + }, ], }).compile(); @@ -86,6 +123,10 @@ describe('McpProtocolService', () => { userRoleService = module.get(UserRoleService); mcpToolExecutorService = module.get(McpToolExecutorService); apiKeyRoleService = module.get(ApiKeyRoleService); + userWorkspaceRepository = module.get( + getRepositoryToken(UserWorkspaceEntity), + ); + workspaceCacheService = module.get(WorkspaceCacheService); }); it('should be defined', () => { @@ -216,6 +257,10 @@ describe('McpProtocolService', () => { it('should handle tools/call method with userWorkspaceId', async () => { featureFlagService.isFeatureEnabled.mockResolvedValue(true); userRoleService.getRoleIdForUserWorkspace.mockResolvedValue(mockRoleId); + userWorkspaceRepository.findOne.mockResolvedValue(mockUserWorkspace); + workspaceCacheService.getOrRecompute.mockResolvedValue({ + flatWorkspaceMemberMaps: mockFlatWorkspaceMemberMaps, + }); const mockTool = { description: 'Test tool', @@ -322,6 +367,10 @@ describe('McpProtocolService', () => { it('should handle tools listing', async () => { featureFlagService.isFeatureEnabled.mockResolvedValue(true); userRoleService.getRoleIdForUserWorkspace.mockResolvedValue(mockRoleId); + userWorkspaceRepository.findOne.mockResolvedValue(mockUserWorkspace); + workspaceCacheService.getOrRecompute.mockResolvedValue({ + flatWorkspaceMemberMaps: mockFlatWorkspaceMemberMaps, + }); const mockToolsMap = { testTool: { @@ -398,6 +447,10 @@ describe('McpProtocolService', () => { it('should handle error when tool is not found', async () => { featureFlagService.isFeatureEnabled.mockResolvedValue(true); userRoleService.getRoleIdForUserWorkspace.mockResolvedValue(mockRoleId); + userWorkspaceRepository.findOne.mockResolvedValue(mockUserWorkspace); + workspaceCacheService.getOrRecompute.mockResolvedValue({ + flatWorkspaceMemberMaps: mockFlatWorkspaceMemberMaps, + }); toolRegistryService.getToolsByCategories.mockResolvedValue({}); mcpToolExecutorService.handleToolCall.mockRejectedValue( diff --git a/packages/twenty-server/src/engine/api/mcp/services/mcp-protocol.service.ts b/packages/twenty-server/src/engine/api/mcp/services/mcp-protocol.service.ts index 0704e8b7bfb..12156bff7df 100644 --- a/packages/twenty-server/src/engine/api/mcp/services/mcp-protocol.service.ts +++ b/packages/twenty-server/src/engine/api/mcp/services/mcp-protocol.service.ts @@ -1,21 +1,27 @@ import { HttpException, HttpStatus, Injectable } from '@nestjs/common'; +import { InjectRepository } from '@nestjs/typeorm'; import { isDefined } from 'twenty-shared/utils'; - -import { type WorkspaceAuthContext } from 'src/engine/api/common/interfaces/workspace-auth-context.interface'; +import { Repository } from 'typeorm'; import { type JsonRpc } from 'src/engine/api/mcp/dtos/json-rpc'; import { McpToolExecutorService } from 'src/engine/api/mcp/services/mcp-tool-executor.service'; import { wrapJsonRpcResponse } from 'src/engine/api/mcp/utils/wrap-jsonrpc-response.util'; import { type ApiKeyEntity } from 'src/engine/core-modules/api-key/api-key.entity'; import { ApiKeyRoleService } from 'src/engine/core-modules/api-key/services/api-key-role.service'; +import { type WorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type'; +import { buildApiKeyAuthContext } from 'src/engine/core-modules/auth/utils/build-api-key-auth-context.util'; +import { buildSystemAuthContext } from 'src/engine/core-modules/auth/utils/build-system-auth-context.util'; +import { buildUserAuthContext } from 'src/engine/core-modules/auth/utils/build-user-auth-context.util'; import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum'; import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service'; import { ToolCategory } from 'src/engine/core-modules/tool-provider/enums/tool-category.enum'; import { ToolRegistryService } from 'src/engine/core-modules/tool-provider/services/tool-registry.service'; import { ToolType } from 'src/engine/core-modules/tool/enums/tool-type.enum'; +import { UserWorkspaceEntity } from 'src/engine/core-modules/user-workspace/user-workspace.entity'; import { type WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; import { UserRoleService } from 'src/engine/metadata-modules/user-role/user-role.service'; +import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service'; @Injectable() export class McpProtocolService { @@ -25,6 +31,9 @@ export class McpProtocolService { private readonly userRoleService: UserRoleService, private readonly mcpToolExecutorService: McpToolExecutorService, private readonly apiKeyRoleService: ApiKeyRoleService, + @InjectRepository(UserWorkspaceEntity) + private readonly userWorkspaceRepository: Repository, + private readonly workspaceCacheService: WorkspaceCacheService, ) {} async checkAiEnabled(workspaceId: string): Promise { @@ -87,19 +96,59 @@ export class McpProtocolService { return roleId; } - private buildAuthContext( + private async buildAuthContext( workspace: WorkspaceEntity, userWorkspaceId?: string, apiKey?: ApiKeyEntity, - ): WorkspaceAuthContext { - return { - user: null, - apiKey: apiKey ?? null, - application: null, - workspace, - workspaceMemberId: undefined, - userWorkspaceId: userWorkspaceId ?? undefined, - } as WorkspaceAuthContext; + ): Promise { + if (isDefined(apiKey)) { + return buildApiKeyAuthContext({ workspace, apiKey }); + } + + if (isDefined(userWorkspaceId)) { + const userWorkspace = await this.userWorkspaceRepository.findOne({ + where: { + id: userWorkspaceId, + }, + relations: { + user: true, + }, + }); + + const user = userWorkspace?.user; + + if (!isDefined(user)) { + throw new HttpException('User not found', HttpStatus.FORBIDDEN); + } + + const { flatWorkspaceMemberMaps } = + await this.workspaceCacheService.getOrRecompute(workspace.id, [ + 'flatWorkspaceMemberMaps', + ]); + + const workspaceMemberId = flatWorkspaceMemberMaps.idByUserId[user.id]; + + const workspaceMember = isDefined(workspaceMemberId) + ? flatWorkspaceMemberMaps.byId[workspaceMemberId] + : undefined; + + if (!isDefined(workspaceMemberId) || !isDefined(workspaceMember)) { + throw new HttpException( + 'Workspace member not found', + HttpStatus.FORBIDDEN, + ); + } + + return buildUserAuthContext({ + workspace, + userWorkspaceId, + user, + workspaceMemberId, + workspaceMember, + }); + } + + return buildSystemAuthContext({ workspace }); } async handleMCPCoreQuery( @@ -137,7 +186,7 @@ export class McpProtocolService { apiKey, ); - const authContext = this.buildAuthContext( + const authContext = await this.buildAuthContext( workspace, userWorkspaceId, apiKey, diff --git a/packages/twenty-server/src/engine/api/rest/core/handlers/rest-api-base.handler.ts b/packages/twenty-server/src/engine/api/rest/core/handlers/rest-api-base.handler.ts index bca8e084308..9bbcef3b0e1 100644 --- a/packages/twenty-server/src/engine/api/rest/core/handlers/rest-api-base.handler.ts +++ b/packages/twenty-server/src/engine/api/rest/core/handlers/rest-api-base.handler.ts @@ -7,8 +7,6 @@ import { isDefined, } from 'twenty-shared/utils'; -import { WorkspaceAuthContext } from 'src/engine/api/common/interfaces/workspace-auth-context.interface'; - import { CommonGroupByOutputItem } from 'src/engine/api/common/types/common-group-by-output-item.type'; import { CommonSelectedFields } from 'src/engine/api/common/types/common-selected-fields-result.type'; import { RestToCommonSelectedFieldsHandler } from 'src/engine/api/rest/core/rest-to-common-args-handlers/selected-fields-handler'; @@ -17,7 +15,11 @@ import { Depth } from 'src/engine/api/rest/input-request-parsers/types/depth.typ import { AuthenticatedRequest } from 'src/engine/api/rest/types/authenticated-request'; import { ActorFromAuthContextService } from 'src/engine/core-modules/actor/services/actor-from-auth-context.service'; import { ApiKeyRoleService } from 'src/engine/core-modules/api-key/services/api-key-role.service'; +import { isApiKeyAuthContext } from 'src/engine/core-modules/auth/guards/is-api-key-auth-context.guard'; +import { isUserAuthContext } from 'src/engine/core-modules/auth/guards/is-user-auth-context.guard'; +import { getWorkspaceAuthContext } from 'src/engine/core-modules/auth/storage/workspace-auth-context.storage'; import { AccessTokenService } from 'src/engine/core-modules/auth/token/services/access-token.service'; +import { WorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type'; import { WorkspaceDomainsService } from 'src/engine/core-modules/domain/workspace-domains/services/workspace-domains.service'; import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service'; import { WorkspaceNotFoundDefaultError } from 'src/engine/core-modules/workspace/workspace.exception'; @@ -79,28 +81,15 @@ export abstract class RestApiBaseHandler { FormatResult | { data: FormatResult[] } | CommonGroupByOutputItem[] >; - public getAuthContextFromRequest( - request: AuthenticatedRequest, - ): WorkspaceAuthContext { - return request; - } - private getObjectsPermissions = async (authContext: WorkspaceAuthContext) => { let roleId: string; - if (isDefined(authContext.apiKey)) { + if (isApiKeyAuthContext(authContext)) { roleId = await this.apiKeyRoleService.getRoleIdForApiKeyId( authContext.apiKey.id, authContext.workspace.id, ); - } else { - if (!isDefined(authContext.userWorkspaceId)) { - throw new PermissionsException( - 'No user workspace ID found in authentication context', - PermissionsExceptionCode.NO_AUTHENTICATION_CONTEXT, - ); - } - + } else if (isUserAuthContext(authContext)) { const userWorkspaceRoleId = await this.userRoleService.getRoleIdForUserWorkspace({ userWorkspaceId: authContext.userWorkspaceId, @@ -115,6 +104,11 @@ export abstract class RestApiBaseHandler { } roleId = userWorkspaceRoleId; + } else { + throw new PermissionsException( + 'Authentication context is invalid', + PermissionsExceptionCode.NO_AUTHENTICATION_CONTEXT, + ); } const { rolesPermissions } = @@ -161,7 +155,7 @@ export abstract class RestApiBaseHandler { objectIdByNameSingular, } = await this.getObjectMetadata(request, parsedObject); - const authContext = this.getAuthContextFromRequest(request); + const authContext = getWorkspaceAuthContext(); return { authContext, diff --git a/packages/twenty-server/src/engine/api/rest/types/authenticated-request.ts b/packages/twenty-server/src/engine/api/rest/types/authenticated-request.ts index c8c7c551790..a9275783dde 100644 --- a/packages/twenty-server/src/engine/api/rest/types/authenticated-request.ts +++ b/packages/twenty-server/src/engine/api/rest/types/authenticated-request.ts @@ -1,5 +1,5 @@ import { type Request } from 'express'; -import { type WorkspaceAuthContext } from 'src/engine/api/common/interfaces/workspace-auth-context.interface'; +import { type WorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type'; export type AuthenticatedRequest = Request & WorkspaceAuthContext; diff --git a/packages/twenty-server/src/engine/core-modules/actor/services/actor-from-auth-context.service.ts b/packages/twenty-server/src/engine/core-modules/actor/services/actor-from-auth-context.service.ts index ba2cdab51f6..b87c7784278 100644 --- a/packages/twenty-server/src/engine/core-modules/actor/services/actor-from-auth-context.service.ts +++ b/packages/twenty-server/src/engine/core-modules/actor/services/actor-from-auth-context.service.ts @@ -3,8 +3,7 @@ import { Injectable, Logger } from '@nestjs/common'; import { type ActorMetadata } from 'twenty-shared/types'; import { assertIsDefinedOrThrow, isDefined } from 'twenty-shared/utils'; -import { type WorkspaceAuthContext } from 'src/engine/api/common/interfaces/workspace-auth-context.interface'; - +import { type WorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type'; import { buildCreatedByFromApiKey } from 'src/engine/core-modules/actor/utils/build-created-by-from-api-key.util'; import { buildCreatedByFromApplication } from 'src/engine/core-modules/actor/utils/build-created-by-from-application.util'; import { buildCreatedByFromFullNameMetadata } from 'src/engine/core-modules/actor/utils/build-created-by-from-full-name-metadata.util'; diff --git a/packages/twenty-server/src/engine/core-modules/auth/guards/is-api-key-auth-context.guard.ts b/packages/twenty-server/src/engine/core-modules/auth/guards/is-api-key-auth-context.guard.ts new file mode 100644 index 00000000000..c9f31d8c3cb --- /dev/null +++ b/packages/twenty-server/src/engine/core-modules/auth/guards/is-api-key-auth-context.guard.ts @@ -0,0 +1,10 @@ +import { + type ApiKeyWorkspaceAuthContext, + type WorkspaceAuthContext, +} from 'src/engine/core-modules/auth/types/workspace-auth-context.type'; + +export const isApiKeyAuthContext = ( + context: WorkspaceAuthContext, +): context is ApiKeyWorkspaceAuthContext => { + return context.type === 'apiKey'; +}; diff --git a/packages/twenty-server/src/engine/core-modules/auth/guards/is-application-auth-context.guard.ts b/packages/twenty-server/src/engine/core-modules/auth/guards/is-application-auth-context.guard.ts new file mode 100644 index 00000000000..18d3d689820 --- /dev/null +++ b/packages/twenty-server/src/engine/core-modules/auth/guards/is-application-auth-context.guard.ts @@ -0,0 +1,10 @@ +import { + type ApplicationWorkspaceAuthContext, + type WorkspaceAuthContext, +} from 'src/engine/core-modules/auth/types/workspace-auth-context.type'; + +export const isApplicationAuthContext = ( + context: WorkspaceAuthContext, +): context is ApplicationWorkspaceAuthContext => { + return context.type === 'application'; +}; diff --git a/packages/twenty-server/src/engine/core-modules/auth/guards/is-pending-activation-user-auth-context.guard.ts b/packages/twenty-server/src/engine/core-modules/auth/guards/is-pending-activation-user-auth-context.guard.ts new file mode 100644 index 00000000000..234c5c76a73 --- /dev/null +++ b/packages/twenty-server/src/engine/core-modules/auth/guards/is-pending-activation-user-auth-context.guard.ts @@ -0,0 +1,10 @@ +import { + type PendingActivationUserWorkspaceAuthContext, + type WorkspaceAuthContext, +} from 'src/engine/core-modules/auth/types/workspace-auth-context.type'; + +export const isPendingActivationUserAuthContext = ( + context: WorkspaceAuthContext, +): context is PendingActivationUserWorkspaceAuthContext => { + return context.type === 'pendingActivationUser'; +}; diff --git a/packages/twenty-server/src/engine/core-modules/auth/guards/is-system-auth-context.guard.ts b/packages/twenty-server/src/engine/core-modules/auth/guards/is-system-auth-context.guard.ts new file mode 100644 index 00000000000..ee85f50e016 --- /dev/null +++ b/packages/twenty-server/src/engine/core-modules/auth/guards/is-system-auth-context.guard.ts @@ -0,0 +1,10 @@ +import { + type SystemWorkspaceAuthContext, + type WorkspaceAuthContext, +} from 'src/engine/core-modules/auth/types/workspace-auth-context.type'; + +export const isSystemAuthContext = ( + context: WorkspaceAuthContext, +): context is SystemWorkspaceAuthContext => { + return context.type === 'system'; +}; diff --git a/packages/twenty-server/src/engine/core-modules/auth/guards/is-user-auth-context.guard.ts b/packages/twenty-server/src/engine/core-modules/auth/guards/is-user-auth-context.guard.ts new file mode 100644 index 00000000000..50181e75f04 --- /dev/null +++ b/packages/twenty-server/src/engine/core-modules/auth/guards/is-user-auth-context.guard.ts @@ -0,0 +1,10 @@ +import { + type UserWorkspaceAuthContext, + type WorkspaceAuthContext, +} from 'src/engine/core-modules/auth/types/workspace-auth-context.type'; + +export const isUserAuthContext = ( + context: WorkspaceAuthContext, +): context is UserWorkspaceAuthContext => { + return context.type === 'user'; +}; diff --git a/packages/twenty-server/src/engine/api/common/utils/is-workspace-auth-context.util.ts b/packages/twenty-server/src/engine/core-modules/auth/guards/is-workspace-auth-context.guard.ts similarity index 78% rename from packages/twenty-server/src/engine/api/common/utils/is-workspace-auth-context.util.ts rename to packages/twenty-server/src/engine/core-modules/auth/guards/is-workspace-auth-context.guard.ts index 6f43513ff09..70d5f74a078 100644 --- a/packages/twenty-server/src/engine/api/common/utils/is-workspace-auth-context.util.ts +++ b/packages/twenty-server/src/engine/core-modules/auth/guards/is-workspace-auth-context.guard.ts @@ -1,8 +1,7 @@ import { isDefined } from 'twenty-shared/utils'; -import { type WorkspaceAuthContext } from 'src/engine/api/common/interfaces/workspace-auth-context.interface'; - import { type AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type'; +import { type WorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type'; export const isWorkspaceAuthContext = ( context: AuthContext, diff --git a/packages/twenty-server/src/engine/core-modules/auth/middlewares/workspace-auth-context.middleware.ts b/packages/twenty-server/src/engine/core-modules/auth/middlewares/workspace-auth-context.middleware.ts index 28a554ec490..51b9c0cbfac 100644 --- a/packages/twenty-server/src/engine/core-modules/auth/middlewares/workspace-auth-context.middleware.ts +++ b/packages/twenty-server/src/engine/core-modules/auth/middlewares/workspace-auth-context.middleware.ts @@ -3,9 +3,16 @@ import { Injectable, type NestMiddleware } from '@nestjs/common'; import { type NextFunction, type Request, type Response } from 'express'; import { isDefined } from 'twenty-shared/utils'; -import { type WorkspaceAuthContext } from 'src/engine/api/common/interfaces/workspace-auth-context.interface'; - +import { + AuthException, + AuthExceptionCode, +} from 'src/engine/core-modules/auth/auth.exception'; import { withWorkspaceAuthContext } from 'src/engine/core-modules/auth/storage/workspace-auth-context.storage'; +import { type WorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type'; +import { buildApiKeyAuthContext } from 'src/engine/core-modules/auth/utils/build-api-key-auth-context.util'; +import { buildApplicationAuthContext } from 'src/engine/core-modules/auth/utils/build-application-auth-context.util'; +import { buildPendingActivationUserAuthContext } from 'src/engine/core-modules/auth/utils/build-pending-activation-user-auth-context.util'; +import { buildUserAuthContext } from 'src/engine/core-modules/auth/utils/build-user-auth-context.util'; @Injectable() export class WorkspaceAuthContextMiddleware implements NestMiddleware { @@ -16,18 +23,54 @@ export class WorkspaceAuthContextMiddleware implements NestMiddleware { return; } - const authContext: WorkspaceAuthContext = { - user: req.user, - workspace: req.workspace, - workspaceMemberId: req.workspaceMemberId, - workspaceMember: req.workspaceMember, - userWorkspaceId: req.userWorkspaceId, - apiKey: req.apiKey, - application: req.application, - } as WorkspaceAuthContext; + const authContext = this.buildAuthContext(req); withWorkspaceAuthContext(authContext, () => { next(); }); } + + private buildAuthContext(req: Request): WorkspaceAuthContext { + if (isDefined(req.apiKey)) { + return buildApiKeyAuthContext({ + workspace: req.workspace!, + apiKey: req.apiKey, + }); + } + + if (isDefined(req.application)) { + return buildApplicationAuthContext({ + workspace: req.workspace!, + application: req.application, + }); + } + + if ( + isDefined(req.userWorkspaceId) && + isDefined(req.workspaceMemberId) && + isDefined(req.workspaceMember) && + isDefined(req.user) + ) { + return buildUserAuthContext({ + workspace: req.workspace!, + userWorkspaceId: req.userWorkspaceId, + user: req.user, + workspaceMemberId: req.workspaceMemberId, + workspaceMember: req.workspaceMember, + }); + } + + if (isDefined(req.userWorkspaceId) && isDefined(req.user)) { + return buildPendingActivationUserAuthContext({ + workspace: req.workspace!, + userWorkspaceId: req.userWorkspaceId, + user: req.user, + }); + } + + throw new AuthException( + 'No authentication context found', + AuthExceptionCode.UNAUTHENTICATED, + ); + } } diff --git a/packages/twenty-server/src/engine/core-modules/auth/storage/workspace-auth-context.storage.ts b/packages/twenty-server/src/engine/core-modules/auth/storage/workspace-auth-context.storage.ts index cb2a19bb4ec..a2edaa74057 100644 --- a/packages/twenty-server/src/engine/core-modules/auth/storage/workspace-auth-context.storage.ts +++ b/packages/twenty-server/src/engine/core-modules/auth/storage/workspace-auth-context.storage.ts @@ -1,6 +1,6 @@ import { AsyncLocalStorage } from 'async_hooks'; -import { type WorkspaceAuthContext } from 'src/engine/api/common/interfaces/workspace-auth-context.interface'; +import { type WorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type'; export const workspaceAuthContextStorage = new AsyncLocalStorage(); diff --git a/packages/twenty-server/src/engine/core-modules/auth/types/workspace-auth-context.type.ts b/packages/twenty-server/src/engine/core-modules/auth/types/workspace-auth-context.type.ts new file mode 100644 index 00000000000..3b224698910 --- /dev/null +++ b/packages/twenty-server/src/engine/core-modules/auth/types/workspace-auth-context.type.ts @@ -0,0 +1,51 @@ +import { type AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type'; + +export type WorkspaceAuthContextType = + | 'system' + | 'user' + | 'apiKey' + | 'application' + | 'pendingActivationUser'; + +interface BaseWorkspaceAuthContext { + type: WorkspaceAuthContextType; + workspace: NonNullable; + workspaceMetadataVersion?: string; +} + +export interface ApiKeyWorkspaceAuthContext extends BaseWorkspaceAuthContext { + type: 'apiKey'; + apiKey: NonNullable; +} + +export interface UserWorkspaceAuthContext extends BaseWorkspaceAuthContext { + type: 'user'; + userWorkspaceId: NonNullable; + user: NonNullable; + workspaceMemberId: NonNullable; + workspaceMember: NonNullable; +} + +export interface ApplicationWorkspaceAuthContext + extends BaseWorkspaceAuthContext { + type: 'application'; + application: NonNullable; +} + +export interface SystemWorkspaceAuthContext extends BaseWorkspaceAuthContext { + type: 'system'; +} + +export interface PendingActivationUserWorkspaceAuthContext + extends BaseWorkspaceAuthContext { + type: 'pendingActivationUser'; + userWorkspaceId: NonNullable; + user: NonNullable; +} + +export type WorkspaceAuthContext = + | ApiKeyWorkspaceAuthContext + | UserWorkspaceAuthContext + | ApplicationWorkspaceAuthContext + | SystemWorkspaceAuthContext + | PendingActivationUserWorkspaceAuthContext; diff --git a/packages/twenty-server/src/engine/core-modules/auth/utils/build-api-key-auth-context.util.ts b/packages/twenty-server/src/engine/core-modules/auth/utils/build-api-key-auth-context.util.ts new file mode 100644 index 00000000000..6bee9becbef --- /dev/null +++ b/packages/twenty-server/src/engine/core-modules/auth/utils/build-api-key-auth-context.util.ts @@ -0,0 +1,19 @@ +import { type AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type'; +import { type ApiKeyWorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type'; + +type ApiKeyAuthContextInput = { + workspace: NonNullable; + apiKey: NonNullable; + workspaceMetadataVersion?: string; +}; + +export const buildApiKeyAuthContext = ( + input: ApiKeyAuthContextInput, +): ApiKeyWorkspaceAuthContext => { + return { + type: 'apiKey', + workspace: input.workspace, + apiKey: input.apiKey, + workspaceMetadataVersion: input.workspaceMetadataVersion, + }; +}; diff --git a/packages/twenty-server/src/engine/core-modules/auth/utils/build-application-auth-context.util.ts b/packages/twenty-server/src/engine/core-modules/auth/utils/build-application-auth-context.util.ts new file mode 100644 index 00000000000..b1bb679d828 --- /dev/null +++ b/packages/twenty-server/src/engine/core-modules/auth/utils/build-application-auth-context.util.ts @@ -0,0 +1,19 @@ +import { type AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type'; +import { type ApplicationWorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type'; + +type ApplicationAuthContextInput = { + workspace: NonNullable; + application: NonNullable; + workspaceMetadataVersion?: string; +}; + +export const buildApplicationAuthContext = ( + input: ApplicationAuthContextInput, +): ApplicationWorkspaceAuthContext => { + return { + type: 'application', + workspace: input.workspace, + application: input.application, + workspaceMetadataVersion: input.workspaceMetadataVersion, + }; +}; diff --git a/packages/twenty-server/src/engine/core-modules/auth/utils/build-pending-activation-user-auth-context.util.ts b/packages/twenty-server/src/engine/core-modules/auth/utils/build-pending-activation-user-auth-context.util.ts new file mode 100644 index 00000000000..218a497d25b --- /dev/null +++ b/packages/twenty-server/src/engine/core-modules/auth/utils/build-pending-activation-user-auth-context.util.ts @@ -0,0 +1,21 @@ +import { type AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type'; +import { type PendingActivationUserWorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type'; + +type PendingActivationUserAuthContextInput = { + workspace: NonNullable; + userWorkspaceId: NonNullable; + user: NonNullable; + workspaceMetadataVersion?: string; +}; + +export const buildPendingActivationUserAuthContext = ( + input: PendingActivationUserAuthContextInput, +): PendingActivationUserWorkspaceAuthContext => { + return { + type: 'pendingActivationUser', + workspace: input.workspace, + userWorkspaceId: input.userWorkspaceId, + user: input.user, + workspaceMetadataVersion: input.workspaceMetadataVersion, + }; +}; diff --git a/packages/twenty-server/src/engine/core-modules/auth/utils/build-system-auth-context.util.ts b/packages/twenty-server/src/engine/core-modules/auth/utils/build-system-auth-context.util.ts new file mode 100644 index 00000000000..4d2ecb177ae --- /dev/null +++ b/packages/twenty-server/src/engine/core-modules/auth/utils/build-system-auth-context.util.ts @@ -0,0 +1,17 @@ +import { type AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type'; +import { type SystemWorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type'; + +type SystemAuthContextInput = { + workspace: NonNullable; + workspaceMetadataVersion?: string; +}; + +export const buildSystemAuthContext = ( + input: SystemAuthContextInput, +): SystemWorkspaceAuthContext => { + return { + type: 'system', + workspace: input.workspace, + workspaceMetadataVersion: input.workspaceMetadataVersion, + }; +}; diff --git a/packages/twenty-server/src/engine/core-modules/auth/utils/build-user-auth-context.util.ts b/packages/twenty-server/src/engine/core-modules/auth/utils/build-user-auth-context.util.ts new file mode 100644 index 00000000000..59efd68fc44 --- /dev/null +++ b/packages/twenty-server/src/engine/core-modules/auth/utils/build-user-auth-context.util.ts @@ -0,0 +1,25 @@ +import { type AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type'; +import { type UserWorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type'; + +type UserAuthContextInput = { + workspace: NonNullable; + userWorkspaceId: NonNullable; + user: NonNullable; + workspaceMemberId: NonNullable; + workspaceMember: NonNullable; + workspaceMetadataVersion?: string; +}; + +export const buildUserAuthContext = ( + input: UserAuthContextInput, +): UserWorkspaceAuthContext => { + return { + type: 'user', + workspace: input.workspace, + userWorkspaceId: input.userWorkspaceId, + user: input.user, + workspaceMemberId: input.workspaceMemberId, + workspaceMember: input.workspaceMember, + workspaceMetadataVersion: input.workspaceMetadataVersion, + }; +}; diff --git a/packages/twenty-server/src/engine/core-modules/record-crud/services/common-api-context-builder.service.ts b/packages/twenty-server/src/engine/core-modules/record-crud/services/common-api-context-builder.service.ts index 42cef41ebce..7f26db9343f 100644 --- a/packages/twenty-server/src/engine/core-modules/record-crud/services/common-api-context-builder.service.ts +++ b/packages/twenty-server/src/engine/core-modules/record-crud/services/common-api-context-builder.service.ts @@ -3,12 +3,14 @@ import { Injectable } from '@nestjs/common'; import { type ObjectsPermissions } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; -import { type WorkspaceAuthContext } from 'src/engine/api/common/interfaces/workspace-auth-context.interface'; - import { type CommonBaseQueryRunnerContext } from 'src/engine/api/common/types/common-base-query-runner-context.type'; import { type CommonSelectedFields } from 'src/engine/api/common/types/common-selected-fields-result.type'; import { getAllSelectableFields } from 'src/engine/api/rest/core/rest-to-common-args-handlers/utils/get-all-selectable-fields.util'; import { ApiKeyRoleService } from 'src/engine/core-modules/api-key/services/api-key-role.service'; +import { isApiKeyAuthContext } from 'src/engine/core-modules/auth/guards/is-api-key-auth-context.guard'; +import { isApplicationAuthContext } from 'src/engine/core-modules/auth/guards/is-application-auth-context.guard'; +import { isUserAuthContext } from 'src/engine/core-modules/auth/guards/is-user-auth-context.guard'; +import { type WorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type'; import { RecordCrudException, RecordCrudExceptionCode, @@ -117,14 +119,17 @@ export class CommonApiContextBuilderService { const workspaceId = authContext.workspace.id; let roleId: string; - if (isDefined(authContext.apiKey)) { + if (isApiKeyAuthContext(authContext)) { roleId = await this.apiKeyRoleService.getRoleIdForApiKeyId( authContext.apiKey.id, workspaceId, ); - } else if (isDefined(authContext.application?.defaultLogicFunctionRoleId)) { + } else if ( + isApplicationAuthContext(authContext) && + isDefined(authContext.application.defaultLogicFunctionRoleId) + ) { roleId = authContext.application.defaultLogicFunctionRoleId; - } else if (isDefined(authContext.userWorkspaceId)) { + } else if (isUserAuthContext(authContext)) { const userWorkspaceRoleId = await this.userRoleService.getRoleIdForUserWorkspace({ userWorkspaceId: authContext.userWorkspaceId, diff --git a/packages/twenty-server/src/engine/core-modules/record-crud/types/record-crud-execution-context.type.ts b/packages/twenty-server/src/engine/core-modules/record-crud/types/record-crud-execution-context.type.ts index 02160d92cb9..b3c27d4cc02 100644 --- a/packages/twenty-server/src/engine/core-modules/record-crud/types/record-crud-execution-context.type.ts +++ b/packages/twenty-server/src/engine/core-modules/record-crud/types/record-crud-execution-context.type.ts @@ -1,5 +1,4 @@ -import { type WorkspaceAuthContext } from 'src/engine/api/common/interfaces/workspace-auth-context.interface'; - +import { type WorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type'; import { type RolePermissionConfig } from 'src/engine/twenty-orm/types/role-permission-config'; export type RecordCrudExecutionContext = { diff --git a/packages/twenty-server/src/engine/core-modules/tool-generator/types/tool-generator.types.ts b/packages/twenty-server/src/engine/core-modules/tool-generator/types/tool-generator.types.ts index 20800e5854b..6e421da62bb 100644 --- a/packages/twenty-server/src/engine/core-modules/tool-generator/types/tool-generator.types.ts +++ b/packages/twenty-server/src/engine/core-modules/tool-generator/types/tool-generator.types.ts @@ -4,8 +4,7 @@ import { type RestrictedFieldsPermissions, } from 'twenty-shared/types'; -import { type WorkspaceAuthContext } from 'src/engine/api/common/interfaces/workspace-auth-context.interface'; - +import { type WorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type'; import { type ObjectMetadataForToolSchema } from 'src/engine/core-modules/record-crud/types/object-metadata-for-tool-schema.type'; import { type RolePermissionConfig } from 'src/engine/twenty-orm/types/role-permission-config'; diff --git a/packages/twenty-server/src/engine/core-modules/tool-provider/interfaces/tool-provider.interface.ts b/packages/twenty-server/src/engine/core-modules/tool-provider/interfaces/tool-provider.interface.ts index b7045307b1e..03e70bca120 100644 --- a/packages/twenty-server/src/engine/core-modules/tool-provider/interfaces/tool-provider.interface.ts +++ b/packages/twenty-server/src/engine/core-modules/tool-provider/interfaces/tool-provider.interface.ts @@ -2,8 +2,7 @@ import { type ToolSet } from 'ai'; import { type CodeExecutionData } from 'twenty-shared/ai'; import { type ActorMetadata } from 'twenty-shared/types'; -import { type WorkspaceAuthContext } from 'src/engine/api/common/interfaces/workspace-auth-context.interface'; - +import { type WorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type'; import { type ToolCategory } from 'src/engine/core-modules/tool-provider/enums/tool-category.enum'; import { type ToolType } from 'src/engine/core-modules/tool/enums/tool-type.enum'; import { type FlatAgentWithRoleId } from 'src/engine/metadata-modules/flat-agent/types/flat-agent.type'; diff --git a/packages/twenty-server/src/engine/core-modules/tool-provider/providers/database-tool.provider.ts b/packages/twenty-server/src/engine/core-modules/tool-provider/providers/database-tool.provider.ts index 3d1bafb06b4..d7a2a56d9e2 100644 --- a/packages/twenty-server/src/engine/core-modules/tool-provider/providers/database-tool.provider.ts +++ b/packages/twenty-server/src/engine/core-modules/tool-provider/providers/database-tool.provider.ts @@ -1,4 +1,5 @@ import { Injectable } from '@nestjs/common'; +import { InjectRepository } from '@nestjs/typeorm'; import { type ToolSet } from 'ai'; import { @@ -6,20 +7,28 @@ import { type ObjectsPermissionsByRoleId, } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; +import { Repository } from 'typeorm'; -import { type WorkspaceAuthContext } from 'src/engine/api/common/interfaces/workspace-auth-context.interface'; import { type ToolProvider, type ToolProviderContext, } from 'src/engine/core-modules/tool-provider/interfaces/tool-provider.interface'; import { getFlatFieldsFromFlatObjectMetadata } from 'src/engine/api/graphql/workspace-schema-builder/utils/get-flat-fields-for-flat-object-metadata.util'; +import { + AuthException, + AuthExceptionCode, +} from 'src/engine/core-modules/auth/auth.exception'; +import { type WorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type'; +import { buildUserAuthContext } from 'src/engine/core-modules/auth/utils/build-user-auth-context.util'; import { CreateRecordService } from 'src/engine/core-modules/record-crud/services/create-record.service'; import { DeleteRecordService } from 'src/engine/core-modules/record-crud/services/delete-record.service'; import { FindRecordsService } from 'src/engine/core-modules/record-crud/services/find-records.service'; import { UpdateRecordService } from 'src/engine/core-modules/record-crud/services/update-record.service'; import { createDirectRecordToolsFactory } from 'src/engine/core-modules/record-crud/tool-factory/direct-record-tools.factory'; import { ToolCategory } from 'src/engine/core-modules/tool-provider/enums/tool-category.enum'; +import { UserEntity } from 'src/engine/core-modules/user/user.entity'; +import { type WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; import { isWorkflowRelatedObject } from 'src/engine/metadata-modules/ai/ai-agent/utils/is-workflow-related-object.util'; import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service'; import { computePermissionIntersection } from 'src/engine/twenty-orm/utils/compute-permission-intersection.util'; @@ -36,6 +45,8 @@ export class DatabaseToolProvider implements ToolProvider { private readonly updateRecordService: UpdateRecordService, private readonly deleteRecordService: DeleteRecordService, private readonly findRecordsService: FindRecordsService, + @InjectRepository(UserEntity) + private readonly userRepository: Repository, ) {} async isAvailable(_context: ToolProviderContext): Promise { @@ -46,22 +57,49 @@ export class DatabaseToolProvider implements ToolProvider { async generateTools(context: ToolProviderContext): Promise { const tools: ToolSet = {}; - // Build authContext from available context info - // userWorkspaceId is required for user-based tool generation - if (!context.userWorkspaceId) { + // Both userId and userWorkspaceId are required for user-based tool generation + if (!isDefined(context.userId) || !isDefined(context.userWorkspaceId)) { return tools; } - const authContext: WorkspaceAuthContext = { - user: context.userId ? { id: context.userId } : null, - workspace: { - id: context.workspaceId, - } as WorkspaceAuthContext['workspace'], - workspaceMemberId: undefined, + const user = await this.userRepository.findOne({ + where: { + id: context.userId, + }, + }); + + if (!isDefined(user)) { + throw new AuthException( + 'User not found', + AuthExceptionCode.UNAUTHENTICATED, + ); + } + + const { flatWorkspaceMemberMaps } = + await this.workspaceCacheService.getOrRecompute(context.workspaceId, [ + 'flatWorkspaceMemberMaps', + ]); + + const workspaceMemberId = flatWorkspaceMemberMaps.idByUserId[user.id]; + + const workspaceMember = isDefined(workspaceMemberId) + ? flatWorkspaceMemberMaps.byId[workspaceMemberId] + : undefined; + + if (!isDefined(workspaceMemberId) || !isDefined(workspaceMember)) { + throw new AuthException( + 'Workspace member not found', + AuthExceptionCode.UNAUTHENTICATED, + ); + } + + const authContext: WorkspaceAuthContext = buildUserAuthContext({ + workspace: { id: context.workspaceId } as WorkspaceEntity, userWorkspaceId: context.userWorkspaceId, - apiKey: null, - application: null, - } as WorkspaceAuthContext; + user, + workspaceMemberId, + workspaceMember, + }); const { rolesPermissions } = await this.workspaceCacheService.getOrRecompute(context.workspaceId, [ diff --git a/packages/twenty-server/src/engine/core-modules/tool-provider/resolvers/tool-index.resolver.ts b/packages/twenty-server/src/engine/core-modules/tool-provider/resolvers/tool-index.resolver.ts index 6884216e9db..854ff0452e2 100644 --- a/packages/twenty-server/src/engine/core-modules/tool-provider/resolvers/tool-index.resolver.ts +++ b/packages/twenty-server/src/engine/core-modules/tool-provider/resolvers/tool-index.resolver.ts @@ -4,8 +4,10 @@ import { Field, ObjectType, Query, Resolver } from '@nestjs/graphql'; import graphqlTypeJson from 'graphql-type-json'; import { ToolRegistryService } from 'src/engine/core-modules/tool-provider/services/tool-registry.service'; +import { UserEntity } from 'src/engine/core-modules/user/user.entity'; import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; import { AuthUserWorkspaceId } from 'src/engine/decorators/auth/auth-user-workspace-id.decorator'; +import { AuthUser } from 'src/engine/decorators/auth/auth-user.decorator'; import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorator'; import { NoPermissionGuard } from 'src/engine/guards/no-permission.guard'; import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard'; @@ -40,6 +42,7 @@ export class ToolIndexResolver { @Query(() => [ToolIndexEntryDTO]) @UseGuards(NoPermissionGuard) async getToolIndex( + @AuthUser({ allowUndefined: true }) user: UserEntity | undefined, @AuthWorkspace() workspace: WorkspaceEntity, @AuthUserWorkspaceId() userWorkspaceId: string, ): Promise { @@ -53,6 +56,7 @@ export class ToolIndexResolver { } return this.toolRegistryService.buildToolIndex(workspace.id, roleId, { + userId: user?.id, userWorkspaceId, }); } diff --git a/packages/twenty-server/src/engine/core-modules/tool-provider/tool-provider.module.ts b/packages/twenty-server/src/engine/core-modules/tool-provider/tool-provider.module.ts index 5847765bf6f..83b2daedb1e 100644 --- a/packages/twenty-server/src/engine/core-modules/tool-provider/tool-provider.module.ts +++ b/packages/twenty-server/src/engine/core-modules/tool-provider/tool-provider.module.ts @@ -1,4 +1,5 @@ import { forwardRef, Module } from '@nestjs/common'; +import { TypeOrmModule } from '@nestjs/typeorm'; import { RecordCrudModule } from 'src/engine/core-modules/record-crud/record-crud.module'; import { ToolGeneratorModule } from 'src/engine/core-modules/tool-generator/tool-generator.module'; @@ -12,6 +13,7 @@ import { LogicFunctionToolProvider } from 'src/engine/core-modules/tool-provider import { ViewToolProvider } from 'src/engine/core-modules/tool-provider/providers/view-tool.provider'; import { WorkflowToolProvider } from 'src/engine/core-modules/tool-provider/providers/workflow-tool.provider'; import { ToolModule } from 'src/engine/core-modules/tool/tool.module'; +import { UserEntity } from 'src/engine/core-modules/user/user.entity'; import { AiAgentExecutionModule } from 'src/engine/metadata-modules/ai/ai-agent-execution/ai-agent-execution.module'; import { AiModelsModule } from 'src/engine/metadata-modules/ai/ai-models/ai-models.module'; import { FieldMetadataModule } from 'src/engine/metadata-modules/field-metadata/field-metadata.module'; @@ -46,6 +48,7 @@ import { ToolRegistryService } from './services/tool-registry.service'; WorkspaceManyOrAllFlatEntityMapsCacheModule, LogicFunctionModule, UserRoleModule, + TypeOrmModule.forFeature([UserEntity]), ], providers: [ ToolIndexResolver, diff --git a/packages/twenty-server/src/engine/metadata-modules/ai/ai-agent-execution/services/agent-async-executor.service.ts b/packages/twenty-server/src/engine/metadata-modules/ai/ai-agent-execution/services/agent-async-executor.service.ts index f2117c1107f..1d928561429 100644 --- a/packages/twenty-server/src/engine/metadata-modules/ai/ai-agent-execution/services/agent-async-executor.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/ai/ai-agent-execution/services/agent-async-executor.service.ts @@ -9,11 +9,13 @@ import { type ToolSet, } from 'ai'; import { type ActorMetadata } from 'twenty-shared/types'; +import { isDefined } from 'twenty-shared/utils'; import { type Repository } from 'typeorm'; -import { type WorkspaceAuthContext } from 'src/engine/api/common/interfaces/workspace-auth-context.interface'; import { type ToolProviderContext } from 'src/engine/core-modules/tool-provider/interfaces/tool-provider.interface'; +import { isUserAuthContext } from 'src/engine/core-modules/auth/guards/is-user-auth-context.guard'; +import { type WorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type'; import { ToolCategory } from 'src/engine/core-modules/tool-provider/enums/tool-category.enum'; import { ToolRegistryService } from 'src/engine/core-modules/tool-provider/services/tool-registry.service'; import { type AgentExecutionResult } from 'src/engine/metadata-modules/ai/ai-agent-execution/types/agent-execution-result.type'; @@ -130,8 +132,14 @@ export class AgentAsyncExecutorService { authContext, actorContext, agent: agent as unknown as ToolProviderContext['agent'], - userId: authContext?.user?.id, - userWorkspaceId: authContext?.userWorkspaceId, + userId: + isDefined(authContext) && isUserAuthContext(authContext) + ? authContext.user.id + : undefined, + userWorkspaceId: + isDefined(authContext) && isUserAuthContext(authContext) + ? authContext.userWorkspaceId + : undefined, }, { categories: [ diff --git a/packages/twenty-server/src/engine/metadata-modules/navigation-menu-item/navigation-menu-item.resolver.ts b/packages/twenty-server/src/engine/metadata-modules/navigation-menu-item/navigation-menu-item.resolver.ts index f7bfd2098c7..731d029a38d 100644 --- a/packages/twenty-server/src/engine/metadata-modules/navigation-menu-item/navigation-menu-item.resolver.ts +++ b/packages/twenty-server/src/engine/metadata-modules/navigation-menu-item/navigation-menu-item.resolver.ts @@ -11,8 +11,7 @@ import { import { isDefined } from 'twenty-shared/utils'; -import { type WorkspaceAuthContext } from 'src/engine/api/common/interfaces/workspace-auth-context.interface'; - +import { type WorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type'; import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars'; import { ApiKeyEntity } from 'src/engine/core-modules/api-key/api-key.entity'; import { ApplicationEntity } from 'src/engine/core-modules/application/application.entity'; diff --git a/packages/twenty-server/src/engine/metadata-modules/navigation-menu-item/navigation-menu-item.service.ts b/packages/twenty-server/src/engine/metadata-modules/navigation-menu-item/navigation-menu-item.service.ts index 584bb396096..de811606a9d 100644 --- a/packages/twenty-server/src/engine/metadata-modules/navigation-menu-item/navigation-menu-item.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/navigation-menu-item/navigation-menu-item.service.ts @@ -2,10 +2,12 @@ import { Injectable } from '@nestjs/common'; import { isDefined } from 'twenty-shared/utils'; -import { type WorkspaceAuthContext } from 'src/engine/api/common/interfaces/workspace-auth-context.interface'; - import { ApiKeyRoleService } from 'src/engine/core-modules/api-key/services/api-key-role.service'; import { ApplicationService } from 'src/engine/core-modules/application/application.service'; +import { isApiKeyAuthContext } from 'src/engine/core-modules/auth/guards/is-api-key-auth-context.guard'; +import { isApplicationAuthContext } from 'src/engine/core-modules/auth/guards/is-application-auth-context.guard'; +import { isUserAuthContext } from 'src/engine/core-modules/auth/guards/is-user-auth-context.guard'; +import { type WorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type'; import { FileService } from 'src/engine/core-modules/file/services/file.service'; import { getRecordDisplayName } from 'src/engine/core-modules/record-crud/utils/get-record-display-name.util'; import { getRecordImageIdentifier } from 'src/engine/core-modules/record-crud/utils/get-record-image-identifier.util'; @@ -356,18 +358,21 @@ export class NavigationMenuItemService { authContext: WorkspaceAuthContext, workspaceId: string, ): Promise { - if (isDefined(authContext.apiKey)) { + if (isApiKeyAuthContext(authContext)) { return this.apiKeyRoleService.getRoleIdForApiKeyId( authContext.apiKey.id, workspaceId, ); } - if (isDefined(authContext.application?.defaultLogicFunctionRoleId)) { + if ( + isApplicationAuthContext(authContext) && + isDefined(authContext.application.defaultLogicFunctionRoleId) + ) { return authContext.application.defaultLogicFunctionRoleId; } - if (isDefined(authContext.userWorkspaceId)) { + if (isUserAuthContext(authContext)) { try { return await this.userRoleService.getRoleIdForUserWorkspace({ userWorkspaceId: authContext.userWorkspaceId, diff --git a/packages/twenty-server/src/engine/twenty-orm/entity-manager/workspace-entity-manager.spec.ts b/packages/twenty-server/src/engine/twenty-orm/entity-manager/workspace-entity-manager.spec.ts index cf71b445375..1ce5d393ab4 100644 --- a/packages/twenty-server/src/engine/twenty-orm/entity-manager/workspace-entity-manager.spec.ts +++ b/packages/twenty-server/src/engine/twenty-orm/entity-manager/workspace-entity-manager.spec.ts @@ -6,9 +6,9 @@ import { EntityManager } from 'typeorm'; import { EntityPersistExecutor } from 'typeorm/persistence/EntityPersistExecutor'; import { PlainObjectToDatabaseEntityTransformer } from 'typeorm/query-builder/transformer/PlainObjectToDatabaseEntityTransformer'; -import { type WorkspaceAuthContext } from 'src/engine/api/common/interfaces/workspace-auth-context.interface'; import { type WorkspaceInternalContext } from 'src/engine/twenty-orm/interfaces/workspace-internal-context.interface'; +import { type WorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type'; import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type'; import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type'; import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type'; 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 e75c4969e49..d0a74ae3bd7 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 @@ -33,10 +33,10 @@ import { PlainObjectToDatabaseEntityTransformer } from 'typeorm/query-builder/tr import { type UpsertOptions } from 'typeorm/repository/UpsertOptions'; import { InstanceChecker } from 'typeorm/util/InstanceChecker'; -import { type WorkspaceAuthContext } from 'src/engine/api/common/interfaces/workspace-auth-context.interface'; import { type FeatureFlagMap } from 'src/engine/core-modules/feature-flag/interfaces/feature-flag-map.interface'; import { type WorkspaceInternalContext } from 'src/engine/twenty-orm/interfaces/workspace-internal-context.interface'; +import { type WorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type'; import { DatabaseEventAction } from 'src/engine/api/graphql/graphql-query-runner/enums/database-event-action'; import { type AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type'; import { InternalServerError } from 'src/engine/core-modules/graphql/utils/graphql-errors.util'; diff --git a/packages/twenty-server/src/engine/twenty-orm/global-workspace-datasource/global-workspace-datasource.ts b/packages/twenty-server/src/engine/twenty-orm/global-workspace-datasource/global-workspace-datasource.ts index 40ec2d44061..732261d74cc 100644 --- a/packages/twenty-server/src/engine/twenty-orm/global-workspace-datasource/global-workspace-datasource.ts +++ b/packages/twenty-server/src/engine/twenty-orm/global-workspace-datasource/global-workspace-datasource.ts @@ -13,9 +13,9 @@ import { import { EntityManagerFactory } from 'typeorm/entity-manager/EntityManagerFactory'; import { EntityMetadataNotFoundError } from 'typeorm/error/EntityMetadataNotFoundError'; -import { type WorkspaceAuthContext } from 'src/engine/api/common/interfaces/workspace-auth-context.interface'; import { type FeatureFlagMap } from 'src/engine/core-modules/feature-flag/interfaces/feature-flag-map.interface'; +import { type WorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type'; import { PermissionsException, PermissionsExceptionCode, diff --git a/packages/twenty-server/src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager.ts b/packages/twenty-server/src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager.ts index 3f9bee83892..ff36091fb51 100644 --- a/packages/twenty-server/src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager.ts +++ b/packages/twenty-server/src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager.ts @@ -2,8 +2,7 @@ import { Injectable, type Type } from '@nestjs/common'; import { type ObjectLiteral } from 'typeorm'; -import { type WorkspaceAuthContext } from 'src/engine/api/common/interfaces/workspace-auth-context.interface'; - +import { type WorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type'; import { getWorkspaceAuthContext } from 'src/engine/core-modules/auth/storage/workspace-auth-context.storage'; import { buildObjectIdByNameMaps } from 'src/engine/metadata-modules/flat-object-metadata/utils/build-object-id-by-name-maps.util'; import { GlobalWorkspaceDataSource } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-datasource'; diff --git a/packages/twenty-server/src/engine/twenty-orm/storage/orm-workspace-context.storage.ts b/packages/twenty-server/src/engine/twenty-orm/storage/orm-workspace-context.storage.ts index b85f985e0a0..6b31f15a412 100644 --- a/packages/twenty-server/src/engine/twenty-orm/storage/orm-workspace-context.storage.ts +++ b/packages/twenty-server/src/engine/twenty-orm/storage/orm-workspace-context.storage.ts @@ -3,8 +3,7 @@ import { AsyncLocalStorage } from 'async_hooks'; import { type ObjectsPermissionsByRoleId } from 'twenty-shared/types'; import { type EntityMetadata } from 'typeorm'; -import { type WorkspaceAuthContext } from 'src/engine/api/common/interfaces/workspace-auth-context.interface'; - +import { type WorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type'; import { type FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum'; import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type'; import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type'; diff --git a/packages/twenty-server/src/engine/twenty-orm/utils/build-system-auth-context.util.ts b/packages/twenty-server/src/engine/twenty-orm/utils/build-system-auth-context.util.ts index 1f48ec8d39d..dd7a533b394 100644 --- a/packages/twenty-server/src/engine/twenty-orm/utils/build-system-auth-context.util.ts +++ b/packages/twenty-server/src/engine/twenty-orm/utils/build-system-auth-context.util.ts @@ -1,15 +1,13 @@ -import { type WorkspaceAuthContext } from 'src/engine/api/common/interfaces/workspace-auth-context.interface'; +import { type SystemWorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type'; +import { buildSystemAuthContext as buildSystemAuthContextUtil } from 'src/engine/core-modules/auth/utils/build-system-auth-context.util'; +import { type WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; // Builds a minimal WorkspaceAuthContext for system operations (jobs, commands, crons) // that don't have a user context but need to operate on a workspace export const buildSystemAuthContext = ( workspaceId: string, -): WorkspaceAuthContext => { - return { - user: null, - workspace: { id: workspaceId } as WorkspaceAuthContext['workspace'], - workspaceMemberId: undefined, - userWorkspaceId: undefined, - apiKey: null, - } as WorkspaceAuthContext; +): SystemWorkspaceAuthContext => { + return buildSystemAuthContextUtil({ + workspace: { id: workspaceId } as WorkspaceEntity, + }); }; diff --git a/packages/twenty-server/src/modules/connected-account/query-hooks/connected-account-delete-one.pre-query.hook.ts b/packages/twenty-server/src/modules/connected-account/query-hooks/connected-account-delete-one.pre-query.hook.ts index 95e9c137384..638903fa7f3 100644 --- a/packages/twenty-server/src/modules/connected-account/query-hooks/connected-account-delete-one.pre-query.hook.ts +++ b/packages/twenty-server/src/modules/connected-account/query-hooks/connected-account-delete-one.pre-query.hook.ts @@ -3,8 +3,8 @@ import { STANDARD_OBJECT_IDS } from 'twenty-shared/metadata'; import { type WorkspacePreQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface'; import { type DeleteOneResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface'; -import { type WorkspaceAuthContext } from 'src/engine/api/common/interfaces/workspace-auth-context.interface'; +import { type WorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type'; import { DatabaseEventAction } from 'src/engine/api/graphql/graphql-query-runner/enums/database-event-action'; import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator'; import { type AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type'; diff --git a/packages/twenty-server/src/modules/dashboard/services/dashboard-duplication.service.ts b/packages/twenty-server/src/modules/dashboard/services/dashboard-duplication.service.ts index ce72656ebbc..c53af593e89 100644 --- a/packages/twenty-server/src/modules/dashboard/services/dashboard-duplication.service.ts +++ b/packages/twenty-server/src/modules/dashboard/services/dashboard-duplication.service.ts @@ -6,8 +6,7 @@ import { isDefined, } from 'twenty-shared/utils'; -import { WorkspaceAuthContext } from 'src/engine/api/common/interfaces/workspace-auth-context.interface'; - +import { WorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type'; import { ActorFromAuthContextService } from 'src/engine/core-modules/actor/services/actor-from-auth-context.service'; import { AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type'; import { WorkspaceNotFoundDefaultError } from 'src/engine/core-modules/workspace/workspace.exception'; diff --git a/packages/twenty-server/src/modules/note/query-hooks/note-post-query-hook.service.ts b/packages/twenty-server/src/modules/note/query-hooks/note-post-query-hook.service.ts index a416acbc4ee..df29db8038d 100644 --- a/packages/twenty-server/src/modules/note/query-hooks/note-post-query-hook.service.ts +++ b/packages/twenty-server/src/modules/note/query-hooks/note-post-query-hook.service.ts @@ -3,8 +3,7 @@ import { Injectable } from '@nestjs/common'; import { assertIsDefinedOrThrow } from 'twenty-shared/utils'; import { In } from 'typeorm'; -import { type WorkspaceAuthContext } from 'src/engine/api/common/interfaces/workspace-auth-context.interface'; - +import { type WorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type'; import { type AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type'; import { WorkspaceNotFoundDefaultError } from 'src/engine/core-modules/workspace/workspace.exception'; import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager'; diff --git a/packages/twenty-server/src/modules/task/query-hooks/task-post-query-hook.service.ts b/packages/twenty-server/src/modules/task/query-hooks/task-post-query-hook.service.ts index a5ed6abcc0b..6f296b3f0de 100644 --- a/packages/twenty-server/src/modules/task/query-hooks/task-post-query-hook.service.ts +++ b/packages/twenty-server/src/modules/task/query-hooks/task-post-query-hook.service.ts @@ -3,8 +3,7 @@ import { Injectable } from '@nestjs/common'; import { assertIsDefinedOrThrow } from 'twenty-shared/utils'; import { In } from 'typeorm'; -import { type WorkspaceAuthContext } from 'src/engine/api/common/interfaces/workspace-auth-context.interface'; - +import { type WorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type'; import { type AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type'; import { WorkspaceNotFoundDefaultError } from 'src/engine/core-modules/workspace/workspace.exception'; import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager'; diff --git a/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-create-many.post-query.hook.ts b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-create-many.post-query.hook.ts index a862972630e..fd7e0a0ae21 100644 --- a/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-create-many.post-query.hook.ts +++ b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-create-many.post-query.hook.ts @@ -1,8 +1,8 @@ import { assertIsDefinedOrThrow } from 'twenty-shared/utils'; import { type WorkspacePostQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface'; -import { type WorkspaceAuthContext } from 'src/engine/api/common/interfaces/workspace-auth-context.interface'; +import { type WorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type'; import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator'; import { WorkspaceQueryHookType } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/types/workspace-query-hook.type'; import { type AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type'; diff --git a/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-create-one.post-query.hook.ts b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-create-one.post-query.hook.ts index 9843f602e68..5f2593046b8 100644 --- a/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-create-one.post-query.hook.ts +++ b/packages/twenty-server/src/modules/workflow/common/query-hooks/workflow-create-one.post-query.hook.ts @@ -1,8 +1,8 @@ import { assertIsDefinedOrThrow } from 'twenty-shared/utils'; import { type WorkspacePostQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface'; -import { type WorkspaceAuthContext } from 'src/engine/api/common/interfaces/workspace-auth-context.interface'; +import { type WorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type'; import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator'; import { WorkspaceQueryHookType } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/types/workspace-query-hook.type'; import { type AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type'; diff --git a/packages/twenty-server/src/modules/workflow/workflow-executor/services/workflow-execution-context.service.ts b/packages/twenty-server/src/modules/workflow/workflow-executor/services/workflow-execution-context.service.ts index 4578646a4c4..3ba4b2c8e15 100644 --- a/packages/twenty-server/src/modules/workflow/workflow-executor/services/workflow-execution-context.service.ts +++ b/packages/twenty-server/src/modules/workflow/workflow-executor/services/workflow-execution-context.service.ts @@ -3,8 +3,9 @@ import { Injectable } from '@nestjs/common'; import { FieldActorSource } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; -import { type WorkspaceAuthContext } from 'src/engine/api/common/interfaces/workspace-auth-context.interface'; - +import { type WorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type'; +import { buildApplicationAuthContext } from 'src/engine/core-modules/auth/utils/build-application-auth-context.util'; +import { buildUserAuthContext } from 'src/engine/core-modules/auth/utils/build-user-auth-context.util'; import { ApplicationService } from 'src/engine/core-modules/application/application.service'; import { UserWorkspaceService } from 'src/engine/core-modules/user-workspace/user-workspace.service'; import { ADMIN_ROLE } from 'src/engine/metadata-modules/role/constants/admin-role'; @@ -70,14 +71,13 @@ export class WorkflowExecutionContextService { workspaceId, }); - const authContext = { - user: userWorkspace.user, - apiKey: null, - application: null, + const authContext: WorkspaceAuthContext = buildUserAuthContext({ workspace: userWorkspace.workspace, - workspaceMemberId: workspaceMember.id, userWorkspaceId: userWorkspace.id, - } as WorkspaceAuthContext; + user: userWorkspace.user, + workspaceMemberId: workspaceMember.id, + workspaceMember, + }); return { isActingOnBehalfOfUser: true, @@ -114,17 +114,13 @@ export class WorkflowExecutionContextService { ? { unionOf: [roleId] } : { shouldBypassPermissionChecks: true as const }; - const authContext = { - user: null, - apiKey: null, + const authContext: WorkspaceAuthContext = buildApplicationAuthContext({ + workspace, application: { ...application, defaultLogicFunctionRoleId: roleId, }, - workspace, - workspaceMemberId: undefined, - userWorkspaceId: undefined, - } as WorkspaceAuthContext; + }); return { isActingOnBehalfOfUser: false, diff --git a/packages/twenty-server/src/modules/workflow/workflow-executor/types/workflow-execution-context.type.ts b/packages/twenty-server/src/modules/workflow/workflow-executor/types/workflow-execution-context.type.ts index f91457ed947..2b46ebe8d57 100644 --- a/packages/twenty-server/src/modules/workflow/workflow-executor/types/workflow-execution-context.type.ts +++ b/packages/twenty-server/src/modules/workflow/workflow-executor/types/workflow-execution-context.type.ts @@ -1,7 +1,6 @@ import { type ActorMetadata } from 'twenty-shared/types'; -import { type WorkspaceAuthContext } from 'src/engine/api/common/interfaces/workspace-auth-context.interface'; - +import { type WorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type'; import { type RolePermissionConfig } from 'src/engine/twenty-orm/types/role-permission-config'; export type WorkflowExecutionContext = { diff --git a/packages/twenty-server/src/modules/workspace-member/query-hooks/workspace-member-delete-one.post-query.hook.ts b/packages/twenty-server/src/modules/workspace-member/query-hooks/workspace-member-delete-one.post-query.hook.ts index 8c6c41bb897..557feb32654 100644 --- a/packages/twenty-server/src/modules/workspace-member/query-hooks/workspace-member-delete-one.post-query.hook.ts +++ b/packages/twenty-server/src/modules/workspace-member/query-hooks/workspace-member-delete-one.post-query.hook.ts @@ -4,8 +4,8 @@ import { assertIsDefinedOrThrow, isDefined } from 'twenty-shared/utils'; import { Repository } from 'typeorm'; import { type WorkspacePostQueryHookInstance } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/interfaces/workspace-query-hook.interface'; -import { type WorkspaceAuthContext } from 'src/engine/api/common/interfaces/workspace-auth-context.interface'; +import { type WorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type'; import { WorkspaceQueryHook } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/decorators/workspace-query-hook.decorator'; import { WorkspaceQueryHookType } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/types/workspace-query-hook.type'; import { type AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type';