Skip to content

Commit

Permalink
add validation if targetGroup is in correct scope and is not a main list
Browse files Browse the repository at this point in the history
  • Loading branch information
raphaelblum committed Oct 7, 2024
1 parent 4160ecd commit 72332f9
Show file tree
Hide file tree
Showing 5 changed files with 35 additions and 20 deletions.
2 changes: 2 additions & 0 deletions packages/api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
"@nestjs/graphql": "^10.0.0",
"@nestjs/platform-express": "^9.0.0",
"@types/jest": "^29.5.0",
"@types/lodash.isequal": "^4.0.0",
"@types/mime-db": "^1.43.5",
"@types/node-fetch": "^2.5.12",
"@types/rimraf": "^3.0.0",
Expand All @@ -64,6 +65,7 @@
"graphql": "^15.5.0",
"jest": "^29.5.0",
"jest-junit": "^15.0.0",
"lodash.isequal": "^4.5.0",
"nestjs-console": "^8.0.0",
"pg-error-constants": "^1.0.0",
"prettier": "^2.0.0",
Expand Down
14 changes: 6 additions & 8 deletions packages/api/src/brevo-contact/brevo-contact-import.console.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,20 +81,18 @@ export function createBrevoContactImportConsole({ Scope }: { Scope: Type<EmailCa
],
})
@CreateRequestContext()
async execute(options: CommandOptions): Promise<void> {
const redirectUrl = this.config.brevo.resolveConfig(options.scope).redirectUrlForImport;
const fileStream = fs.createReadStream(options.path);
if (!this.validateRedirectUrl(redirectUrl, options.scope)) {
async execute({ scope, path, targetGroupIds }: CommandOptions): Promise<void> {
const redirectUrl = this.config.brevo.resolveConfig(scope).redirectUrlForImport;
const fileStream = fs.createReadStream(path);
if (!this.validateRedirectUrl(redirectUrl, scope)) {
throw new InvalidOptionArgumentError("Invalid scope. Scope is not allowed");
}

const targetGroups = await this.targetGroupRepository.find({ id: { $in: options.targetGroupIds } });

const result = await this.brevoContactImportService.importContactsFromCsv({
fileStream,
scope: options.scope,
scope,
redirectUrl,
targetGroups,
targetGroupIds,
});

this.logger.log(result);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
import { CometValidationException, RequiredPermission } from "@comet/cms-api";
import { EntityRepository } from "@mikro-orm/core";
import { InjectRepository } from "@mikro-orm/nestjs";
import { Body, Controller, Inject, Post, Type, UploadedFile, UseInterceptors } from "@nestjs/common";
import { FileInterceptor } from "@nestjs/platform-express";
import { TargetGroupInterface } from "src/target-group/entity/target-group-entity.factory";
import { Readable } from "stream";

import { BrevoContactImportService } from "../brevo-contact/brevo-contact-import.service";
Expand All @@ -18,7 +15,6 @@ export function createBrevoContactImportController({ Scope }: { Scope: Type<Emai
constructor(
@Inject(BREVO_MODULE_CONFIG) private readonly config: BrevoModuleConfig,
@Inject(BrevoContactImportService) private readonly brevoContactImportService: BrevoContactImportService,
@InjectRepository("TargetGroup") private readonly targetGroupRepository: EntityRepository<TargetGroupInterface>,
) {}

@Post("upload")
Expand All @@ -43,17 +39,15 @@ export function createBrevoContactImportController({ Scope }: { Scope: Type<Emai
const parsedScope = JSON.parse(scope) as EmailCampaignScopeInterface;
const redirectUrl = this.config.brevo.resolveConfig(parsedScope).redirectUrlForImport;

let parsedListIds = undefined;
if (listIds) parsedListIds = JSON.parse(listIds) as string[];

const targetGroups = await this.targetGroupRepository.find({ id: { $in: parsedListIds } });
let targetGroupIds = undefined;
if (listIds) targetGroupIds = JSON.parse(listIds) as string[];

const stream = Readable.from(file.buffer);
return this.brevoContactImportService.importContactsFromCsv({
fileStream: stream,
scope: parsedScope,
redirectUrl,
targetGroups,
targetGroupIds,
isAdminImport: true,
});
}
Expand Down
21 changes: 18 additions & 3 deletions packages/api/src/brevo-contact/brevo-contact-import.service.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import * as csv from "@fast-csv/parse";
import { EntityRepository } from "@mikro-orm/core";
import { InjectRepository } from "@mikro-orm/nestjs";
import { Inject, Injectable } from "@nestjs/common";
import { IsEmail, IsNotEmpty, validateSync } from "class-validator";
import isEqual from "lodash.isequal";
import { TargetGroupInterface } from "src/target-group/entity/target-group-entity.factory";
import { Readable } from "stream";

import { isErrorFromBrevo } from "../brevo-api/brevo-api.utils";
import { BrevoApiContactsService, CreateDoubleOptInContactData } from "../brevo-api/brevo-api-contact.service";
import { BrevoContactsService } from "../brevo-contact/brevo-contacts.service";
import { BrevoModuleConfig } from "../config/brevo-module.config";
import { BREVO_MODULE_CONFIG } from "../config/brevo-module.constants";
import { TargetGroupInterface } from "../target-group/entity/target-group-entity.factory";
import { TargetGroupsService } from "../target-group/target-groups.service";
import { EmailCampaignScopeInterface } from "../types";

Expand All @@ -33,7 +36,7 @@ interface ImportContactsFromCsvParams {
fileStream: Readable;
scope: EmailCampaignScopeInterface;
redirectUrl: string;
targetGroups?: TargetGroupInterface[];
targetGroupIds?: string[];
isAdminImport?: boolean;
}

Expand All @@ -44,16 +47,28 @@ export class BrevoContactImportService {
private readonly brevoApiContactsService: BrevoApiContactsService,
private readonly brevoContactsService: BrevoContactsService,
private readonly targetGroupsService: TargetGroupsService,
@InjectRepository("TargetGroup") private readonly targetGroupRepository: EntityRepository<TargetGroupInterface>,
) {}

async importContactsFromCsv({
fileStream,
scope,
redirectUrl,
targetGroups = [],
targetGroupIds = [],
isAdminImport = false,
}: ImportContactsFromCsvParams): Promise<CsvImportInformation> {
const failedColumns: unknown[] = [];
const targetGroups = await this.targetGroupRepository.find({ id: { $in: targetGroupIds } });

for (const targetGroup of targetGroups) {
if (targetGroup.isMainList) {
throw new Error("Main lists are not allowed as target groups for import");
}

if (!isEqual({ ...targetGroup.scope }, scope)) {
throw new Error("Target group scope does not match the scope of the import file");
}
}

const manuallyAssignedBrevoContacts = await Promise.all(
targetGroups.map((targetGroup) => {
Expand Down
6 changes: 6 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 72332f9

Please sign in to comment.