diff --git a/backend/packages/Upgrade/src/api/controllers/SegmentController.ts b/backend/packages/Upgrade/src/api/controllers/SegmentController.ts index 74769ffab9..47292a0676 100644 --- a/backend/packages/Upgrade/src/api/controllers/SegmentController.ts +++ b/backend/packages/Upgrade/src/api/controllers/SegmentController.ts @@ -2,7 +2,7 @@ import { JsonController, Get, Delete, Authorized, Post, Req, Body, QueryParams, import { SegmentService, SegmentWithStatus } from '../services/SegmentService'; import { Segment } from '../models/Segment'; import { AppRequest, PaginationResponse } from '../../types'; -import { SEGMENT_STATUS } from 'upgrade_types'; +import { IImportError, SEGMENT_STATUS } from 'upgrade_types'; import { DeleteListInputValidator, IdValidator, @@ -12,6 +12,7 @@ import { SegmentIdValidator, SegmentImportError, SegmentInputValidator, + SegmentListImportValidation, } from './validators/SegmentInputValidator'; import { SegmentPaginatedParamsValidator } from './validators/SegmentPaginatedParamsValidator'; import { ExperimentSegmentInclusion } from '../models/ExperimentSegmentInclusion'; @@ -622,6 +623,41 @@ export class SegmentController { return this.segmentService.importSegments(segments, request.logger); } + /** + * @swagger + * /segments/list/import: + * post: + * description: Import a list to a parent segment + * tags: + * - Segment + * produces: + * - application/json + * parameters: + * - in: body + * name: segment + * description: Segment list object + * required: true + * schema: + * type: object + * $ref: '#/definitions/Segment' + * responses: + * '200': + * description: Import a list to a parent segment + * schema: + * $ref: '#/definitions/segmentResponse' + * '401': + * description: Authorization Required Error + * '500': + * description: Internal Server Error, Insert Error in database, SegmentId is not valid, JSON format is not valid + */ + @Post('/list/import') + public importLists( + @Body({ validate: true }) lists: SegmentListImportValidation, + @Req() request: AppRequest + ): Promise { + return this.segmentService.importLists(lists, request.logger); + } + /** * @swagger * /segments/validation: diff --git a/backend/packages/Upgrade/src/api/controllers/validators/SegmentInputValidator.ts b/backend/packages/Upgrade/src/api/controllers/validators/SegmentInputValidator.ts index 7f6dc268ee..c423231f0f 100644 --- a/backend/packages/Upgrade/src/api/controllers/validators/SegmentInputValidator.ts +++ b/backend/packages/Upgrade/src/api/controllers/validators/SegmentInputValidator.ts @@ -120,3 +120,14 @@ export class SegmentIdValidator { @IsUUID() public segmentId: string; } + +export class SegmentListImportValidation { + @IsArray() + @ValidateNested({ each: true }) + @Type(() => SegmentFile) + public files: SegmentFile[]; + + @IsUUID() + @IsNotEmpty() + public parentSegmentId: string; +} diff --git a/backend/packages/Upgrade/src/api/services/SegmentService.ts b/backend/packages/Upgrade/src/api/services/SegmentService.ts index 226fae002e..7848b62f69 100644 --- a/backend/packages/Upgrade/src/api/services/SegmentService.ts +++ b/backend/packages/Upgrade/src/api/services/SegmentService.ts @@ -31,6 +31,7 @@ import { Group, SegmentValidationObj, ListInputValidator, + SegmentListImportValidation, } from '../controllers/validators/SegmentInputValidator'; import { ExperimentSegmentExclusionRepository } from '../repositories/ExperimentSegmentExclusionRepository'; import { ExperimentSegmentInclusionRepository } from '../repositories/ExperimentSegmentInclusionRepository'; @@ -518,6 +519,20 @@ export class SegmentService { return validatedSegments.importErrors; } + public async importLists(lists: SegmentListImportValidation, logger: UpgradeLogger): Promise { + const validatedLists = await this.checkSegmentsValidity(lists.files); + + for (const list of validatedLists.segments) { + // Giving new id to avoid segment duplication + list.id = uuid(); + list.type = SEGMENT_TYPE.PRIVATE; + + logger.info({ message: `Import segment list => ${JSON.stringify(list, undefined, 2)}` }); + await this.addList({ ...list, parentSegmentId: lists.parentSegmentId }, logger); + } + return validatedLists.importErrors; + } + public async checkSegmentsValidity(fileData: SegmentFile[]): Promise { const importFileErrors: SegmentImportError[] = []; const segments = fileData.filter((segment) => path.extname(segment.fileName) === '.json'); diff --git a/backend/packages/Upgrade/test/unit/services/SegmentService.test.ts b/backend/packages/Upgrade/test/unit/services/SegmentService.test.ts index c892e017ec..5e530237a3 100644 --- a/backend/packages/Upgrade/test/unit/services/SegmentService.test.ts +++ b/backend/packages/Upgrade/test/unit/services/SegmentService.test.ts @@ -523,6 +523,21 @@ describe('Segment Service Testing', () => { expect(segments).toEqual(returnSegment); }); + it('should import a segment list', async () => { + const returnSegment = [ + { + fileName: 'seg1.json', + error: null, + compatibilityType: IMPORT_COMPATIBILITY_TYPE.COMPATIBLE, + }, + ]; + service.getSegmentByIds = jest.fn().mockResolvedValue([seg1, seg2]); + repo.find = jest.fn().mockResolvedValue([]); + service.addList = jest.fn().mockResolvedValue(segValSegment); + const segments = await service.importLists({ parentSegmentId: 'seg1', files: [segValImportFile] }, logger); + expect(segments).toEqual(returnSegment); + }); + it('should throw an error when trying to import a segment that includes an unknown subsegment', async () => { const returnSegment = [ {