Skip to content

Commit

Permalink
feat(api): more changes
Browse files Browse the repository at this point in the history
  • Loading branch information
tatarco committed Oct 31, 2024
1 parent bf9299c commit c0ab421
Show file tree
Hide file tree
Showing 9 changed files with 97 additions and 163 deletions.
Original file line number Diff line number Diff line change
@@ -1,29 +1,27 @@
import {
ControlsSchema,
DEFAULT_WORKFLOW_PREFERENCES,
PreferencesResponseDto,
PreferencesTypeEnum,
ShortIsPrefixEnum,
Slug,
slugify,
StepResponseDto,
StepTypeEnum,
WorkflowListResponseDto,
WorkflowOriginEnum,
WorkflowResponseDto,
WorkflowStatusEnum,
WorkflowTypeEnum,
slugify,
} from '@novu/shared';
import { ControlValuesEntity, NotificationStepEntity, NotificationTemplateEntity } from '@novu/dal';
import { NotificationStepEntity, NotificationTemplateEntity } from '@novu/dal';
import { GetPreferencesResponseDto } from '@novu/application-generic';
import { encodeBase62 } from '../../shared/helpers';

const SLUG_DELIMITER = '_';

export function toResponseWorkflowDto(
template: NotificationTemplateEntity,
preferences: GetPreferencesResponseDto | undefined,
stepIdToControlValuesMap: { [p: string]: ControlValuesEntity }
preferences: GetPreferencesResponseDto | undefined
): WorkflowResponseDto {
const preferencesDto: PreferencesResponseDto = {
user: preferences?.source[PreferencesTypeEnum.USER_WORKFLOW] || null,
Expand All @@ -39,7 +37,7 @@ export function toResponseWorkflowDto(
tags: template.tags,
active: template.active,
preferences: preferencesDto,
steps: getSteps(template, stepIdToControlValuesMap),
steps: getSteps(template),
description: template.description,
origin: computeOrigin(template),
updatedAt: template.updatedAt || 'Missing Updated At',
Expand All @@ -48,14 +46,10 @@ export function toResponseWorkflowDto(
};
}

function getSteps(template: NotificationTemplateEntity, controlValuesMap: { [p: string]: ControlValuesEntity }) {
function getSteps(template: NotificationTemplateEntity) {
const steps: StepResponseDto[] = [];
for (const step of template.steps) {
const stepResponseDto = toStepResponseDto(step);
const controlValues = controlValuesMap[step._templateId];
if (controlValues?.controls && Object.entries(controlValues?.controls).length) {
stepResponseDto.controlValues = controlValues.controls;
}
steps.push(stepResponseDto);
}

Expand Down Expand Up @@ -91,8 +85,6 @@ function toStepResponseDto(step: NotificationStepEntity): StepResponseDto {
name: stepName,
stepId: step.stepId || 'Missing Step Id',
type: step.template?.type || StepTypeEnum.EMAIL,
controls: convertControls(step),
controlValues: step.controlVariables || {},
} satisfies StepResponseDto;
}

Expand All @@ -104,14 +96,6 @@ function buildSlug(entityName: string, shortIsPrefix: ShortIsPrefixEnum, interna
return `${slugify(entityName)}${SLUG_DELIMITER}${shortIsPrefix}${encodeBase62(internalId)}`;
}

function convertControls(step: NotificationStepEntity): ControlsSchema {
if (step.template?.controls) {
return { schema: step.template.controls.schema };
}

return { schema: {} }; // This is not a usecase, it's only here to be backwards compatible with V1 Notification Entities
}

function buildStepTypeOverview(step: NotificationStepEntity): StepTypeEnum | undefined {
return step.template?.type;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {
ChannelTypeEnum,
ControlPreviewIssue,
ControlPreviewIssueTypeEnum,
ControlsSchema,
ControlSchemas,
GeneratePreviewRequestDto,
GeneratePreviewResponseDto,
JSONSchemaDto,
Expand All @@ -14,16 +14,17 @@ import { merge } from 'lodash/fp';
import { difference, isArray, isObject, reduce } from 'lodash';
import { GeneratePreviewCommand } from './generate-preview-command';
import { PreviewStep, PreviewStepCommand } from '../../../bridge/usecases/preview-step';
import { GetWorkflowUseCase } from '../get-workflow/get-workflow.usecase';
import { CreateMockPayloadUseCase } from '../placeholder-enrichment/payload-preview-value-generator.usecase';
import { StepNotFoundException } from '../../exceptions/step-not-found-exception';
import { ExtractDefaultsUsecase } from '../get-default-values-from-schema/extract-defaults.usecase';
import { GetWorkflowByIdsUseCase } from '../get-workflow-by-ids/get-workflow-by-ids.usecase';
import { OriginMissingException, StepIdMissingException } from './step-id-missing.exception';

@Injectable()
export class GeneratePreviewUsecase {
constructor(
private legacyPreviewStepUseCase: PreviewStep,
private getWorkflowUseCase: GetWorkflowUseCase,
private getWorkflowByIdsUseCase: GetWorkflowByIdsUseCase,
private createMockPayloadUseCase: CreateMockPayloadUseCase,
private extractDefaultsUseCase: ExtractDefaultsUsecase
) {}
Expand All @@ -49,7 +50,7 @@ export class GeneratePreviewUsecase {
);
}

private addMissingValuesToControlValues(command: GeneratePreviewCommand, stepControlSchema: ControlsSchema) {
private addMissingValuesToControlValues(command: GeneratePreviewCommand, stepControlSchema: ControlSchemas) {
const defaultValues = this.extractDefaultsUseCase.execute({
jsonSchemaDto: stepControlSchema.schema as JSONSchemaDto,
});
Expand Down Expand Up @@ -108,12 +109,19 @@ export class GeneratePreviewUsecase {
}
private async executePreviewUsecase(
workflowId: string,
stepId: string,
origin: WorkflowOriginEnum,
stepId: string | undefined,
origin: WorkflowOriginEnum | undefined,
hydratedPayload: Record<string, unknown>,
updatedControlValues: Record<string, unknown>,
command: GeneratePreviewCommand
) {
if (!stepId) {
throw new StepIdMissingException(workflowId);
}
if (!origin) {
throw new OriginMissingException(stepId);
}

return await this.legacyPreviewStepUseCase.execute(
PreviewStepCommand.create({
payload: hydratedPayload,
Expand All @@ -129,22 +137,22 @@ export class GeneratePreviewUsecase {
}

private async getWorkflowUserIdentifierFromWorkflowObject(command: GeneratePreviewCommand) {
const workflowResponseDto = await this.getWorkflowUseCase.execute({
const persistedWorkflow = await this.getWorkflowByIdsUseCase.execute({
identifierOrInternalId: command.workflowId,
user: command.user,
});
const { workflowId, steps } = workflowResponseDto;
const { steps } = persistedWorkflow;
const step = steps.find((stepDto) => stepDto._id === command.stepUuid);
if (!step) {
if (!step || !step.template || !step.controls) {
throw new StepNotFoundException(command.stepUuid);
}

return {
workflowId,
workflowId: persistedWorkflow.triggers[0].identifier,
stepId: step.stepId,
stepType: step.type,
stepType: step.template.type,
stepControlSchema: step.controls,
origin: workflowResponseDto.origin,
origin: persistedWorkflow.origin,
};
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { InternalServerErrorException } from '@nestjs/common';

export class StepIdMissingException extends InternalServerErrorException {
constructor(workflowId: string) {
super({ message: `StepId is missing for the workflowId: ${workflowId}`, workflowId });
}
}

export class OriginMissingException extends InternalServerErrorException {
constructor(stepId: string) {
super({ message: `Origin is missing for the stepId: ${stepId}`, stepId });
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,7 @@
import { Injectable } from '@nestjs/common';

import {
ControlValuesEntity,
ControlValuesRepository,
NotificationStepEntity,
NotificationTemplateEntity,
} from '@novu/dal';
import { ControlValuesLevelEnum, WorkflowResponseDto } from '@novu/shared';
import { NotificationTemplateEntity } from '@novu/dal';
import { WorkflowResponseDto } from '@novu/shared';
import { GetPreferences, GetPreferencesCommand } from '@novu/application-generic';
import { GetWorkflowCommand } from './get-workflow.command';
import { toResponseWorkflowDto } from '../../mappers/notification-template-mapper';
Expand All @@ -17,7 +12,6 @@ import { GetWorkflowByIdsCommand } from '../get-workflow-by-ids/get-workflow-by-
export class GetWorkflowUseCase {
constructor(
private getWorkflowByIdsUseCase: GetWorkflowByIdsUseCase,
private controlValuesRepository: ControlValuesRepository,
private getPreferencesUseCase: GetPreferences
) {}
async execute(command: GetWorkflowCommand): Promise<WorkflowResponseDto> {
Expand All @@ -28,7 +22,6 @@ export class GetWorkflowUseCase {
})
);

const stepIdToControlValuesMap = await this.getControlsValuesMap(workflowEntity.steps, command, workflowEntity._id);
const preferences = await this.getPreferencesUseCase.safeExecute(
GetPreferencesCommand.create({
environmentId: command.user.environmentId,
Expand All @@ -37,36 +30,6 @@ export class GetWorkflowUseCase {
})
);

return toResponseWorkflowDto(workflowEntity, preferences, stepIdToControlValuesMap);
}

private async getControlsValuesMap(
steps: NotificationStepEntity[],
command: GetWorkflowCommand,
_workflowId: string
): Promise<{ [key: string]: ControlValuesEntity }> {
const acc: { [key: string]: ControlValuesEntity } = {};

for (const step of steps) {
const controlValuesEntity = await this.buildControlValuesForStep(step, command, _workflowId);
if (controlValuesEntity) {
acc[step._templateId] = controlValuesEntity;
}
}

return acc;
}
private async buildControlValuesForStep(
step: NotificationStepEntity,
command: GetWorkflowCommand,
_workflowId: string
): Promise<ControlValuesEntity | null> {
return await this.controlValuesRepository.findFirst({
_environmentId: command.user.environmentId,
_organizationId: command.user.organizationId,
_workflowId,
_stepId: step._templateId,
level: ControlValuesLevelEnum.STEP_CONTROLS,
});
return toResponseWorkflowDto(workflowEntity, preferences);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ function buildUpsertControlValuesCommand(
command: UpsertWorkflowCommand,
persistedStep: NotificationStepEntity,
persistedWorkflow: NotificationTemplateEntity,
stepInDto: StepDto
stepInDto: StepUpdateDto | StepCreateDto
): UpsertControlValuesCommand {
return UpsertControlValuesCommand.create({
organizationId: command.user.organizationId,
Expand Down Expand Up @@ -78,10 +78,10 @@ export class UpsertWorkflowUseCase {
)
: null;
const workflow = await this.createOrUpdateWorkflow(workflowForUpdate, command);
const stepIdToControlValuesMap = await this.upsertControlValues(workflow, command);
await this.upsertControlValues(workflow, command);
const preferences = await this.upsertPreference(command, workflow);

return toResponseWorkflowDto(workflow, preferences, stepIdToControlValuesMap);
return toResponseWorkflowDto(workflow, preferences);
}

private async upsertControlValues(workflow: NotificationTemplateEntity, command: UpsertWorkflowCommand) {
Expand Down Expand Up @@ -274,7 +274,7 @@ export class UpsertWorkflowUseCase {

private mapSingleStep(
persistedWorkflow: NotificationTemplateEntity | undefined,
step: StepDto | (StepDto & { stepUuid: string })
step: StepUpdateDto | StepCreateDto
): NotificationStep {
const foundPersistedStep = this.getPersistedStepIfFound(persistedWorkflow, step);
const stepEntityToReturn = this.buildBaseStepEntity(step, foundPersistedStep);
Expand Down
Loading

0 comments on commit c0ab421

Please sign in to comment.