Reorganize logic function files (#17766)
reorganize according to <img width="1243" height="725" alt="Pasted Graphic" src="https://github.com/user-attachments/assets/ba65dd10-8eec-4b13-ad49-9726edd3b79c" /> Not working yet
This commit is contained in:
-2
@@ -1,5 +1,3 @@
|
||||
// Default tool input schema matching the seed-project template
|
||||
// Template params: { a: string; b: number; }
|
||||
export const DEFAULT_TOOL_INPUT_SCHEMA = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
|
||||
+3
-1
@@ -5,9 +5,11 @@ export const FLAT_LOGIC_FUNCTION_EDITABLE_PROPERTIES = [
|
||||
'description',
|
||||
'timeoutSeconds',
|
||||
'checksum',
|
||||
'code',
|
||||
'sourceHandlerPath',
|
||||
'handlerName',
|
||||
'toolInputSchema',
|
||||
'isTool',
|
||||
'cronTriggerSettings',
|
||||
'databaseEventTriggerSettings',
|
||||
'httpRouteTriggerSettings',
|
||||
] as const satisfies (keyof FlatLogicFunction)[];
|
||||
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
import { Field, HideField, InputType } from '@nestjs/graphql';
|
||||
|
||||
import {
|
||||
IsBoolean,
|
||||
IsNotEmpty,
|
||||
IsNumber,
|
||||
IsObject,
|
||||
IsOptional,
|
||||
IsString,
|
||||
Max,
|
||||
Min,
|
||||
} from 'class-validator';
|
||||
import graphqlTypeJson from 'graphql-type-json';
|
||||
|
||||
@InputType()
|
||||
export class CreateDefaultLogicFunctionInput {
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
@Field()
|
||||
name: string;
|
||||
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
@Field({ nullable: true })
|
||||
description?: string;
|
||||
|
||||
@IsNumber()
|
||||
@Field({ nullable: true })
|
||||
@Min(1)
|
||||
@Max(900)
|
||||
@IsOptional()
|
||||
timeoutSeconds?: number;
|
||||
|
||||
@HideField()
|
||||
applicationId?: string;
|
||||
|
||||
@HideField()
|
||||
universalIdentifier?: string;
|
||||
|
||||
@HideField()
|
||||
id?: string;
|
||||
|
||||
@Field(() => graphqlTypeJson, { nullable: true })
|
||||
@IsObject()
|
||||
@IsOptional()
|
||||
toolInputSchema?: object;
|
||||
|
||||
@IsBoolean()
|
||||
@Field({ nullable: true })
|
||||
@IsOptional()
|
||||
isTool?: boolean;
|
||||
}
|
||||
+31
-18
@@ -11,7 +11,13 @@ import {
|
||||
Min,
|
||||
} from 'class-validator';
|
||||
import graphqlTypeJson from 'graphql-type-json';
|
||||
import { Sources } from 'twenty-shared/types';
|
||||
import {
|
||||
CronTriggerSettings,
|
||||
DatabaseEventTriggerSettings,
|
||||
HttpRouteTriggerSettings,
|
||||
} from 'twenty-shared/application';
|
||||
|
||||
import type { JsonbProperty } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/jsonb-property.type';
|
||||
|
||||
@InputType()
|
||||
export class CreateLogicFunctionInput {
|
||||
@@ -33,36 +39,28 @@ export class CreateLogicFunctionInput {
|
||||
timeoutSeconds?: number;
|
||||
|
||||
@HideField()
|
||||
applicationId?: string;
|
||||
applicationId: string;
|
||||
|
||||
@HideField()
|
||||
universalIdentifier?: string;
|
||||
|
||||
@HideField()
|
||||
id?: string;
|
||||
id: string;
|
||||
|
||||
@HideField()
|
||||
checksum?: string;
|
||||
|
||||
@Field(() => graphqlTypeJson, { nullable: true })
|
||||
@IsObject()
|
||||
@IsOptional()
|
||||
code?: Sources;
|
||||
checksum: string;
|
||||
|
||||
@IsString()
|
||||
@Field({ nullable: true })
|
||||
@IsOptional()
|
||||
handlerName?: string;
|
||||
@Field({ nullable: false })
|
||||
handlerName: string;
|
||||
|
||||
@IsString()
|
||||
@Field({ nullable: true })
|
||||
@IsOptional()
|
||||
sourceHandlerPath?: string;
|
||||
@Field({ nullable: false })
|
||||
sourceHandlerPath: string;
|
||||
|
||||
@IsString()
|
||||
@Field({ nullable: true })
|
||||
@IsOptional()
|
||||
builtHandlerPath?: string;
|
||||
@Field({ nullable: false })
|
||||
builtHandlerPath: string;
|
||||
|
||||
@Field(() => graphqlTypeJson, { nullable: true })
|
||||
@IsObject()
|
||||
@@ -73,4 +71,19 @@ export class CreateLogicFunctionInput {
|
||||
@Field({ nullable: true })
|
||||
@IsOptional()
|
||||
isTool?: boolean;
|
||||
|
||||
@IsObject()
|
||||
@Field(() => graphqlTypeJson, { nullable: true })
|
||||
@IsOptional()
|
||||
cronTriggerSettings?: JsonbProperty<CronTriggerSettings>;
|
||||
|
||||
@IsObject()
|
||||
@Field(() => graphqlTypeJson, { nullable: true })
|
||||
@IsOptional()
|
||||
databaseEventTriggerSettings?: JsonbProperty<DatabaseEventTriggerSettings>;
|
||||
|
||||
@IsObject()
|
||||
@Field(() => graphqlTypeJson, { nullable: true })
|
||||
@IsOptional()
|
||||
httpRouteTriggerSettings?: JsonbProperty<HttpRouteTriggerSettings>;
|
||||
}
|
||||
|
||||
-9
@@ -1,9 +0,0 @@
|
||||
import { ID, InputType } from '@nestjs/graphql';
|
||||
|
||||
import { IDField } from '@ptc-org/nestjs-query-graphql';
|
||||
|
||||
@InputType()
|
||||
export class GetLogicFunctionSourceCodeInput {
|
||||
@IDField(() => ID, { description: 'The id of the function.' })
|
||||
id!: string;
|
||||
}
|
||||
+3
-3
@@ -16,13 +16,13 @@ import {
|
||||
IsUUID,
|
||||
} from 'class-validator';
|
||||
import graphqlTypeJson from 'graphql-type-json';
|
||||
|
||||
import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars';
|
||||
import {
|
||||
CronTriggerSettings,
|
||||
DatabaseEventTriggerSettings,
|
||||
HttpRouteTriggerSettings,
|
||||
} from 'src/engine/metadata-modules/logic-function/logic-function.entity';
|
||||
} from 'twenty-shared/application';
|
||||
|
||||
import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars';
|
||||
|
||||
@ObjectType('LogicFunction')
|
||||
@Authorize({
|
||||
|
||||
+27
-8
@@ -14,10 +14,14 @@ import {
|
||||
ValidateNested,
|
||||
} from 'class-validator';
|
||||
import graphqlTypeJson from 'graphql-type-json';
|
||||
|
||||
import type { Sources } from 'twenty-shared/types';
|
||||
import {
|
||||
CronTriggerSettings,
|
||||
DatabaseEventTriggerSettings,
|
||||
HttpRouteTriggerSettings,
|
||||
} from 'twenty-shared/application';
|
||||
|
||||
import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars';
|
||||
import type { JsonbProperty } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/jsonb-property.type';
|
||||
|
||||
@InputType()
|
||||
class UpdateLogicFunctionInputUpdates {
|
||||
@@ -38,11 +42,6 @@ class UpdateLogicFunctionInputUpdates {
|
||||
@IsOptional()
|
||||
timeoutSeconds?: number;
|
||||
|
||||
@Field(() => graphqlTypeJson, { nullable: true })
|
||||
@IsObject()
|
||||
@IsOptional()
|
||||
code?: Sources;
|
||||
|
||||
@IsString()
|
||||
@Field({ nullable: true })
|
||||
@IsOptional()
|
||||
@@ -67,10 +66,30 @@ class UpdateLogicFunctionInputUpdates {
|
||||
@Field({ nullable: true })
|
||||
@IsOptional()
|
||||
isTool?: boolean;
|
||||
|
||||
@IsString()
|
||||
@Field({ nullable: true })
|
||||
@IsOptional()
|
||||
checksum?: string;
|
||||
|
||||
@IsObject()
|
||||
@Field(() => graphqlTypeJson, { nullable: true })
|
||||
@IsOptional()
|
||||
cronTriggerSettings?: JsonbProperty<CronTriggerSettings>;
|
||||
|
||||
@IsObject()
|
||||
@Field(() => graphqlTypeJson, { nullable: true })
|
||||
@IsOptional()
|
||||
databaseEventTriggerSettings?: JsonbProperty<DatabaseEventTriggerSettings>;
|
||||
|
||||
@IsObject()
|
||||
@Field(() => graphqlTypeJson, { nullable: true })
|
||||
@IsOptional()
|
||||
httpRouteTriggerSettings?: JsonbProperty<HttpRouteTriggerSettings>;
|
||||
}
|
||||
|
||||
@InputType()
|
||||
export class UpdateLogicFunctionInput {
|
||||
export class UpdateLogicFunctionSourceInput {
|
||||
@Field(() => UUIDScalarType, {
|
||||
description: 'Id of the logic function to update',
|
||||
})
|
||||
|
||||
+5
-17
@@ -1,4 +1,3 @@
|
||||
import { HTTPMethod } from 'twenty-shared/types';
|
||||
import {
|
||||
Check,
|
||||
Column,
|
||||
@@ -9,26 +8,15 @@ import {
|
||||
PrimaryGeneratedColumn,
|
||||
UpdateDateColumn,
|
||||
} from 'typeorm';
|
||||
import {
|
||||
CronTriggerSettings,
|
||||
DatabaseEventTriggerSettings,
|
||||
HttpRouteTriggerSettings,
|
||||
} from 'twenty-shared/application';
|
||||
|
||||
import { SyncableEntity } from 'src/engine/workspace-manager/types/syncable-entity.interface';
|
||||
import { type JsonbProperty } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/jsonb-property.type';
|
||||
|
||||
export type CronTriggerSettings = {
|
||||
pattern: string;
|
||||
};
|
||||
|
||||
export type DatabaseEventTriggerSettings = {
|
||||
eventName: string;
|
||||
updatedFields?: string[];
|
||||
};
|
||||
|
||||
export type HttpRouteTriggerSettings = {
|
||||
path: string;
|
||||
httpMethod: HTTPMethod;
|
||||
isAuthRequired: boolean;
|
||||
forwardedRequestHeaders?: string[];
|
||||
};
|
||||
|
||||
const DEFAULT_LOGIC_FUNCTION_TIMEOUT_SECONDS = 300; // 5 minutes
|
||||
|
||||
export enum LogicFunctionRuntime {
|
||||
|
||||
+7
-11
@@ -10,48 +10,44 @@ import { TokenModule } from 'src/engine/core-modules/auth/token/token.module';
|
||||
import { FeatureFlagEntity } from 'src/engine/core-modules/feature-flag/feature-flag.entity';
|
||||
import { FeatureFlagModule } from 'src/engine/core-modules/feature-flag/feature-flag.module';
|
||||
import { FileUploadModule } from 'src/engine/core-modules/file/file-upload/file-upload.module';
|
||||
import { FileModule } from 'src/engine/core-modules/file/file.module';
|
||||
import { LogicFunctionExecutorModule } from 'src/engine/core-modules/logic-function/logic-function-executor/logic-function-executor.module';
|
||||
import { LogicFunctionSourceBuilderModule } from 'src/engine/core-modules/logic-function/logic-function-source-builder/logic-function-source-builder.module';
|
||||
import { LogicFunctionResourceModule } from 'src/engine/core-modules/logic-function/logic-function-resource/logic-function-resource.module';
|
||||
import { SecretEncryptionModule } from 'src/engine/core-modules/secret-encryption/secret-encryption.module';
|
||||
import { ThrottlerModule } from 'src/engine/core-modules/throttler/throttler.module';
|
||||
import { WorkspaceManyOrAllFlatEntityMapsCacheModule } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.module';
|
||||
import { LogicFunctionLayerModule } from 'src/engine/metadata-modules/logic-function-layer/logic-function-layer.module';
|
||||
import { LogicFunctionEntity } from 'src/engine/metadata-modules/logic-function/logic-function.entity';
|
||||
import { LogicFunctionResolver } from 'src/engine/metadata-modules/logic-function/logic-function.resolver';
|
||||
import { LogicFunctionService } from 'src/engine/metadata-modules/logic-function/services/logic-function.service';
|
||||
import { LogicFunctionMetadataService } from 'src/engine/metadata-modules/logic-function/services/logic-function-metadata.service';
|
||||
import { WorkspaceFlatLogicFunctionMapCacheService } from 'src/engine/metadata-modules/logic-function/services/workspace-flat-logic-function-map-cache.service';
|
||||
import { PermissionsModule } from 'src/engine/metadata-modules/permissions/permissions.module';
|
||||
import { SubscriptionsModule } from 'src/engine/subscriptions/subscriptions.module';
|
||||
import { WorkspaceCacheModule } from 'src/engine/workspace-cache/workspace-cache.module';
|
||||
import { WorkspaceMigrationModule } from 'src/engine/workspace-manager/workspace-migration/workspace-migration.module';
|
||||
import { ApplicationLayerModule } from 'src/engine/core-modules/application-layer/application-layer.module';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
FileUploadModule,
|
||||
NestjsQueryTypeOrmModule.forFeature([LogicFunctionEntity]),
|
||||
TypeOrmModule.forFeature([ApplicationEntity, FeatureFlagEntity]),
|
||||
FileModule,
|
||||
ThrottlerModule,
|
||||
ApplicationModule,
|
||||
ApplicationLayerModule,
|
||||
AuditModule,
|
||||
FeatureFlagModule,
|
||||
PermissionsModule,
|
||||
WorkspaceManyOrAllFlatEntityMapsCacheModule,
|
||||
WorkspaceMigrationModule,
|
||||
LogicFunctionLayerModule,
|
||||
LogicFunctionExecutorModule,
|
||||
LogicFunctionSourceBuilderModule,
|
||||
LogicFunctionResourceModule,
|
||||
SubscriptionsModule,
|
||||
WorkspaceCacheModule,
|
||||
TokenModule,
|
||||
SecretEncryptionModule,
|
||||
],
|
||||
providers: [
|
||||
LogicFunctionService,
|
||||
LogicFunctionMetadataService,
|
||||
LogicFunctionResolver,
|
||||
WorkspaceFlatLogicFunctionMapCacheService,
|
||||
],
|
||||
exports: [LogicFunctionService, LogicFunctionExecutorModule],
|
||||
exports: [LogicFunctionMetadataService],
|
||||
})
|
||||
export class LogicFunctionModule {}
|
||||
|
||||
+95
-60
@@ -4,34 +4,35 @@ import { Args, Mutation, Query, Resolver, Subscription } from '@nestjs/graphql';
|
||||
import graphqlTypeJson from 'graphql-type-json';
|
||||
import { PermissionFlagType } from 'twenty-shared/constants';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/services/application.service';
|
||||
import { PreventNestToAutoLogGraphqlErrorsFilter } from 'src/engine/core-modules/graphql/filters/prevent-nest-to-auto-log-graphql-errors.filter';
|
||||
import { ResolverValidationPipe } from 'src/engine/core-modules/graphql/pipes/resolver-validation.pipe';
|
||||
import { LogicFunctionExecutorService } from 'src/engine/core-modules/logic-function/logic-function-executor/services/logic-function-executor.service';
|
||||
import { LogicFunctionSourceBuilderService } from 'src/engine/core-modules/logic-function/logic-function-source-builder/logic-function-source-builder.service';
|
||||
import { LogicFunctionResourceService } from 'src/engine/core-modules/logic-function/logic-function-resource/logic-function-resource.service';
|
||||
import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorator';
|
||||
import { FeatureFlagGuard } from 'src/engine/guards/feature-flag.guard';
|
||||
import { SettingsPermissionGuard } from 'src/engine/guards/settings-permission.guard';
|
||||
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
|
||||
import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service';
|
||||
import { CreateLogicFunctionInput } from 'src/engine/metadata-modules/logic-function/dtos/create-logic-function.input';
|
||||
import { ExecuteOneLogicFunctionInput } from 'src/engine/metadata-modules/logic-function/dtos/execute-logic-function.input';
|
||||
import { GetLogicFunctionSourceCodeInput } from 'src/engine/metadata-modules/logic-function/dtos/get-logic-function-source-code.input';
|
||||
import { LogicFunctionExecutionResultDTO } from 'src/engine/metadata-modules/logic-function/dtos/logic-function-execution-result.dto';
|
||||
import { LogicFunctionIdInput } from 'src/engine/metadata-modules/logic-function/dtos/logic-function-id.input';
|
||||
import { LogicFunctionLogsDTO } from 'src/engine/metadata-modules/logic-function/dtos/logic-function-logs.dto';
|
||||
import { LogicFunctionLogsInput } from 'src/engine/metadata-modules/logic-function/dtos/logic-function-logs.input';
|
||||
import { LogicFunctionDTO } from 'src/engine/metadata-modules/logic-function/dtos/logic-function.dto';
|
||||
import { UpdateLogicFunctionSourceInput } from 'src/engine/metadata-modules/logic-function/dtos/update-logic-function-source.input';
|
||||
import { LogicFunctionService } from 'src/engine/metadata-modules/logic-function/services/logic-function.service';
|
||||
import { LogicFunctionMetadataService } from 'src/engine/metadata-modules/logic-function/services/logic-function-metadata.service';
|
||||
import { FlatLogicFunction } from 'src/engine/metadata-modules/logic-function/types/flat-logic-function.type';
|
||||
import { findFlatLogicFunctionOrThrow } from 'src/engine/metadata-modules/logic-function/utils/find-flat-logic-function-or-throw.util';
|
||||
import { fromFlatLogicFunctionToLogicFunctionDto } from 'src/engine/metadata-modules/logic-function/utils/from-flat-logic-function-to-logic-function-dto.util';
|
||||
import { logicFunctionGraphQLApiExceptionHandler } from 'src/engine/metadata-modules/logic-function/utils/logic-function-graphql-api-exception-handler.utils';
|
||||
import { SubscriptionChannel } from 'src/engine/subscriptions/enums/subscription-channel.enum';
|
||||
import { SubscriptionService } from 'src/engine/subscriptions/subscription.service';
|
||||
import { LogicFunctionExecutorService } from 'src/engine/core-modules/logic-function/logic-function-executor/logic-function-executor.service';
|
||||
import { ApplicationLayerService } from 'src/engine/core-modules/application-layer/application-layer.service';
|
||||
import { CreateDefaultLogicFunctionInput } from 'src/engine/metadata-modules/logic-function/dtos/create-default-logic-function.input';
|
||||
|
||||
@UseGuards(
|
||||
WorkspaceAuthGuard,
|
||||
@@ -43,44 +44,15 @@ import { SubscriptionService } from 'src/engine/subscriptions/subscription.servi
|
||||
@UseFilters(PreventNestToAutoLogGraphqlErrorsFilter)
|
||||
export class LogicFunctionResolver {
|
||||
constructor(
|
||||
private readonly logicFunctionService: LogicFunctionService,
|
||||
private readonly logicFunctionExecutorService: LogicFunctionExecutorService,
|
||||
private readonly logicFunctionSourceBuilderService: LogicFunctionSourceBuilderService,
|
||||
private readonly logicFunctionMetadataService: LogicFunctionMetadataService,
|
||||
private readonly logicFunctionResourceService: LogicFunctionResourceService,
|
||||
private readonly applicationService: ApplicationService,
|
||||
private readonly applicationLayerService: ApplicationLayerService,
|
||||
private readonly subscriptionService: SubscriptionService,
|
||||
private readonly flatEntityMapsCacheService: WorkspaceManyOrAllFlatEntityMapsCacheService,
|
||||
) {}
|
||||
|
||||
private async getLogicFunctionContext({
|
||||
id,
|
||||
workspaceId,
|
||||
}: {
|
||||
id: string;
|
||||
workspaceId: string;
|
||||
}) {
|
||||
const [{ flatLogicFunctionMaps }, { workspaceCustomFlatApplication }] =
|
||||
await Promise.all([
|
||||
this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps({
|
||||
workspaceId,
|
||||
flatMapsKeys: ['flatLogicFunctionMaps'],
|
||||
}),
|
||||
this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow(
|
||||
{ workspaceId },
|
||||
),
|
||||
]);
|
||||
|
||||
const flatLogicFunction = findFlatLogicFunctionOrThrow({
|
||||
id,
|
||||
flatLogicFunctionMaps,
|
||||
});
|
||||
|
||||
return {
|
||||
flatLogicFunction,
|
||||
applicationUniversalIdentifier:
|
||||
workspaceCustomFlatApplication.universalIdentifier,
|
||||
};
|
||||
}
|
||||
|
||||
@Query(() => LogicFunctionDTO)
|
||||
async findOneLogicFunction(
|
||||
@Args('input') { id }: LogicFunctionIdInput,
|
||||
@@ -138,9 +110,15 @@ export class LogicFunctionResolver {
|
||||
}
|
||||
|
||||
@Query(() => graphqlTypeJson)
|
||||
async getAvailablePackages(@Args('input') { id }: LogicFunctionIdInput) {
|
||||
async getAvailablePackages(
|
||||
@Args('input') { id }: LogicFunctionIdInput,
|
||||
@AuthWorkspace() { id: workspaceId }: WorkspaceEntity,
|
||||
) {
|
||||
try {
|
||||
return await this.logicFunctionExecutorService.getAvailablePackages(id);
|
||||
return await this.applicationLayerService.getAvailablePackages({
|
||||
logicFunctionId: id,
|
||||
workspaceId,
|
||||
});
|
||||
} catch (error) {
|
||||
return logicFunctionGraphQLApiExceptionHandler(error);
|
||||
}
|
||||
@@ -153,10 +131,11 @@ export class LogicFunctionResolver {
|
||||
@AuthWorkspace() { id: workspaceId }: WorkspaceEntity,
|
||||
): Promise<LogicFunctionDTO> {
|
||||
try {
|
||||
const flatLogicFunction = await this.logicFunctionService.destroyOne({
|
||||
id: input.id,
|
||||
workspaceId,
|
||||
});
|
||||
const flatLogicFunction =
|
||||
await this.logicFunctionMetadataService.destroyOne({
|
||||
id: input.id,
|
||||
workspaceId,
|
||||
});
|
||||
|
||||
return fromFlatLogicFunctionToLogicFunctionDto({
|
||||
flatLogicFunction,
|
||||
@@ -168,16 +147,42 @@ export class LogicFunctionResolver {
|
||||
|
||||
@Mutation(() => LogicFunctionDTO)
|
||||
@UseGuards(SettingsPermissionGuard(PermissionFlagType.WORKFLOWS))
|
||||
async createOneLogicFunction(
|
||||
async createDefaultLogicFunction(
|
||||
@Args('input')
|
||||
input: CreateLogicFunctionInput,
|
||||
input: CreateDefaultLogicFunctionInput,
|
||||
@AuthWorkspace() { id: workspaceId }: WorkspaceEntity,
|
||||
): Promise<LogicFunctionDTO> {
|
||||
try {
|
||||
const flatLogicFunction = await this.logicFunctionService.createOne({
|
||||
input,
|
||||
workspaceId,
|
||||
});
|
||||
const { workspaceCustomFlatApplication } =
|
||||
await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow(
|
||||
{
|
||||
workspaceId,
|
||||
},
|
||||
);
|
||||
|
||||
const logicFunctionId = input.id ?? v4();
|
||||
|
||||
const { sourceHandlerPath, builtHandlerPath, handlerName, checksum } =
|
||||
await this.logicFunctionResourceService.seedSourceFiles({
|
||||
sourceSubfolder: logicFunctionId,
|
||||
workspaceId,
|
||||
applicationUniversalIdentifier:
|
||||
workspaceCustomFlatApplication.universalIdentifier,
|
||||
});
|
||||
|
||||
const flatLogicFunction =
|
||||
await this.logicFunctionMetadataService.createOne({
|
||||
input: {
|
||||
...input,
|
||||
id: logicFunctionId,
|
||||
sourceHandlerPath,
|
||||
builtHandlerPath,
|
||||
handlerName,
|
||||
checksum,
|
||||
},
|
||||
workspaceId,
|
||||
ownerFlatApplication: workspaceCustomFlatApplication,
|
||||
});
|
||||
|
||||
return fromFlatLogicFunctionToLogicFunctionDto({
|
||||
flatLogicFunction,
|
||||
@@ -193,32 +198,32 @@ export class LogicFunctionResolver {
|
||||
@Args('input') { id, payload, forceRebuild }: ExecuteOneLogicFunctionInput,
|
||||
@AuthWorkspace() { id: workspaceId }: WorkspaceEntity,
|
||||
): Promise<LogicFunctionExecutionResultDTO> {
|
||||
// TODO: remove forceRebuild parameter and add a column called shouldRebuild or isBuiltUpToDate
|
||||
try {
|
||||
if (forceRebuild) {
|
||||
const { flatLogicFunction, applicationUniversalIdentifier } =
|
||||
await this.getLogicFunctionContext({ id, workspaceId });
|
||||
|
||||
const { checksum } =
|
||||
await this.logicFunctionSourceBuilderService.buildFromSource({
|
||||
await this.logicFunctionResourceService.buildFromSource({
|
||||
workspaceId,
|
||||
applicationUniversalIdentifier,
|
||||
sourceHandlerPath: flatLogicFunction.sourceHandlerPath,
|
||||
builtHandlerPath: flatLogicFunction.builtHandlerPath,
|
||||
});
|
||||
|
||||
await this.logicFunctionService.updateChecksum({
|
||||
await this.logicFunctionMetadataService.updateChecksum({
|
||||
id,
|
||||
checksum,
|
||||
workspaceId,
|
||||
});
|
||||
}
|
||||
|
||||
const result =
|
||||
await this.logicFunctionExecutorService.executeOneLogicFunction({
|
||||
id,
|
||||
workspaceId,
|
||||
payload,
|
||||
});
|
||||
const result = await this.logicFunctionExecutorService.execute({
|
||||
logicFunctionId: id,
|
||||
workspaceId,
|
||||
payload,
|
||||
});
|
||||
|
||||
return {
|
||||
data: result.data as LogicFunctionExecutionResultDTO['data'],
|
||||
@@ -242,14 +247,14 @@ export class LogicFunctionResolver {
|
||||
|
||||
@Query(() => graphqlTypeJson, { nullable: true })
|
||||
async getLogicFunctionSourceCode(
|
||||
@Args('input') { id }: GetLogicFunctionSourceCodeInput,
|
||||
@Args('input') { id }: LogicFunctionIdInput,
|
||||
@AuthWorkspace() { id: workspaceId }: WorkspaceEntity,
|
||||
) {
|
||||
try {
|
||||
const { flatLogicFunction, applicationUniversalIdentifier } =
|
||||
await this.getLogicFunctionContext({ id, workspaceId });
|
||||
|
||||
return this.logicFunctionSourceBuilderService.getSourceCode({
|
||||
return this.logicFunctionResourceService.getSourceCode({
|
||||
workspaceId,
|
||||
applicationUniversalIdentifier,
|
||||
sourceHandlerPath: flatLogicFunction.sourceHandlerPath,
|
||||
@@ -269,7 +274,7 @@ export class LogicFunctionResolver {
|
||||
const { flatLogicFunction, applicationUniversalIdentifier } =
|
||||
await this.getLogicFunctionContext({ id, workspaceId });
|
||||
|
||||
await this.logicFunctionSourceBuilderService.updateSourceFiles({
|
||||
await this.logicFunctionResourceService.updateSourceFiles({
|
||||
workspaceId,
|
||||
applicationUniversalIdentifier,
|
||||
sourceHandlerPath: flatLogicFunction.sourceHandlerPath,
|
||||
@@ -325,4 +330,34 @@ export class LogicFunctionResolver {
|
||||
workspaceId: workspace.id,
|
||||
});
|
||||
}
|
||||
|
||||
private async getLogicFunctionContext({
|
||||
id,
|
||||
workspaceId,
|
||||
}: {
|
||||
id: string;
|
||||
workspaceId: string;
|
||||
}) {
|
||||
const [{ flatLogicFunctionMaps }, { workspaceCustomFlatApplication }] =
|
||||
await Promise.all([
|
||||
this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps({
|
||||
workspaceId,
|
||||
flatMapsKeys: ['flatLogicFunctionMaps'],
|
||||
}),
|
||||
this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow(
|
||||
{ workspaceId },
|
||||
),
|
||||
]);
|
||||
|
||||
const flatLogicFunction = findFlatLogicFunctionOrThrow({
|
||||
id,
|
||||
flatLogicFunctionMaps,
|
||||
});
|
||||
|
||||
return {
|
||||
flatLogicFunction,
|
||||
applicationUniversalIdentifier:
|
||||
workspaceCustomFlatApplication.universalIdentifier,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
+4
-27
@@ -4,13 +4,11 @@ import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/services/application.service';
|
||||
import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
|
||||
import { FileStorageService } from 'src/engine/core-modules/file-storage/file-storage.service';
|
||||
import { LogicFunctionSourceBuilderService } from 'src/engine/core-modules/logic-function/logic-function-source-builder/logic-function-source-builder.service';
|
||||
import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service';
|
||||
import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
|
||||
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
|
||||
import type { CreateLogicFunctionInput } from 'src/engine/metadata-modules/logic-function/dtos/create-logic-function.input';
|
||||
import type { UpdateLogicFunctionInput } from 'src/engine/metadata-modules/logic-function/dtos/update-logic-function.input';
|
||||
import type { UpdateLogicFunctionSourceInput } from 'src/engine/metadata-modules/logic-function/dtos/update-logic-function.input';
|
||||
import {
|
||||
LogicFunctionException,
|
||||
LogicFunctionExceptionCode,
|
||||
@@ -19,19 +17,15 @@ import { FlatLogicFunction } from 'src/engine/metadata-modules/logic-function/ty
|
||||
import { findFlatLogicFunctionOrThrow } from 'src/engine/metadata-modules/logic-function/utils/find-flat-logic-function-or-throw.util';
|
||||
import { fromCreateLogicFunctionInputToFlatLogicFunction } from 'src/engine/metadata-modules/logic-function/utils/from-create-logic-function-input-to-flat-logic-function.util';
|
||||
import { fromUpdateLogicFunctionInputToFlatLogicFunctionToUpdateOrThrow } from 'src/engine/metadata-modules/logic-function/utils/from-update-logic-function-input-to-flat-logic-function-to-update-or-throw.util';
|
||||
import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service';
|
||||
import { WorkspaceMigrationBuilderException } from 'src/engine/workspace-manager/workspace-migration/exceptions/workspace-migration-builder-exception';
|
||||
import { WorkspaceMigrationValidateBuildAndRunService } from 'src/engine/workspace-manager/workspace-migration/services/workspace-migration-validate-build-and-run-service';
|
||||
|
||||
@Injectable()
|
||||
export class LogicFunctionService {
|
||||
export class LogicFunctionMetadataService {
|
||||
constructor(
|
||||
private readonly flatEntityMapsCacheService: WorkspaceManyOrAllFlatEntityMapsCacheService,
|
||||
private readonly workspaceMigrationValidateBuildAndRunService: WorkspaceMigrationValidateBuildAndRunService,
|
||||
private readonly applicationService: ApplicationService,
|
||||
private readonly workspaceCacheService: WorkspaceCacheService,
|
||||
private readonly fileStorageService: FileStorageService,
|
||||
private readonly logicFunctionSourceBuilderService: LogicFunctionSourceBuilderService,
|
||||
) {}
|
||||
|
||||
async createOne({
|
||||
@@ -40,9 +34,8 @@ export class LogicFunctionService {
|
||||
ownerFlatApplication,
|
||||
}: {
|
||||
input: Omit<CreateLogicFunctionInput, 'applicationId'>;
|
||||
ownerFlatApplication?: FlatApplication;
|
||||
ownerFlatApplication: FlatApplication;
|
||||
workspaceId: string;
|
||||
applicationId?: string;
|
||||
}) {
|
||||
const resolvedOwnerFlatApplication =
|
||||
ownerFlatApplication ??
|
||||
@@ -52,7 +45,6 @@ export class LogicFunctionService {
|
||||
)
|
||||
).workspaceCustomFlatApplication;
|
||||
|
||||
// Generate flat logic function to get the ID
|
||||
const flatLogicFunctionToCreate =
|
||||
fromCreateLogicFunctionInputToFlatLogicFunction({
|
||||
createLogicFunctionInput: input,
|
||||
@@ -60,21 +52,6 @@ export class LogicFunctionService {
|
||||
ownerFlatApplication: resolvedOwnerFlatApplication,
|
||||
});
|
||||
|
||||
// Seed the source files (uses provided code or default seed project)
|
||||
const { sourceHandlerPath, builtHandlerPath, checksum } =
|
||||
await this.logicFunctionSourceBuilderService.seedSourceFiles({
|
||||
logicFunctionId: flatLogicFunctionToCreate.id,
|
||||
workspaceId,
|
||||
applicationUniversalIdentifier:
|
||||
resolvedOwnerFlatApplication.universalIdentifier,
|
||||
code: input.code,
|
||||
});
|
||||
|
||||
// Update paths and checksum with actual values from seeding
|
||||
flatLogicFunctionToCreate.sourceHandlerPath = sourceHandlerPath;
|
||||
flatLogicFunctionToCreate.builtHandlerPath = builtHandlerPath;
|
||||
flatLogicFunctionToCreate.checksum = checksum;
|
||||
|
||||
const validateAndBuildResult =
|
||||
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
|
||||
{
|
||||
@@ -109,7 +86,7 @@ export class LogicFunctionService {
|
||||
ownerFlatApplication,
|
||||
}: {
|
||||
id: string;
|
||||
update: UpdateLogicFunctionInput['update'];
|
||||
update: UpdateLogicFunctionSourceInput['update'];
|
||||
workspaceId: string;
|
||||
ownerFlatApplication?: FlatApplication;
|
||||
}) {
|
||||
+12
-35
@@ -1,22 +1,15 @@
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
|
||||
import { DEFAULT_TOOL_INPUT_SCHEMA } from 'src/engine/metadata-modules/logic-function/constants/default-tool-input-schema.constant';
|
||||
import { type CreateLogicFunctionInput } from 'src/engine/metadata-modules/logic-function/dtos/create-logic-function.input';
|
||||
import {
|
||||
DEFAULT_BUILT_HANDLER_PATH,
|
||||
DEFAULT_HANDLER_NAME,
|
||||
DEFAULT_SOURCE_HANDLER_PATH,
|
||||
LogicFunctionRuntime,
|
||||
} from 'src/engine/metadata-modules/logic-function/logic-function.entity';
|
||||
import { type FlatLogicFunction } from 'src/engine/metadata-modules/logic-function/types/flat-logic-function.type';
|
||||
import { logicFunctionCreateHash } from 'src/engine/metadata-modules/logic-function/utils/logic-function-create-hash.utils';
|
||||
|
||||
const WORKFLOW_BASE_FOLDER_PREFIX = 'workflow';
|
||||
|
||||
export type FromCreateLogicFunctionInputToFlatLogicFunctionArgs = {
|
||||
createLogicFunctionInput: CreateLogicFunctionInput;
|
||||
createLogicFunctionInput: Omit<CreateLogicFunctionInput, 'applicationId'>;
|
||||
workspaceId: string;
|
||||
ownerFlatApplication: FlatApplication;
|
||||
};
|
||||
@@ -26,34 +19,25 @@ export const fromCreateLogicFunctionInputToFlatLogicFunction = ({
|
||||
workspaceId,
|
||||
ownerFlatApplication,
|
||||
}: FromCreateLogicFunctionInputToFlatLogicFunctionArgs): FlatLogicFunction => {
|
||||
const id = rawCreateLogicFunctionInput.id ?? v4();
|
||||
const id = rawCreateLogicFunctionInput.id;
|
||||
const currentDate = new Date();
|
||||
|
||||
// Build full paths including the base folder
|
||||
const baseFolder = `${WORKFLOW_BASE_FOLDER_PREFIX}/${id}`;
|
||||
const sourceHandlerPath =
|
||||
rawCreateLogicFunctionInput.sourceHandlerPath ??
|
||||
`${baseFolder}/${DEFAULT_SOURCE_HANDLER_PATH}`;
|
||||
const builtHandlerPath =
|
||||
rawCreateLogicFunctionInput.builtHandlerPath ??
|
||||
`${baseFolder}/${DEFAULT_BUILT_HANDLER_PATH}`;
|
||||
const sourceHandlerPath = rawCreateLogicFunctionInput.sourceHandlerPath;
|
||||
const builtHandlerPath = rawCreateLogicFunctionInput.builtHandlerPath;
|
||||
|
||||
const universalIdentifier =
|
||||
rawCreateLogicFunctionInput.universalIdentifier ?? v4();
|
||||
|
||||
const checksum = isDefined(rawCreateLogicFunctionInput.checksum)
|
||||
? rawCreateLogicFunctionInput.checksum
|
||||
: rawCreateLogicFunctionInput?.code
|
||||
? logicFunctionCreateHash(
|
||||
JSON.stringify(rawCreateLogicFunctionInput.code),
|
||||
)
|
||||
: null;
|
||||
const checksum = rawCreateLogicFunctionInput.checksum;
|
||||
|
||||
return {
|
||||
id,
|
||||
cronTriggerSettings: null,
|
||||
databaseEventTriggerSettings: null,
|
||||
httpRouteTriggerSettings: null,
|
||||
cronTriggerSettings:
|
||||
rawCreateLogicFunctionInput.cronTriggerSettings ?? null,
|
||||
databaseEventTriggerSettings:
|
||||
rawCreateLogicFunctionInput.databaseEventTriggerSettings ?? null,
|
||||
httpRouteTriggerSettings:
|
||||
rawCreateLogicFunctionInput.httpRouteTriggerSettings ?? null,
|
||||
name: rawCreateLogicFunctionInput.name,
|
||||
description: rawCreateLogicFunctionInput.description ?? null,
|
||||
sourceHandlerPath,
|
||||
@@ -68,15 +52,8 @@ export const fromCreateLogicFunctionInputToFlatLogicFunction = ({
|
||||
runtime: LogicFunctionRuntime.NODE22,
|
||||
timeoutSeconds: rawCreateLogicFunctionInput.timeoutSeconds ?? 300,
|
||||
workspaceId,
|
||||
code: rawCreateLogicFunctionInput?.code,
|
||||
checksum,
|
||||
// If no schema provided and no code provided, use default schema
|
||||
// (because the default template will be used)
|
||||
toolInputSchema: isDefined(rawCreateLogicFunctionInput?.toolInputSchema)
|
||||
? rawCreateLogicFunctionInput.toolInputSchema
|
||||
: !isDefined(rawCreateLogicFunctionInput?.code)
|
||||
? DEFAULT_TOOL_INPUT_SCHEMA
|
||||
: null,
|
||||
toolInputSchema: rawCreateLogicFunctionInput.toolInputSchema ?? null,
|
||||
isTool: rawCreateLogicFunctionInput?.isTool ?? false,
|
||||
applicationUniversalIdentifier: ownerFlatApplication.universalIdentifier,
|
||||
};
|
||||
|
||||
+4
-23
@@ -1,22 +1,17 @@
|
||||
import {
|
||||
extractAndSanitizeObjectStringFields,
|
||||
isDefined,
|
||||
trimAndRemoveDuplicatedWhitespacesFromObjectStringProperties,
|
||||
} from 'twenty-shared/utils';
|
||||
import { trimAndRemoveDuplicatedWhitespacesFromObjectStringProperties } from 'twenty-shared/utils';
|
||||
|
||||
import { type MetadataFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/metadata-flat-entity-maps.type';
|
||||
import { FLAT_LOGIC_FUNCTION_EDITABLE_PROPERTIES } from 'src/engine/metadata-modules/logic-function/constants/flat-logic-function-editable-properties.constant';
|
||||
import { type UpdateLogicFunctionInput } from 'src/engine/metadata-modules/logic-function/dtos/update-logic-function.input';
|
||||
import { type UpdateLogicFunctionSourceInput } from 'src/engine/metadata-modules/logic-function/dtos/update-logic-function.input';
|
||||
import { type FlatLogicFunction } from 'src/engine/metadata-modules/logic-function/types/flat-logic-function.type';
|
||||
import { findFlatLogicFunctionOrThrow } from 'src/engine/metadata-modules/logic-function/utils/find-flat-logic-function-or-throw.util';
|
||||
import { logicFunctionCreateHash } from 'src/engine/metadata-modules/logic-function/utils/logic-function-create-hash.utils';
|
||||
import { mergeUpdateInExistingRecord } from 'src/utils/merge-update-in-existing-record.util';
|
||||
|
||||
export const fromUpdateLogicFunctionInputToFlatLogicFunctionToUpdateOrThrow = ({
|
||||
updateLogicFunctionInput: rawUpdateLogicFunctionInput,
|
||||
flatLogicFunctionMaps,
|
||||
}: {
|
||||
updateLogicFunctionInput: UpdateLogicFunctionInput;
|
||||
updateLogicFunctionInput: UpdateLogicFunctionSourceInput;
|
||||
flatLogicFunctionMaps: MetadataFlatEntityMaps<'logicFunction'>;
|
||||
}): FlatLogicFunction => {
|
||||
const { id: logicFunctionToUpdateId } =
|
||||
@@ -30,23 +25,9 @@ export const fromUpdateLogicFunctionInputToFlatLogicFunctionToUpdateOrThrow = ({
|
||||
flatLogicFunctionMaps,
|
||||
});
|
||||
|
||||
const update = rawUpdateLogicFunctionInput.update;
|
||||
const updatedEditableFieldProperties = {
|
||||
...extractAndSanitizeObjectStringFields(
|
||||
{
|
||||
...update,
|
||||
...(isDefined(update.code) && {
|
||||
checksum: logicFunctionCreateHash(JSON.stringify(update.code)),
|
||||
}),
|
||||
},
|
||||
FLAT_LOGIC_FUNCTION_EDITABLE_PROPERTIES,
|
||||
),
|
||||
...(isDefined(update.code) && { code: update.code }),
|
||||
};
|
||||
|
||||
return mergeUpdateInExistingRecord({
|
||||
existing: existingFlatLogicFunctionToUpdate,
|
||||
properties: FLAT_LOGIC_FUNCTION_EDITABLE_PROPERTIES,
|
||||
update: updatedEditableFieldProperties,
|
||||
update: rawUpdateLogicFunctionInput.update,
|
||||
});
|
||||
};
|
||||
|
||||
+1
@@ -1,5 +1,6 @@
|
||||
import { createHash } from 'crypto';
|
||||
|
||||
// TODO: migrate to twenty-shared and spread everywhere
|
||||
export const logicFunctionCreateHash = (fileContent: string) => {
|
||||
return createHash('sha512')
|
||||
.update(fileContent)
|
||||
|
||||
Reference in New Issue
Block a user