Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3881cdd675 | |||
| 892022de04 |
@@ -1454,6 +1454,7 @@ type EmailingDomain {
|
||||
|
||||
enum EmailingDomainDriver {
|
||||
AWS_SES
|
||||
LOG
|
||||
}
|
||||
|
||||
enum EmailingDomainStatus {
|
||||
|
||||
@@ -1111,7 +1111,7 @@ export interface EmailingDomain {
|
||||
__typename: 'EmailingDomain'
|
||||
}
|
||||
|
||||
export type EmailingDomainDriver = 'AWS_SES'
|
||||
export type EmailingDomainDriver = 'AWS_SES' | 'LOG'
|
||||
|
||||
export type EmailingDomainStatus = 'PENDING' | 'VERIFIED' | 'FAILED' | 'TEMPORARY_FAILURE'
|
||||
|
||||
@@ -8733,7 +8733,8 @@ export const enumPageLayoutType = {
|
||||
}
|
||||
|
||||
export const enumEmailingDomainDriver = {
|
||||
AWS_SES: 'AWS_SES' as const
|
||||
AWS_SES: 'AWS_SES' as const,
|
||||
LOG: 'LOG' as const
|
||||
}
|
||||
|
||||
export const enumEmailingDomainStatus = {
|
||||
|
||||
@@ -1473,7 +1473,8 @@ export type EmailingDomain = {
|
||||
};
|
||||
|
||||
export enum EmailingDomainDriver {
|
||||
AWS_SES = 'AWS_SES'
|
||||
AWS_SES = 'AWS_SES',
|
||||
LOG = 'LOG'
|
||||
}
|
||||
|
||||
export enum EmailingDomainStatus {
|
||||
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
import { type QueryRunner } from 'typeorm';
|
||||
|
||||
import { RegisteredInstanceCommand } from 'src/engine/core-modules/upgrade/decorators/registered-instance-command.decorator';
|
||||
import { type FastInstanceCommand } from 'src/engine/core-modules/upgrade/interfaces/fast-instance-command.interface';
|
||||
|
||||
@RegisteredInstanceCommand('2.11.0', 1780754108000)
|
||||
export class AddLogEmailingDomainDriverFastInstanceCommand
|
||||
implements FastInstanceCommand
|
||||
{
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`ALTER TYPE "core"."emailingDomain_driver_enum" ADD VALUE IF NOT EXISTS 'LOG' AFTER 'AWS_SES'`,
|
||||
);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."emailingDomain" ALTER COLUMN "driver" TYPE character varying`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`UPDATE "core"."emailingDomain" SET "driver" = 'AWS_SES' WHERE "driver" = 'LOG'`,
|
||||
);
|
||||
await queryRunner.query(`DROP TYPE "core"."emailingDomain_driver_enum"`);
|
||||
await queryRunner.query(
|
||||
`CREATE TYPE "core"."emailingDomain_driver_enum" AS ENUM('AWS_SES')`,
|
||||
);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."emailingDomain" ALTER COLUMN "driver" TYPE "core"."emailingDomain_driver_enum" USING "driver"::"core"."emailingDomain_driver_enum"`,
|
||||
);
|
||||
}
|
||||
}
|
||||
+2
@@ -59,6 +59,7 @@ import { EmailingDomainTenantStatusAndGlobalUniquenessFastInstanceCommand } from
|
||||
import { AddLogicFunctionExecutionModeFastInstanceCommand } from 'src/database/commands/upgrade-version-command/2-9/2-9-instance-command-fast-1799000030000-add-logic-function-execution-mode';
|
||||
import { EncryptNonSecretApplicationVariableSlowInstanceCommand } from 'src/database/commands/upgrade-version-command/2-9/2-9-instance-command-slow-1798400000000-encrypt-non-secret-application-variable';
|
||||
import { MigrateAiModelPreferencesSlowInstanceCommand } from 'src/database/commands/upgrade-version-command/2-9/2-9-instance-command-slow-1799000010000-migrate-ai-model-preferences';
|
||||
import { AddLogEmailingDomainDriverFastInstanceCommand } from 'src/database/commands/upgrade-version-command/2-11/2-11-instance-command-fast-1780754108000-add-log-emailing-domain-driver';
|
||||
|
||||
export const INSTANCE_COMMANDS = [
|
||||
AddViewFieldGroupIdIndexOnViewFieldFastInstanceCommand,
|
||||
@@ -120,4 +121,5 @@ export const INSTANCE_COMMANDS = [
|
||||
AddLogicFunctionExecutionModeFastInstanceCommand,
|
||||
MigrateAiModelPreferencesSlowInstanceCommand,
|
||||
EncryptNonSecretApplicationVariableSlowInstanceCommand,
|
||||
AddLogEmailingDomainDriverFastInstanceCommand,
|
||||
];
|
||||
|
||||
+18
-9
@@ -8,6 +8,7 @@ import { AwsSesRegisterDomainService } from 'src/engine/core-modules/emailing-do
|
||||
import { AwsSesDriver } from 'src/engine/core-modules/emailing-domain/drivers/aws-ses/services/aws-ses-driver.service';
|
||||
import { AwsSesHandleErrorService } from 'src/engine/core-modules/emailing-domain/drivers/aws-ses/services/aws-ses-handle-error.service';
|
||||
import { AwsSesSendEmailService } from 'src/engine/core-modules/emailing-domain/drivers/aws-ses/services/aws-ses-send-email.service';
|
||||
import { LogEmailingDomainDriver } from 'src/engine/core-modules/emailing-domain/drivers/log/services/log-emailing-domain-driver.service';
|
||||
import { EmailingDomainDriver } from 'src/engine/core-modules/emailing-domain/drivers/types/emailing-domain-driver.type';
|
||||
import { DriverFactoryBase } from 'src/engine/core-modules/twenty-config/dynamic-factory.base';
|
||||
import { ConfigVariablesGroup } from 'src/engine/core-modules/twenty-config/enums/config-variables-group.enum';
|
||||
@@ -23,26 +24,31 @@ export class EmailingDomainDriverFactory extends DriverFactoryBase<EmailingDomai
|
||||
private readonly awsSesHandleErrorService: AwsSesHandleErrorService,
|
||||
private readonly awsSesRegisterDomainService: AwsSesRegisterDomainService,
|
||||
private readonly awsSesSendEmailService: AwsSesSendEmailService,
|
||||
private readonly logEmailingDomainDriver: LogEmailingDomainDriver,
|
||||
) {
|
||||
super(twentyConfigService, configGroupHashService);
|
||||
}
|
||||
|
||||
protected buildConfigKey(): string {
|
||||
const driver = EmailingDomainDriver.AWS_SES;
|
||||
const driver = this.twentyConfigService.get('EMAILING_DOMAIN_DRIVER');
|
||||
|
||||
if (driver === EmailingDomainDriver.AWS_SES) {
|
||||
const awsConfigHash = this.configGroupHashService.computeHash(
|
||||
ConfigVariablesGroup.AWS_SES_SETTINGS,
|
||||
);
|
||||
switch (driver) {
|
||||
case EmailingDomainDriver.AWS_SES: {
|
||||
const awsConfigHash = this.configGroupHashService.computeHash(
|
||||
ConfigVariablesGroup.AWS_SES_SETTINGS,
|
||||
);
|
||||
|
||||
return `aws-ses|${awsConfigHash}`;
|
||||
return `aws-ses|${awsConfigHash}`;
|
||||
}
|
||||
case EmailingDomainDriver.LOG:
|
||||
return 'log';
|
||||
default:
|
||||
throw new Error(`Unsupported emailing domain driver: ${driver}`);
|
||||
}
|
||||
|
||||
throw new Error(`Unsupported emailing domain driver: ${driver}`);
|
||||
}
|
||||
|
||||
protected createDriver(): EmailingDomainDriverInterface {
|
||||
const driver = EmailingDomainDriver.AWS_SES;
|
||||
const driver = this.twentyConfigService.get('EMAILING_DOMAIN_DRIVER');
|
||||
|
||||
switch (driver) {
|
||||
case EmailingDomainDriver.AWS_SES: {
|
||||
@@ -76,6 +82,9 @@ export class EmailingDomainDriverFactory extends DriverFactoryBase<EmailingDomai
|
||||
);
|
||||
}
|
||||
|
||||
case EmailingDomainDriver.LOG:
|
||||
return this.logEmailingDomainDriver;
|
||||
|
||||
default:
|
||||
throw new Error(`Invalid emailing domain driver: ${driver}`);
|
||||
}
|
||||
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import {
|
||||
type EmailingDomainDriverInterface,
|
||||
type EmailingDomainResourceInput,
|
||||
type EmailingDomainVerificationResult,
|
||||
} from 'src/engine/core-modules/emailing-domain/drivers/interfaces/emailing-domain-driver.interface';
|
||||
import { EmailingDomainStatus } from 'src/engine/core-modules/emailing-domain/drivers/types/emailing-domain-status.type';
|
||||
import {
|
||||
type EmailingDomainSendEmailInput,
|
||||
type EmailingDomainSendEmailResult,
|
||||
} from 'src/engine/core-modules/emailing-domain/drivers/types/send-email';
|
||||
|
||||
@Injectable()
|
||||
export class LogEmailingDomainDriver implements EmailingDomainDriverInterface {
|
||||
private readonly logger = new Logger(LogEmailingDomainDriver.name);
|
||||
|
||||
async provisionWorkspace(workspaceId: string): Promise<void> {
|
||||
this.logger.log(`[log-driver] provisionWorkspace(${workspaceId})`);
|
||||
}
|
||||
|
||||
async deprovisionWorkspace(workspaceId: string): Promise<void> {
|
||||
this.logger.log(`[log-driver] deprovisionWorkspace(${workspaceId})`);
|
||||
}
|
||||
|
||||
async verifyDomain(
|
||||
input: EmailingDomainResourceInput,
|
||||
): Promise<EmailingDomainVerificationResult> {
|
||||
this.logger.log(
|
||||
`[log-driver] verifyDomain(${input.domain}) → VERIFIED (instant)`,
|
||||
);
|
||||
|
||||
return {
|
||||
status: EmailingDomainStatus.VERIFIED,
|
||||
verificationRecords: [],
|
||||
};
|
||||
}
|
||||
|
||||
async getDomainStatus(
|
||||
input: EmailingDomainResourceInput,
|
||||
): Promise<EmailingDomainVerificationResult> {
|
||||
this.logger.log(`[log-driver] getDomainStatus(${input.domain}) → VERIFIED`);
|
||||
|
||||
return {
|
||||
status: EmailingDomainStatus.VERIFIED,
|
||||
verificationRecords: [],
|
||||
};
|
||||
}
|
||||
|
||||
async registerDomain(input: EmailingDomainResourceInput): Promise<void> {
|
||||
this.logger.log(`[log-driver] registerDomain(${input.domain})`);
|
||||
}
|
||||
|
||||
async cleanupDomain(input: EmailingDomainResourceInput): Promise<void> {
|
||||
this.logger.log(`[log-driver] cleanupDomain(${input.domain})`);
|
||||
}
|
||||
|
||||
async sendEmail(
|
||||
input: EmailingDomainSendEmailInput,
|
||||
): Promise<EmailingDomainSendEmailResult> {
|
||||
const messageId = `log-${v4()}`;
|
||||
|
||||
this.logger.log(
|
||||
`[log-driver] sendEmail from=${input.from} to=${input.to.join(',')} subject="${input.subject}" → fake messageId=${messageId}`,
|
||||
);
|
||||
|
||||
return { messageId };
|
||||
}
|
||||
}
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
export enum EmailingDomainDriver {
|
||||
AWS_SES = 'AWS_SES',
|
||||
LOG = 'LOG',
|
||||
}
|
||||
|
||||
+2
@@ -8,6 +8,7 @@ import { AwsSesRegisterDomainService } from 'src/engine/core-modules/emailing-do
|
||||
import { AwsSesHandleErrorService } from 'src/engine/core-modules/emailing-domain/drivers/aws-ses/services/aws-ses-handle-error.service';
|
||||
import { AwsSesSendEmailService } from 'src/engine/core-modules/emailing-domain/drivers/aws-ses/services/aws-ses-send-email.service';
|
||||
import { EmailingDomainDriverFactory } from 'src/engine/core-modules/emailing-domain/drivers/emailing-domain-driver.factory';
|
||||
import { LogEmailingDomainDriver } from 'src/engine/core-modules/emailing-domain/drivers/log/services/log-emailing-domain-driver.service';
|
||||
import { EmailingDomainEntity } from 'src/engine/core-modules/emailing-domain/emailing-domain.entity';
|
||||
import { EmailingDomainResolver } from 'src/engine/core-modules/emailing-domain/emailing-domain.resolver';
|
||||
import { EmailingDomainWorkspaceCleanupJob } from 'src/engine/core-modules/emailing-domain/jobs/emailing-domain-workspace-cleanup.job';
|
||||
@@ -34,6 +35,7 @@ import { provideWorkspaceScopedRepository } from 'src/engine/twenty-orm/workspac
|
||||
AwsSesHandleErrorService,
|
||||
AwsSesRegisterDomainService,
|
||||
AwsSesSendEmailService,
|
||||
LogEmailingDomainDriver,
|
||||
provideWorkspaceScopedRepository(EmailingDomainEntity),
|
||||
],
|
||||
})
|
||||
|
||||
@@ -20,6 +20,7 @@ import { SupportDriver } from 'src/engine/core-modules/twenty-config/interfaces/
|
||||
import { CaptchaDriverType } from 'src/engine/core-modules/captcha/interfaces';
|
||||
import { CodeInterpreterDriverType } from 'src/engine/core-modules/code-interpreter/code-interpreter.interface';
|
||||
import { EmailDriver } from 'src/engine/core-modules/email/enums/email-driver.enum';
|
||||
import { EmailingDomainDriver } from 'src/engine/core-modules/emailing-domain/drivers/types/emailing-domain-driver.type';
|
||||
import { ExceptionHandlerDriver } from 'src/engine/core-modules/exception-handler/interfaces';
|
||||
import { StorageDriverType } from 'src/engine/core-modules/file-storage/interfaces';
|
||||
import { LoggerDriverType } from 'src/engine/core-modules/logger/interfaces';
|
||||
@@ -1697,6 +1698,16 @@ export class ConfigVariables {
|
||||
@IsOptional()
|
||||
MINTLIFY_SUBDOMAIN: string;
|
||||
|
||||
@ConfigVariablesMetadata({
|
||||
group: ConfigVariablesGroup.AWS_SES_SETTINGS,
|
||||
description:
|
||||
'Driver used for the emailing domain feature — AWS_SES for production, LOG for local development (no AWS credentials needed)',
|
||||
type: ConfigVariableType.ENUM,
|
||||
options: Object.values(EmailingDomainDriver),
|
||||
})
|
||||
@CastToUpperSnakeCase()
|
||||
EMAILING_DOMAIN_DRIVER: EmailingDomainDriver = EmailingDomainDriver.AWS_SES;
|
||||
|
||||
@ConfigVariablesMetadata({
|
||||
group: ConfigVariablesGroup.AWS_SES_SETTINGS,
|
||||
description: 'AWS region',
|
||||
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
import { type QueryRunner } from 'typeorm';
|
||||
|
||||
import { EmailingDomainDriver } from 'src/engine/core-modules/emailing-domain/drivers/types/emailing-domain-driver.type';
|
||||
import { EmailingDomainStatus } from 'src/engine/core-modules/emailing-domain/drivers/types/emailing-domain-status.type';
|
||||
import { EmailingDomainTenantStatus } from 'src/engine/core-modules/emailing-domain/drivers/types/emailing-domain-tenant-status.type';
|
||||
|
||||
const tableName = 'emailingDomain';
|
||||
|
||||
const DEV_EMAILING_DOMAIN = 'dev.twenty.local';
|
||||
|
||||
type SeedEmailingDomainsArgs = {
|
||||
queryRunner: QueryRunner;
|
||||
schemaName: string;
|
||||
workspaceId: string;
|
||||
};
|
||||
|
||||
export const seedEmailingDomains = async ({
|
||||
queryRunner,
|
||||
schemaName,
|
||||
workspaceId,
|
||||
}: SeedEmailingDomainsArgs) => {
|
||||
const domain = `${workspaceId.slice(0, 8)}.${DEV_EMAILING_DOMAIN}`;
|
||||
|
||||
await queryRunner.manager
|
||||
.createQueryBuilder()
|
||||
.insert()
|
||||
.into(`${schemaName}.${tableName}`, [
|
||||
'workspaceId',
|
||||
'domain',
|
||||
'driver',
|
||||
'status',
|
||||
'verificationRecords',
|
||||
'verifiedAt',
|
||||
'tenantStatus',
|
||||
])
|
||||
.orIgnore()
|
||||
.values([
|
||||
{
|
||||
workspaceId,
|
||||
domain,
|
||||
driver: EmailingDomainDriver.LOG,
|
||||
status: EmailingDomainStatus.VERIFIED,
|
||||
verificationRecords: JSON.stringify([]),
|
||||
verifiedAt: new Date(),
|
||||
tenantStatus: EmailingDomainTenantStatus.ACTIVE,
|
||||
},
|
||||
])
|
||||
.execute();
|
||||
};
|
||||
+8
@@ -6,6 +6,7 @@ import { v4 } from 'uuid';
|
||||
|
||||
import { ApplicationRegistrationService } from 'src/engine/core-modules/application/application-registration/application-registration.service';
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/application.service';
|
||||
import { EmailingDomainDriver } from 'src/engine/core-modules/emailing-domain/drivers/types/emailing-domain-driver.type';
|
||||
import { SdkClientGenerationService } from 'src/engine/core-modules/sdk-client/sdk-client-generation.service';
|
||||
import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service';
|
||||
import { UpgradeMigrationService } from 'src/engine/core-modules/upgrade/services/upgrade-migration.service';
|
||||
@@ -27,6 +28,7 @@ import {
|
||||
import { DevSeederPermissionsService } from 'src/engine/workspace-manager/dev-seeder/core/services/dev-seeder-permissions.service';
|
||||
import { seedAgents } from 'src/engine/workspace-manager/dev-seeder/core/utils/seed-agents.util';
|
||||
import { seedApiKeys } from 'src/engine/workspace-manager/dev-seeder/core/utils/seed-api-keys.util';
|
||||
import { seedEmailingDomains } from 'src/engine/workspace-manager/dev-seeder/core/utils/seed-emailing-domains.util';
|
||||
import { seedFeatureFlags } from 'src/engine/workspace-manager/dev-seeder/core/utils/seed-feature-flags.util';
|
||||
import { seedMetadataEntities } from 'src/engine/workspace-manager/dev-seeder/core/utils/seed-metadata-entities.util';
|
||||
import { seedPageLayouts } from 'src/engine/workspace-manager/dev-seeder/core/utils/seed-page-layouts.util';
|
||||
@@ -319,6 +321,12 @@ export class DevSeederService {
|
||||
|
||||
await seedAgents({ queryRunner, schemaName, workspaceId });
|
||||
await seedApiKeys({ queryRunner, schemaName, workspaceId });
|
||||
if (
|
||||
this.twentyConfigService.get('EMAILING_DOMAIN_DRIVER') ===
|
||||
EmailingDomainDriver.LOG
|
||||
) {
|
||||
await seedEmailingDomains({ queryRunner, schemaName, workspaceId });
|
||||
}
|
||||
await seedFeatureFlags({ queryRunner, schemaName, workspaceId });
|
||||
|
||||
if (seedBilling) {
|
||||
|
||||
Reference in New Issue
Block a user