Create record action (#8460)
- Add create record action - Migrate all step name => action in a common folder - Separate types
This commit is contained in:
@ -2,8 +2,8 @@ import { Field, InputType } from '@nestjs/graphql';
|
|||||||
|
|
||||||
import graphqlTypeJson from 'graphql-type-json';
|
import graphqlTypeJson from 'graphql-type-json';
|
||||||
|
|
||||||
|
import { WorkflowAction } from 'src/modules/workflow/workflow-executor/workflow-actions/types/workflow-action.type';
|
||||||
import { WorkflowTrigger } from 'src/modules/workflow/workflow-trigger/types/workflow-trigger.type';
|
import { WorkflowTrigger } from 'src/modules/workflow/workflow-trigger/types/workflow-trigger.type';
|
||||||
import { WorkflowStep } from 'src/modules/workflow/workflow-executor/types/workflow-action.type';
|
|
||||||
|
|
||||||
@InputType()
|
@InputType()
|
||||||
export class ComputeStepOutputSchemaInput {
|
export class ComputeStepOutputSchemaInput {
|
||||||
@ -11,5 +11,5 @@ export class ComputeStepOutputSchemaInput {
|
|||||||
description: 'Step JSON format',
|
description: 'Step JSON format',
|
||||||
nullable: false,
|
nullable: false,
|
||||||
})
|
})
|
||||||
step: WorkflowTrigger | WorkflowStep;
|
step: WorkflowTrigger | WorkflowAction;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorat
|
|||||||
import { UserAuthGuard } from 'src/engine/guards/user-auth.guard';
|
import { UserAuthGuard } from 'src/engine/guards/user-auth.guard';
|
||||||
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
|
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
|
||||||
import { WorkflowBuilderWorkspaceService } from 'src/modules/workflow/workflow-builder/workflow-builder.workspace-service';
|
import { WorkflowBuilderWorkspaceService } from 'src/modules/workflow/workflow-builder/workflow-builder.workspace-service';
|
||||||
import { OutputSchema } from 'src/modules/workflow/workflow-executor/types/workflow-step-settings.type';
|
import { OutputSchema } from 'src/modules/workflow/workflow-executor/workflow-actions/types/workflow-action-settings.type';
|
||||||
|
|
||||||
@Resolver()
|
@Resolver()
|
||||||
@UseGuards(WorkspaceAuthGuard, UserAuthGuard)
|
@UseGuards(WorkspaceAuthGuard, UserAuthGuard)
|
||||||
|
|||||||
@ -21,7 +21,7 @@ import { FavoriteWorkspaceEntity } from 'src/modules/favorite/standard-objects/f
|
|||||||
import { TimelineActivityWorkspaceEntity } from 'src/modules/timeline/standard-objects/timeline-activity.workspace-entity';
|
import { TimelineActivityWorkspaceEntity } from 'src/modules/timeline/standard-objects/timeline-activity.workspace-entity';
|
||||||
import { WorkflowRunWorkspaceEntity } from 'src/modules/workflow/common/standard-objects/workflow-run.workspace-entity';
|
import { WorkflowRunWorkspaceEntity } from 'src/modules/workflow/common/standard-objects/workflow-run.workspace-entity';
|
||||||
import { WorkflowWorkspaceEntity } from 'src/modules/workflow/common/standard-objects/workflow.workspace-entity';
|
import { WorkflowWorkspaceEntity } from 'src/modules/workflow/common/standard-objects/workflow.workspace-entity';
|
||||||
import { WorkflowStep } from 'src/modules/workflow/workflow-executor/types/workflow-action.type';
|
import { WorkflowAction } from 'src/modules/workflow/workflow-executor/workflow-actions/types/workflow-action.type';
|
||||||
import { WorkflowTrigger } from 'src/modules/workflow/workflow-trigger/types/workflow-trigger.type';
|
import { WorkflowTrigger } from 'src/modules/workflow/workflow-trigger/types/workflow-trigger.type';
|
||||||
|
|
||||||
export enum WorkflowVersionStatus {
|
export enum WorkflowVersionStatus {
|
||||||
@ -98,7 +98,7 @@ export class WorkflowVersionWorkspaceEntity extends BaseWorkspaceEntity {
|
|||||||
icon: 'IconSettingsAutomation',
|
icon: 'IconSettingsAutomation',
|
||||||
})
|
})
|
||||||
@WorkspaceIsNullable()
|
@WorkspaceIsNullable()
|
||||||
steps: WorkflowStep[] | null;
|
steps: WorkflowAction[] | null;
|
||||||
|
|
||||||
@WorkspaceField({
|
@WorkspaceField({
|
||||||
standardId: WORKFLOW_VERSION_STANDARD_FIELD_IDS.status,
|
standardId: WORKFLOW_VERSION_STANDARD_FIELD_IDS.status,
|
||||||
|
|||||||
@ -5,24 +5,24 @@ import { join } from 'path';
|
|||||||
|
|
||||||
import { Repository } from 'typeorm';
|
import { Repository } from 'typeorm';
|
||||||
|
|
||||||
|
import { DatabaseEventAction } from 'src/engine/api/graphql/graphql-query-runner/enums/database-event-action';
|
||||||
|
import { checkStringIsDatabaseEventAction } from 'src/engine/api/graphql/graphql-query-runner/utils/check-string-is-database-event-action';
|
||||||
import { INDEX_FILE_NAME } from 'src/engine/core-modules/serverless/drivers/constants/index-file-name';
|
import { INDEX_FILE_NAME } from 'src/engine/core-modules/serverless/drivers/constants/index-file-name';
|
||||||
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
||||||
import { ServerlessFunctionService } from 'src/engine/metadata-modules/serverless-function/serverless-function.service';
|
import { ServerlessFunctionService } from 'src/engine/metadata-modules/serverless-function/serverless-function.service';
|
||||||
import { CodeIntrospectionService } from 'src/modules/code-introspection/code-introspection.service';
|
import { CodeIntrospectionService } from 'src/modules/code-introspection/code-introspection.service';
|
||||||
import { generateFakeObjectRecord } from 'src/modules/workflow/workflow-builder/utils/generate-fake-object-record';
|
import { generateFakeObjectRecord } from 'src/modules/workflow/workflow-builder/utils/generate-fake-object-record';
|
||||||
|
import { generateFakeObjectRecordEvent } from 'src/modules/workflow/workflow-builder/utils/generate-fake-object-record-event';
|
||||||
|
import { WorkflowSendEmailStepOutputSchema } from 'src/modules/workflow/workflow-executor/workflow-actions/mail-sender/send-email.workflow-action';
|
||||||
import {
|
import {
|
||||||
|
WorkflowAction,
|
||||||
WorkflowActionType,
|
WorkflowActionType,
|
||||||
WorkflowStep,
|
} from 'src/modules/workflow/workflow-executor/workflow-actions/types/workflow-action.type';
|
||||||
} from 'src/modules/workflow/workflow-executor/types/workflow-action.type';
|
|
||||||
import { WorkflowSendEmailStepOutputSchema } from 'src/modules/workflow/workflow-executor/types/workflow-step-settings.type';
|
|
||||||
import {
|
import {
|
||||||
WorkflowTrigger,
|
WorkflowTrigger,
|
||||||
WorkflowTriggerType,
|
WorkflowTriggerType,
|
||||||
} from 'src/modules/workflow/workflow-trigger/types/workflow-trigger.type';
|
} from 'src/modules/workflow/workflow-trigger/types/workflow-trigger.type';
|
||||||
import { isDefined } from 'src/utils/is-defined';
|
import { isDefined } from 'src/utils/is-defined';
|
||||||
import { checkStringIsDatabaseEventAction } from 'src/engine/api/graphql/graphql-query-runner/utils/check-string-is-database-event-action';
|
|
||||||
import { generateFakeObjectRecordEvent } from 'src/modules/workflow/workflow-builder/utils/generate-fake-object-record-event';
|
|
||||||
import { DatabaseEventAction } from 'src/engine/api/graphql/graphql-query-runner/enums/database-event-action';
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class WorkflowBuilderWorkspaceService {
|
export class WorkflowBuilderWorkspaceService {
|
||||||
@ -37,7 +37,7 @@ export class WorkflowBuilderWorkspaceService {
|
|||||||
step,
|
step,
|
||||||
workspaceId,
|
workspaceId,
|
||||||
}: {
|
}: {
|
||||||
step: WorkflowTrigger | WorkflowStep;
|
step: WorkflowTrigger | WorkflowAction;
|
||||||
workspaceId: string;
|
workspaceId: string;
|
||||||
}): Promise<object> {
|
}): Promise<object> {
|
||||||
const stepType = step.type;
|
const stepType = step.type;
|
||||||
@ -57,7 +57,7 @@ export class WorkflowBuilderWorkspaceService {
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
return await this.computeManualTriggerOutputSchema({
|
return await this.computeRecordOutputSchema({
|
||||||
objectType,
|
objectType,
|
||||||
workspaceId,
|
workspaceId,
|
||||||
objectMetadataRepository: this.objectMetadataRepository,
|
objectMetadataRepository: this.objectMetadataRepository,
|
||||||
@ -78,6 +78,12 @@ export class WorkflowBuilderWorkspaceService {
|
|||||||
codeIntrospectionService: this.codeIntrospectionService,
|
codeIntrospectionService: this.codeIntrospectionService,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
case WorkflowActionType.RECORD_CRUD:
|
||||||
|
return await this.computeRecordOutputSchema({
|
||||||
|
objectType: step.settings.input.objectName,
|
||||||
|
workspaceId,
|
||||||
|
objectMetadataRepository: this.objectMetadataRepository,
|
||||||
|
});
|
||||||
default:
|
default:
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@ -116,7 +122,7 @@ export class WorkflowBuilderWorkspaceService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async computeManualTriggerOutputSchema<Entity>({
|
private async computeRecordOutputSchema<Entity>({
|
||||||
objectType,
|
objectType,
|
||||||
workspaceId,
|
workspaceId,
|
||||||
objectMetadataRepository,
|
objectMetadataRepository,
|
||||||
|
|||||||
@ -2,19 +2,21 @@ import { Injectable } from '@nestjs/common';
|
|||||||
|
|
||||||
import { WorkflowAction } from 'src/modules/workflow/workflow-executor/interfaces/workflow-action.interface';
|
import { WorkflowAction } from 'src/modules/workflow/workflow-executor/interfaces/workflow-action.interface';
|
||||||
|
|
||||||
import { WorkflowActionType } from 'src/modules/workflow/workflow-executor/types/workflow-action.type';
|
|
||||||
import {
|
import {
|
||||||
WorkflowStepExecutorException,
|
WorkflowStepExecutorException,
|
||||||
WorkflowStepExecutorExceptionCode,
|
WorkflowStepExecutorExceptionCode,
|
||||||
} from 'src/modules/workflow/workflow-executor/exceptions/workflow-step-executor.exception';
|
} from 'src/modules/workflow/workflow-executor/exceptions/workflow-step-executor.exception';
|
||||||
import { CodeWorkflowAction } from 'src/modules/serverless/workflow-actions/code.workflow-action';
|
import { CodeWorkflowAction } from 'src/modules/workflow/workflow-executor/workflow-actions/code/code.workflow-action';
|
||||||
import { SendEmailWorkflowAction } from 'src/modules/mail-sender/workflow-actions/send-email.workflow-action';
|
import { SendEmailWorkflowAction } from 'src/modules/workflow/workflow-executor/workflow-actions/mail-sender/send-email.workflow-action';
|
||||||
|
import { RecordCRUDWorkflowAction } from 'src/modules/workflow/workflow-executor/workflow-actions/record-crud/record-crud.workflow-action';
|
||||||
|
import { WorkflowActionType } from 'src/modules/workflow/workflow-executor/workflow-actions/types/workflow-action.type';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class WorkflowActionFactory {
|
export class WorkflowActionFactory {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly codeWorkflowAction: CodeWorkflowAction,
|
private readonly codeWorkflowAction: CodeWorkflowAction,
|
||||||
private readonly sendEmailWorkflowAction: SendEmailWorkflowAction,
|
private readonly sendEmailWorkflowAction: SendEmailWorkflowAction,
|
||||||
|
private readonly recordCRUDWorkflowAction: RecordCRUDWorkflowAction,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
get(stepType: WorkflowActionType): WorkflowAction {
|
get(stepType: WorkflowActionType): WorkflowAction {
|
||||||
@ -23,6 +25,8 @@ export class WorkflowActionFactory {
|
|||||||
return this.codeWorkflowAction;
|
return this.codeWorkflowAction;
|
||||||
case WorkflowActionType.SEND_EMAIL:
|
case WorkflowActionType.SEND_EMAIL:
|
||||||
return this.sendEmailWorkflowAction;
|
return this.sendEmailWorkflowAction;
|
||||||
|
case WorkflowActionType.RECORD_CRUD:
|
||||||
|
return this.recordCRUDWorkflowAction;
|
||||||
default:
|
default:
|
||||||
throw new WorkflowStepExecutorException(
|
throw new WorkflowStepExecutorException(
|
||||||
`Workflow step executor not found for step type '${stepType}'`,
|
`Workflow step executor not found for step type '${stepType}'`,
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { WorkflowActionResult } from 'src/modules/workflow/workflow-executor/types/workflow-action-result.type';
|
import { WorkflowActionResult } from 'src/modules/workflow/workflow-executor/workflow-actions/types/workflow-action-result.type';
|
||||||
|
|
||||||
export interface WorkflowAction {
|
export interface WorkflowAction {
|
||||||
execute(workflowStepInput: unknown): Promise<WorkflowActionResult>;
|
execute(workflowStepInput: unknown): Promise<WorkflowActionResult>;
|
||||||
|
|||||||
@ -1,30 +0,0 @@
|
|||||||
import {
|
|
||||||
WorkflowCodeStepSettings,
|
|
||||||
WorkflowSendEmailStepSettings,
|
|
||||||
WorkflowStepSettings,
|
|
||||||
} from 'src/modules/workflow/workflow-executor/types/workflow-step-settings.type';
|
|
||||||
|
|
||||||
export enum WorkflowActionType {
|
|
||||||
CODE = 'CODE',
|
|
||||||
SEND_EMAIL = 'SEND_EMAIL',
|
|
||||||
}
|
|
||||||
|
|
||||||
type BaseWorkflowStep = {
|
|
||||||
id: string;
|
|
||||||
name: string;
|
|
||||||
type: WorkflowActionType;
|
|
||||||
settings: WorkflowStepSettings;
|
|
||||||
valid: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type WorkflowCodeStep = BaseWorkflowStep & {
|
|
||||||
type: WorkflowActionType.CODE;
|
|
||||||
settings: WorkflowCodeStepSettings;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type WorkflowSendEmailStep = BaseWorkflowStep & {
|
|
||||||
type: WorkflowActionType.SEND_EMAIL;
|
|
||||||
settings: WorkflowSendEmailStepSettings;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type WorkflowStep = WorkflowCodeStep | WorkflowSendEmailStep;
|
|
||||||
@ -1,45 +0,0 @@
|
|||||||
export type OutputSchema = object;
|
|
||||||
|
|
||||||
type BaseWorkflowStepSettings = {
|
|
||||||
input: object;
|
|
||||||
outputSchema: OutputSchema;
|
|
||||||
errorHandlingOptions: {
|
|
||||||
retryOnFailure: {
|
|
||||||
value: boolean;
|
|
||||||
};
|
|
||||||
continueOnFailure: {
|
|
||||||
value: boolean;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export type WorkflowCodeStepInput = {
|
|
||||||
serverlessFunctionId: string;
|
|
||||||
serverlessFunctionVersion: string;
|
|
||||||
serverlessFunctionInput: {
|
|
||||||
[key: string]: any;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export type WorkflowCodeStepSettings = BaseWorkflowStepSettings & {
|
|
||||||
input: WorkflowCodeStepInput;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type WorkflowSendEmailStepInput = {
|
|
||||||
connectedAccountId: string;
|
|
||||||
email: string;
|
|
||||||
subject?: string;
|
|
||||||
body?: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type WorkflowSendEmailStepOutputSchema = {
|
|
||||||
success: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type WorkflowSendEmailStepSettings = BaseWorkflowStepSettings & {
|
|
||||||
input: WorkflowSendEmailStepInput;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type WorkflowStepSettings =
|
|
||||||
| WorkflowSendEmailStepSettings
|
|
||||||
| WorkflowCodeStepSettings;
|
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
import { Module } from '@nestjs/common';
|
||||||
|
|
||||||
|
import { ServerlessFunctionModule } from 'src/engine/metadata-modules/serverless-function/serverless-function.module';
|
||||||
|
import { ScopedWorkspaceContextFactory } from 'src/engine/twenty-orm/factories/scoped-workspace-context.factory';
|
||||||
|
import { CodeWorkflowAction } from 'src/modules/workflow/workflow-executor/workflow-actions/code/code.workflow-action';
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
imports: [ServerlessFunctionModule],
|
||||||
|
providers: [ScopedWorkspaceContextFactory, CodeWorkflowAction],
|
||||||
|
exports: [CodeWorkflowAction],
|
||||||
|
})
|
||||||
|
export class CodeActionModule {}
|
||||||
@ -8,8 +8,8 @@ import {
|
|||||||
WorkflowStepExecutorException,
|
WorkflowStepExecutorException,
|
||||||
WorkflowStepExecutorExceptionCode,
|
WorkflowStepExecutorExceptionCode,
|
||||||
} from 'src/modules/workflow/workflow-executor/exceptions/workflow-step-executor.exception';
|
} from 'src/modules/workflow/workflow-executor/exceptions/workflow-step-executor.exception';
|
||||||
import { WorkflowActionResult } from 'src/modules/workflow/workflow-executor/types/workflow-action-result.type';
|
import { WorkflowCodeActionInput } from 'src/modules/workflow/workflow-executor/workflow-actions/code/types/workflow-code-action-input.type';
|
||||||
import { WorkflowCodeStepInput } from 'src/modules/workflow/workflow-executor/types/workflow-step-settings.type';
|
import { WorkflowActionResult } from 'src/modules/workflow/workflow-executor/workflow-actions/types/workflow-action-result.type';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class CodeWorkflowAction implements WorkflowAction {
|
export class CodeWorkflowAction implements WorkflowAction {
|
||||||
@ -19,7 +19,7 @@ export class CodeWorkflowAction implements WorkflowAction {
|
|||||||
) {}
|
) {}
|
||||||
|
|
||||||
async execute(
|
async execute(
|
||||||
workflowStepInput: WorkflowCodeStepInput,
|
workflowActionInput: WorkflowCodeActionInput,
|
||||||
): Promise<WorkflowActionResult> {
|
): Promise<WorkflowActionResult> {
|
||||||
try {
|
try {
|
||||||
const { workspaceId } = this.scopedWorkspaceContextFactory.create();
|
const { workspaceId } = this.scopedWorkspaceContextFactory.create();
|
||||||
@ -33,9 +33,9 @@ export class CodeWorkflowAction implements WorkflowAction {
|
|||||||
|
|
||||||
const result =
|
const result =
|
||||||
await this.serverlessFunctionService.executeOneServerlessFunction(
|
await this.serverlessFunctionService.executeOneServerlessFunction(
|
||||||
workflowStepInput.serverlessFunctionId,
|
workflowActionInput.serverlessFunctionId,
|
||||||
workspaceId,
|
workspaceId,
|
||||||
workflowStepInput.serverlessFunctionInput,
|
workflowActionInput.serverlessFunctionInput,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (result.error) {
|
if (result.error) {
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
export type WorkflowCodeActionInput = {
|
||||||
|
serverlessFunctionId: string;
|
||||||
|
serverlessFunctionVersion: string;
|
||||||
|
serverlessFunctionInput: {
|
||||||
|
[key: string]: any;
|
||||||
|
};
|
||||||
|
};
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
import { WorkflowCodeActionInput } from 'src/modules/workflow/workflow-executor/workflow-actions/code/types/workflow-code-action-input.type';
|
||||||
|
import { BaseWorkflowActionSettings } from 'src/modules/workflow/workflow-executor/workflow-actions/types/workflow-action-settings.type';
|
||||||
|
|
||||||
|
export type WorkflowCodeActionSettings = BaseWorkflowActionSettings & {
|
||||||
|
input: WorkflowCodeActionInput;
|
||||||
|
};
|
||||||
@ -1,13 +1,13 @@
|
|||||||
import { CustomException } from 'src/utils/custom-exception';
|
import { CustomException } from 'src/utils/custom-exception';
|
||||||
|
|
||||||
export class MailSenderException extends CustomException {
|
export class SendEmailActionException extends CustomException {
|
||||||
code: MailSenderExceptionCode;
|
code: SendEmailActionExceptionCode;
|
||||||
constructor(message: string, code: MailSenderExceptionCode) {
|
constructor(message: string, code: SendEmailActionExceptionCode) {
|
||||||
super(message, code);
|
super(message, code);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum MailSenderExceptionCode {
|
export enum SendEmailActionExceptionCode {
|
||||||
PROVIDER_NOT_SUPPORTED = 'PROVIDER_NOT_SUPPORTED',
|
PROVIDER_NOT_SUPPORTED = 'PROVIDER_NOT_SUPPORTED',
|
||||||
CONNECTED_ACCOUNT_NOT_FOUND = 'CONNECTED_ACCOUNT_NOT_FOUND',
|
CONNECTED_ACCOUNT_NOT_FOUND = 'CONNECTED_ACCOUNT_NOT_FOUND',
|
||||||
}
|
}
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
import { Module } from '@nestjs/common';
|
||||||
|
|
||||||
|
import { ScopedWorkspaceContextFactory } from 'src/engine/twenty-orm/factories/scoped-workspace-context.factory';
|
||||||
|
import { OAuth2ClientManagerModule } from 'src/modules/connected-account/oauth2-client-manager/oauth2-client-manager.module';
|
||||||
|
import { GmailClientProvider } from 'src/modules/messaging/message-import-manager/drivers/gmail/providers/gmail-client.provider';
|
||||||
|
import { SendEmailWorkflowAction } from 'src/modules/workflow/workflow-executor/workflow-actions/mail-sender/send-email.workflow-action';
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
imports: [OAuth2ClientManagerModule],
|
||||||
|
providers: [
|
||||||
|
GmailClientProvider,
|
||||||
|
ScopedWorkspaceContextFactory,
|
||||||
|
SendEmailWorkflowAction,
|
||||||
|
],
|
||||||
|
exports: [SendEmailWorkflowAction],
|
||||||
|
})
|
||||||
|
export class SendEmailActionModule {}
|
||||||
@ -9,22 +9,23 @@ import { WorkflowAction } from 'src/modules/workflow/workflow-executor/interface
|
|||||||
import { ScopedWorkspaceContextFactory } from 'src/engine/twenty-orm/factories/scoped-workspace-context.factory';
|
import { ScopedWorkspaceContextFactory } from 'src/engine/twenty-orm/factories/scoped-workspace-context.factory';
|
||||||
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
|
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
|
||||||
import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity';
|
import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity';
|
||||||
import {
|
|
||||||
MailSenderException,
|
|
||||||
MailSenderExceptionCode,
|
|
||||||
} from 'src/modules/mail-sender/exceptions/mail-sender.exception';
|
|
||||||
import { GmailClientProvider } from 'src/modules/messaging/message-import-manager/drivers/gmail/providers/gmail-client.provider';
|
import { GmailClientProvider } from 'src/modules/messaging/message-import-manager/drivers/gmail/providers/gmail-client.provider';
|
||||||
import {
|
import {
|
||||||
WorkflowStepExecutorException,
|
WorkflowStepExecutorException,
|
||||||
WorkflowStepExecutorExceptionCode,
|
WorkflowStepExecutorExceptionCode,
|
||||||
} from 'src/modules/workflow/workflow-executor/exceptions/workflow-step-executor.exception';
|
} from 'src/modules/workflow/workflow-executor/exceptions/workflow-step-executor.exception';
|
||||||
import { WorkflowActionResult } from 'src/modules/workflow/workflow-executor/types/workflow-action-result.type';
|
|
||||||
import {
|
import {
|
||||||
WorkflowSendEmailStepInput,
|
SendEmailActionException,
|
||||||
WorkflowSendEmailStepOutputSchema,
|
SendEmailActionExceptionCode,
|
||||||
} from 'src/modules/workflow/workflow-executor/types/workflow-step-settings.type';
|
} from 'src/modules/workflow/workflow-executor/workflow-actions/mail-sender/exceptions/send-email-action.exception';
|
||||||
|
import { WorkflowSendEmailActionInput } from 'src/modules/workflow/workflow-executor/workflow-actions/mail-sender/types/workflow-send-email-action-input.type';
|
||||||
|
import { WorkflowActionResult } from 'src/modules/workflow/workflow-executor/workflow-actions/types/workflow-action-result.type';
|
||||||
import { isDefined } from 'src/utils/is-defined';
|
import { isDefined } from 'src/utils/is-defined';
|
||||||
|
|
||||||
|
export type WorkflowSendEmailStepOutputSchema = {
|
||||||
|
success: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class SendEmailWorkflowAction implements WorkflowAction {
|
export class SendEmailWorkflowAction implements WorkflowAction {
|
||||||
private readonly logger = new Logger(SendEmailWorkflowAction.name);
|
private readonly logger = new Logger(SendEmailWorkflowAction.name);
|
||||||
@ -54,9 +55,9 @@ export class SendEmailWorkflowAction implements WorkflowAction {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (!isDefined(connectedAccount)) {
|
if (!isDefined(connectedAccount)) {
|
||||||
throw new MailSenderException(
|
throw new SendEmailActionException(
|
||||||
`Connected Account '${connectedAccountId}' not found`,
|
`Connected Account '${connectedAccountId}' not found`,
|
||||||
MailSenderExceptionCode.CONNECTED_ACCOUNT_NOT_FOUND,
|
SendEmailActionExceptionCode.CONNECTED_ACCOUNT_NOT_FOUND,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,20 +65,20 @@ export class SendEmailWorkflowAction implements WorkflowAction {
|
|||||||
case 'google':
|
case 'google':
|
||||||
return await this.gmailClientProvider.getGmailClient(connectedAccount);
|
return await this.gmailClientProvider.getGmailClient(connectedAccount);
|
||||||
default:
|
default:
|
||||||
throw new MailSenderException(
|
throw new SendEmailActionException(
|
||||||
`Provider ${connectedAccount.provider} is not supported`,
|
`Provider ${connectedAccount.provider} is not supported`,
|
||||||
MailSenderExceptionCode.PROVIDER_NOT_SUPPORTED,
|
SendEmailActionExceptionCode.PROVIDER_NOT_SUPPORTED,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async execute(
|
async execute(
|
||||||
workflowStepInput: WorkflowSendEmailStepInput,
|
workflowActionInput: WorkflowSendEmailActionInput,
|
||||||
): Promise<WorkflowActionResult> {
|
): Promise<WorkflowActionResult> {
|
||||||
const emailProvider = await this.getEmailClient(
|
const emailProvider = await this.getEmailClient(
|
||||||
workflowStepInput.connectedAccountId,
|
workflowActionInput.connectedAccountId,
|
||||||
);
|
);
|
||||||
const { email, body, subject } = workflowStepInput;
|
const { email, body, subject } = workflowActionInput;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const emailSchema = z.string().trim().email('Invalid email');
|
const emailSchema = z.string().trim().email('Invalid email');
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
export type WorkflowSendEmailActionInput = {
|
||||||
|
connectedAccountId: string;
|
||||||
|
email: string;
|
||||||
|
subject?: string;
|
||||||
|
body?: string;
|
||||||
|
};
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
import { WorkflowSendEmailActionInput } from 'src/modules/workflow/workflow-executor/workflow-actions/mail-sender/types/workflow-send-email-action-input.type';
|
||||||
|
import { BaseWorkflowActionSettings } from 'src/modules/workflow/workflow-executor/workflow-actions/types/workflow-action-settings.type';
|
||||||
|
|
||||||
|
export type WorkflowSendEmailActionSettings = BaseWorkflowActionSettings & {
|
||||||
|
input: WorkflowSendEmailActionInput;
|
||||||
|
};
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
import { Module } from '@nestjs/common';
|
||||||
|
|
||||||
|
import { RecordCRUDWorkflowAction } from 'src/modules/workflow/workflow-executor/workflow-actions/record-crud/record-crud.workflow-action';
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
providers: [RecordCRUDWorkflowAction],
|
||||||
|
exports: [RecordCRUDWorkflowAction],
|
||||||
|
})
|
||||||
|
export class RecordCRUDActionModule {}
|
||||||
@ -0,0 +1,45 @@
|
|||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
|
||||||
|
import { WorkflowAction } from 'src/modules/workflow/workflow-executor/interfaces/workflow-action.interface';
|
||||||
|
|
||||||
|
import { TwentyORMManager } from 'src/engine/twenty-orm/twenty-orm.manager';
|
||||||
|
import {
|
||||||
|
WorkflowCreateRecordActionInput,
|
||||||
|
WorkflowRecordCRUDActionInput,
|
||||||
|
WorkflowRecordCRUDType,
|
||||||
|
} from 'src/modules/workflow/workflow-executor/workflow-actions/record-crud/types/workflow-record-crud-action-input.type';
|
||||||
|
import { WorkflowActionResult } from 'src/modules/workflow/workflow-executor/workflow-actions/types/workflow-action-result.type';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class RecordCRUDWorkflowAction implements WorkflowAction {
|
||||||
|
constructor(private readonly twentyORMManager: TwentyORMManager) {}
|
||||||
|
|
||||||
|
async execute(
|
||||||
|
workflowActionInput: WorkflowRecordCRUDActionInput,
|
||||||
|
): Promise<WorkflowActionResult> {
|
||||||
|
switch (workflowActionInput.type) {
|
||||||
|
case WorkflowRecordCRUDType.CREATE:
|
||||||
|
return this.createRecord(workflowActionInput);
|
||||||
|
default:
|
||||||
|
throw new Error(
|
||||||
|
`Unknown record operation type: ${workflowActionInput.type}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async createRecord(
|
||||||
|
workflowActionInput: WorkflowCreateRecordActionInput,
|
||||||
|
): Promise<WorkflowActionResult> {
|
||||||
|
const repository = await this.twentyORMManager.getRepository(
|
||||||
|
workflowActionInput.objectName,
|
||||||
|
);
|
||||||
|
|
||||||
|
const objectRecord = await repository.create(
|
||||||
|
workflowActionInput.objectRecord,
|
||||||
|
);
|
||||||
|
|
||||||
|
const createdObjectRecord = await repository.save(objectRecord);
|
||||||
|
|
||||||
|
return { result: createdObjectRecord };
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,31 @@
|
|||||||
|
type ObjectRecord = Record<string, any>;
|
||||||
|
|
||||||
|
export enum WorkflowRecordCRUDType {
|
||||||
|
CREATE = 'create',
|
||||||
|
UPDATE = 'update',
|
||||||
|
DELETE = 'delete',
|
||||||
|
}
|
||||||
|
|
||||||
|
export type WorkflowCreateRecordActionInput = {
|
||||||
|
type: WorkflowRecordCRUDType.CREATE;
|
||||||
|
objectName: string;
|
||||||
|
objectRecord: ObjectRecord;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type WorkflowUpdateRecordActionInput = {
|
||||||
|
type: WorkflowRecordCRUDType.UPDATE;
|
||||||
|
objectName: string;
|
||||||
|
objectRecord: ObjectRecord;
|
||||||
|
objectRecordId: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type WorkflowDeleteRecordActionInput = {
|
||||||
|
type: WorkflowRecordCRUDType.DELETE;
|
||||||
|
objectName: string;
|
||||||
|
objectRecordId: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type WorkflowRecordCRUDActionInput =
|
||||||
|
| WorkflowCreateRecordActionInput
|
||||||
|
| WorkflowUpdateRecordActionInput
|
||||||
|
| WorkflowDeleteRecordActionInput;
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
import { WorkflowRecordCRUDActionInput } from 'src/modules/workflow/workflow-executor/workflow-actions/record-crud/types/workflow-record-crud-action-input.type';
|
||||||
|
import { BaseWorkflowActionSettings } from 'src/modules/workflow/workflow-executor/workflow-actions/types/workflow-action-settings.type';
|
||||||
|
|
||||||
|
export type WorkflowRecordCRUDActionSettings = BaseWorkflowActionSettings & {
|
||||||
|
input: WorkflowRecordCRUDActionInput;
|
||||||
|
};
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
import { WorkflowCodeActionSettings } from 'src/modules/workflow/workflow-executor/workflow-actions/code/types/workflow-code-action-settings.type';
|
||||||
|
import { WorkflowSendEmailActionSettings } from 'src/modules/workflow/workflow-executor/workflow-actions/mail-sender/types/workflow-send-email-action-settings.type';
|
||||||
|
import { WorkflowRecordCRUDActionSettings } from 'src/modules/workflow/workflow-executor/workflow-actions/record-crud/types/workflow-record-crud-action-settings.type';
|
||||||
|
|
||||||
|
export type OutputSchema = object;
|
||||||
|
|
||||||
|
export type BaseWorkflowActionSettings = {
|
||||||
|
input: object;
|
||||||
|
outputSchema: OutputSchema;
|
||||||
|
errorHandlingOptions: {
|
||||||
|
retryOnFailure: {
|
||||||
|
value: boolean;
|
||||||
|
};
|
||||||
|
continueOnFailure: {
|
||||||
|
value: boolean;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export type WorkflowActionSettings =
|
||||||
|
| WorkflowSendEmailActionSettings
|
||||||
|
| WorkflowCodeActionSettings
|
||||||
|
| WorkflowRecordCRUDActionSettings;
|
||||||
@ -0,0 +1,38 @@
|
|||||||
|
import { WorkflowCodeActionSettings } from 'src/modules/workflow/workflow-executor/workflow-actions/code/types/workflow-code-action-settings.type';
|
||||||
|
import { WorkflowSendEmailActionSettings } from 'src/modules/workflow/workflow-executor/workflow-actions/mail-sender/types/workflow-send-email-action-settings.type';
|
||||||
|
import { WorkflowRecordCRUDActionSettings } from 'src/modules/workflow/workflow-executor/workflow-actions/record-crud/types/workflow-record-crud-action-settings.type';
|
||||||
|
import { WorkflowActionSettings } from 'src/modules/workflow/workflow-executor/workflow-actions/types/workflow-action-settings.type';
|
||||||
|
|
||||||
|
export enum WorkflowActionType {
|
||||||
|
CODE = 'CODE',
|
||||||
|
SEND_EMAIL = 'SEND_EMAIL',
|
||||||
|
RECORD_CRUD = 'RECORD_CRUD',
|
||||||
|
}
|
||||||
|
|
||||||
|
type BaseWorkflowAction = {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
type: WorkflowActionType;
|
||||||
|
settings: WorkflowActionSettings;
|
||||||
|
valid: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type WorkflowCodeAction = BaseWorkflowAction & {
|
||||||
|
type: WorkflowActionType.CODE;
|
||||||
|
settings: WorkflowCodeActionSettings;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type WorkflowSendEmailAction = BaseWorkflowAction & {
|
||||||
|
type: WorkflowActionType.SEND_EMAIL;
|
||||||
|
settings: WorkflowSendEmailActionSettings;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type WorkflowRecordCRUDAction = BaseWorkflowAction & {
|
||||||
|
type: WorkflowActionType.RECORD_CRUD;
|
||||||
|
settings: WorkflowRecordCRUDActionSettings;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type WorkflowAction =
|
||||||
|
| WorkflowCodeAction
|
||||||
|
| WorkflowSendEmailAction
|
||||||
|
| WorkflowRecordCRUDAction;
|
||||||
@ -1,26 +1,24 @@
|
|||||||
import { Module } from '@nestjs/common';
|
import { Module } from '@nestjs/common';
|
||||||
|
|
||||||
import { ServerlessFunctionModule } from 'src/engine/metadata-modules/serverless-function/serverless-function.module';
|
|
||||||
import { ScopedWorkspaceContextFactory } from 'src/engine/twenty-orm/factories/scoped-workspace-context.factory';
|
import { ScopedWorkspaceContextFactory } from 'src/engine/twenty-orm/factories/scoped-workspace-context.factory';
|
||||||
import { SendEmailWorkflowAction } from 'src/modules/mail-sender/workflow-actions/send-email.workflow-action';
|
|
||||||
import { MessagingGmailDriverModule } from 'src/modules/messaging/message-import-manager/drivers/gmail/messaging-gmail-driver.module';
|
|
||||||
import { CodeWorkflowAction } from 'src/modules/serverless/workflow-actions/code.workflow-action';
|
|
||||||
import { WorkflowCommonModule } from 'src/modules/workflow/common/workflow-common.module';
|
import { WorkflowCommonModule } from 'src/modules/workflow/common/workflow-common.module';
|
||||||
import { WorkflowActionFactory } from 'src/modules/workflow/workflow-executor/factories/workflow-action.factory';
|
import { WorkflowActionFactory } from 'src/modules/workflow/workflow-executor/factories/workflow-action.factory';
|
||||||
|
import { CodeActionModule } from 'src/modules/workflow/workflow-executor/workflow-actions/code/code-action.module';
|
||||||
|
import { SendEmailActionModule } from 'src/modules/workflow/workflow-executor/workflow-actions/mail-sender/send-email-action.module';
|
||||||
|
import { RecordCRUDActionModule } from 'src/modules/workflow/workflow-executor/workflow-actions/record-crud/record-crud-action.module';
|
||||||
import { WorkflowExecutorWorkspaceService } from 'src/modules/workflow/workflow-executor/workspace-services/workflow-executor.workspace-service';
|
import { WorkflowExecutorWorkspaceService } from 'src/modules/workflow/workflow-executor/workspace-services/workflow-executor.workspace-service';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
WorkflowCommonModule,
|
WorkflowCommonModule,
|
||||||
ServerlessFunctionModule,
|
CodeActionModule,
|
||||||
MessagingGmailDriverModule,
|
SendEmailActionModule,
|
||||||
|
RecordCRUDActionModule,
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
WorkflowExecutorWorkspaceService,
|
WorkflowExecutorWorkspaceService,
|
||||||
ScopedWorkspaceContextFactory,
|
ScopedWorkspaceContextFactory,
|
||||||
WorkflowActionFactory,
|
WorkflowActionFactory,
|
||||||
CodeWorkflowAction,
|
|
||||||
SendEmailWorkflowAction,
|
|
||||||
],
|
],
|
||||||
exports: [WorkflowExecutorWorkspaceService],
|
exports: [WorkflowExecutorWorkspaceService],
|
||||||
})
|
})
|
||||||
|
|||||||
@ -5,8 +5,8 @@ import {
|
|||||||
WorkflowRunStatus,
|
WorkflowRunStatus,
|
||||||
} from 'src/modules/workflow/common/standard-objects/workflow-run.workspace-entity';
|
} from 'src/modules/workflow/common/standard-objects/workflow-run.workspace-entity';
|
||||||
import { WorkflowActionFactory } from 'src/modules/workflow/workflow-executor/factories/workflow-action.factory';
|
import { WorkflowActionFactory } from 'src/modules/workflow/workflow-executor/factories/workflow-action.factory';
|
||||||
import { WorkflowStep } from 'src/modules/workflow/workflow-executor/types/workflow-action.type';
|
|
||||||
import { resolveInput } from 'src/modules/workflow/workflow-executor/utils/variable-resolver.util';
|
import { resolveInput } from 'src/modules/workflow/workflow-executor/utils/variable-resolver.util';
|
||||||
|
import { WorkflowAction } from 'src/modules/workflow/workflow-executor/workflow-actions/types/workflow-action.type';
|
||||||
|
|
||||||
const MAX_RETRIES_ON_FAILURE = 3;
|
const MAX_RETRIES_ON_FAILURE = 3;
|
||||||
|
|
||||||
@ -27,7 +27,7 @@ export class WorkflowExecutorWorkspaceService {
|
|||||||
attemptCount = 1,
|
attemptCount = 1,
|
||||||
}: {
|
}: {
|
||||||
currentStepIndex: number;
|
currentStepIndex: number;
|
||||||
steps: WorkflowStep[];
|
steps: WorkflowAction[];
|
||||||
output: WorkflowExecutorOutput;
|
output: WorkflowExecutorOutput;
|
||||||
context: Record<string, unknown>;
|
context: Record<string, unknown>;
|
||||||
attemptCount?: number;
|
attemptCount?: number;
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { OutputSchema } from 'src/modules/workflow/workflow-executor/types/workflow-step-settings.type';
|
import { OutputSchema } from 'src/modules/workflow/workflow-executor/workflow-actions/types/workflow-action-settings.type';
|
||||||
|
|
||||||
export enum WorkflowTriggerType {
|
export enum WorkflowTriggerType {
|
||||||
DATABASE_EVENT = 'DATABASE_EVENT',
|
DATABASE_EVENT = 'DATABASE_EVENT',
|
||||||
|
|||||||
Reference in New Issue
Block a user