diff --git a/apps/api/src/app/workflows/e2e/create-notification-templates.e2e.ts b/apps/api/src/app/workflows/e2e/create-notification-templates.e2e.ts index 874e6668e82..641ca0964b3 100644 --- a/apps/api/src/app/workflows/e2e/create-notification-templates.e2e.ts +++ b/apps/api/src/app/workflows/e2e/create-notification-templates.e2e.ts @@ -101,6 +101,21 @@ describe('Create Workflow - /workflows (POST)', async () => { type: StepTypeEnum.EMAIL, }, active: defaultMessageIsActive, + filters: [ + { + isNegated: false, + type: 'GROUP', + value: 'AND', + children: [ + { + on: FilterPartTypeEnum.TENANT, + field: 'name', + value: 'Titans', + operator: 'EQUAL', + }, + ], + }, + ], }, ], }, diff --git a/apps/api/src/app/workflows/e2e/update-notification-template.e2e.ts b/apps/api/src/app/workflows/e2e/update-notification-template.e2e.ts index 44fac240adc..74f8702a747 100644 --- a/apps/api/src/app/workflows/e2e/update-notification-template.e2e.ts +++ b/apps/api/src/app/workflows/e2e/update-notification-template.e2e.ts @@ -1,6 +1,6 @@ import { expect } from 'chai'; import { UserSession, NotificationTemplateService } from '@novu/testing'; -import { StepTypeEnum, INotificationTemplate, IUpdateNotificationTemplateDto } from '@novu/shared'; +import { StepTypeEnum, INotificationTemplate, IUpdateNotificationTemplateDto, FilterPartTypeEnum } from '@novu/shared'; import { ChangeRepository } from '@novu/dal'; import { CreateWorkflowRequestDto, UpdateWorkflowRequestDto } from '../dto'; import { WorkflowResponse } from '../dto/workflow-response.dto'; @@ -31,12 +31,42 @@ describe('Update workflow by id - /workflows/:workflowId (PUT)', async () => { }, variants: [ { + filters: [ + { + isNegated: false, + type: 'GROUP', + value: 'AND', + children: [ + { + on: FilterPartTypeEnum.TENANT, + field: 'name', + value: 'Titans', + operator: 'EQUAL', + }, + ], + }, + ], template: { type: StepTypeEnum.IN_APP, content: 'first content', }, }, { + filters: [ + { + isNegated: false, + type: 'GROUP', + value: 'AND', + children: [ + { + on: FilterPartTypeEnum.TENANT, + field: 'name', + value: 'Titans', + operator: 'EQUAL', + }, + ], + }, + ], template: { type: StepTypeEnum.IN_APP, content: 'second content', diff --git a/apps/api/src/app/workflows/usecases/create-notification-template/create-notification-template.usecase.ts b/apps/api/src/app/workflows/usecases/create-notification-template/create-notification-template.usecase.ts index 5bb61667e45..147e4472b44 100644 --- a/apps/api/src/app/workflows/usecases/create-notification-template/create-notification-template.usecase.ts +++ b/apps/api/src/app/workflows/usecases/create-notification-template/create-notification-template.usecase.ts @@ -43,6 +43,9 @@ export class CreateNotificationTemplate { async execute(usecaseCommand: CreateNotificationTemplateCommand) { const blueprintCommand = await this.processBlueprint(usecaseCommand); const command = blueprintCommand ?? usecaseCommand; + + this.validatePayload(command); + const triggerIdentifier = `${slugify(command.name, { lower: true, strict: true, @@ -61,6 +64,16 @@ export class CreateNotificationTemplate { return storedWorkflow; } + private validatePayload(command: CreateNotificationTemplateCommand) { + const variants = command.steps ? command.steps?.flatMap((step) => step.variants || []) : []; + + for (const variant of variants) { + if (!variant.filters?.length) { + throw new ApiException(`Variant conditions are required, variant name ${variant.name} id ${variant._id}`); + } + } + } + private async createNotificationTrigger( command: CreateNotificationTemplateCommand, triggerIdentifier: string diff --git a/apps/api/src/app/workflows/usecases/update-notification-template/update-notification-template.usecase.ts b/apps/api/src/app/workflows/usecases/update-notification-template/update-notification-template.usecase.ts index 6e1f87fae49..ce3562fc4ce 100644 --- a/apps/api/src/app/workflows/usecases/update-notification-template/update-notification-template.usecase.ts +++ b/apps/api/src/app/workflows/usecases/update-notification-template/update-notification-template.usecase.ts @@ -52,6 +52,8 @@ export class UpdateNotificationTemplate { ) {} async execute(command: UpdateNotificationTemplateCommand): Promise { + this.validatePayload(command); + const existingTemplate = await this.notificationTemplateRepository.findById(command.id, command.environmentId); if (!existingTemplate) throw new NotFoundException(`Notification template with id ${command.id} not found`); @@ -208,6 +210,16 @@ export class UpdateNotificationTemplate { } } + private validatePayload(command: UpdateNotificationTemplateCommand) { + const variants = command.steps ? command.steps?.flatMap((step) => step.variants || []) : []; + + for (const variant of variants) { + if (!variant.filters?.length) { + throw new ApiException(`Variant filters are required, variant name ${variant.name} id ${variant._id}`); + } + } + } + private async updateMessageTemplates( steps: NotificationStep[], command: UpdateNotificationTemplateCommand,