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

fix(api): Resolve circular import issue for workflow update validation #7151

Merged
merged 9 commits into from
Nov 28, 2024
2 changes: 1 addition & 1 deletion .cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -703,7 +703,7 @@
"xyflow",
"zulip",
"zwnj",
"lstrip",
"SOLOPRENEUR",
"rstrip",
"truncatewords",
"xmlschema",
Expand Down
7 changes: 6 additions & 1 deletion apps/api/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@novu/api",
"version": "2.0.9",
"version": "2.1.0",
"description": "description",
"author": "",
"private": "true",
Expand Down Expand Up @@ -132,5 +132,10 @@
"@novu/ee-billing": "workspace:*",
"@novu/ee-shared-services": "workspace:*",
"@novu/ee-translation": "workspace:*"
},
"nx": {
"tags": [
"type:app"
]
}
}
2 changes: 2 additions & 0 deletions apps/api/src/.example.env
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,5 @@ TUNNEL_BASE_ADDRESS=
PLAIN_SUPPORT_KEY='PLAIN_SUPPORT_KEY'
PLAIN_IDENTITY_VERIFICATION_SECRET_KEY='PLAIN_IDENTITY_VERIFICATION_SECRET_KEY'
NOVU_INTERNAL_SECRET_KEY=
# expressed in seconds or a string describing a time span [zeit/ms](https://github.com/zeit/ms.js). Eg: 60, "2 days", "10h", "7d"
SUBSCRIBER_WIDGET_JWT_EXPIRATION_TIME='15 days'
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { Injectable } from '@nestjs/common';
import { Event, ExecuteOutput, HttpQueryKeysEnum, PostActionEnum } from '@novu/framework/internal';
import { ExecuteBridgeRequest, ExecuteBridgeRequestCommand } from '@novu/application-generic';
import { ExecuteBridgeRequest, ExecuteBridgeRequestCommand, InstrumentUsecase } from '@novu/application-generic';

import { PreviewStepCommand } from './preview-step.command';

@Injectable()
export class PreviewStep {
constructor(private executeBridgeRequest: ExecuteBridgeRequest) {}

@InstrumentUsecase()
async execute(command: PreviewStepCommand): Promise<ExecuteOutput> {
const event = this.buildBridgeEventPayload(command);
const executeCommand = this.createExecuteCommand(command, event);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { workflow } from '@novu/framework/express';
import { ActionStep, ChannelStep, JsonSchema, Step, StepOptions, StepOutput, Workflow } from '@novu/framework/internal';
import { NotificationStepEntity, NotificationTemplateEntity, NotificationTemplateRepository } from '@novu/dal';
import { StepTypeEnum } from '@novu/shared';
import { Instrument, InstrumentUsecase } from '@novu/application-generic';
import { ConstructFrameworkWorkflowCommand } from './construct-framework-workflow.command';
import {
ChatOutputRendererUsecase,
Expand All @@ -28,6 +29,7 @@ export class ConstructFrameworkWorkflow {
private digestOutputRendererUseCase: DigestOutputRendererUsecase
) {}

@InstrumentUsecase()
async execute(command: ConstructFrameworkWorkflowCommand): Promise<Workflow> {
const dbWorkflow = await this.getDbWorkflow(command.environmentId, command.workflowId);
if (command.controlValues) {
Expand All @@ -39,6 +41,7 @@ export class ConstructFrameworkWorkflow {
return this.constructFrameworkWorkflow(dbWorkflow);
}

@Instrument()
private constructFrameworkWorkflow(newWorkflow: NotificationTemplateEntity): Workflow {
return workflow(
newWorkflow.triggers[0].identifier,
Expand Down Expand Up @@ -67,6 +70,7 @@ export class ConstructFrameworkWorkflow {
);
}

@Instrument()
private constructStep(
step: Step,
staticStep: NotificationStepEntity,
Expand Down Expand Up @@ -154,6 +158,7 @@ export class ConstructFrameworkWorkflow {
}
}

@Instrument()
private constructChannelStepOptions(staticStep: NotificationStepEntity): Required<Parameters<ChannelStep>[2]> {
return {
...this.constructCommonStepOptions(staticStep),
Expand All @@ -164,12 +169,14 @@ export class ConstructFrameworkWorkflow {
};
}

@Instrument()
private constructActionStepOptions(staticStep: NotificationStepEntity): Required<Parameters<ActionStep>[2]> {
return {
...this.constructCommonStepOptions(staticStep),
};
}

@Instrument()
private constructCommonStepOptions(staticStep: NotificationStepEntity): Required<StepOptions> {
return {
// TODO: fix the `JSONSchemaDto` type to enforce a non-primitive schema type.
Expand All @@ -181,6 +188,8 @@ export class ConstructFrameworkWorkflow {
skip: (controlValues) => false,
};
}

@Instrument()
private async getDbWorkflow(environmentId: string, workflowId: string): Promise<NotificationTemplateEntity> {
const foundWorkflow = await this.workflowsRepository.findByTriggerIdentifier(environmentId, workflowId);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
// Concrete Renderer for Chat Preview
import { ChatRenderOutput } from '@novu/shared';
import { Injectable } from '@nestjs/common';
import { InstrumentUsecase } from '@novu/application-generic';
import { RenderCommand } from './render-command';

@Injectable()
export class ChatOutputRendererUsecase {
@InstrumentUsecase()
execute(renderCommand: RenderCommand): ChatRenderOutput {
const body = renderCommand.controlValues.body as string;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Injectable } from '@nestjs/common';
import { DelayRenderOutput } from '@novu/shared';
import { InstrumentUsecase } from '@novu/application-generic';
import { RenderCommand } from './render-command';
import {
DelayTimeControlType,
Expand All @@ -8,6 +9,7 @@ import {

@Injectable()
export class DelayOutputRendererUsecase {
@InstrumentUsecase()
execute(renderCommand: RenderCommand): DelayRenderOutput {
const delayTimeControlType: DelayTimeControlType = DelayTimeControlZodSchema.parse(renderCommand.controlValues);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Injectable, InternalServerErrorException } from '@nestjs/common';
import { DigestRenderOutput } from '@novu/shared';
import { InstrumentUsecase } from '@novu/application-generic';
import { RenderCommand } from './render-command';
import {
DigestControlSchemaType,
Expand All @@ -10,6 +11,7 @@ import {

@Injectable()
export class DigestOutputRendererUsecase {
@InstrumentUsecase()
execute(renderCommand: RenderCommand): DigestRenderOutput {
const parse: DigestControlSchemaType = DigestControlZodSchema.parse(renderCommand.controlValues);
if (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Concrete Renderer for In-App Message Preview
import { InAppRenderOutput, RedirectTargetEnum } from '@novu/shared';
import { Injectable } from '@nestjs/common';
import { Instrument, InstrumentUsecase } from '@novu/application-generic';
import { RenderCommand } from './render-command';
import {
InAppActionType,
Expand All @@ -12,6 +13,7 @@ import { isValidUrlForActionButton } from '../../../workflows-v2/util/url-utils'

@Injectable()
export class InAppOutputRendererUsecase {
@InstrumentUsecase()
execute(renderCommand: RenderCommand): InAppRenderOutput {
const inApp: InAppControlType = InAppControlZodSchema.parse(renderCommand.controlValues);
if (!inApp) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { PushRenderOutput } from '@novu/shared';
import { Injectable } from '@nestjs/common';
import { InstrumentUsecase } from '@novu/application-generic';
import { RenderCommand } from './render-command';

@Injectable()
export class PushOutputRendererUsecase {
@InstrumentUsecase()
execute(renderCommand: RenderCommand): PushRenderOutput {
const subject = renderCommand.controlValues.subject as string;
const body = renderCommand.controlValues.body as string;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { EmailRenderOutput } from '@novu/shared';
import { EmailRenderOutput, TipTapNode } from '@novu/shared';
import { Injectable } from '@nestjs/common';
import { render } from '@maily-to/render';
import { render as mailyRender } from '@maily-to/render';
import { Instrument, InstrumentUsecase } from '@novu/application-generic';
import { FullPayloadForRender, RenderCommand } from './render-command';
import { ExpandEmailEditorSchemaUsecase } from './expand-email-editor-schema.usecase';
import { EmailStepControlZodSchema } from '../../../workflows-v2/shared';
Expand All @@ -9,17 +10,24 @@ export class RenderEmailOutputCommand extends RenderCommand {}

@Injectable()
export class RenderEmailOutputUsecase {
constructor(private expendEmailEditorSchemaUseCase: ExpandEmailEditorSchemaUsecase) {}
constructor(private expandEmailEditorSchemaUseCase: ExpandEmailEditorSchemaUsecase) {}

@InstrumentUsecase()
async execute(renderCommand: RenderEmailOutputCommand): Promise<EmailRenderOutput> {
const { emailEditor, subject } = EmailStepControlZodSchema.parse(renderCommand.controlValues);
const expandedSchema = this.transformForAndShowLogic(emailEditor, renderCommand.fullPayloadForRender);
const htmlRendered = await render(expandedSchema);
const htmlRendered = await this.renderEmail(expandedSchema);

return { subject, body: htmlRendered };
}

@Instrument()
private renderEmail(content: TipTapNode): Promise<string> {
return mailyRender(content);
}

@Instrument()
private transformForAndShowLogic(body: string, fullPayloadForRender: FullPayloadForRender) {
return this.expendEmailEditorSchemaUseCase.execute({ emailEditorJson: body, fullPayloadForRender });
return this.expandEmailEditorSchemaUseCase.execute({ emailEditorJson: body, fullPayloadForRender });
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
// Concrete Renderer for SMS Preview
import { SmsRenderOutput } from '@novu/shared';
import { Injectable } from '@nestjs/common';
import { InstrumentUsecase } from '@novu/application-generic';
import { RenderCommand } from './render-command';

@Injectable()
export class SmsOutputRendererUsecase {
@InstrumentUsecase()
execute(renderCommand: RenderCommand): SmsRenderOutput {
const body = renderCommand.controlValues.body as string;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { BadRequestException, Injectable } from '@nestjs/common';
import { ControlValuesLevelEnum, StepDataDto, WorkflowOriginEnum } from '@novu/shared';
import { ControlValuesRepository, NotificationStepEntity, NotificationTemplateEntity } from '@novu/dal';
import { GetWorkflowByIdsUseCase } from '@novu/application-generic';
import { GetWorkflowByIdsUseCase, Instrument, InstrumentUsecase } from '@novu/application-generic';
import { BuildStepDataCommand } from './build-step-data.command';
import { InvalidStepException } from '../../exceptions/invalid-step.exception';
import { BuildAvailableVariableSchemaUsecase } from '../build-variable-schema';
Expand All @@ -14,6 +14,7 @@ export class BuildStepDataUsecase {
private buildAvailableVariableSchemaUsecase: BuildAvailableVariableSchemaUsecase // Dependency injection for new use case
) {}

@InstrumentUsecase()
async execute(command: BuildStepDataCommand): Promise<StepDataDto> {
const workflow = await this.fetchWorkflow(command);

Expand Down Expand Up @@ -49,6 +50,7 @@ export class BuildStepDataUsecase {
};
}

@Instrument()
private async fetchWorkflow(command: BuildStepDataCommand) {
return await this.getWorkflowByIdsUseCase.execute({
identifierOrInternalId: command.identifierOrInternalId,
Expand All @@ -58,6 +60,7 @@ export class BuildStepDataUsecase {
});
}

@Instrument()
private async getValues(command: BuildStepDataCommand, currentStep: NotificationStepEntity, _workflowId: string) {
const controlValuesEntity = await this.controlValuesRepository.findOne({
_environmentId: command.user.environmentId,
Expand All @@ -70,6 +73,7 @@ export class BuildStepDataUsecase {
return controlValuesEntity?.controls || {};
}

@Instrument()
private async loadStepsFromDb(command: BuildStepDataCommand, workflow: NotificationTemplateEntity) {
const currentStep = workflow.steps.find(
(stepItem) => stepItem._id === command.stepId || stepItem.stepId === command.stepId
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,19 @@ import { Injectable } from '@nestjs/common';
import { NotificationStepEntity, NotificationTemplateEntity } from '@novu/dal';
import { JSONSchemaDto, StepTypeEnum, UserSessionData, WorkflowTestDataResponseDto } from '@novu/shared';

import { GetWorkflowByIdsCommand, GetWorkflowByIdsUseCase } from '@novu/application-generic';
import {
GetWorkflowByIdsCommand,
GetWorkflowByIdsUseCase,
Instrument,
InstrumentUsecase,
} from '@novu/application-generic';
import { WorkflowTestDataCommand } from './build-workflow-test-data.command';

@Injectable()
export class BuildWorkflowTestDataUseCase {
constructor(private getWorkflowByIdsUseCase: GetWorkflowByIdsUseCase) {}

@InstrumentUsecase()
async execute(command: WorkflowTestDataCommand): Promise<WorkflowTestDataResponseDto> {
const _workflowEntity: NotificationTemplateEntity = await this.fetchWorkflow(command);
const toSchema = buildToFieldSchema({ user: command.user, steps: _workflowEntity.steps });
Expand All @@ -20,6 +26,7 @@ export class BuildWorkflowTestDataUseCase {
};
}

@Instrument()
private async fetchWorkflow(command: WorkflowTestDataCommand): Promise<NotificationTemplateEntity> {
return await this.getWorkflowByIdsUseCase.execute(
GetWorkflowByIdsCommand.create({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
StepDataDto,
UserSessionData,
} from '@novu/shared';
import { Instrument, InstrumentUsecase } from '@novu/application-generic';
import { PreviewStep, PreviewStepCommand } from '../../../bridge/usecases/preview-step';
import { FrameworkPreviousStepsOutputState } from '../../../bridge/usecases/preview-step/preview-step.command';
import { StepMissingControlsException } from '../../exceptions/step-not-found-exception';
Expand All @@ -23,6 +24,7 @@ export class GeneratePreviewUsecase {
private buildStepDataUsecase: BuildStepDataUsecase
) {}

@InstrumentUsecase()
async execute(command: GeneratePreviewCommand): Promise<GeneratePreviewResponseDto> {
const dto = command.generatePreviewRequestDto;
const stepData = await this.getStepData(command);
Expand All @@ -45,6 +47,7 @@ export class GeneratePreviewUsecase {
};
}

@Instrument()
private async getValidatedContent(dto: GeneratePreviewRequestDto, stepData: StepDataDto, user: UserSessionData) {
if (!stepData.controls?.dataSchema) {
throw new StepMissingControlsException(stepData.stepId, stepData);
Expand All @@ -60,16 +63,20 @@ export class GeneratePreviewUsecase {
});
}

@Instrument()
private async getStepData(command: GeneratePreviewCommand) {
return await this.buildStepDataUsecase.execute({
identifierOrInternalId: command.workflowId,
stepId: command.stepDatabaseId,
user: command.user,
});
}

private isFrameworkError(obj: any): obj is FrameworkError {
return typeof obj === 'object' && obj.status === '400' && obj.name === 'BridgeRequestError';
}

@Instrument()
private async executePreviewUsecase(
command: GeneratePreviewCommand,
stepData: StepDataDto,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import { Injectable } from '@nestjs/common';

import { WorkflowResponseDto } from '@novu/shared';
import { GetWorkflowByIdsCommand, GetWorkflowByIdsUseCase } from '@novu/application-generic';
import { GetWorkflowByIdsCommand, GetWorkflowByIdsUseCase, InstrumentUsecase } from '@novu/application-generic';

import { GetWorkflowCommand } from './get-workflow.command';
import { toResponseWorkflowDto } from '../../mappers/notification-template-mapper';

@Injectable()
export class GetWorkflowUseCase {
constructor(private getWorkflowByIdsUseCase: GetWorkflowByIdsUseCase) {}

@InstrumentUsecase()
async execute(command: GetWorkflowCommand): Promise<WorkflowResponseDto> {
const workflowEntity = await this.getWorkflowByIdsUseCase.execute(
GetWorkflowByIdsCommand.create({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@ import { Injectable } from '@nestjs/common';

import { NotificationTemplateRepository } from '@novu/dal';
import { ListWorkflowResponse } from '@novu/shared';
import { InstrumentUsecase } from '@novu/application-generic';
import { ListWorkflowsCommand } from './list-workflows.command';
import { toWorkflowsMinifiedDtos } from '../../mappers/notification-template-mapper';

@Injectable()
export class ListWorkflowsUseCase {
constructor(private notificationTemplateRepository: NotificationTemplateRepository) {}

@InstrumentUsecase()
async execute(command: ListWorkflowsCommand): Promise<ListWorkflowResponse> {
const res = await this.notificationTemplateRepository.getList(
command.user.organizationId,
Expand Down
Loading
Loading