Skip to content

Commit

Permalink
chore(api, worker): Instrument workflow v2 controller and bridge use-…
Browse files Browse the repository at this point in the history
…cases (#7150)
  • Loading branch information
rifont authored Nov 27, 2024
1 parent 77da246 commit 3fe3c28
Show file tree
Hide file tree
Showing 24 changed files with 160 additions and 50 deletions.
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
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ import {
WorkflowResponseDto,
WorkflowStatusEnum,
} from '@novu/shared';
import { ControlValuesRepository, NotificationStepEntity, NotificationTemplateRepository } from '@novu/dal';
import { NotificationStepEntity, NotificationTemplateRepository } from '@novu/dal';
import { Injectable } from '@nestjs/common';
import { WorkflowInternalResponseDto } from '@novu/application-generic';
import { Instrument, InstrumentUsecase, WorkflowInternalResponseDto } from '@novu/application-generic';

import { PostProcessWorkflowUpdateCommand } from './post-process-workflow-update.command';
import { OverloadContentDataOnWorkflowUseCase } from '../overload-content-data';
Expand All @@ -32,10 +32,10 @@ import { OverloadContentDataOnWorkflowUseCase } from '../overload-content-data';
export class PostProcessWorkflowUpdate {
constructor(
private notificationTemplateRepository: NotificationTemplateRepository,
private controlValuesRepository: ControlValuesRepository,
private overloadContentDataOnWorkflowUseCase: OverloadContentDataOnWorkflowUseCase
) {}

@InstrumentUsecase()
async execute(command: PostProcessWorkflowUpdateCommand): Promise<WorkflowInternalResponseDto> {
const workflowIssues = await this.validateWorkflow(command);
const stepIssues = this.validateSteps(command.workflow.steps, command.workflow._id);
Expand Down Expand Up @@ -107,6 +107,7 @@ export class PostProcessWorkflowUpdate {
return stepIdToIssues;
}

@Instrument()
private async validateWorkflow(
command: PostProcessWorkflowUpdateCommand
): Promise<Record<keyof WorkflowResponseDto, RuntimeIssue[]>> {
Expand All @@ -117,6 +118,7 @@ export class PostProcessWorkflowUpdate {
return issues;
}

@Instrument()
private async addTriggerIdentifierNotUniqueIfApplicable(
command: PostProcessWorkflowUpdateCommand,
issues: Record<keyof WorkflowResponseDto, RuntimeIssue[]>
Expand Down
Loading

0 comments on commit 3fe3c28

Please sign in to comment.