Api keys and webhook migration to core (#13011)

TODO: check Zapier trigger records work as expected

---------

Co-authored-by: Weiko <corentin@twenty.com>
This commit is contained in:
nitin
2025-07-09 20:33:54 +05:30
committed by GitHub
parent 18792f9f74
commit 484c267aa6
113 changed files with 4563 additions and 1060 deletions

View File

@ -9,7 +9,6 @@ import { BlocklistQueryHookModule } from 'src/modules/blocklist/query-hooks/bloc
import { CalendarQueryHookModule } from 'src/modules/calendar/common/query-hooks/calendar-query-hook.module';
import { ConnectedAccountQueryHookModule } from 'src/modules/connected-account/query-hooks/connected-account-query-hook.module';
import { MessagingQueryHookModule } from 'src/modules/messaging/common/query-hooks/messaging-query-hook.module';
import { WebhookQueryHookModule } from 'src/modules/webhook/query-hooks/webhook-query-hook.module';
import { WorkspaceMemberQueryHookModule } from 'src/modules/workspace-member/query-hooks/workspace-member-query-hook.module';
@Module({
@ -18,7 +17,6 @@ import { WorkspaceMemberQueryHookModule } from 'src/modules/workspace-member/que
CalendarQueryHookModule,
ConnectedAccountQueryHookModule,
BlocklistQueryHookModule,
WebhookQueryHookModule,
WorkspaceMemberQueryHookModule,
DiscoveryModule,
],

View File

@ -10,9 +10,17 @@ import { RestoreManyResolverFactory } from 'src/engine/api/graphql/workspace-res
import { RestoreOneResolverFactory } from 'src/engine/api/graphql/workspace-resolver-builder/factories/restore-one-resolver.factory';
import { UpdateManyResolverFactory } from 'src/engine/api/graphql/workspace-resolver-builder/factories/update-many-resolver.factory';
import { WorkspaceResolverBuilderService } from 'src/engine/api/graphql/workspace-resolver-builder/workspace-resolver-builder.service';
import {
AuthException,
AuthExceptionCode,
} from 'src/engine/core-modules/auth/auth.exception';
import { AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type';
import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service';
import { ObjectMetadataMaps } from 'src/engine/metadata-modules/types/object-metadata-maps';
import { metadataArgsStorage } from 'src/engine/twenty-orm/storage/metadata-args.storage';
import { getResolverName } from 'src/engine/utils/get-resolver-name.util';
import { standardObjectMetadataDefinitions } from 'src/engine/workspace-manager/workspace-sync-metadata/standard-objects';
import { isGatedAndNotEnabled } from 'src/engine/workspace-manager/workspace-sync-metadata/utils/is-gate-and-not-enabled.util';
import { CreateManyResolverFactory } from './factories/create-many-resolver.factory';
import { CreateOneResolverFactory } from './factories/create-one-resolver.factory';
@ -46,6 +54,7 @@ export class WorkspaceResolverFactory {
private readonly restoreManyResolverFactory: RestoreManyResolverFactory,
private readonly destroyManyResolverFactory: DestroyManyResolverFactory,
private readonly workspaceResolverBuilderService: WorkspaceResolverBuilderService,
private readonly featureFlagService: FeatureFlagService,
) {}
async create(
@ -76,9 +85,44 @@ export class WorkspaceResolverFactory {
Mutation: {},
};
const workspaceId = authContext.workspace?.id;
if (!workspaceId) {
throw new AuthException(
'Unauthenticated',
AuthExceptionCode.UNAUTHENTICATED,
);
}
const workspaceFeatureFlagsMap =
await this.featureFlagService.getWorkspaceFeatureFlagsMap(workspaceId);
for (const objectMetadata of Object.values(objectMetadataMaps.byId).filter(
isDefined,
)) {
const workspaceEntity = standardObjectMetadataDefinitions.find(
(entity) => {
const entityMetadata = metadataArgsStorage.filterEntities(entity);
return entityMetadata?.standardId === objectMetadata.standardId;
},
);
if (workspaceEntity) {
const entityMetadata =
metadataArgsStorage.filterEntities(workspaceEntity);
if (
isGatedAndNotEnabled(
entityMetadata?.gate,
workspaceFeatureFlagsMap,
'graphql',
)
) {
continue;
}
}
// Generate query resolvers
for (const methodName of workspaceResolverBuilderMethods.queries) {
const resolverName = getResolverName(objectMetadata, methodName);

View File

@ -9,14 +9,22 @@ import { ScalarsExplorerService } from 'src/engine/api/graphql/services/scalars-
import { workspaceResolverBuilderMethodNames } from 'src/engine/api/graphql/workspace-resolver-builder/factories/factories';
import { WorkspaceResolverFactory } from 'src/engine/api/graphql/workspace-resolver-builder/workspace-resolver.factory';
import { WorkspaceGraphQLSchemaFactory } from 'src/engine/api/graphql/workspace-schema-builder/workspace-graphql-schema.factory';
import {
AuthException,
AuthExceptionCode,
} from 'src/engine/core-modules/auth/auth.exception';
import { AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type';
import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service';
import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service';
import {
WorkspaceMetadataCacheException,
WorkspaceMetadataCacheExceptionCode,
} from 'src/engine/metadata-modules/workspace-metadata-cache/exceptions/workspace-metadata-cache.exception';
import { WorkspaceMetadataCacheService } from 'src/engine/metadata-modules/workspace-metadata-cache/services/workspace-metadata-cache.service';
import { metadataArgsStorage } from 'src/engine/twenty-orm/storage/metadata-args.storage';
import { WorkspaceCacheStorageService } from 'src/engine/workspace-cache-storage/workspace-cache-storage.service';
import { standardObjectMetadataDefinitions } from 'src/engine/workspace-manager/workspace-sync-metadata/standard-objects';
import { isGatedAndNotEnabled } from 'src/engine/workspace-manager/workspace-sync-metadata/utils/is-gate-and-not-enabled.util';
@Injectable()
export class WorkspaceSchemaFactory {
@ -27,6 +35,7 @@ export class WorkspaceSchemaFactory {
private readonly workspaceResolverFactory: WorkspaceResolverFactory,
private readonly workspaceCacheStorageService: WorkspaceCacheStorageService,
private readonly workspaceMetadataCacheService: WorkspaceMetadataCacheService,
private readonly featureFlagService: FeatureFlagService,
) {}
async createGraphQLSchema(authContext: AuthContext): Promise<GraphQLSchema> {
@ -57,13 +66,49 @@ export class WorkspaceSchemaFactory {
);
}
const workspaceId = authContext.workspace.id;
if (!workspaceId) {
throw new AuthException(
'Unauthenticated',
AuthExceptionCode.UNAUTHENTICATED,
);
}
const workspaceFeatureFlagsMap =
await this.featureFlagService.getWorkspaceFeatureFlagsMap(workspaceId);
const objectMetadataCollection = Object.values(objectMetadataMaps.byId)
.filter(isDefined)
.map((objectMetadataItem) => ({
...objectMetadataItem,
fields: Object.values(objectMetadataItem.fieldsById),
indexes: objectMetadataItem.indexMetadatas,
}));
}))
.filter((objectMetadata) => {
// Find the corresponding workspace entity for this object metadata
const workspaceEntity = standardObjectMetadataDefinitions.find(
(entity) => {
const entityMetadata = metadataArgsStorage.filterEntities(entity);
return entityMetadata?.standardId === objectMetadata.standardId;
},
);
if (!workspaceEntity) {
return true; // Include non-workspace entities (custom objects, etc.)
}
const entityMetadata =
metadataArgsStorage.filterEntities(workspaceEntity);
// Filter out entities that are GraphQL-gated and not enabled
return !isGatedAndNotEnabled(
entityMetadata?.gate,
workspaceFeatureFlagsMap,
'graphql',
);
});
// Get typeDefs from cache
let typeDefs = await this.workspaceCacheStorageService.getGraphQLTypeDefs(