Skip to content

Commit 1bbb9b1

Browse files
committed
feat: refactor usecase position
1 parent 46c0897 commit 1bbb9b1

File tree

24 files changed

+1000
-569
lines changed

24 files changed

+1000
-569
lines changed

apps/api/src/app/bridge/bridge.module.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import { USECASES } from './usecases';
2424
import { BuildVariableSchemaUsecase } from '../workflows-v2/usecases';
2525
import { CreateVariablesObject } from '../workflows-v2/usecases/create-variables-object/create-variables-object.usecase';
2626
import { BuildStepIssuesUsecase } from '../workflows-v2/usecases/build-step-issues/build-step-issues.usecase';
27+
import { WebhooksModule } from '../webhooks/webhooks.module';
2728

2829
const PROVIDERS = [
2930
CreateWorkflow,
@@ -51,7 +52,7 @@ const PROVIDERS = [
5152
];
5253

5354
@Module({
54-
imports: [SharedModule],
55+
imports: [SharedModule, WebhooksModule],
5556
providers: [...PROVIDERS, ...USECASES],
5657
controllers: [BridgeController],
5758
exports: [...USECASES],
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,5 @@
1-
import { ApiProperty } from '@nestjs/swagger';
2-
import { WorkflowResponseDto } from '../../workflows-v2/dtos/workflow-response.dto';
1+
import { WebhookEventEnum, WebhookObjectTypeEnum } from '@novu/shared';
2+
import { WrapperDto } from '@novu/application-generic';
33

4-
export enum WebhookEventEnum {
5-
WORKFLOW_CREATED = 'workflow.created',
6-
WORKFLOW_UPDATED = 'workflow.updated',
7-
WORKFLOW_DELETED = 'workflow.deleted',
8-
}
9-
10-
export enum WebhookObjectTypeEnum {
11-
WORKFLOW = 'workflow',
12-
}
13-
14-
export class WrapperDto<T> {
15-
@ApiProperty({
16-
description: 'The type of the webhook',
17-
enum: WebhookEventEnum,
18-
})
19-
type: WebhookEventEnum;
20-
21-
@ApiProperty({
22-
description: 'The payload of the webhook',
23-
type: 'object',
24-
})
25-
data: T;
26-
27-
@ApiProperty({
28-
description: 'The timestamp of the webhook',
29-
type: 'string',
30-
})
31-
timestamp: string;
32-
33-
@ApiProperty({
34-
description: 'The environment connected to the webhook',
35-
type: 'string',
36-
})
37-
environmentId: string;
38-
39-
@ApiProperty({
40-
description: 'The object of the webhook',
41-
enum: WebhookObjectTypeEnum,
42-
})
43-
object: WebhookObjectTypeEnum;
44-
}
45-
46-
export class WorkflowUpdatedWebhookDto extends WrapperDto<WorkflowResponseDto> {
47-
type: WebhookEventEnum.WORKFLOW_UPDATED;
48-
object: WebhookObjectTypeEnum.WORKFLOW;
49-
}
50-
51-
export class WorkflowCreatedWebhookDto extends WrapperDto<WorkflowResponseDto> {
52-
type: WebhookEventEnum.WORKFLOW_CREATED;
53-
object: WebhookObjectTypeEnum.WORKFLOW;
54-
}
55-
56-
export class WorkflowDeletedWebhookDto extends WrapperDto<WorkflowResponseDto> {
57-
type: WebhookEventEnum.WORKFLOW_DELETED;
58-
object: WebhookObjectTypeEnum.WORKFLOW;
59-
}
4+
// Re-export for backward compatibility
5+
export { WebhookEventEnum, WebhookObjectTypeEnum, WrapperDto };

apps/api/src/app/webhooks/usecases/send-webhook-message/send-webhook-message.command.ts

-25
This file was deleted.
+16-4
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,33 @@
11
import { WebhookEventEnum, WebhookObjectTypeEnum } from './dtos/webhook-payload.dto';
22
import { WorkflowResponseDto } from '../workflows-v2/dtos/workflow-response.dto';
33

4+
export class WebhookUpdatedWorkflowDto {
5+
object: WorkflowResponseDto;
6+
previousObject: WorkflowResponseDto;
7+
}
8+
9+
export class WebhookCreatedWorkflowDto {
10+
object: WorkflowResponseDto;
11+
}
12+
13+
export class WebhookDeletedWorkflowDto {
14+
object: WorkflowResponseDto;
15+
}
16+
417
export const webhookEvents = [
518
{
619
event: WebhookEventEnum.WORKFLOW_UPDATED,
7-
payloadDto: WorkflowResponseDto,
20+
payloadDto: WebhookUpdatedWorkflowDto,
821
objectType: WebhookObjectTypeEnum.WORKFLOW,
922
},
1023
{
1124
event: WebhookEventEnum.WORKFLOW_CREATED,
12-
payloadDto: WorkflowResponseDto,
25+
payloadDto: WebhookCreatedWorkflowDto,
1326
objectType: WebhookObjectTypeEnum.WORKFLOW,
1427
},
1528
{
1629
event: WebhookEventEnum.WORKFLOW_DELETED,
17-
payloadDto: WorkflowResponseDto,
30+
payloadDto: WebhookDeletedWorkflowDto,
1831
objectType: WebhookObjectTypeEnum.WORKFLOW,
1932
},
20-
// Add other webhook events here as needed
2133
];
+3-17
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,13 @@
1-
import { Module, Provider } from '@nestjs/common';
2-
import { Svix } from 'svix'; // Import Svix SDK
1+
import { Module } from '@nestjs/common';
2+
import { SvixProviderService, SendWebhookMessage } from '@novu/application-generic';
33
import { SharedModule } from '../shared/shared.module';
44
import { WebhooksController } from './webhooks.controller';
55
import { GetWebhookPortalTokenUsecase } from './usecases/get-webhook-portal-token/get-webhook-portal-token.usecase';
6-
import { SendWebhookMessage } from './usecases/send-webhook-message/send-webhook-message.usecase';
7-
8-
// Define the custom provider for the Svix client
9-
const svixProvider: Provider = {
10-
provide: 'SVIX_CLIENT', // The injection token used in the use case
11-
useFactory: () => {
12-
const apiKey = process.env.SVIX_API_KEY;
13-
if (!apiKey) {
14-
throw new Error('SVIX_API_KEY environment variable is not set.');
15-
}
16-
17-
return new Svix(apiKey || '');
18-
},
19-
};
206

217
@Module({
228
imports: [SharedModule],
239
controllers: [WebhooksController],
24-
providers: [GetWebhookPortalTokenUsecase, svixProvider, SendWebhookMessage],
10+
providers: [GetWebhookPortalTokenUsecase, SvixProviderService, SendWebhookMessage],
2511
exports: [SendWebhookMessage],
2612
})
2713
export class WebhooksModule {}

apps/api/src/app/workflows-v1/workflow-v1.module.ts

+10-1
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,18 @@ import { NotificationTemplateController } from './notification-template.controll
88
import { USE_CASES } from './usecases';
99
import { WorkflowControllerV1 } from './workflow-v1.controller';
1010
import { PreferencesModule } from '../preferences';
11+
import { WebhooksModule } from '../webhooks/webhooks.module';
1112

1213
@Module({
13-
imports: [SharedModule, MessageTemplateModule, ChangeModule, AuthModule, IntegrationModule, PreferencesModule],
14+
imports: [
15+
SharedModule,
16+
MessageTemplateModule,
17+
ChangeModule,
18+
AuthModule,
19+
IntegrationModule,
20+
PreferencesModule,
21+
WebhooksModule,
22+
],
1423
controllers: [NotificationTemplateController, WorkflowControllerV1],
1524
providers: [...USE_CASES],
1625
exports: [...USE_CASES],

apps/api/src/app/workflows-v2/usecases/patch-workflow/patch-workflow.usecase.ts

+10-5
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
import { Injectable } from '@nestjs/common';
2-
import { UserSessionData, WorkflowStatusEnum } from '@novu/shared';
2+
import { UserSessionData, WebhookObjectTypeEnum, WebhookEventEnum, WorkflowStatusEnum } from '@novu/shared';
33
import { NotificationTemplateEntity, NotificationTemplateRepository } from '@novu/dal';
4-
import { GetWorkflowWithPreferencesUseCase, WorkflowWithPreferencesResponseDto } from '@novu/application-generic';
5-
import { SendWebhookMessage } from '../../../webhooks/usecases/send-webhook-message/send-webhook-message.usecase';
4+
import {
5+
GetWorkflowWithPreferencesUseCase,
6+
SendWebhookMessage,
7+
WorkflowWithPreferencesResponseDto,
8+
} from '@novu/application-generic';
69
import { PatchWorkflowCommand } from './patch-workflow.command';
710
import { GetWorkflowUseCase } from '../get-workflow';
811
import { WorkflowResponseDto } from '../../dtos';
9-
import { WebhookEventEnum, WebhookObjectTypeEnum } from '../../../webhooks/dtos/webhook-payload.dto';
1012

1113
@Injectable()
1214
export class PatchWorkflowUsecase {
@@ -30,7 +32,10 @@ export class PatchWorkflowUsecase {
3032
await this.sendWebhookMessage.execute({
3133
eventType: WebhookEventEnum.WORKFLOW_UPDATED,
3234
objectType: WebhookObjectTypeEnum.WORKFLOW,
33-
payload: updatedWorkflow,
35+
payload: {
36+
object: updatedWorkflow,
37+
previousObject: persistedWorkflow,
38+
},
3439
organizationId: command.user.organizationId,
3540
environmentId: command.user.environmentId,
3641
});

apps/api/src/app/workflows-v2/usecases/upsert-workflow/upsert-workflow.usecase.ts

+25-9
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
UpdateWorkflowCommand,
1515
UpsertControlValuesCommand,
1616
UpsertControlValuesUseCase,
17+
SendWebhookMessage,
1718
} from '@novu/application-generic';
1819
import {
1920
ControlSchemas,
@@ -26,6 +27,8 @@ import {
2627
ControlValuesLevelEnum,
2728
DEFAULT_WORKFLOW_PREFERENCES,
2829
slugify,
30+
WebhookEventEnum,
31+
WebhookObjectTypeEnum,
2932
WorkflowCreationSourceEnum,
3033
WorkflowOriginEnum,
3134
WorkflowTypeEnum,
@@ -37,8 +40,6 @@ import { BuildStepIssuesUsecase } from '../build-step-issues/build-step-issues.u
3740
import { GetWorkflowCommand, GetWorkflowUseCase } from '../get-workflow';
3841
import { UpsertStepDataCommand, UpsertWorkflowCommand } from './upsert-workflow.command';
3942
import { StepIssuesDto, WorkflowResponseDto } from '../../dtos';
40-
import { SendWebhookMessage } from '../../../webhooks/usecases/send-webhook-message/send-webhook-message.usecase';
41-
import { WebhookEventEnum, WebhookObjectTypeEnum } from '../../../webhooks/dtos/webhook-payload.dto';
4243

4344
@Injectable()
4445
export class UpsertWorkflowUseCase {
@@ -94,13 +95,28 @@ export class UpsertWorkflowUseCase {
9495
})
9596
);
9697

97-
await this.sendWebhookMessage.execute({
98-
eventType: WebhookEventEnum.WORKFLOW_UPDATED,
99-
objectType: WebhookObjectTypeEnum.WORKFLOW,
100-
payload: updatedWorkflow,
101-
organizationId: command.user.organizationId,
102-
environmentId: command.user.environmentId,
103-
});
98+
if (existingWorkflow) {
99+
await this.sendWebhookMessage.execute({
100+
eventType: WebhookEventEnum.WORKFLOW_UPDATED,
101+
objectType: WebhookObjectTypeEnum.WORKFLOW,
102+
payload: {
103+
object: updatedWorkflow,
104+
previousObject: existingWorkflow,
105+
},
106+
organizationId: command.user.organizationId,
107+
environmentId: command.user.environmentId,
108+
});
109+
} else {
110+
await this.sendWebhookMessage.execute({
111+
eventType: WebhookEventEnum.WORKFLOW_CREATED,
112+
objectType: WebhookObjectTypeEnum.WORKFLOW,
113+
payload: {
114+
object: updatedWorkflow,
115+
},
116+
organizationId: command.user.organizationId,
117+
environmentId: command.user.environmentId,
118+
});
119+
}
104120

105121
return updatedWorkflow;
106122
}

libs/application-generic/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@
8181
"ioredis": "^5.2.4",
8282
"jsonwebtoken": "9.0.0",
8383
"@launchdarkly/node-server-sdk": "^9.7.3",
84+
"svix": "^1.64.1",
8485
"lodash": "^4.17.15",
8586
"mixpanel": "^0.17.0",
8687
"nanoid": "^3.1.20",

libs/application-generic/src/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,4 @@ export * from './utils';
1818
export * from './schemas/control';
1919
export * from './services/resource-validator.service';
2020
export * from './value-objects';
21+
export * from './webhooks';

libs/application-generic/src/usecases/workflow/delete-workflow/delete-workflow.usecase.ts

+14-2
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,14 @@ import {
55
NotificationTemplateEntity,
66
NotificationTemplateRepository,
77
} from '@novu/dal';
8-
import { PreferencesTypeEnum } from '@novu/shared';
8+
import { PreferencesTypeEnum, WebhookEventEnum, WebhookObjectTypeEnum } from '@novu/shared';
99

1010
import { DeleteWorkflowCommand } from './delete-workflow.command';
1111
import { GetWorkflowByIdsUseCase } from '../get-workflow-by-ids/get-workflow-by-ids.usecase';
1212
import { GetWorkflowWithPreferencesCommand } from '../get-workflow-with-preferences/get-workflow-with-preferences.command';
1313
import { DeletePreferencesUseCase, DeletePreferencesCommand } from '../../delete-preferences';
1414
import { Instrument, InstrumentUsecase } from '../../../instrumentation';
15+
import { SendWebhookMessage } from '../../../webhooks/usecases/send-webhook-message/send-webhook-message.usecase';
1516

1617
@Injectable()
1718
export class DeleteWorkflowUseCase {
@@ -20,7 +21,8 @@ export class DeleteWorkflowUseCase {
2021
private messageTemplateRepository: MessageTemplateRepository,
2122
private getWorkflowByIdsUseCase: GetWorkflowByIdsUseCase,
2223
private controlValuesRepository: ControlValuesRepository,
23-
private deletePreferencesUsecase: DeletePreferencesUseCase
24+
private deletePreferencesUsecase: DeletePreferencesUseCase,
25+
private sendWebhookMessage: SendWebhookMessage
2426
) {}
2527

2628
@InstrumentUsecase()
@@ -33,6 +35,16 @@ export class DeleteWorkflowUseCase {
3335
);
3436

3537
await this.deleteRelatedEntities(command, workflowEntity);
38+
39+
await this.sendWebhookMessage.execute({
40+
eventType: WebhookEventEnum.WORKFLOW_DELETED,
41+
objectType: WebhookObjectTypeEnum.WORKFLOW,
42+
payload: {
43+
object: workflowEntity,
44+
},
45+
organizationId: command.organizationId,
46+
environmentId: command.environmentId,
47+
});
3648
}
3749

3850
@Instrument()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './webhook-payload.dto';
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { ApiProperty } from '@nestjs/swagger';
2+
import { WebhookEventEnum, WebhookObjectTypeEnum } from '@novu/shared';
3+
4+
export class WrapperDto<T> {
5+
@ApiProperty({
6+
description: 'The type of the webhook',
7+
enum: WebhookEventEnum,
8+
})
9+
type: WebhookEventEnum;
10+
11+
@ApiProperty({
12+
description: 'The payload of the webhook',
13+
type: 'object',
14+
})
15+
data: T;
16+
17+
@ApiProperty({
18+
description: 'The timestamp of the webhook',
19+
type: 'string',
20+
})
21+
timestamp: string;
22+
23+
@ApiProperty({
24+
description: 'The environment connected to the webhook',
25+
type: 'string',
26+
})
27+
environmentId: string;
28+
29+
@ApiProperty({
30+
description: 'The object of the webhook',
31+
enum: WebhookObjectTypeEnum,
32+
})
33+
object: WebhookObjectTypeEnum;
34+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export * from './dtos';
2+
export * from './services';
3+
export * from './usecases';
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './svix-provider.service';

0 commit comments

Comments
 (0)