Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

6658 workflows add a first twenty piece email sender #6965

Merged
merged 24 commits into from
Sep 12, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Remove useless factory
  • Loading branch information
martmull committed Sep 11, 2024
commit 77e78a853001daa291e491dfd4da5a35fc33339d

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
import { WorkflowCodeSettings } from 'src/modules/workflow/common/types/settings/workflow-code-settings.type';
import { WorkflowSystemActionSettings } from 'src/modules/workflow/common/types/settings/workflow-system-action-settings.type';

export enum WorkflowStepType {
CODE_ACTION = 'CODE_ACTION',
SYSTEM_ACTION = 'SYSTEM_ACTION',
SEND_EMAIL_ACTION = 'SEND_EMAIL_ACTION',
}

type BaseWorkflowSettings = {
errorHandlingOptions: {
retryOnFailure: {
martmull marked this conversation as resolved.
Show resolved Hide resolved
value: boolean;
};
continueOnFailure: {
value: boolean;
};
};
};

type BaseWorkflowStep = {
id: string;
name: string;
Expand All @@ -14,12 +22,22 @@ type BaseWorkflowStep = {

export type WorkflowCodeStep = BaseWorkflowStep & {
type: WorkflowStepType.CODE_ACTION;
settings: WorkflowCodeSettings;
settings: BaseWorkflowSettings & {
serverlessFunctionId: string;
martmull marked this conversation as resolved.
Show resolved Hide resolved
};
};

export type WorkflowSystemStep = BaseWorkflowStep & {
type: WorkflowStepType.SYSTEM_ACTION;
settings: WorkflowSystemActionSettings;
export type WorkflowSendEmailStep = BaseWorkflowStep & {
type: WorkflowStepType.SEND_EMAIL_ACTION;
settings: BaseWorkflowSettings & {
subject?: string;
template?: string;
title?: string;
callToAction?: {
value: string;
href: string;
};
};
};

export type WorkflowStep = WorkflowCodeStep | WorkflowSystemStep;
export type WorkflowStep = WorkflowCodeStep | WorkflowSendEmailStep;

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,9 @@ import {
WorkflowStepExecutorException,
WorkflowStepExecutorExceptionCode,
} from 'src/modules/workflow/workflow-step-executor/workflow-step-executor.exception';
import { WorkflowStepExecutor } from 'src/modules/workflow/workflow-step-executor/workflow-step-executor.interface';

@Injectable()
export class CodeActionExecutor implements WorkflowStepExecutor {
export class CodeActionExecutorFactory {
constructor(
private readonly serverlessFunctionService: ServerlessFunctionService,
private readonly scopedWorkspaceContextFactory: ScopedWorkspaceContextFactory,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { Injectable, Logger } from '@nestjs/common';

import { z } from 'zod';
import Handlebars from 'handlebars';
import { JSDOM } from 'jsdom';
import DOMPurify from 'dompurify';
import { WorkflowActionEmail } from 'twenty-emails';
import { render } from '@react-email/components';

import { WorkflowStepResult } from 'src/modules/workflow/common/types/workflow-step-result.type';
import { WorkflowSendEmailStep } from 'src/modules/workflow/common/types/workflow-step.type';
import { EnvironmentService } from 'src/engine/integrations/environment/environment.service';
import { EmailService } from 'src/engine/integrations/email/email.service';

@Injectable()
export class SendEmailActionExecutorFactory {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is not a factory to me : a factory is providing an implementation of an abstract service.
I feel we are over-using this factory naming in the backend codebase

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, I felt the same, but it is done like that everywhere else in the project, so I did the same

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New naming proposal for factories:
image

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

workflow-step-executors instead of factories actually

private readonly logger = new Logger(SendEmailActionExecutorFactory.name);
constructor(
private readonly environmentService: EnvironmentService,
private readonly emailService: EmailService,
) {}

async execute({
step,
payload,
}: {
step: WorkflowSendEmailStep;
payload: {
email: string;
[key: string]: string;
};
}): Promise<WorkflowStepResult> {
try {
const emailSchema = z.string().trim().email('Invalid email');

const result = emailSchema.safeParse(payload.email);

if (!result.success) {
this.logger.warn(`Email '${payload.email}' invalid`);

return { data: { success: false } };
}

const mainText = Handlebars.compile(step.settings.template)(payload);

const window = new JSDOM('').window;
const purify = DOMPurify(window);
const safeHTML = purify.sanitize(mainText || '');

const email = WorkflowActionEmail({
dangerousHTML: safeHTML,
title: step.settings.title,
callToAction: step.settings.callToAction,
});
const html = render(email, {
pretty: true,
});
const text = render(email, {
plainText: true,
});

await this.emailService.send({
from: `${this.environmentService.get(
'EMAIL_FROM_NAME',
)} <${this.environmentService.get('EMAIL_FROM_ADDRESS')}>`,
to: payload.email,
subject: step.settings.subject || '',
text,
html,
});

return { data: { success: true } };
} catch (error) {
return { error };
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,22 @@ import {
WorkflowStepExecutorExceptionCode,
} from 'src/modules/workflow/workflow-step-executor/workflow-step-executor.exception';
import { WorkflowStepExecutor } from 'src/modules/workflow/workflow-step-executor/workflow-step-executor.interface';
import { CodeActionExecutor } from 'src/modules/workflow/workflow-step-executor/workflow-step-executors/code-action-executor';
import { SystemActionExecutor } from 'src/modules/workflow/workflow-step-executor/workflow-step-executors/system-action-executor';
import { CodeActionExecutorFactory } from 'src/modules/workflow/workflow-step-executor/factories/code-action-executor.factory';
import { SendEmailActionExecutorFactory } from 'src/modules/workflow/workflow-step-executor/factories/send-email-action-executor.factory';

@Injectable()
export class WorkflowStepExecutorFactory {
constructor(
private readonly codeActionExecutor: CodeActionExecutor,
private readonly systemActionExecutor: SystemActionExecutor,
private readonly codeActionExecutor: CodeActionExecutorFactory,
private readonly sendEmailActionExecutor: SendEmailActionExecutorFactory,
) {}

get(stepType: WorkflowStepType): WorkflowStepExecutor {
switch (stepType) {
case WorkflowStepType.CODE_ACTION:
return this.codeActionExecutor;
case WorkflowStepType.SYSTEM_ACTION:
return this.systemActionExecutor;
case WorkflowStepType.SEND_EMAIL_ACTION:
return this.sendEmailActionExecutor;
default:
throw new WorkflowStepExecutorException(
`Workflow step executor not found for step type '${stepType}'`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,15 @@ 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 { WorkflowStepExecutorFactory } from 'src/modules/workflow/workflow-step-executor/workflow-step-executor.factory';
import { CodeActionExecutor } from 'src/modules/workflow/workflow-step-executor/workflow-step-executors/code-action-executor';
import { SystemActionExecutor } from 'src/modules/workflow/workflow-step-executor/workflow-step-executors/system-action-executor';
import { WorkflowSystemActionModule } from 'src/modules/workflow/workflow-system-action/workflow-system-action.module';
import { CodeActionExecutorFactory } from 'src/modules/workflow/workflow-step-executor/factories/code-action-executor.factory';
import { SendEmailActionExecutorFactory } from 'src/modules/workflow/workflow-step-executor/factories/send-email-action-executor.factory';

@Module({
imports: [ServerlessFunctionModule, WorkflowSystemActionModule],
imports: [ServerlessFunctionModule],
providers: [
WorkflowStepExecutorFactory,
CodeActionExecutor,
SystemActionExecutor,
CodeActionExecutorFactory,
SendEmailActionExecutorFactory,
ScopedWorkspaceContextFactory,
],
exports: [WorkflowStepExecutorFactory],
Expand Down

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

Loading
Loading