From 4a3d9da7da60b2726224c19e6a5ab19ee62b2c12 Mon Sep 17 00:00:00 2001 From: Gosha Date: Tue, 19 Nov 2024 17:52:04 +0200 Subject: [PATCH] feat(api): refactor --- .../generate-preview.usecase.ts | 4 +- ...erload-content-data-on-workflow.usecase.ts | 4 +- .../post-process-workflow-update.usecase.ts | 1 - .../prepare-and-validate-content.command.ts | 4 +- .../prepare-and-validate-content.usecase.ts | 113 ++---------------- .../src/app/workflows-v2/workflow.module.ts | 2 + 6 files changed, 17 insertions(+), 111 deletions(-) diff --git a/apps/api/src/app/workflows-v2/usecases/generate-preview/generate-preview.usecase.ts b/apps/api/src/app/workflows-v2/usecases/generate-preview/generate-preview.usecase.ts index d01d23ba3e0..8478ce21703 100644 --- a/apps/api/src/app/workflows-v2/usecases/generate-preview/generate-preview.usecase.ts +++ b/apps/api/src/app/workflows-v2/usecases/generate-preview/generate-preview.usecase.ts @@ -56,9 +56,7 @@ export class GeneratePreviewUsecase { controlDataSchema: stepData.controls.dataSchema, variableSchema: stepData.variables, previewPayloadFromDto: dto.previewPayload, - environmentId: user.environmentId, - organizationId: user.organizationId, - userId: user._id, + user, }); } diff --git a/apps/api/src/app/workflows-v2/usecases/overload-content-data/overload-content-data-on-workflow.usecase.ts b/apps/api/src/app/workflows-v2/usecases/overload-content-data/overload-content-data-on-workflow.usecase.ts index e093b8676b5..8d8803fbec0 100644 --- a/apps/api/src/app/workflows-v2/usecases/overload-content-data/overload-content-data-on-workflow.usecase.ts +++ b/apps/api/src/app/workflows-v2/usecases/overload-content-data/overload-content-data-on-workflow.usecase.ts @@ -53,9 +53,7 @@ export class OverloadContentDataOnWorkflowUseCase { controlDataSchema: controls.schema, controlValues, variableSchema: jsonSchemaDto, - environmentId: user.environmentId, - organizationId: user.organizationId, - userId: user._id, + user, }); } diff --git a/apps/api/src/app/workflows-v2/usecases/post-process-workflow-update/post-process-workflow-update.usecase.ts b/apps/api/src/app/workflows-v2/usecases/post-process-workflow-update/post-process-workflow-update.usecase.ts index 119a670d7db..4499be54f27 100644 --- a/apps/api/src/app/workflows-v2/usecases/post-process-workflow-update/post-process-workflow-update.usecase.ts +++ b/apps/api/src/app/workflows-v2/usecases/post-process-workflow-update/post-process-workflow-update.usecase.ts @@ -47,7 +47,6 @@ export class PostProcessWorkflowUpdate { constructor( private notificationTemplateRepository: NotificationTemplateRepository, private controlValuesRepository: ControlValuesRepository, - private organizationRepository: OrganizationRepository, private overloadContentDataOnWorkflowUseCase: OverloadContentDataOnWorkflowUseCase ) {} diff --git a/apps/api/src/app/workflows-v2/usecases/validate-content/prepare-and-validate-content/prepare-and-validate-content.command.ts b/apps/api/src/app/workflows-v2/usecases/validate-content/prepare-and-validate-content/prepare-and-validate-content.command.ts index 986bb2e2d86..ee1736128a6 100644 --- a/apps/api/src/app/workflows-v2/usecases/validate-content/prepare-and-validate-content/prepare-and-validate-content.command.ts +++ b/apps/api/src/app/workflows-v2/usecases/validate-content/prepare-and-validate-content/prepare-and-validate-content.command.ts @@ -1,8 +1,8 @@ -import { EnvironmentWithUserCommand } from '@novu/application-generic'; +import { EnvironmentWithUserObjectCommand } from '@novu/application-generic'; import { JSONSchemaDto, PreviewPayload, StepTypeEnum } from '@novu/shared'; // eslint-disable-next-line @typescript-eslint/naming-convention -export interface PrepareAndValidateContentCommand extends EnvironmentWithUserCommand { +export interface PrepareAndValidateContentCommand extends EnvironmentWithUserObjectCommand { controlValues: Record; controlDataSchema: JSONSchemaDto; variableSchema: JSONSchemaDto; diff --git a/apps/api/src/app/workflows-v2/usecases/validate-content/prepare-and-validate-content/prepare-and-validate-content.usecase.ts b/apps/api/src/app/workflows-v2/usecases/validate-content/prepare-and-validate-content/prepare-and-validate-content.usecase.ts index a73b6713f71..77bfd1c983a 100644 --- a/apps/api/src/app/workflows-v2/usecases/validate-content/prepare-and-validate-content/prepare-and-validate-content.usecase.ts +++ b/apps/api/src/app/workflows-v2/usecases/validate-content/prepare-and-validate-content/prepare-and-validate-content.usecase.ts @@ -1,15 +1,13 @@ import { Injectable } from '@nestjs/common'; import { - ApiServiceLevelEnum, ContentIssue, - DigestUnitEnum, JSONSchemaDto, PreviewPayload, StepContentIssueEnum, StepTypeEnum, + UserSessionData, } from '@novu/shared'; import { merge } from 'lodash'; -import { OrganizationEntity, OrganizationRepository } from '@novu/dal'; import { PrepareAndValidateContentCommand } from './prepare-and-validate-content.command'; import { mergeObjects } from '../../../util/jsonUtils'; import { findMissingKeys } from '../../../util/utils'; @@ -18,9 +16,7 @@ import { ValidatedPlaceholderAggregation, ValidatePlaceholderUsecase } from '../ import { CollectPlaceholderWithDefaultsUsecase, PlaceholderAggregation } from '../collect-placeholders'; import { ExtractDefaultValuesFromSchemaUsecase } from '../../extract-default-values-from-schema'; import { ValidatedContentResponse } from './validated-content.response'; - -const MAX_DELAY_DAYS_FREE_TIER = 30; -const MAX_DELAY_DAYS_BUSINESS_TIER = 90; +import { ValidateControlByTierUsecase } from '../validateControlByTier/validate-control-by-tier.usecase'; /** * Validates and prepares workflow step content by collecting placeholders, @@ -36,7 +32,7 @@ export class PrepareAndValidateContentUsecase { private validatePlaceholdersUseCase: ValidatePlaceholderUsecase, private collectPlaceholderWithDefaultsUsecase: CollectPlaceholderWithDefaultsUsecase, private extractDefaultsFromSchemaUseCase: ExtractDefaultValuesFromSchemaUsecase, - private organizationRepository: OrganizationRepository + private validateControlByTierUsecase: ValidateControlByTierUsecase ) {} async execute(command: PrepareAndValidateContentCommand): Promise { @@ -58,7 +54,7 @@ export class PrepareAndValidateContentUsecase { defaultControlValues, command.controlValues, controlValueToValidPlaceholders, - command.organizationId, + command.user, command.stepType ); @@ -150,17 +146,19 @@ export class PrepareAndValidateContentUsecase { defaultControlValues: Record, userProvidedValues: Record, valueToPlaceholders: Record, - organizationId: string, + user: UserSessionData, stepType?: StepTypeEnum ): Promise> { let finalIssues: Record = {}; finalIssues = mergeObjects(finalIssues, this.computeIllegalVariablesIssues(valueToPlaceholders)); finalIssues = mergeObjects(finalIssues, this.getMissingInPayload(providedPayload, valueToPlaceholders, payload)); finalIssues = mergeObjects(finalIssues, this.computeMissingControlValue(defaultControlValues, userProvidedValues)); - finalIssues = mergeObjects( - finalIssues, - await this.computeTierLimitExceeded(defaultControlValues, organizationId, stepType) - ); + const tierIssues = await this.validateControlByTierUsecase.execute({ + controlValues: defaultControlValues, + user, + stepType, + }); + finalIssues = mergeObjects(finalIssues, tierIssues); return finalIssues; } @@ -233,93 +231,4 @@ export class PrepareAndValidateContentUsecase { return result; } - - private async computeTierLimitExceeded( - defaultControlValues: Record, - organizationId: string, - stepType?: StepTypeEnum - ) { - const issues: Record = {}; - let organization: OrganizationEntity | null = null; - const controlValues = defaultControlValues; - if ( - controlValues.unit && - controlValues.amount && - this.isNumber(controlValues.amount) && - this.isValidDigestUnit(controlValues.unit) - ) { - organization = await this.getOrganization(organization, organizationId); - - const delayInDays = this.calculateDaysFromUnit(controlValues.amount, controlValues.unit); - - const tier = organization?.apiServiceLevel; - if (tier === undefined || tier === ApiServiceLevelEnum.BUSINESS || tier === ApiServiceLevelEnum.ENTERPRISE) { - if (delayInDays > MAX_DELAY_DAYS_BUSINESS_TIER) { - issues.tier = [ - ...(issues.tier || []), - { - issueType: StepContentIssueEnum.TIER_LIMIT_EXCEEDED, - message: - `The maximum delay allowed is ${MAX_DELAY_DAYS_BUSINESS_TIER} days.` + - 'Please contact our support team to discuss extending this limit for your use case.', - }, - ]; - } - } - - if (tier === ApiServiceLevelEnum.FREE) { - if (delayInDays > MAX_DELAY_DAYS_FREE_TIER) { - issues.tier = [ - ...(issues.tier || []), - { - issueType: StepContentIssueEnum.TIER_LIMIT_EXCEEDED, - message: - `The maximum delay allowed is ${MAX_DELAY_DAYS_FREE_TIER} days.` + - 'Please contact our support team to discuss extending this limit for your use case.', - }, - ]; - } - } - } - - return issues; - } - - private isValidDigestUnit(unit: unknown): unit is DigestUnitEnum { - return Object.values(DigestUnitEnum).includes(unit as DigestUnitEnum); - } - - private isNumber(value: unknown): value is number { - return !Number.isNaN(Number(value)); - } - - private calculateDaysFromUnit(amount: number, unit: DigestUnitEnum): number { - switch (unit) { - case DigestUnitEnum.SECONDS: - return amount / (24 * 60 * 60); - case DigestUnitEnum.MINUTES: - return amount / (24 * 60); - case DigestUnitEnum.HOURS: - return amount / 24; - case DigestUnitEnum.DAYS: - return amount; - case DigestUnitEnum.WEEKS: - return amount * 7; - case DigestUnitEnum.MONTHS: - return amount * 30; // Using 30 days as an approximation for a month - default: - return 0; - } - } - - private async getOrganization( - organization: OrganizationEntity | null, - organizationId: string - ): Promise { - if (organization === null) { - return await this.organizationRepository.findById(organizationId); - } - - return organization; - } } diff --git a/apps/api/src/app/workflows-v2/workflow.module.ts b/apps/api/src/app/workflows-v2/workflow.module.ts index b1f56b78321..d0634a1d953 100644 --- a/apps/api/src/app/workflows-v2/workflow.module.ts +++ b/apps/api/src/app/workflows-v2/workflow.module.ts @@ -36,6 +36,7 @@ import { HydrateEmailSchemaUseCase } from '../environments-v1/usecases/output-re import { OverloadContentDataOnWorkflowUseCase } from './usecases/overload-content-data'; import { PatchWorkflowUsecase } from './usecases/patch-workflow'; import { PatchStepUsecase } from './usecases/patch-step-data/patch-step.usecase'; +import { ValidateControlByTierUsecase } from './usecases/validate-content/validateControlByTier/validate-control-by-tier.usecase'; @Module({ imports: [SharedModule, MessageTemplateModule, ChangeModule, AuthModule, BridgeModule, IntegrationModule], @@ -67,6 +68,7 @@ import { PatchStepUsecase } from './usecases/patch-step-data/patch-step.usecase' PostProcessWorkflowUpdate, OverloadContentDataOnWorkflowUseCase, PatchWorkflowUsecase, + ValidateControlByTierUsecase, ], }) export class WorkflowModule implements NestModule {