From cc5da6fde0a0d15c681c715e4a28ad81dfbf76a1 Mon Sep 17 00:00:00 2001 From: Firas Shmit Date: Thu, 7 Nov 2024 12:33:13 +0100 Subject: [PATCH 01/61] EW-1060 testing the new export via a test endpoint --- ansible/roles/common-cartridge/tasks/main.yml | 16 ++-- .../controller/common-cartridge.controller.ts | 6 ++ .../dto/exported-course.dto.ts | 28 +++++++ .../common-cartridge-export.service.ts | 77 ++++++++++++++++++- .../uc/common-cartridge.uc.ts | 7 ++ 5 files changed, 124 insertions(+), 10 deletions(-) create mode 100644 apps/server/src/modules/common-cartridge/dto/exported-course.dto.ts diff --git a/ansible/roles/common-cartridge/tasks/main.yml b/ansible/roles/common-cartridge/tasks/main.yml index a4d6e99575e..6771d9f73f8 100644 --- a/ansible/roles/common-cartridge/tasks/main.yml +++ b/ansible/roles/common-cartridge/tasks/main.yml @@ -52,11 +52,11 @@ - service # This is a testing route and will not be deployed -# - name: Ingress -# kubernetes.core.k8s: -# kubeconfig: ~/.kube/config -# namespace: "{{ NAMESPACE }}" -# template: ingress.yml.j2 -# when: WITH_COMMON_CARTRIDGE is defined and WITH_COMMON_CARTRIDGE|bool -# tags: -# - ingress +- name: Ingress + kubernetes.core.k8s: + kubeconfig: ~/.kube/config + namespace: "{{ NAMESPACE }}" + template: ingress.yml.j2 + when: WITH_COMMON_CARTRIDGE is defined and WITH_COMMON_CARTRIDGE|bool + tags: + - ingress diff --git a/apps/server/src/modules/common-cartridge/controller/common-cartridge.controller.ts b/apps/server/src/modules/common-cartridge/controller/common-cartridge.controller.ts index bd609c4ff88..3f6b60d3e51 100644 --- a/apps/server/src/modules/common-cartridge/controller/common-cartridge.controller.ts +++ b/apps/server/src/modules/common-cartridge/controller/common-cartridge.controller.ts @@ -3,6 +3,7 @@ import { ApiTags } from '@nestjs/swagger'; import { CommonCartridgeUc } from '../uc/common-cartridge.uc'; import { ExportCourseParams } from './dto'; import { CourseExportBodyResponse } from './dto/course-export-body.response'; +import { ExportedCourse } from '../dto/exported-course.dto'; @ApiTags('common-cartridge') @Controller('common-cartridge') @@ -13,4 +14,9 @@ export class CommonCartridgeController { public async exportCourse(@Param() exportCourseParams: ExportCourseParams): Promise { return this.commonCartridgeUC.exportCourse(exportCourseParams.parentId); } + + @Get('testexport/:parentId') + public async exportCourseToCommonCartridge(@Param() exportCourseParams: ExportCourseParams): Promise { + return this.commonCartridgeUC.exportCourseToCommonCartridge(exportCourseParams.parentId); + } } diff --git a/apps/server/src/modules/common-cartridge/dto/exported-course.dto.ts b/apps/server/src/modules/common-cartridge/dto/exported-course.dto.ts new file mode 100644 index 00000000000..537986612fd --- /dev/null +++ b/apps/server/src/modules/common-cartridge/dto/exported-course.dto.ts @@ -0,0 +1,28 @@ +import { BoardSkeletonDto } from '../common-cartridge-client/board-client'; +import { CardListResponseDto } from '../common-cartridge-client/card-client/dto/card-list-response.dto'; +import { CourseCommonCartridgeMetadataDto } from '../common-cartridge-client/course-client'; +import { LessonDto, LessonLinkedTaskDto } from '../common-cartridge-client/lesson-client/dto'; +import { RoomBoardDto } from '../common-cartridge-client/room-client/dto/room-board.dto'; + +export class ExportedCourse { + metadata: CourseCommonCartridgeMetadataDto; + + board: BoardSkeletonDto[]; + + roomBoard: RoomBoardDto; + + cards: CardListResponseDto; + + lessons: LessonDto[]; + + linkedTasks: LessonLinkedTaskDto[]; + + constructor(props: ExportedCourse) { + this.metadata = props.metadata; + this.board = props.board; + this.roomBoard = props.roomBoard; + this.cards = props.cards; + this.lessons = props.lessons; + this.linkedTasks = props.linkedTasks; + } +} diff --git a/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts b/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts index 05895643bf1..75fc34f7dd3 100644 --- a/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts +++ b/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts @@ -1,11 +1,16 @@ import { FileDto, FilesStorageClientAdapterService } from '@modules/files-storage-client'; import { Injectable } from '@nestjs/common'; -import { BoardClientAdapter } from '../common-cartridge-client/board-client'; +import { BoardClientAdapter, BoardSkeletonDto } from '../common-cartridge-client/board-client'; import { CourseCommonCartridgeMetadataDto, CoursesClientAdapter } from '../common-cartridge-client/course-client'; import { CourseRoomsClientAdapter } from '../common-cartridge-client/room-client'; import { RoomBoardDto } from '../common-cartridge-client/room-client/dto/room-board.dto'; import { CardClientAdapter } from '../common-cartridge-client/card-client/card-client.adapter'; import { CardListResponseDto } from '../common-cartridge-client/card-client/dto/card-list-response.dto'; +import { ExportedCourse } from '../dto/exported-course.dto'; +import { LessonClientAdapter } from '../common-cartridge-client/lesson-client/lesson-client.adapter'; +import { BoardColumnBoardDto } from '../common-cartridge-client/room-client/dto/board-column-board.dto'; +import { BoardLessonDto } from '../common-cartridge-client/room-client/dto/board-lesson.dto'; +import { LessonDto, LessonLinkedTaskDto } from '../common-cartridge-client/lesson-client/dto'; @Injectable() export class CommonCartridgeExportService { @@ -14,9 +19,59 @@ export class CommonCartridgeExportService { private readonly boardClientAdapter: BoardClientAdapter, private readonly cardClientAdapter: CardClientAdapter, private readonly coursesClientAdapter: CoursesClientAdapter, - private readonly courseRoomsClientAdapter: CourseRoomsClientAdapter + private readonly courseRoomsClientAdapter: CourseRoomsClientAdapter, + private readonly lessonClinetAdapter: LessonClientAdapter ) {} + public async exportCourse(courseId: string): Promise { + const courseCommonCartridgeMetadata: CourseCommonCartridgeMetadataDto = + await this.findCourseCommonCartridgeMetadata(courseId); + + // get room board + const roomBoard: RoomBoardDto = await this.findRoomBoardByCourseId(courseId); + + // get lessons ids + const lessonsIds = roomBoard.elements + .filter((element) => element.content instanceof BoardLessonDto) + .map((element) => element.content.id); + + // get lessons + const lessons = await Promise.all(lessonsIds.map((elementId) => this.findLessonById(elementId))); + + // get lessons tasks + const lessonsTasks = await Promise.all(lessonsIds.map((elementId) => this.findLessonTasks(elementId))); + + // get column boards ids + const columnBoardsIds = roomBoard.elements + .filter((element) => element.content instanceof BoardColumnBoardDto) + .map((element) => element.content.id); + + // get board skeleton of columnm boards + const boardSkeleton: BoardSkeletonDto[] = await Promise.all( + columnBoardsIds.map((elementId) => this.findBoardSkeletonById(elementId)) + ); + + // get cards ids + const columnsOfBoardSkeleton = boardSkeleton.map((board) => board.columns); + const cardsOfColumns = columnsOfBoardSkeleton.map((columns) => columns.map((column) => column.cards)); + const cardsIds = cardsOfColumns.flat(2).map((card) => card.cardId); + + // get cards + const cards = await this.findAllCardsByIds(cardsIds); + + // export course to common cartridge + const exportedCourse: ExportedCourse = { + metadata: courseCommonCartridgeMetadata, + board: boardSkeleton, + roomBoard, + cards, + lessons, + linkedTasks: lessonsTasks.flat(1), + }; + + return exportedCourse; + } + public async findCourseFileRecords(courseId: string): Promise { const courseFiles = await this.filesService.listFilesOfParent(courseId); @@ -35,9 +90,27 @@ export class CommonCartridgeExportService { return courseRooms; } + public async findBoardSkeletonById(boardId: string): Promise { + const boardSkeleton = await this.boardClientAdapter.getBoardSkeletonById(boardId); + + return boardSkeleton; + } + public async findAllCardsByIds(ids: Array): Promise { const cards = await this.cardClientAdapter.getAllBoardCardsByIds(ids); return cards; } + + public async findLessonById(lessonId: string): Promise { + const lesson = await this.lessonClinetAdapter.getLessonById(lessonId); + + return lesson; + } + + public async findLessonTasks(lessonId: string): Promise { + const lessonTasks = await this.lessonClinetAdapter.getLessonTasks(lessonId); + + return lessonTasks; + } } diff --git a/apps/server/src/modules/common-cartridge/uc/common-cartridge.uc.ts b/apps/server/src/modules/common-cartridge/uc/common-cartridge.uc.ts index 8caa9381633..b76970e8890 100644 --- a/apps/server/src/modules/common-cartridge/uc/common-cartridge.uc.ts +++ b/apps/server/src/modules/common-cartridge/uc/common-cartridge.uc.ts @@ -4,6 +4,7 @@ import { CourseFileIdsResponse } from '../controller/dto'; import { CommonCartridgeExportService } from '../service/common-cartridge-export.service'; import { CourseExportBodyResponse } from '../controller/dto/course-export-body.response'; import { CourseCommonCartridgeMetadataDto } from '../common-cartridge-client/course-client'; +import { ExportedCourse } from '../dto/exported-course.dto'; @Injectable() export class CommonCartridgeUc { @@ -22,4 +23,10 @@ export class CommonCartridgeUc { return response; } + + public async exportCourseToCommonCartridge(courseId: EntityId): Promise { + const exportedCourse = await this.exportService.exportCourse(courseId); + + return exportedCourse; + } } From 7729acc45b441bc3af3c43fd2b272d18020e9815 Mon Sep 17 00:00:00 2001 From: Firas Shmit Date: Thu, 7 Nov 2024 14:45:25 +0100 Subject: [PATCH 02/61] EW-1060 moved linked task to lesson dto --- .../lesson-client/dto/lesson.dto.ts | 4 ++++ .../lesson-client/lesson-client.adapter.ts | 1 + .../common-cartridge/dto/exported-course.dto.ts | 5 +---- .../service/common-cartridge-export.service.ts | 16 +++------------- 4 files changed, 9 insertions(+), 17 deletions(-) diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/lesson.dto.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/lesson.dto.ts index 864b6502f19..00dc9c9cb76 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/lesson.dto.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/lesson.dto.ts @@ -1,4 +1,5 @@ import { LessonContentDto } from './lesson-contents.dto'; +import { LessonLinkedTaskDto } from './lesson-linked-task.dto'; import { LessonMaterialsDto } from './lesson-materials.dto'; export class LessonDto { @@ -18,6 +19,8 @@ export class LessonDto { materials: LessonMaterialsDto[]; + linkedTasks?: LessonLinkedTaskDto[]; + constructor(props: LessonDto) { this.lessonId = props.lessonId; this.name = props.name; @@ -27,5 +30,6 @@ export class LessonDto { this.position = props.position; this.contents = props.contents; this.materials = props.materials; + this.linkedTasks = props.linkedTasks; } } diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lesson-client.adapter.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lesson-client.adapter.ts index 22e8abf7eec..2f3930ad9f9 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lesson-client.adapter.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lesson-client.adapter.ts @@ -15,6 +15,7 @@ export class LessonClientAdapter { const options = this.createOptionParams(); const response = await this.lessonApi.lessonControllerGetLesson(lessonId, options); const lessonDto = LessonDtoMapper.mapToLessonDto(response.data); + lessonDto.linkedTasks = await this.getLessonTasks(lessonId); return lessonDto; } diff --git a/apps/server/src/modules/common-cartridge/dto/exported-course.dto.ts b/apps/server/src/modules/common-cartridge/dto/exported-course.dto.ts index 537986612fd..4864557ce1a 100644 --- a/apps/server/src/modules/common-cartridge/dto/exported-course.dto.ts +++ b/apps/server/src/modules/common-cartridge/dto/exported-course.dto.ts @@ -1,7 +1,7 @@ import { BoardSkeletonDto } from '../common-cartridge-client/board-client'; import { CardListResponseDto } from '../common-cartridge-client/card-client/dto/card-list-response.dto'; import { CourseCommonCartridgeMetadataDto } from '../common-cartridge-client/course-client'; -import { LessonDto, LessonLinkedTaskDto } from '../common-cartridge-client/lesson-client/dto'; +import { LessonDto } from '../common-cartridge-client/lesson-client/dto'; import { RoomBoardDto } from '../common-cartridge-client/room-client/dto/room-board.dto'; export class ExportedCourse { @@ -15,14 +15,11 @@ export class ExportedCourse { lessons: LessonDto[]; - linkedTasks: LessonLinkedTaskDto[]; - constructor(props: ExportedCourse) { this.metadata = props.metadata; this.board = props.board; this.roomBoard = props.roomBoard; this.cards = props.cards; this.lessons = props.lessons; - this.linkedTasks = props.linkedTasks; } } diff --git a/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts b/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts index 75fc34f7dd3..11696410a30 100644 --- a/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts +++ b/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts @@ -10,7 +10,7 @@ import { ExportedCourse } from '../dto/exported-course.dto'; import { LessonClientAdapter } from '../common-cartridge-client/lesson-client/lesson-client.adapter'; import { BoardColumnBoardDto } from '../common-cartridge-client/room-client/dto/board-column-board.dto'; import { BoardLessonDto } from '../common-cartridge-client/room-client/dto/board-lesson.dto'; -import { LessonDto, LessonLinkedTaskDto } from '../common-cartridge-client/lesson-client/dto'; +import { LessonDto } from '../common-cartridge-client/lesson-client/dto'; @Injectable() export class CommonCartridgeExportService { @@ -35,12 +35,9 @@ export class CommonCartridgeExportService { .filter((element) => element.content instanceof BoardLessonDto) .map((element) => element.content.id); - // get lessons + // get lessons and lesson tasks const lessons = await Promise.all(lessonsIds.map((elementId) => this.findLessonById(elementId))); - // get lessons tasks - const lessonsTasks = await Promise.all(lessonsIds.map((elementId) => this.findLessonTasks(elementId))); - // get column boards ids const columnBoardsIds = roomBoard.elements .filter((element) => element.content instanceof BoardColumnBoardDto) @@ -66,7 +63,6 @@ export class CommonCartridgeExportService { roomBoard, cards, lessons, - linkedTasks: lessonsTasks.flat(1), }; return exportedCourse; @@ -102,15 +98,9 @@ export class CommonCartridgeExportService { return cards; } - public async findLessonById(lessonId: string): Promise { + private async findLessonById(lessonId: string): Promise { const lesson = await this.lessonClinetAdapter.getLessonById(lessonId); return lesson; } - - public async findLessonTasks(lessonId: string): Promise { - const lessonTasks = await this.lessonClinetAdapter.getLessonTasks(lessonId); - - return lessonTasks; - } } From 414b696c3ab5dd8b252a9af0b6fba82c2bb0b3d0 Mon Sep 17 00:00:00 2001 From: Firas Shmit Date: Mon, 11 Nov 2024 10:50:32 +0100 Subject: [PATCH 03/61] EW-1060 implemented new cc export service via microservice --- .../lesson-client/dto/lesson-contents.dto.ts | 3 + .../lesson-client/mapper/lesson-dto.mapper.ts | 1 + .../controller/common-cartridge.controller.ts | 23 +- .../controller/dto/course.query.params.ts | 15 ++ .../dto/exported-course.dto.ts | 1 + .../common-cartridge-export.service.ts | 231 +++++++++++++++--- .../service/common-cartridge.mapper.ts | 173 +++++++++++++ .../uc/common-cartridge.uc.ts | 6 +- 8 files changed, 407 insertions(+), 46 deletions(-) create mode 100644 apps/server/src/modules/common-cartridge/controller/dto/course.query.params.ts create mode 100644 apps/server/src/modules/common-cartridge/service/common-cartridge.mapper.ts diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/lesson-contents.dto.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/lesson-contents.dto.ts index e9f00a471d4..789f7a1e560 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/lesson-contents.dto.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/lesson-contents.dto.ts @@ -1,4 +1,6 @@ export class LessonContentDto { + id: string | undefined; + content: object; title: string; @@ -22,6 +24,7 @@ export const LessonContentDtoComponentValues = { RESOURCES: 'resources', TEXT: 'text', NE_XBOARD: 'neXboard', + LERNSTORE: 'lernstore', } as const; export type LessonContentDtoComponent = diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/mapper/lesson-dto.mapper.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/mapper/lesson-dto.mapper.ts index 150037ddaee..640867bf9d6 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/mapper/lesson-dto.mapper.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/mapper/lesson-dto.mapper.ts @@ -57,6 +57,7 @@ export class LessonDtoMapper { private static mapToLessenContentDto(lessonContentResponse: LessonContentResponse): LessonContentDto { const lessonContentDto = new LessonContentDto({ + id: lessonContentResponse.id, content: lessonContentResponse.content, title: lessonContentResponse.title, component: lessonContentResponse.component, diff --git a/apps/server/src/modules/common-cartridge/controller/common-cartridge.controller.ts b/apps/server/src/modules/common-cartridge/controller/common-cartridge.controller.ts index 3f6b60d3e51..7893a28ac56 100644 --- a/apps/server/src/modules/common-cartridge/controller/common-cartridge.controller.ts +++ b/apps/server/src/modules/common-cartridge/controller/common-cartridge.controller.ts @@ -1,9 +1,10 @@ -import { Controller, Get, Param } from '@nestjs/common'; +import { Controller, Get, Param, Query, Res, StreamableFile } from '@nestjs/common'; import { ApiTags } from '@nestjs/swagger'; +import { Response } from 'express'; import { CommonCartridgeUc } from '../uc/common-cartridge.uc'; import { ExportCourseParams } from './dto'; import { CourseExportBodyResponse } from './dto/course-export-body.response'; -import { ExportedCourse } from '../dto/exported-course.dto'; +import { CourseQueryParams } from './dto/course.query.params'; @ApiTags('common-cartridge') @Controller('common-cartridge') @@ -16,7 +17,21 @@ export class CommonCartridgeController { } @Get('testexport/:parentId') - public async exportCourseToCommonCartridge(@Param() exportCourseParams: ExportCourseParams): Promise { - return this.commonCartridgeUC.exportCourseToCommonCartridge(exportCourseParams.parentId); + public async exportCourseToCommonCartridge( + @Param() exportCourseParams: ExportCourseParams, + @Query() queryParams: CourseQueryParams, + @Res({ passthrough: true }) response: Response + ): Promise { + const result = await this.commonCartridgeUC.exportCourseToCommonCartridge( + exportCourseParams.parentId, + queryParams.version + ); + + response.set({ + 'Content-Type': 'application/zip', + 'Content-Disposition': `attachment; filename=course_${exportCourseParams.parentId}.zip`, + }); + + return new StreamableFile(result); } } diff --git a/apps/server/src/modules/common-cartridge/controller/dto/course.query.params.ts b/apps/server/src/modules/common-cartridge/controller/dto/course.query.params.ts new file mode 100644 index 00000000000..6ca66a57442 --- /dev/null +++ b/apps/server/src/modules/common-cartridge/controller/dto/course.query.params.ts @@ -0,0 +1,15 @@ +import { IsString, Matches } from 'class-validator'; +import { ApiProperty } from '@nestjs/swagger'; +import { CommonCartridgeVersion } from '../../export/common-cartridge.enums'; + +export class CourseQueryParams { + @IsString() + @Matches(Object.values(CommonCartridgeVersion).join('|')) + @ApiProperty({ + description: 'The version of CC export', + required: true, + nullable: false, + enum: CommonCartridgeVersion, + }) + public readonly version!: CommonCartridgeVersion; +} diff --git a/apps/server/src/modules/common-cartridge/dto/exported-course.dto.ts b/apps/server/src/modules/common-cartridge/dto/exported-course.dto.ts index 4864557ce1a..9b2061bdf1b 100644 --- a/apps/server/src/modules/common-cartridge/dto/exported-course.dto.ts +++ b/apps/server/src/modules/common-cartridge/dto/exported-course.dto.ts @@ -4,6 +4,7 @@ import { CourseCommonCartridgeMetadataDto } from '../common-cartridge-client/cou import { LessonDto } from '../common-cartridge-client/lesson-client/dto'; import { RoomBoardDto } from '../common-cartridge-client/room-client/dto/room-board.dto'; +// TODO to be removed export class ExportedCourse { metadata: CourseCommonCartridgeMetadataDto; diff --git a/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts b/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts index 11696410a30..6409b09bcb5 100644 --- a/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts +++ b/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts @@ -1,16 +1,33 @@ import { FileDto, FilesStorageClientAdapterService } from '@modules/files-storage-client'; import { Injectable } from '@nestjs/common'; -import { BoardClientAdapter, BoardSkeletonDto } from '../common-cartridge-client/board-client'; +import { BoardClientAdapter, BoardSkeletonDto, ColumnSkeletonDto } from '../common-cartridge-client/board-client'; import { CourseCommonCartridgeMetadataDto, CoursesClientAdapter } from '../common-cartridge-client/course-client'; import { CourseRoomsClientAdapter } from '../common-cartridge-client/room-client'; import { RoomBoardDto } from '../common-cartridge-client/room-client/dto/room-board.dto'; import { CardClientAdapter } from '../common-cartridge-client/card-client/card-client.adapter'; import { CardListResponseDto } from '../common-cartridge-client/card-client/dto/card-list-response.dto'; -import { ExportedCourse } from '../dto/exported-course.dto'; import { LessonClientAdapter } from '../common-cartridge-client/lesson-client/lesson-client.adapter'; import { BoardColumnBoardDto } from '../common-cartridge-client/room-client/dto/board-column-board.dto'; import { BoardLessonDto } from '../common-cartridge-client/room-client/dto/board-lesson.dto'; -import { LessonDto } from '../common-cartridge-client/lesson-client/dto'; +import { LessonContentDto, LessonDto } from '../common-cartridge-client/lesson-client/dto'; +import { CommonCartridgeFileBuilder } from '../export/builders/common-cartridge-file-builder'; +import { CommonCartridgeVersion } from '../export/common-cartridge.enums'; +import { CommonCartridgeExportMapper } from './common-cartridge.mapper'; +import { CommonCartridgeOrganizationNode } from '../export/builders/common-cartridge-organization-node'; +import { BoardTaskDto } from '../common-cartridge-client/room-client/dto/board-task.dto'; +import { createIdentifier } from '../export/utils'; +import { BoardElementDto } from '../common-cartridge-client/room-client/dto/board-element.dto'; +import { BoardElementDtoType } from '../common-cartridge-client/room-client/enums/board-element.enum'; +import { CardResponseDto } from '../common-cartridge-client/card-client/dto/card-response.dto'; +import { CardResponseElementsInnerDto } from '../common-cartridge-client/card-client/types/card-response-elements-inner.type'; +import { RichTextElementResponseDto } from '../common-cartridge-client/card-client/dto/rich-text-element-response.dto'; +import { LinkElementResponseDto } from '../common-cartridge-client/card-client/dto/link-element-response.dto'; + +export const isRichTextElement = (reference: unknown): reference is RichTextElementResponseDto => + reference instanceof RichTextElementResponseDto; + +export const isLinkElement = (reference: unknown): reference is LinkElementResponseDto => + reference instanceof LinkElementResponseDto; @Injectable() export class CommonCartridgeExportService { @@ -20,52 +37,31 @@ export class CommonCartridgeExportService { private readonly cardClientAdapter: CardClientAdapter, private readonly coursesClientAdapter: CoursesClientAdapter, private readonly courseRoomsClientAdapter: CourseRoomsClientAdapter, - private readonly lessonClinetAdapter: LessonClientAdapter + private readonly lessonClinetAdapter: LessonClientAdapter, + private readonly mapper: CommonCartridgeExportMapper ) {} - public async exportCourse(courseId: string): Promise { + public async exportCourse(courseId: string, version: CommonCartridgeVersion): Promise { + const builder = new CommonCartridgeFileBuilder(this.mapper.mapCourseToManifestNew(version, courseId)); + const courseCommonCartridgeMetadata: CourseCommonCartridgeMetadataDto = await this.findCourseCommonCartridgeMetadata(courseId); - // get room board - const roomBoard: RoomBoardDto = await this.findRoomBoardByCourseId(courseId); - - // get lessons ids - const lessonsIds = roomBoard.elements - .filter((element) => element.content instanceof BoardLessonDto) - .map((element) => element.content.id); - - // get lessons and lesson tasks - const lessons = await Promise.all(lessonsIds.map((elementId) => this.findLessonById(elementId))); + builder.addMetadata(this.mapper.mapCourseToMetadata(courseCommonCartridgeMetadata)); - // get column boards ids - const columnBoardsIds = roomBoard.elements - .filter((element) => element.content instanceof BoardColumnBoardDto) - .map((element) => element.content.id); - - // get board skeleton of columnm boards - const boardSkeleton: BoardSkeletonDto[] = await Promise.all( - columnBoardsIds.map((elementId) => this.findBoardSkeletonById(elementId)) - ); + // get room board and the structure of the course + const roomBoard: RoomBoardDto = await this.findRoomBoardByCourseId(courseId); - // get cards ids - const columnsOfBoardSkeleton = boardSkeleton.map((board) => board.columns); - const cardsOfColumns = columnsOfBoardSkeleton.map((columns) => columns.map((column) => column.cards)); - const cardsIds = cardsOfColumns.flat(2).map((card) => card.cardId); + // add lessons to organization + await this.addLessons(builder, version, roomBoard.elements); - // get cards - const cards = await this.findAllCardsByIds(cardsIds); + // add tasks to organization + this.addTasks(builder, version, roomBoard.elements); - // export course to common cartridge - const exportedCourse: ExportedCourse = { - metadata: courseCommonCartridgeMetadata, - board: boardSkeleton, - roomBoard, - cards, - lessons, - }; + // add column boards and cards to organization + await this.addColumnBoards(builder, roomBoard.elements); - return exportedCourse; + return builder.build(); } public async findCourseFileRecords(courseId: string): Promise { @@ -103,4 +99,161 @@ export class CommonCartridgeExportService { return lesson; } + + private addComponentToOrganization( + component: LessonContentDto, + lessonOrganization: CommonCartridgeOrganizationNode + ): void { + const resources = this.mapper.mapContentToResources(component); + + if (Array.isArray(resources)) { + const componentOrganization = lessonOrganization.createChild(this.mapper.mapContentToOrganization(component)); + + resources.forEach((resource) => { + componentOrganization.addResource(resource); + }); + } else { + lessonOrganization.addResource(resources); + } + } + + private async addLessons( + builder: CommonCartridgeFileBuilder, + version: CommonCartridgeVersion, + elements: BoardElementDto[] + ): Promise { + // get lessons ids from room board + const filteredLessons = this.filterLessonFromBoardElements(elements); + const lessonsIds = filteredLessons.map((lesson) => lesson.id); + + // get lessons and lesson's linked tasks from the server + const lessons = await Promise.all(lessonsIds.map((elementId) => this.findLessonById(elementId))); + + lessons.forEach((lesson) => { + const lessonsOrganization = builder.createOrganization(this.mapper.mapLessonToOrganization(lesson)); + + lesson.contents.forEach((content) => { + this.addComponentToOrganization(content, lessonsOrganization); + }); + + lesson.linkedTasks?.forEach((task) => { + lessonsOrganization.addResource(this.mapper.mapLinkedTaskToResource(task, version)); + }); + }); + } + + private addTasks( + builder: CommonCartridgeFileBuilder, + version: CommonCartridgeVersion, + elements: BoardElementDto[] + ): void { + if (!elements) { + return; + } + + const tasks: BoardTaskDto[] = this.filterTasksFromBoardElements(elements); + + const tasksOrganization = builder.createOrganization({ + title: 'Aufgaben', + identifier: createIdentifier(), + }); + + tasks.forEach((task) => { + tasksOrganization.addResource(this.mapper.mapTaskToResource(task, version)); + }); + } + + private async addColumnBoards(builder: CommonCartridgeFileBuilder, elements: BoardElementDto[]): Promise { + const columnBoards = this.filterColumnBoardFromBoardElement(elements); + const columnBoardsIds = columnBoards.map((element) => element.columnBoardId); + + // get board skeleton of columnm boards from the server + const boardSkeletons: BoardSkeletonDto[] = await Promise.all( + columnBoardsIds.map((elementId) => this.findBoardSkeletonById(elementId)) + ); + + await Promise.all( + boardSkeletons.map(async (boardSkeleton) => { + const columnBoardOrganization = builder.createOrganization({ + title: boardSkeleton.title, + identifier: createIdentifier(boardSkeleton.boardId), + }); + + await Promise.all( + boardSkeleton.columns.map((column) => this.addColumnToOrganization(column, columnBoardOrganization)) + ); + }) + ); + } + + private async addColumnToOrganization( + column: ColumnSkeletonDto, + columnBoardOrganization: CommonCartridgeOrganizationNode + ): Promise { + const { columnId } = column; + const columnOrganization = columnBoardOrganization.createChild({ + title: column.title ?? '', + identifier: createIdentifier(columnId), + }); + + // get cards ids by every column + const cardsIds = column.cards.map((card) => card.cardId); + const listOfCards: CardListResponseDto = await this.findAllCardsByIds(cardsIds); + + listOfCards.data.forEach((card) => { + this.addCardToOrganization(card, columnOrganization); + }); + } + + private addCardToOrganization(card: CardResponseDto, columnOrganization: CommonCartridgeOrganizationNode): void { + const cardOrganization = columnOrganization.createChild({ + title: card.title ?? '', + identifier: createIdentifier(card.id), + }); + + card.elements.forEach((element) => { + this.addCardElementToOrganization(element, cardOrganization); + }); + } + + private addCardElementToOrganization( + element: CardResponseElementsInnerDto, + cardOrganization: CommonCartridgeOrganizationNode + ): void { + if (isRichTextElement(element)) { + const resource = this.mapper.mapRichTextElementToResource(element); + + cardOrganization.addResource(resource); + } + + if (isLinkElement(element)) { + const resource = this.mapper.mapLinkElementToResource(element); + + cardOrganization.addResource(resource); + } + } + + private filterTasksFromBoardElements(elements: BoardElementDto[]): BoardTaskDto[] { + const tasks: BoardTaskDto[] = elements + .filter((element) => element.type === BoardElementDtoType.TASK) + .map((element) => element.content as BoardTaskDto); + + return tasks; + } + + private filterLessonFromBoardElements(elements: BoardElementDto[]): BoardLessonDto[] { + const lessons: BoardLessonDto[] = elements + .filter((element) => element.content instanceof BoardLessonDto) + .map((element) => element.content as BoardLessonDto); + + return lessons; + } + + private filterColumnBoardFromBoardElement(elements: BoardElementDto[]): BoardColumnBoardDto[] { + const columnBoard: BoardColumnBoardDto[] = elements + .filter((element) => element.type === BoardElementDtoType.COLUMN_BOARD) + .map((element) => element.content as BoardColumnBoardDto); + + return columnBoard; + } } diff --git a/apps/server/src/modules/common-cartridge/service/common-cartridge.mapper.ts b/apps/server/src/modules/common-cartridge/service/common-cartridge.mapper.ts new file mode 100644 index 00000000000..125afde4ac1 --- /dev/null +++ b/apps/server/src/modules/common-cartridge/service/common-cartridge.mapper.ts @@ -0,0 +1,173 @@ +import sanitizeHtml from 'sanitize-html'; +import { CourseCommonCartridgeMetadataDto } from '../common-cartridge-client/course-client'; +import { + LessonContentDto, + LessonContentDtoComponentValues, + LessonDto, + LessonLinkedTaskDto, +} from '../common-cartridge-client/lesson-client/dto'; +import { CommonCartridgeOrganizationProps } from '../export/builders/common-cartridge-file-builder'; +import { + CommonCartridgeElementType, + CommonCartridgeIntendedUseType, + CommonCartridgeResourceType, + CommonCartridgeVersion, +} from '../export/common-cartridge.enums'; +import { CommonCartridgeElementProps } from '../export/elements/common-cartridge-element-factory'; +import { createIdentifier } from '../export/utils'; +import { CommonCartridgeResourceProps } from '../export/resources/common-cartridge-resource-factory'; +import { BoardTaskDto } from '../common-cartridge-client/room-client/dto/board-task.dto'; +import { RichTextElementResponseDto } from '../common-cartridge-client/card-client/dto/rich-text-element-response.dto'; +import { LinkElementResponseDto } from '../common-cartridge-client/card-client/dto/link-element-response.dto'; + +export class CommonCartridgeExportMapper { + private static readonly GEOGEBRA_BASE_URL: string = 'https://geogebra.org'; + + public mapCourseToManifestNew( + version: CommonCartridgeVersion, + courseId: string + ): { version: CommonCartridgeVersion; identifier: string } { + return { + version, + identifier: createIdentifier(courseId), + }; + } + + public mapCourseToMetadata(courseMetadata: CourseCommonCartridgeMetadataDto): CommonCartridgeElementProps { + return { + type: CommonCartridgeElementType.METADATA, + title: courseMetadata.title, + copyrightOwners: courseMetadata.copyRightOwners, + creationDate: courseMetadata.creationDate ? new Date(courseMetadata.creationDate) : new Date(), + }; + } + + public mapLessonToOrganization(lesson: LessonDto): CommonCartridgeOrganizationProps { + return { + identifier: createIdentifier(lesson.lessonId), + title: lesson.name, + }; + } + + public mapContentToResources( + lessonContent: LessonContentDto + ): CommonCartridgeResourceProps | CommonCartridgeResourceProps[] { + switch (lessonContent.component) { + case LessonContentDtoComponentValues.TEXT: + return { + type: CommonCartridgeResourceType.WEB_CONTENT, + identifier: createIdentifier(lessonContent.id), + title: lessonContent.title, + html: `

${lessonContent.title}

${lessonContent.content.toString()}

`, + intendedUse: CommonCartridgeIntendedUseType.UNSPECIFIED, + }; + case LessonContentDtoComponentValues.GEO_GEBRA: + return { + type: CommonCartridgeResourceType.WEB_LINK, + identifier: createIdentifier(lessonContent.id), + title: lessonContent.title, + // TODO - check if the url is correct + url: `${CommonCartridgeExportMapper.GEOGEBRA_BASE_URL}/m/${lessonContent.content.toString()}`, + }; + case LessonContentDtoComponentValues.ETHERPAD: + return { + type: CommonCartridgeResourceType.WEB_LINK, + identifier: createIdentifier(lessonContent.id), + // TODO - better solution for title + title: `${lessonContent.title} - ${lessonContent.content.toString()}`, + // TODO better solution for url + url: lessonContent.content.toString(), + }; + case LessonContentDtoComponentValues.LERNSTORE: + return { + type: CommonCartridgeResourceType.WEB_LINK, + identifier: createIdentifier(lessonContent.id), + title: lessonContent.title, + // TODO better solution for url + url: lessonContent.content.toString(), + }; + default: + return []; + } + } + + public mapContentToOrganization(content: LessonContentDto): CommonCartridgeOrganizationProps { + return { + identifier: createIdentifier(content.id), + title: content.title, + }; + } + + public mapTaskToResource(task: BoardTaskDto, version: CommonCartridgeVersion): CommonCartridgeResourceProps { + const intendedUse = (() => { + switch (version) { + case CommonCartridgeVersion.V_1_1_0: + return CommonCartridgeIntendedUseType.UNSPECIFIED; + case CommonCartridgeVersion.V_1_3_0: + return CommonCartridgeIntendedUseType.ASSIGNMENT; + default: + return CommonCartridgeIntendedUseType.UNSPECIFIED; + } + })(); + + return { + type: CommonCartridgeResourceType.WEB_CONTENT, + identifier: createIdentifier(task.id), + title: task.name, + html: `

${task.name}

${task.description ?? ''}

`, + intendedUse, + }; + } + + public mapLinkedTaskToResource( + task: LessonLinkedTaskDto, + version: CommonCartridgeVersion + ): CommonCartridgeResourceProps { + const intendedUse = (() => { + switch (version) { + case CommonCartridgeVersion.V_1_1_0: + return CommonCartridgeIntendedUseType.UNSPECIFIED; + case CommonCartridgeVersion.V_1_3_0: + return CommonCartridgeIntendedUseType.ASSIGNMENT; + default: + return CommonCartridgeIntendedUseType.UNSPECIFIED; + } + })(); + + return { + type: CommonCartridgeResourceType.WEB_CONTENT, + identifier: createIdentifier(), + title: task.name, + html: `

${task.name}

${task.description}

`, + intendedUse, + }; + } + + public mapRichTextElementToResource(element: RichTextElementResponseDto): CommonCartridgeResourceProps { + return { + type: CommonCartridgeResourceType.WEB_CONTENT, + identifier: createIdentifier(element.id), + title: this.getTextTitle(element.content.text), + html: `

${element.content.text}

`, + intendedUse: CommonCartridgeIntendedUseType.UNSPECIFIED, + }; + } + + public mapLinkElementToResource(element: LinkElementResponseDto): CommonCartridgeResourceProps { + return { + type: CommonCartridgeResourceType.WEB_LINK, + identifier: createIdentifier(element.id), + title: element.content.title, + url: element.content.url, + }; + } + + private getTextTitle(text: string): string { + const title = sanitizeHtml(text, { + allowedTags: [], + allowedAttributes: {}, + }).slice(0, 50); + + return title; + } +} diff --git a/apps/server/src/modules/common-cartridge/uc/common-cartridge.uc.ts b/apps/server/src/modules/common-cartridge/uc/common-cartridge.uc.ts index b76970e8890..89903c8bea8 100644 --- a/apps/server/src/modules/common-cartridge/uc/common-cartridge.uc.ts +++ b/apps/server/src/modules/common-cartridge/uc/common-cartridge.uc.ts @@ -4,7 +4,7 @@ import { CourseFileIdsResponse } from '../controller/dto'; import { CommonCartridgeExportService } from '../service/common-cartridge-export.service'; import { CourseExportBodyResponse } from '../controller/dto/course-export-body.response'; import { CourseCommonCartridgeMetadataDto } from '../common-cartridge-client/course-client'; -import { ExportedCourse } from '../dto/exported-course.dto'; +import { CommonCartridgeVersion } from '../export/common-cartridge.enums'; @Injectable() export class CommonCartridgeUc { @@ -24,8 +24,8 @@ export class CommonCartridgeUc { return response; } - public async exportCourseToCommonCartridge(courseId: EntityId): Promise { - const exportedCourse = await this.exportService.exportCourse(courseId); + public async exportCourseToCommonCartridge(courseId: EntityId, version: CommonCartridgeVersion): Promise { + const exportedCourse = await this.exportService.exportCourse(courseId, version); return exportedCourse; } From cf66e8fe0336290934fa4c075e1c27b3bd0b4c36 Mon Sep 17 00:00:00 2001 From: Firas Shmit Date: Mon, 11 Nov 2024 11:13:47 +0100 Subject: [PATCH 04/61] EW-1060 resolved dependecy of the new cc mapper --- .../src/modules/common-cartridge/common-cartridge.module.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/server/src/modules/common-cartridge/common-cartridge.module.ts b/apps/server/src/modules/common-cartridge/common-cartridge.module.ts index babe99d04d3..ab1cfbd8d68 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge.module.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge.module.ts @@ -13,6 +13,7 @@ import { CommonCartridgeUc } from './uc/common-cartridge.uc'; import { CourseRoomsModule } from './common-cartridge-client/room-client'; import { CardClientModule } from './common-cartridge-client/card-client/card-client.module'; import { LessonClientModule } from './common-cartridge-client/lesson-client/lesson-client.module'; +import { CommonCartridgeExportMapper } from './service/common-cartridge.mapper'; @Module({ imports: [ @@ -43,7 +44,7 @@ import { LessonClientModule } from './common-cartridge-client/lesson-client/less basePath: `${Configuration.get('API_HOST') as string}/v3/`, }), ], - providers: [CommonCartridgeUc, CommonCartridgeExportService], + providers: [CommonCartridgeExportMapper, CommonCartridgeUc, CommonCartridgeExportService], exports: [CommonCartridgeUc], }) export class CommonCartridgeModule {} From b456cb8c97a6d5944ce594b5039d2713e300ea8d Mon Sep 17 00:00:00 2001 From: Firas Shmit Date: Mon, 11 Nov 2024 11:54:38 +0100 Subject: [PATCH 05/61] EW-1060 deleted testing dto of cc export --- .../dto/exported-course.dto.ts | 26 ------------------- 1 file changed, 26 deletions(-) delete mode 100644 apps/server/src/modules/common-cartridge/dto/exported-course.dto.ts diff --git a/apps/server/src/modules/common-cartridge/dto/exported-course.dto.ts b/apps/server/src/modules/common-cartridge/dto/exported-course.dto.ts deleted file mode 100644 index 9b2061bdf1b..00000000000 --- a/apps/server/src/modules/common-cartridge/dto/exported-course.dto.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { BoardSkeletonDto } from '../common-cartridge-client/board-client'; -import { CardListResponseDto } from '../common-cartridge-client/card-client/dto/card-list-response.dto'; -import { CourseCommonCartridgeMetadataDto } from '../common-cartridge-client/course-client'; -import { LessonDto } from '../common-cartridge-client/lesson-client/dto'; -import { RoomBoardDto } from '../common-cartridge-client/room-client/dto/room-board.dto'; - -// TODO to be removed -export class ExportedCourse { - metadata: CourseCommonCartridgeMetadataDto; - - board: BoardSkeletonDto[]; - - roomBoard: RoomBoardDto; - - cards: CardListResponseDto; - - lessons: LessonDto[]; - - constructor(props: ExportedCourse) { - this.metadata = props.metadata; - this.board = props.board; - this.roomBoard = props.roomBoard; - this.cards = props.cards; - this.lessons = props.lessons; - } -} From 4eb28900189b2eee7eb532572b0f3715b5ff7b6c Mon Sep 17 00:00:00 2001 From: Firas Shmit Date: Tue, 12 Nov 2024 15:15:12 +0100 Subject: [PATCH 06/61] EW-1060 created some classes instead of interfaces --- .../controller/dto/lesson-content.response.ts | 85 +++++++++++++++++-- openapitools.json | 24 ++++++ package.json | 3 +- 3 files changed, 103 insertions(+), 9 deletions(-) diff --git a/apps/server/src/modules/lesson/controller/dto/lesson-content.response.ts b/apps/server/src/modules/lesson/controller/dto/lesson-content.response.ts index 0af0d4006ba..b30c96acaed 100644 --- a/apps/server/src/modules/lesson/controller/dto/lesson-content.response.ts +++ b/apps/server/src/modules/lesson/controller/dto/lesson-content.response.ts @@ -1,4 +1,4 @@ -import { ApiProperty } from '@nestjs/swagger'; +import { ApiExtraModels, ApiProperty, getSchemaPath } from '@nestjs/swagger'; import { EntityId } from '@shared/domain/types'; import { ComponentEtherpadProperties, @@ -11,6 +11,64 @@ import { ComponentType, } from '@shared/domain/entity/lesson.entity'; +class ComponentTextPropsImpl implements ComponentTextProperties { + @ApiProperty({ nullable: false }) + text!: string; +} + +class ComponentEtherpadPropsImpl implements ComponentEtherpadProperties { + @ApiProperty({ nullable: false, description: 'description of a Etherpad component' }) + description!: string; + + @ApiProperty({ nullable: false, description: 'title of a Etherpad component' }) + title!: string; + + @ApiProperty({ nullable: false, description: 'url of a Etherpad component' }) + url!: string; +} + +class ComponentNexboardPropsImpl implements ComponentNexboardProperties { + @ApiProperty({ nullable: false, description: 'board of a Nexboard component' }) + board!: string; + + @ApiProperty({ nullable: false, description: 'description of a Nexboard component' }) + description!: string; + + @ApiProperty({ nullable: false, description: 'title of a Nexboard component' }) + title!: string; + + @ApiProperty({ nullable: false, description: 'url of a Nexboard component' }) + url!: string; +} + +class ComponentGeogebraPropsImpl implements ComponentGeogebraProperties { + @ApiProperty({ nullable: false, description: 'materialId of a Geogebra component' }) + materialId!: string; +} + +class ComponentInternalPropsImpl implements ComponentInternalProperties { + @ApiProperty({ nullable: false, description: 'url of a Internal component' }) + url!: string; +} + +class ComponentLernstorePropsImpl implements ComponentLernstoreProperties { + @ApiProperty({ nullable: false, description: 'resources of a Lernstore component' }) + resources!: { + client: string; + description: string; + merlinReference?: string; + title: string; + url: string; + }[]; +} +@ApiExtraModels( + ComponentTextPropsImpl, + ComponentEtherpadPropsImpl, + ComponentGeogebraPropsImpl, + ComponentInternalPropsImpl, + ComponentLernstorePropsImpl, + ComponentNexboardPropsImpl +) export class LessonContentResponse { constructor(lessonContent: ComponentProperties) { this.id = lessonContent._id; @@ -22,14 +80,25 @@ export class LessonContentResponse { this.content = lessonContent.content; } - @ApiProperty() + @ApiProperty({ + items: { + oneOf: [ + { $ref: getSchemaPath(ComponentTextPropsImpl) }, + { $ref: getSchemaPath(ComponentEtherpadPropsImpl) }, + { $ref: getSchemaPath(ComponentGeogebraPropsImpl) }, + { $ref: getSchemaPath(ComponentInternalPropsImpl) }, + { $ref: getSchemaPath(ComponentLernstorePropsImpl) }, + { $ref: getSchemaPath(ComponentNexboardPropsImpl) }, + ], + }, + }) content?: - | ComponentTextProperties - | ComponentEtherpadProperties - | ComponentGeogebraProperties - | ComponentInternalProperties - | ComponentLernstoreProperties - | ComponentNexboardProperties; + | ComponentTextPropsImpl + | ComponentEtherpadPropsImpl + | ComponentGeogebraPropsImpl + | ComponentInternalPropsImpl + | ComponentLernstorePropsImpl + | ComponentNexboardPropsImpl; @ApiProperty({ description: 'The id of the Material entity', diff --git a/openapitools.json b/openapitools.json index bd567305968..e22e8da1698 100644 --- a/openapitools.json +++ b/openapitools.json @@ -27,6 +27,30 @@ "withInterfaces": true, "withSeparateModelsAndApi": true } + }, + "svs-lesson-api": { + "generatorName": "typescript-axios", + "inputSpec": "http://localhost:3030/api/v3/docs-json", + "output": "./apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/new-lesson-api-client", + "skipValidateSpec": true, + "enablePostProcessFile": true, + "openapiNormalizer": { + "FILTER": "operationId:LessonController_getLesson|LessonController_getLessonTasks" + }, + "globalProperty": { + "models": "LessonResponse:LessonLinkedTaskResponse:LessonContentResponse:ComponentTextPropsImpl:ComponentEtherpadPropsImpl:ComponentGeogebraPropsImpl:ComponentInternalPropsImpl:ComponentLernstorePropsImpl:ComponentNexboardPropsImpl", + "apis": "", + "supportingFiles": "" + }, + "additionalProperties": { + "apiPackage": "api", + "enumNameSuffix": "", + "enumPropertyNaming": "UPPERCASE", + "modelPackage": "models", + "supportsES6": true, + "withInterfaces": true, + "withSeparateModelsAndApi": true + } } } } diff --git a/package.json b/package.json index 37f044e9f3e..a7e8ef709e2 100644 --- a/package.json +++ b/package.json @@ -123,7 +123,8 @@ "generate-client:authorization": "node ./scripts/generate-client.js -u 'http://localhost:3030/api/v3/docs-json/' -p 'apps/server/src/infra/authorization-client/authorization-api-client' -c 'openapitools-config.json' -f 'operationId:AuthorizationReferenceController_authorizeByReference'", "generate-client:etherpad": "node ./scripts/generate-client.js -u 'http://localhost:9001/api/openapi.json' -p 'apps/server/src/infra/etherpad-client/etherpad-api-client' -c 'openapitools-config.json'", "pregenerate-client:tsp-api": "rimraf ./apps/server/src/infra/tsp-client/generated", - "generate-client:tsp-api": "openapi-generator-cli generate -c ./openapitools.json --generator-key tsp-api" + "generate-client:tsp-api": "openapi-generator-cli generate -c ./openapitools.json --generator-key tsp-api", + "generate-client:lessons-api":"openapi-generator-cli generate -c ./openapitools.json --generator-key svs-lesson-api" }, "dependencies": { "@aws-sdk/lib-storage": "^3.617.0", From c403e2e1aed61ad5182759344b4cc80e641af1dc Mon Sep 17 00:00:00 2001 From: Maximilian Kreuzkam Date: Tue, 12 Nov 2024 17:01:51 +0100 Subject: [PATCH 07/61] Regenerate lesson api client. --- .../.openapi-generator/FILES | 7 +++ .../models/component-etherpad-props-impl.ts | 42 ++++++++++++++++ .../models/component-geogebra-props-impl.ts | 30 ++++++++++++ .../models/component-internal-props-impl.ts | 30 ++++++++++++ .../models/component-lernstore-props-impl.ts | 30 ++++++++++++ .../models/component-nexboard-props-impl.ts | 48 +++++++++++++++++++ .../models/component-text-props-impl.ts | 30 ++++++++++++ .../lessons-api-client/models/index.ts | 7 +++ .../lesson-content-response-content-inner.ts | 41 ++++++++++++++++ .../models/lesson-content-response.ts | 7 ++- 10 files changed, 270 insertions(+), 2 deletions(-) create mode 100644 apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lessons-api-client/models/component-etherpad-props-impl.ts create mode 100644 apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lessons-api-client/models/component-geogebra-props-impl.ts create mode 100644 apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lessons-api-client/models/component-internal-props-impl.ts create mode 100644 apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lessons-api-client/models/component-lernstore-props-impl.ts create mode 100644 apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lessons-api-client/models/component-nexboard-props-impl.ts create mode 100644 apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lessons-api-client/models/component-text-props-impl.ts create mode 100644 apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lessons-api-client/models/lesson-content-response-content-inner.ts diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lessons-api-client/.openapi-generator/FILES b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lessons-api-client/.openapi-generator/FILES index 96db8953479..ed91d4d5091 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lessons-api-client/.openapi-generator/FILES +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lessons-api-client/.openapi-generator/FILES @@ -8,7 +8,14 @@ common.ts configuration.ts git_push.sh index.ts +models/component-etherpad-props-impl.ts +models/component-geogebra-props-impl.ts +models/component-internal-props-impl.ts +models/component-lernstore-props-impl.ts +models/component-nexboard-props-impl.ts +models/component-text-props-impl.ts models/index.ts +models/lesson-content-response-content-inner.ts models/lesson-content-response.ts models/lesson-linked-task-response.ts models/lesson-metadata-list-response.ts diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lessons-api-client/models/component-etherpad-props-impl.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lessons-api-client/models/component-etherpad-props-impl.ts new file mode 100644 index 00000000000..2c18cef729c --- /dev/null +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lessons-api-client/models/component-etherpad-props-impl.ts @@ -0,0 +1,42 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Schulcloud-Verbund-Software Server API + * This is v3 of Schulcloud-Verbund-Software Server. Checkout /docs for v1. + * + * The version of the OpenAPI document: 3.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + + +/** + * + * @export + * @interface ComponentEtherpadPropsImpl + */ +export interface ComponentEtherpadPropsImpl { + /** + * description of a Etherpad component + * @type {string} + * @memberof ComponentEtherpadPropsImpl + */ + 'description': string; + /** + * title of a Etherpad component + * @type {string} + * @memberof ComponentEtherpadPropsImpl + */ + 'title': string; + /** + * url of a Etherpad component + * @type {string} + * @memberof ComponentEtherpadPropsImpl + */ + 'url': string; +} + diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lessons-api-client/models/component-geogebra-props-impl.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lessons-api-client/models/component-geogebra-props-impl.ts new file mode 100644 index 00000000000..9f8f609c364 --- /dev/null +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lessons-api-client/models/component-geogebra-props-impl.ts @@ -0,0 +1,30 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Schulcloud-Verbund-Software Server API + * This is v3 of Schulcloud-Verbund-Software Server. Checkout /docs for v1. + * + * The version of the OpenAPI document: 3.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + + +/** + * + * @export + * @interface ComponentGeogebraPropsImpl + */ +export interface ComponentGeogebraPropsImpl { + /** + * materialId of a Geogebra component + * @type {string} + * @memberof ComponentGeogebraPropsImpl + */ + 'materialId': string; +} + diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lessons-api-client/models/component-internal-props-impl.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lessons-api-client/models/component-internal-props-impl.ts new file mode 100644 index 00000000000..97b65de6639 --- /dev/null +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lessons-api-client/models/component-internal-props-impl.ts @@ -0,0 +1,30 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Schulcloud-Verbund-Software Server API + * This is v3 of Schulcloud-Verbund-Software Server. Checkout /docs for v1. + * + * The version of the OpenAPI document: 3.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + + +/** + * + * @export + * @interface ComponentInternalPropsImpl + */ +export interface ComponentInternalPropsImpl { + /** + * url of a Internal component + * @type {string} + * @memberof ComponentInternalPropsImpl + */ + 'url': string; +} + diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lessons-api-client/models/component-lernstore-props-impl.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lessons-api-client/models/component-lernstore-props-impl.ts new file mode 100644 index 00000000000..b8f4ad7ec17 --- /dev/null +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lessons-api-client/models/component-lernstore-props-impl.ts @@ -0,0 +1,30 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Schulcloud-Verbund-Software Server API + * This is v3 of Schulcloud-Verbund-Software Server. Checkout /docs for v1. + * + * The version of the OpenAPI document: 3.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + + +/** + * + * @export + * @interface ComponentLernstorePropsImpl + */ +export interface ComponentLernstorePropsImpl { + /** + * resources of a Lernstore component + * @type {Array} + * @memberof ComponentLernstorePropsImpl + */ + 'resources': Array; +} + diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lessons-api-client/models/component-nexboard-props-impl.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lessons-api-client/models/component-nexboard-props-impl.ts new file mode 100644 index 00000000000..e12f6298288 --- /dev/null +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lessons-api-client/models/component-nexboard-props-impl.ts @@ -0,0 +1,48 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Schulcloud-Verbund-Software Server API + * This is v3 of Schulcloud-Verbund-Software Server. Checkout /docs for v1. + * + * The version of the OpenAPI document: 3.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + + +/** + * + * @export + * @interface ComponentNexboardPropsImpl + */ +export interface ComponentNexboardPropsImpl { + /** + * board of a Nexboard component + * @type {string} + * @memberof ComponentNexboardPropsImpl + */ + 'board': string; + /** + * description of a Nexboard component + * @type {string} + * @memberof ComponentNexboardPropsImpl + */ + 'description': string; + /** + * title of a Nexboard component + * @type {string} + * @memberof ComponentNexboardPropsImpl + */ + 'title': string; + /** + * url of a Nexboard component + * @type {string} + * @memberof ComponentNexboardPropsImpl + */ + 'url': string; +} + diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lessons-api-client/models/component-text-props-impl.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lessons-api-client/models/component-text-props-impl.ts new file mode 100644 index 00000000000..6ee414db6d5 --- /dev/null +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lessons-api-client/models/component-text-props-impl.ts @@ -0,0 +1,30 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Schulcloud-Verbund-Software Server API + * This is v3 of Schulcloud-Verbund-Software Server. Checkout /docs for v1. + * + * The version of the OpenAPI document: 3.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + + +/** + * + * @export + * @interface ComponentTextPropsImpl + */ +export interface ComponentTextPropsImpl { + /** + * + * @type {string} + * @memberof ComponentTextPropsImpl + */ + 'text': string; +} + diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lessons-api-client/models/index.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lessons-api-client/models/index.ts index 9abd938430d..baa052b379a 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lessons-api-client/models/index.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lessons-api-client/models/index.ts @@ -1,4 +1,11 @@ +export * from './component-etherpad-props-impl'; +export * from './component-geogebra-props-impl'; +export * from './component-internal-props-impl'; +export * from './component-lernstore-props-impl'; +export * from './component-nexboard-props-impl'; +export * from './component-text-props-impl'; export * from './lesson-content-response'; +export * from './lesson-content-response-content-inner'; export * from './lesson-linked-task-response'; export * from './lesson-metadata-list-response'; export * from './lesson-metadata-response'; diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lessons-api-client/models/lesson-content-response-content-inner.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lessons-api-client/models/lesson-content-response-content-inner.ts new file mode 100644 index 00000000000..2a552d7a1c7 --- /dev/null +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lessons-api-client/models/lesson-content-response-content-inner.ts @@ -0,0 +1,41 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Schulcloud-Verbund-Software Server API + * This is v3 of Schulcloud-Verbund-Software Server. Checkout /docs for v1. + * + * The version of the OpenAPI document: 3.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +// May contain unused imports in some cases +// @ts-ignore +import type { ComponentEtherpadPropsImpl } from './component-etherpad-props-impl'; +// May contain unused imports in some cases +// @ts-ignore +import type { ComponentGeogebraPropsImpl } from './component-geogebra-props-impl'; +// May contain unused imports in some cases +// @ts-ignore +import type { ComponentInternalPropsImpl } from './component-internal-props-impl'; +// May contain unused imports in some cases +// @ts-ignore +import type { ComponentLernstorePropsImpl } from './component-lernstore-props-impl'; +// May contain unused imports in some cases +// @ts-ignore +import type { ComponentNexboardPropsImpl } from './component-nexboard-props-impl'; +// May contain unused imports in some cases +// @ts-ignore +import type { ComponentTextPropsImpl } from './component-text-props-impl'; + +/** + * @type LessonContentResponseContentInner + * @export + */ +export type LessonContentResponseContentInner = ComponentEtherpadPropsImpl | ComponentGeogebraPropsImpl | ComponentInternalPropsImpl | ComponentLernstorePropsImpl | ComponentNexboardPropsImpl | ComponentTextPropsImpl; + + diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lessons-api-client/models/lesson-content-response.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lessons-api-client/models/lesson-content-response.ts index da12106638f..63b9329a467 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lessons-api-client/models/lesson-content-response.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lessons-api-client/models/lesson-content-response.ts @@ -13,6 +13,9 @@ */ +// May contain unused imports in some cases +// @ts-ignore +import type { LessonContentResponseContentInner } from './lesson-content-response-content-inner'; /** * @@ -22,10 +25,10 @@ export interface LessonContentResponse { /** * - * @type {object} + * @type {Array} * @memberof LessonContentResponse */ - 'content': object; + 'content': Array; /** * The id of the Material entity * @type {string} From a531b703a17d552fc6082e9bdded24359968a257 Mon Sep 17 00:00:00 2001 From: Firas Shmit Date: Wed, 13 Nov 2024 10:08:58 +0100 Subject: [PATCH 08/61] EW-1060 implemented new mapping of lesson content --- .../dto/component-etherpad-props.dto.ts | 15 +++++++ .../dto/component-geogebra-props.dto.ts | 9 ++++ .../dto/component-internal-props.dto.ts | 9 ++++ .../dto/component-lernstore-props.dto.ts | 9 ++++ .../dto/component-nexboard-props-dto.ts | 18 ++++++++ .../dto/component-text-props.dto.ts | 9 ++++ .../dto/lesson-content-response-inner.dto.ts | 14 +++++++ .../lesson-client/dto/lesson-contents.dto.ts | 4 +- .../lesson-client/mapper/lesson-dto.mapper.ts | 41 ++++++++++++++++++- 9 files changed, 126 insertions(+), 2 deletions(-) create mode 100644 apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-etherpad-props.dto.ts create mode 100644 apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-geogebra-props.dto.ts create mode 100644 apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-internal-props.dto.ts create mode 100644 apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-lernstore-props.dto.ts create mode 100644 apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-nexboard-props-dto.ts create mode 100644 apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-text-props.dto.ts create mode 100644 apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/lesson-content-response-inner.dto.ts diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-etherpad-props.dto.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-etherpad-props.dto.ts new file mode 100644 index 00000000000..998a10a2538 --- /dev/null +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-etherpad-props.dto.ts @@ -0,0 +1,15 @@ +import { ComponentEtherpadPropsImpl } from '../lessons-api-client'; + +export class ComponentEtherpadPropsDto { + description!: string; + + title!: string; + + url!: string; + + constructor(etherpadContent: ComponentEtherpadPropsImpl) { + this.description = etherpadContent.description; + this.title = etherpadContent.title; + this.url = etherpadContent.url; + } +} diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-geogebra-props.dto.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-geogebra-props.dto.ts new file mode 100644 index 00000000000..3caaef9d602 --- /dev/null +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-geogebra-props.dto.ts @@ -0,0 +1,9 @@ +import { ComponentGeogebraPropsImpl } from '../lessons-api-client'; + +export class ComponentGeogebraPropsDto { + materialId!: string; + + constructor(geogebraContent: ComponentGeogebraPropsImpl) { + this.materialId = geogebraContent.materialId; + } +} diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-internal-props.dto.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-internal-props.dto.ts new file mode 100644 index 00000000000..f6982b5b4d5 --- /dev/null +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-internal-props.dto.ts @@ -0,0 +1,9 @@ +import { ComponentInternalPropsImpl } from '../lessons-api-client'; + +export class ComponentInternalPropsDto { + url!: string; + + constructor(internalContent: ComponentInternalPropsImpl) { + this.url = internalContent.url; + } +} diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-lernstore-props.dto.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-lernstore-props.dto.ts new file mode 100644 index 00000000000..0392f05052a --- /dev/null +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-lernstore-props.dto.ts @@ -0,0 +1,9 @@ +import { ComponentLernstorePropsImpl } from '../lessons-api-client'; + +export class ComponentLernstorePropsDto { + resources!: string[]; + + constructor(lernstoreContent: ComponentLernstorePropsImpl) { + this.resources = lernstoreContent.resources; + } +} diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-nexboard-props-dto.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-nexboard-props-dto.ts new file mode 100644 index 00000000000..100a51c5348 --- /dev/null +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-nexboard-props-dto.ts @@ -0,0 +1,18 @@ +import { ComponentNexboardPropsImpl } from '../lessons-api-client'; + +export class ComponentNexboardPropsDto { + board!: string; + + description!: string; + + title!: string; + + url!: string; + + constructor(nexboardContent: ComponentNexboardPropsImpl) { + this.board = nexboardContent.board; + this.description = nexboardContent.description; + this.title = nexboardContent.title; + this.url = nexboardContent.url; + } +} diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-text-props.dto.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-text-props.dto.ts new file mode 100644 index 00000000000..be7a16bdd41 --- /dev/null +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-text-props.dto.ts @@ -0,0 +1,9 @@ +import { ComponentTextPropsImpl } from '../lessons-api-client'; + +export class ComponentTextPropsDto { + text!: string; + + constructor(textContent: ComponentTextPropsImpl) { + this.text = textContent.text; + } +} diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/lesson-content-response-inner.dto.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/lesson-content-response-inner.dto.ts new file mode 100644 index 00000000000..bebfcd784eb --- /dev/null +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/lesson-content-response-inner.dto.ts @@ -0,0 +1,14 @@ +import { ComponentEtherpadPropsDto } from './component-etherpad-props.dto'; +import { ComponentGeogebraPropsDto } from './component-geogebra-props.dto'; +import { ComponentInternalPropsDto } from './component-internal-props.dto'; +import { ComponentLernstorePropsDto } from './component-lernstore-props.dto'; +import { ComponentNexboardPropsDto } from './component-nexboard-props-dto'; +import { ComponentTextPropsDto } from './component-text-props.dto'; + +export type LessonContentResponseContentInnerDto = + | ComponentEtherpadPropsDto + | ComponentGeogebraPropsDto + | ComponentInternalPropsDto + | ComponentLernstorePropsDto + | ComponentTextPropsDto + | ComponentNexboardPropsDto; diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/lesson-contents.dto.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/lesson-contents.dto.ts index 789f7a1e560..bdef61bab5f 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/lesson-contents.dto.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/lesson-contents.dto.ts @@ -1,7 +1,9 @@ +import { LessonContentResponseContentInnerDto } from './lesson-content-response-inner.dto'; + export class LessonContentDto { id: string | undefined; - content: object; + content: Array; title: string; diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/mapper/lesson-dto.mapper.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/mapper/lesson-dto.mapper.ts index 640867bf9d6..97b11f67d89 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/mapper/lesson-dto.mapper.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/mapper/lesson-dto.mapper.ts @@ -1,6 +1,21 @@ import { LessonContentDto, LessonDto, LessonLinkedTaskDto, LessonMaterialsDto } from '../dto'; +import { ComponentEtherpadPropsDto } from '../dto/component-etherpad-props.dto'; +import { ComponentGeogebraPropsDto } from '../dto/component-geogebra-props.dto'; +import { ComponentInternalPropsDto } from '../dto/component-internal-props.dto'; +import { ComponentLernstorePropsDto } from '../dto/component-lernstore-props.dto'; +import { ComponentNexboardPropsDto } from '../dto/component-nexboard-props-dto'; +import { ComponentTextPropsDto } from '../dto/component-text-props.dto'; +import { LessonContentResponseContentInnerDto } from '../dto/lesson-content-response-inner.dto'; import { + ComponentEtherpadPropsImpl, + ComponentGeogebraPropsImpl, + ComponentInternalPropsImpl, + ComponentLernstorePropsImpl, + ComponentNexboardPropsImpl, + ComponentTextPropsImpl, LessonContentResponse, + LessonContentResponseComponent, + LessonContentResponseContentInner, LessonLinkedTaskResponse, LessonResponse, MaterialResponse, @@ -58,7 +73,9 @@ export class LessonDtoMapper { private static mapToLessenContentDto(lessonContentResponse: LessonContentResponse): LessonContentDto { const lessonContentDto = new LessonContentDto({ id: lessonContentResponse.id, - content: lessonContentResponse.content, + content: lessonContentResponse.content.map((contentInner) => + this.mapToLessonContentResponseInner(lessonContentResponse.component, contentInner) + ), title: lessonContentResponse.title, component: lessonContentResponse.component, hidden: lessonContentResponse.hidden, @@ -66,4 +83,26 @@ export class LessonDtoMapper { return lessonContentDto; } + + private static mapToLessonContentResponseInner( + component: LessonContentResponseComponent, + contentResponseInner: LessonContentResponseContentInner + ): LessonContentResponseContentInnerDto { + switch (component) { + case LessonContentResponseComponent.TEXT: + return new ComponentTextPropsDto(contentResponseInner as ComponentTextPropsImpl); + case LessonContentResponseComponent.ETHERPAD: + return new ComponentEtherpadPropsDto(contentResponseInner as ComponentEtherpadPropsImpl); + case LessonContentResponseComponent.GEO_GEBRA: + return new ComponentGeogebraPropsDto(contentResponseInner as ComponentGeogebraPropsImpl); + case LessonContentResponseComponent.INTERNAL: + return new ComponentInternalPropsDto(contentResponseInner as ComponentInternalPropsImpl); + case LessonContentResponseComponent.RESOURCES: + return new ComponentLernstorePropsDto(contentResponseInner as ComponentLernstorePropsImpl); + case LessonContentResponseComponent.NE_XBOARD: + return new ComponentNexboardPropsDto(contentResponseInner as ComponentNexboardPropsImpl); + default: + throw new Error(`Unknown component type of lesson content`); + } + } } From 718f3098492fc8a19fb52bf50619e69427bc30ef Mon Sep 17 00:00:00 2001 From: Firas Shmit Date: Wed, 13 Nov 2024 10:53:17 +0100 Subject: [PATCH 09/61] EW-1060 modified mapper --- .../lesson-client/dto/lesson-contents.dto.ts | 2 +- .../lesson-client/mapper/lesson-dto.mapper.ts | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/lesson-contents.dto.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/lesson-contents.dto.ts index bdef61bab5f..986c22dd16f 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/lesson-contents.dto.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/lesson-contents.dto.ts @@ -3,7 +3,7 @@ import { LessonContentResponseContentInnerDto } from './lesson-content-response- export class LessonContentDto { id: string | undefined; - content: Array; + content: LessonContentResponseContentInnerDto[]; title: string; diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/mapper/lesson-dto.mapper.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/mapper/lesson-dto.mapper.ts index 97b11f67d89..2be10455a81 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/mapper/lesson-dto.mapper.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/mapper/lesson-dto.mapper.ts @@ -73,12 +73,12 @@ export class LessonDtoMapper { private static mapToLessenContentDto(lessonContentResponse: LessonContentResponse): LessonContentDto { const lessonContentDto = new LessonContentDto({ id: lessonContentResponse.id, - content: lessonContentResponse.content.map((contentInner) => - this.mapToLessonContentResponseInner(lessonContentResponse.component, contentInner) - ), title: lessonContentResponse.title, component: lessonContentResponse.component, hidden: lessonContentResponse.hidden, + content: lessonContentResponse.content.map((contentInner) => + this.mapToLessonContentResponseInner(lessonContentResponse.component, contentInner) + ), }); return lessonContentDto; From 4d198a57624959385aecd3b62c105b305b3d0e87 Mon Sep 17 00:00:00 2001 From: Firas Shmit Date: Wed, 13 Nov 2024 13:11:08 +0100 Subject: [PATCH 10/61] EW-1060 modified mapper of lesson dto --- .../lesson-client/mapper/lesson-dto.mapper.ts | 107 +++++++++++++----- 1 file changed, 81 insertions(+), 26 deletions(-) diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/mapper/lesson-dto.mapper.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/mapper/lesson-dto.mapper.ts index 2be10455a81..57bcc8d0c93 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/mapper/lesson-dto.mapper.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/mapper/lesson-dto.mapper.ts @@ -5,7 +5,6 @@ import { ComponentInternalPropsDto } from '../dto/component-internal-props.dto'; import { ComponentLernstorePropsDto } from '../dto/component-lernstore-props.dto'; import { ComponentNexboardPropsDto } from '../dto/component-nexboard-props-dto'; import { ComponentTextPropsDto } from '../dto/component-text-props.dto'; -import { LessonContentResponseContentInnerDto } from '../dto/lesson-content-response-inner.dto'; import { ComponentEtherpadPropsImpl, ComponentGeogebraPropsImpl, @@ -15,7 +14,6 @@ import { ComponentTextPropsImpl, LessonContentResponse, LessonContentResponseComponent, - LessonContentResponseContentInner, LessonLinkedTaskResponse, LessonResponse, MaterialResponse, @@ -71,38 +69,95 @@ export class LessonDtoMapper { } private static mapToLessenContentDto(lessonContentResponse: LessonContentResponse): LessonContentDto { - const lessonContentDto = new LessonContentDto({ - id: lessonContentResponse.id, - title: lessonContentResponse.title, - component: lessonContentResponse.component, - hidden: lessonContentResponse.hidden, - content: lessonContentResponse.content.map((contentInner) => - this.mapToLessonContentResponseInner(lessonContentResponse.component, contentInner) - ), - }); - - return lessonContentDto; - } - - private static mapToLessonContentResponseInner( - component: LessonContentResponseComponent, - contentResponseInner: LessonContentResponseContentInner - ): LessonContentResponseContentInnerDto { - switch (component) { + switch (lessonContentResponse.component) { case LessonContentResponseComponent.TEXT: - return new ComponentTextPropsDto(contentResponseInner as ComponentTextPropsImpl); + return new LessonContentDto({ + id: lessonContentResponse.id, + title: lessonContentResponse.title, + component: lessonContentResponse.component, + hidden: lessonContentResponse.hidden, + content: lessonContentResponse.content.map((contentInner) => + this.mapToComponentTextPropsDto(contentInner as ComponentTextPropsImpl) + ), + }); case LessonContentResponseComponent.ETHERPAD: - return new ComponentEtherpadPropsDto(contentResponseInner as ComponentEtherpadPropsImpl); + return new LessonContentDto({ + id: lessonContentResponse.id, + title: lessonContentResponse.title, + component: lessonContentResponse.component, + hidden: lessonContentResponse.hidden, + content: lessonContentResponse.content.map((contentInner) => + this.mapToComponentEtherpadPropsDto(contentInner as ComponentEtherpadPropsImpl) + ), + }); case LessonContentResponseComponent.GEO_GEBRA: - return new ComponentGeogebraPropsDto(contentResponseInner as ComponentGeogebraPropsImpl); + return new LessonContentDto({ + id: lessonContentResponse.id, + title: lessonContentResponse.title, + component: lessonContentResponse.component, + hidden: lessonContentResponse.hidden, + content: lessonContentResponse.content.map((contentInner) => + this.mapToComponentGeogebraPropsDto(contentInner as ComponentGeogebraPropsImpl) + ), + }); case LessonContentResponseComponent.INTERNAL: - return new ComponentInternalPropsDto(contentResponseInner as ComponentInternalPropsImpl); + return new LessonContentDto({ + id: lessonContentResponse.id, + title: lessonContentResponse.title, + component: lessonContentResponse.component, + hidden: lessonContentResponse.hidden, + content: lessonContentResponse.content.map((contentInner) => + this.mapToComponentInternalPropsDto(contentInner as ComponentInternalPropsImpl) + ), + }); case LessonContentResponseComponent.RESOURCES: - return new ComponentLernstorePropsDto(contentResponseInner as ComponentLernstorePropsImpl); + return new LessonContentDto({ + id: lessonContentResponse.id, + title: lessonContentResponse.title, + component: lessonContentResponse.component, + hidden: lessonContentResponse.hidden, + content: lessonContentResponse.content.map((contentInner) => + this.mapToComponentLernstorePropsDto(contentInner as ComponentLernstorePropsImpl) + ), + }); case LessonContentResponseComponent.NE_XBOARD: - return new ComponentNexboardPropsDto(contentResponseInner as ComponentNexboardPropsImpl); + return new LessonContentDto({ + id: lessonContentResponse.id, + title: lessonContentResponse.title, + component: lessonContentResponse.component, + hidden: lessonContentResponse.hidden, + content: lessonContentResponse.content.map((contentInner) => + this.mapToComponentNexboardPropsDto(contentInner as ComponentNexboardPropsImpl) + ), + }); default: throw new Error(`Unknown component type of lesson content`); } } + + private static mapToComponentTextPropsDto(contentInner: ComponentTextPropsImpl): ComponentTextPropsDto { + return new ComponentTextPropsDto(contentInner); + } + + private static mapToComponentEtherpadPropsDto(contentInner: ComponentEtherpadPropsImpl): ComponentEtherpadPropsDto { + return new ComponentEtherpadPropsDto(contentInner); + } + + private static mapToComponentGeogebraPropsDto(contentInner: ComponentGeogebraPropsImpl): ComponentGeogebraPropsDto { + return new ComponentGeogebraPropsDto(contentInner); + } + + private static mapToComponentInternalPropsDto(contentInner: ComponentInternalPropsImpl): ComponentInternalPropsDto { + return new ComponentInternalPropsDto(contentInner); + } + + private static mapToComponentLernstorePropsDto( + contentInner: ComponentLernstorePropsImpl + ): ComponentLernstorePropsDto { + return new ComponentLernstorePropsDto(contentInner); + } + + private static mapToComponentNexboardPropsDto(contentInner: ComponentNexboardPropsImpl): ComponentNexboardPropsDto { + return new ComponentNexboardPropsDto(contentInner); + } } From 0d53c297fecc2e0c101415a9b6ee83ff7e9ae8fc Mon Sep 17 00:00:00 2001 From: Firas Shmit Date: Wed, 13 Nov 2024 14:59:03 +0100 Subject: [PATCH 11/61] EW-1060 removed items from api property --- .../controller/dto/lesson-content.response.ts | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/apps/server/src/modules/lesson/controller/dto/lesson-content.response.ts b/apps/server/src/modules/lesson/controller/dto/lesson-content.response.ts index b30c96acaed..86844f8f2c2 100644 --- a/apps/server/src/modules/lesson/controller/dto/lesson-content.response.ts +++ b/apps/server/src/modules/lesson/controller/dto/lesson-content.response.ts @@ -81,16 +81,14 @@ export class LessonContentResponse { } @ApiProperty({ - items: { - oneOf: [ - { $ref: getSchemaPath(ComponentTextPropsImpl) }, - { $ref: getSchemaPath(ComponentEtherpadPropsImpl) }, - { $ref: getSchemaPath(ComponentGeogebraPropsImpl) }, - { $ref: getSchemaPath(ComponentInternalPropsImpl) }, - { $ref: getSchemaPath(ComponentLernstorePropsImpl) }, - { $ref: getSchemaPath(ComponentNexboardPropsImpl) }, - ], - }, + oneOf: [ + { $ref: getSchemaPath(ComponentTextPropsImpl) }, + { $ref: getSchemaPath(ComponentEtherpadPropsImpl) }, + { $ref: getSchemaPath(ComponentGeogebraPropsImpl) }, + { $ref: getSchemaPath(ComponentInternalPropsImpl) }, + { $ref: getSchemaPath(ComponentLernstorePropsImpl) }, + { $ref: getSchemaPath(ComponentNexboardPropsImpl) }, + ], }) content?: | ComponentTextPropsImpl From 224c5568c93cc635a66964537bb08cd083af7ac6 Mon Sep 17 00:00:00 2001 From: Maximilian Kreuzkam Date: Wed, 13 Nov 2024 15:12:43 +0100 Subject: [PATCH 12/61] Regenerate lesson client. --- .../.openapi-generator/FILES | 3 +- .../lessons-api-client/models/index.ts | 2 +- .../models/lesson-content-response-content.ts | 41 +++++++++++++++++++ .../models/lesson-content-response.ts | 6 +-- 4 files changed, 46 insertions(+), 6 deletions(-) create mode 100644 apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lessons-api-client/models/lesson-content-response-content.ts diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lessons-api-client/.openapi-generator/FILES b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lessons-api-client/.openapi-generator/FILES index ed91d4d5091..db7a3e25e1d 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lessons-api-client/.openapi-generator/FILES +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lessons-api-client/.openapi-generator/FILES @@ -1,6 +1,5 @@ .gitignore .npmignore -.openapi-generator-ignore api.ts api/lesson-api.ts base.ts @@ -15,7 +14,7 @@ models/component-lernstore-props-impl.ts models/component-nexboard-props-impl.ts models/component-text-props-impl.ts models/index.ts -models/lesson-content-response-content-inner.ts +models/lesson-content-response-content.ts models/lesson-content-response.ts models/lesson-linked-task-response.ts models/lesson-metadata-list-response.ts diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lessons-api-client/models/index.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lessons-api-client/models/index.ts index baa052b379a..bced2458355 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lessons-api-client/models/index.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lessons-api-client/models/index.ts @@ -5,7 +5,7 @@ export * from './component-lernstore-props-impl'; export * from './component-nexboard-props-impl'; export * from './component-text-props-impl'; export * from './lesson-content-response'; -export * from './lesson-content-response-content-inner'; +export * from './lesson-content-response-content'; export * from './lesson-linked-task-response'; export * from './lesson-metadata-list-response'; export * from './lesson-metadata-response'; diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lessons-api-client/models/lesson-content-response-content.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lessons-api-client/models/lesson-content-response-content.ts new file mode 100644 index 00000000000..87cf1155cf7 --- /dev/null +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lessons-api-client/models/lesson-content-response-content.ts @@ -0,0 +1,41 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Schulcloud-Verbund-Software Server API + * This is v3 of Schulcloud-Verbund-Software Server. Checkout /docs for v1. + * + * The version of the OpenAPI document: 3.0 + * + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + + +// May contain unused imports in some cases +// @ts-ignore +import type { ComponentEtherpadPropsImpl } from './component-etherpad-props-impl'; +// May contain unused imports in some cases +// @ts-ignore +import type { ComponentGeogebraPropsImpl } from './component-geogebra-props-impl'; +// May contain unused imports in some cases +// @ts-ignore +import type { ComponentInternalPropsImpl } from './component-internal-props-impl'; +// May contain unused imports in some cases +// @ts-ignore +import type { ComponentLernstorePropsImpl } from './component-lernstore-props-impl'; +// May contain unused imports in some cases +// @ts-ignore +import type { ComponentNexboardPropsImpl } from './component-nexboard-props-impl'; +// May contain unused imports in some cases +// @ts-ignore +import type { ComponentTextPropsImpl } from './component-text-props-impl'; + +/** + * @type LessonContentResponseContent + * @export + */ +export type LessonContentResponseContent = ComponentEtherpadPropsImpl | ComponentGeogebraPropsImpl | ComponentInternalPropsImpl | ComponentLernstorePropsImpl | ComponentNexboardPropsImpl | ComponentTextPropsImpl; + + diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lessons-api-client/models/lesson-content-response.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lessons-api-client/models/lesson-content-response.ts index 63b9329a467..542789dc1b1 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lessons-api-client/models/lesson-content-response.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lessons-api-client/models/lesson-content-response.ts @@ -15,7 +15,7 @@ // May contain unused imports in some cases // @ts-ignore -import type { LessonContentResponseContentInner } from './lesson-content-response-content-inner'; +import type { LessonContentResponseContent } from './lesson-content-response-content'; /** * @@ -25,10 +25,10 @@ import type { LessonContentResponseContentInner } from './lesson-content-respons export interface LessonContentResponse { /** * - * @type {Array} + * @type {LessonContentResponseContent} * @memberof LessonContentResponse */ - 'content': Array; + 'content': LessonContentResponseContent; /** * The id of the Material entity * @type {string} From ef5334b317e16128a3a952025516ff47e3d603cc Mon Sep 17 00:00:00 2001 From: Maximilian Kreuzkam Date: Wed, 13 Nov 2024 15:14:00 +0100 Subject: [PATCH 13/61] regen lesson api. --- .../.openapi-generator/FILES | 1 + .../lesson-content-response-content-inner.ts | 41 ------------------- 2 files changed, 1 insertion(+), 41 deletions(-) delete mode 100644 apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lessons-api-client/models/lesson-content-response-content-inner.ts diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lessons-api-client/.openapi-generator/FILES b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lessons-api-client/.openapi-generator/FILES index db7a3e25e1d..3cfa46d40b7 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lessons-api-client/.openapi-generator/FILES +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lessons-api-client/.openapi-generator/FILES @@ -1,5 +1,6 @@ .gitignore .npmignore +.openapi-generator-ignore api.ts api/lesson-api.ts base.ts diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lessons-api-client/models/lesson-content-response-content-inner.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lessons-api-client/models/lesson-content-response-content-inner.ts deleted file mode 100644 index 2a552d7a1c7..00000000000 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lessons-api-client/models/lesson-content-response-content-inner.ts +++ /dev/null @@ -1,41 +0,0 @@ -/* tslint:disable */ -/* eslint-disable */ -/** - * Schulcloud-Verbund-Software Server API - * This is v3 of Schulcloud-Verbund-Software Server. Checkout /docs for v1. - * - * The version of the OpenAPI document: 3.0 - * - * - * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). - * https://openapi-generator.tech - * Do not edit the class manually. - */ - - -// May contain unused imports in some cases -// @ts-ignore -import type { ComponentEtherpadPropsImpl } from './component-etherpad-props-impl'; -// May contain unused imports in some cases -// @ts-ignore -import type { ComponentGeogebraPropsImpl } from './component-geogebra-props-impl'; -// May contain unused imports in some cases -// @ts-ignore -import type { ComponentInternalPropsImpl } from './component-internal-props-impl'; -// May contain unused imports in some cases -// @ts-ignore -import type { ComponentLernstorePropsImpl } from './component-lernstore-props-impl'; -// May contain unused imports in some cases -// @ts-ignore -import type { ComponentNexboardPropsImpl } from './component-nexboard-props-impl'; -// May contain unused imports in some cases -// @ts-ignore -import type { ComponentTextPropsImpl } from './component-text-props-impl'; - -/** - * @type LessonContentResponseContentInner - * @export - */ -export type LessonContentResponseContentInner = ComponentEtherpadPropsImpl | ComponentGeogebraPropsImpl | ComponentInternalPropsImpl | ComponentLernstorePropsImpl | ComponentNexboardPropsImpl | ComponentTextPropsImpl; - - From 3e2a730cc02eba209cd74d50ce01fe6fbf5a294c Mon Sep 17 00:00:00 2001 From: Firas Shmit Date: Wed, 13 Nov 2024 15:29:20 +0100 Subject: [PATCH 14/61] EW-1060 modified mapper of lesson content --- .../lesson-client/dto/lesson-contents.dto.ts | 2 +- .../lesson-client/mapper/lesson-dto.mapper.ts | 51 +++---------------- 2 files changed, 8 insertions(+), 45 deletions(-) diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/lesson-contents.dto.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/lesson-contents.dto.ts index 986c22dd16f..ce45a7772df 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/lesson-contents.dto.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/lesson-contents.dto.ts @@ -3,7 +3,7 @@ import { LessonContentResponseContentInnerDto } from './lesson-content-response- export class LessonContentDto { id: string | undefined; - content: LessonContentResponseContentInnerDto[]; + content: LessonContentResponseContentInnerDto; title: string; diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/mapper/lesson-dto.mapper.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/mapper/lesson-dto.mapper.ts index 57bcc8d0c93..71343bb4da9 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/mapper/lesson-dto.mapper.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/mapper/lesson-dto.mapper.ts @@ -69,6 +69,7 @@ export class LessonDtoMapper { } private static mapToLessenContentDto(lessonContentResponse: LessonContentResponse): LessonContentDto { + console.log(lessonContentResponse.content); switch (lessonContentResponse.component) { case LessonContentResponseComponent.TEXT: return new LessonContentDto({ @@ -76,9 +77,7 @@ export class LessonDtoMapper { title: lessonContentResponse.title, component: lessonContentResponse.component, hidden: lessonContentResponse.hidden, - content: lessonContentResponse.content.map((contentInner) => - this.mapToComponentTextPropsDto(contentInner as ComponentTextPropsImpl) - ), + content: new ComponentTextPropsDto(lessonContentResponse.content as ComponentTextPropsImpl), }); case LessonContentResponseComponent.ETHERPAD: return new LessonContentDto({ @@ -86,9 +85,7 @@ export class LessonDtoMapper { title: lessonContentResponse.title, component: lessonContentResponse.component, hidden: lessonContentResponse.hidden, - content: lessonContentResponse.content.map((contentInner) => - this.mapToComponentEtherpadPropsDto(contentInner as ComponentEtherpadPropsImpl) - ), + content: new ComponentEtherpadPropsDto(lessonContentResponse.content as ComponentEtherpadPropsImpl), }); case LessonContentResponseComponent.GEO_GEBRA: return new LessonContentDto({ @@ -96,9 +93,7 @@ export class LessonDtoMapper { title: lessonContentResponse.title, component: lessonContentResponse.component, hidden: lessonContentResponse.hidden, - content: lessonContentResponse.content.map((contentInner) => - this.mapToComponentGeogebraPropsDto(contentInner as ComponentGeogebraPropsImpl) - ), + content: new ComponentGeogebraPropsDto(lessonContentResponse.content as ComponentGeogebraPropsImpl), }); case LessonContentResponseComponent.INTERNAL: return new LessonContentDto({ @@ -106,9 +101,7 @@ export class LessonDtoMapper { title: lessonContentResponse.title, component: lessonContentResponse.component, hidden: lessonContentResponse.hidden, - content: lessonContentResponse.content.map((contentInner) => - this.mapToComponentInternalPropsDto(contentInner as ComponentInternalPropsImpl) - ), + content: new ComponentInternalPropsDto(lessonContentResponse.content as ComponentInternalPropsImpl), }); case LessonContentResponseComponent.RESOURCES: return new LessonContentDto({ @@ -116,9 +109,7 @@ export class LessonDtoMapper { title: lessonContentResponse.title, component: lessonContentResponse.component, hidden: lessonContentResponse.hidden, - content: lessonContentResponse.content.map((contentInner) => - this.mapToComponentLernstorePropsDto(contentInner as ComponentLernstorePropsImpl) - ), + content: new ComponentLernstorePropsDto(lessonContentResponse.content as ComponentLernstorePropsImpl), }); case LessonContentResponseComponent.NE_XBOARD: return new LessonContentDto({ @@ -126,38 +117,10 @@ export class LessonDtoMapper { title: lessonContentResponse.title, component: lessonContentResponse.component, hidden: lessonContentResponse.hidden, - content: lessonContentResponse.content.map((contentInner) => - this.mapToComponentNexboardPropsDto(contentInner as ComponentNexboardPropsImpl) - ), + content: new ComponentNexboardPropsDto(lessonContentResponse.content as ComponentNexboardPropsImpl), }); default: throw new Error(`Unknown component type of lesson content`); } } - - private static mapToComponentTextPropsDto(contentInner: ComponentTextPropsImpl): ComponentTextPropsDto { - return new ComponentTextPropsDto(contentInner); - } - - private static mapToComponentEtherpadPropsDto(contentInner: ComponentEtherpadPropsImpl): ComponentEtherpadPropsDto { - return new ComponentEtherpadPropsDto(contentInner); - } - - private static mapToComponentGeogebraPropsDto(contentInner: ComponentGeogebraPropsImpl): ComponentGeogebraPropsDto { - return new ComponentGeogebraPropsDto(contentInner); - } - - private static mapToComponentInternalPropsDto(contentInner: ComponentInternalPropsImpl): ComponentInternalPropsDto { - return new ComponentInternalPropsDto(contentInner); - } - - private static mapToComponentLernstorePropsDto( - contentInner: ComponentLernstorePropsImpl - ): ComponentLernstorePropsDto { - return new ComponentLernstorePropsDto(contentInner); - } - - private static mapToComponentNexboardPropsDto(contentInner: ComponentNexboardPropsImpl): ComponentNexboardPropsDto { - return new ComponentNexboardPropsDto(contentInner); - } } From 709ea25f38fc49a228935c0b6d5642890b518525 Mon Sep 17 00:00:00 2001 From: Firas Shmit Date: Wed, 13 Nov 2024 15:49:46 +0100 Subject: [PATCH 15/61] EW-1060 edited common cartridge mapper --- .../lesson-client/mapper/lesson-dto.mapper.ts | 1 - .../service/common-cartridge.mapper.ts | 24 +++++++++++-------- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/mapper/lesson-dto.mapper.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/mapper/lesson-dto.mapper.ts index 71343bb4da9..a2fbff7354d 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/mapper/lesson-dto.mapper.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/mapper/lesson-dto.mapper.ts @@ -69,7 +69,6 @@ export class LessonDtoMapper { } private static mapToLessenContentDto(lessonContentResponse: LessonContentResponse): LessonContentDto { - console.log(lessonContentResponse.content); switch (lessonContentResponse.component) { case LessonContentResponseComponent.TEXT: return new LessonContentDto({ diff --git a/apps/server/src/modules/common-cartridge/service/common-cartridge.mapper.ts b/apps/server/src/modules/common-cartridge/service/common-cartridge.mapper.ts index 125afde4ac1..9463ade1a19 100644 --- a/apps/server/src/modules/common-cartridge/service/common-cartridge.mapper.ts +++ b/apps/server/src/modules/common-cartridge/service/common-cartridge.mapper.ts @@ -19,6 +19,10 @@ import { CommonCartridgeResourceProps } from '../export/resources/common-cartrid import { BoardTaskDto } from '../common-cartridge-client/room-client/dto/board-task.dto'; import { RichTextElementResponseDto } from '../common-cartridge-client/card-client/dto/rich-text-element-response.dto'; import { LinkElementResponseDto } from '../common-cartridge-client/card-client/dto/link-element-response.dto'; +import { ComponentTextPropsDto } from '../common-cartridge-client/lesson-client/dto/component-text-props.dto'; +import { ComponentGeogebraPropsDto } from '../common-cartridge-client/lesson-client/dto/component-geogebra-props.dto'; +import { ComponentLernstorePropsDto } from '../common-cartridge-client/lesson-client/dto/component-lernstore-props.dto'; +import { ComponentEtherpadPropsDto } from '../common-cartridge-client/lesson-client/dto/component-etherpad-props.dto'; export class CommonCartridgeExportMapper { private static readonly GEOGEBRA_BASE_URL: string = 'https://geogebra.org'; @@ -58,7 +62,7 @@ export class CommonCartridgeExportMapper { type: CommonCartridgeResourceType.WEB_CONTENT, identifier: createIdentifier(lessonContent.id), title: lessonContent.title, - html: `

${lessonContent.title}

${lessonContent.content.toString()}

`, + html: `

${lessonContent.title}

${(lessonContent.content as ComponentTextPropsDto).text}

`, intendedUse: CommonCartridgeIntendedUseType.UNSPECIFIED, }; case LessonContentDtoComponentValues.GEO_GEBRA: @@ -66,25 +70,25 @@ export class CommonCartridgeExportMapper { type: CommonCartridgeResourceType.WEB_LINK, identifier: createIdentifier(lessonContent.id), title: lessonContent.title, - // TODO - check if the url is correct - url: `${CommonCartridgeExportMapper.GEOGEBRA_BASE_URL}/m/${lessonContent.content.toString()}`, + url: `${CommonCartridgeExportMapper.GEOGEBRA_BASE_URL}/m/${ + (lessonContent.content as ComponentGeogebraPropsDto).materialId + }`, }; case LessonContentDtoComponentValues.ETHERPAD: return { type: CommonCartridgeResourceType.WEB_LINK, identifier: createIdentifier(lessonContent.id), - // TODO - better solution for title - title: `${lessonContent.title} - ${lessonContent.content.toString()}`, - // TODO better solution for url - url: lessonContent.content.toString(), + title: `${(lessonContent.content as ComponentEtherpadPropsDto).title} - ${ + (lessonContent.content as ComponentEtherpadPropsDto).description + }`, + url: (lessonContent.content as ComponentEtherpadPropsDto).url, }; case LessonContentDtoComponentValues.LERNSTORE: return { type: CommonCartridgeResourceType.WEB_LINK, identifier: createIdentifier(lessonContent.id), - title: lessonContent.title, - // TODO better solution for url - url: lessonContent.content.toString(), + title: (lessonContent.content as ComponentLernstorePropsDto).resources.join(', '), + url: (lessonContent.content as ComponentLernstorePropsDto & { url: string }).url, }; default: return []; From fc5d3e34506e7fbd2c07505bb527bb0c93a57b7e Mon Sep 17 00:00:00 2001 From: Firas Shmit Date: Thu, 14 Nov 2024 12:43:05 +0100 Subject: [PATCH 16/61] EW-1060 added control options of course element --- .../controller/common-cartridge.controller.ts | 9 +- .../dto/course-export.body.params.ts | 25 ++++ .../common-cartridge-export.service.ts | 107 +++++++++++------- .../uc/common-cartridge.uc.ts | 10 +- 4 files changed, 104 insertions(+), 47 deletions(-) create mode 100644 apps/server/src/modules/common-cartridge/controller/dto/course-export.body.params.ts diff --git a/apps/server/src/modules/common-cartridge/controller/common-cartridge.controller.ts b/apps/server/src/modules/common-cartridge/controller/common-cartridge.controller.ts index 7893a28ac56..a5b8209e241 100644 --- a/apps/server/src/modules/common-cartridge/controller/common-cartridge.controller.ts +++ b/apps/server/src/modules/common-cartridge/controller/common-cartridge.controller.ts @@ -1,10 +1,11 @@ -import { Controller, Get, Param, Query, Res, StreamableFile } from '@nestjs/common'; +import { Body, Controller, Get, Param, Query, Res, StreamableFile } from '@nestjs/common'; import { ApiTags } from '@nestjs/swagger'; import { Response } from 'express'; import { CommonCartridgeUc } from '../uc/common-cartridge.uc'; import { ExportCourseParams } from './dto'; import { CourseExportBodyResponse } from './dto/course-export-body.response'; import { CourseQueryParams } from './dto/course.query.params'; +import { CourseExportBodyParams } from './dto/course-export.body.params'; @ApiTags('common-cartridge') @Controller('common-cartridge') @@ -20,11 +21,15 @@ export class CommonCartridgeController { public async exportCourseToCommonCartridge( @Param() exportCourseParams: ExportCourseParams, @Query() queryParams: CourseQueryParams, + @Body() bodyParams: CourseExportBodyParams, @Res({ passthrough: true }) response: Response ): Promise { const result = await this.commonCartridgeUC.exportCourseToCommonCartridge( exportCourseParams.parentId, - queryParams.version + queryParams.version, + bodyParams.topics, + bodyParams.tasks, + bodyParams.columnBoards ); response.set({ diff --git a/apps/server/src/modules/common-cartridge/controller/dto/course-export.body.params.ts b/apps/server/src/modules/common-cartridge/controller/dto/course-export.body.params.ts new file mode 100644 index 00000000000..4bfe89851bc --- /dev/null +++ b/apps/server/src/modules/common-cartridge/controller/dto/course-export.body.params.ts @@ -0,0 +1,25 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { IsArray } from 'class-validator'; + +export class CourseExportBodyParams { + @IsArray() + @ApiProperty({ + description: 'The list of ids of topics which should be exported. If empty no topics are exported.', + type: [String], + }) + public readonly topics!: string[]; + + @IsArray() + @ApiProperty({ + description: 'The list of ids of tasks which should be exported. If empty no tasks are exported.', + type: [String], + }) + public readonly tasks!: string[]; + + @IsArray() + @ApiProperty({ + description: 'The list of ids of column boards which should be exported. If empty no column boards are exported.', + type: [String], + }) + public readonly columnBoards!: string[]; +} diff --git a/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts b/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts index 6409b09bcb5..c7be8361898 100644 --- a/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts +++ b/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts @@ -23,10 +23,10 @@ import { CardResponseElementsInnerDto } from '../common-cartridge-client/card-cl import { RichTextElementResponseDto } from '../common-cartridge-client/card-client/dto/rich-text-element-response.dto'; import { LinkElementResponseDto } from '../common-cartridge-client/card-client/dto/link-element-response.dto'; -export const isRichTextElement = (reference: unknown): reference is RichTextElementResponseDto => +const isRichTextElement = (reference: unknown): reference is RichTextElementResponseDto => reference instanceof RichTextElementResponseDto; -export const isLinkElement = (reference: unknown): reference is LinkElementResponseDto => +const isLinkElement = (reference: unknown): reference is LinkElementResponseDto => reference instanceof LinkElementResponseDto; @Injectable() @@ -41,35 +41,6 @@ export class CommonCartridgeExportService { private readonly mapper: CommonCartridgeExportMapper ) {} - public async exportCourse(courseId: string, version: CommonCartridgeVersion): Promise { - const builder = new CommonCartridgeFileBuilder(this.mapper.mapCourseToManifestNew(version, courseId)); - - const courseCommonCartridgeMetadata: CourseCommonCartridgeMetadataDto = - await this.findCourseCommonCartridgeMetadata(courseId); - - builder.addMetadata(this.mapper.mapCourseToMetadata(courseCommonCartridgeMetadata)); - - // get room board and the structure of the course - const roomBoard: RoomBoardDto = await this.findRoomBoardByCourseId(courseId); - - // add lessons to organization - await this.addLessons(builder, version, roomBoard.elements); - - // add tasks to organization - this.addTasks(builder, version, roomBoard.elements); - - // add column boards and cards to organization - await this.addColumnBoards(builder, roomBoard.elements); - - return builder.build(); - } - - public async findCourseFileRecords(courseId: string): Promise { - const courseFiles = await this.filesService.listFilesOfParent(courseId); - - return courseFiles; - } - public async findCourseCommonCartridgeMetadata(courseId: string): Promise { const courseCommonCartridgeMetadata = await this.coursesClientAdapter.getCourseCommonCartridgeMetadata(courseId); @@ -100,6 +71,42 @@ export class CommonCartridgeExportService { return lesson; } + // export course to common cartridge + public async exportCourse( + courseId: string, + version: CommonCartridgeVersion, + exportedTopics: string[], + exportedTasks: string[], + exportedColumnBoards: string[] + ): Promise { + const builder = new CommonCartridgeFileBuilder(this.mapper.mapCourseToManifestNew(version, courseId)); + + const courseCommonCartridgeMetadata: CourseCommonCartridgeMetadataDto = + await this.findCourseCommonCartridgeMetadata(courseId); + + builder.addMetadata(this.mapper.mapCourseToMetadata(courseCommonCartridgeMetadata)); + + // get room board and the structure of the course + const roomBoard: RoomBoardDto = await this.findRoomBoardByCourseId(courseId); + + // add lessons to organization + await this.addLessons(builder, version, roomBoard.elements, exportedTopics); + + // add tasks to organization + this.addTasks(builder, version, roomBoard.elements, exportedTasks); + + // add column boards and cards to organization + await this.addColumnBoards(builder, roomBoard.elements, exportedColumnBoards); + + return builder.build(); + } + + public async findCourseFileRecords(courseId: string): Promise { + const courseFiles = await this.filesService.listFilesOfParent(courseId); + + return courseFiles; + } + private addComponentToOrganization( component: LessonContentDto, lessonOrganization: CommonCartridgeOrganizationNode @@ -120,13 +127,16 @@ export class CommonCartridgeExportService { private async addLessons( builder: CommonCartridgeFileBuilder, version: CommonCartridgeVersion, - elements: BoardElementDto[] + elements: BoardElementDto[], + topics: string[] ): Promise { - // get lessons ids from room board const filteredLessons = this.filterLessonFromBoardElements(elements); - const lessonsIds = filteredLessons.map((lesson) => lesson.id); + const lessonsIds = filteredLessons.filter((lesson) => topics.includes(lesson.id)).map((lesson) => lesson.id); + + if (!lessonsIds) { + return; + } - // get lessons and lesson's linked tasks from the server const lessons = await Promise.all(lessonsIds.map((elementId) => this.findLessonById(elementId))); lessons.forEach((lesson) => { @@ -145,14 +155,17 @@ export class CommonCartridgeExportService { private addTasks( builder: CommonCartridgeFileBuilder, version: CommonCartridgeVersion, - elements: BoardElementDto[] + elements: BoardElementDto[], + exportedTasks: string[] ): void { - if (!elements) { + const tasks: BoardTaskDto[] = this.filterTasksFromBoardElements(elements).filter((task) => + exportedTasks.includes(task.id) + ); + + if (!tasks) { return; } - const tasks: BoardTaskDto[] = this.filterTasksFromBoardElements(elements); - const tasksOrganization = builder.createOrganization({ title: 'Aufgaben', identifier: createIdentifier(), @@ -163,11 +176,20 @@ export class CommonCartridgeExportService { }); } - private async addColumnBoards(builder: CommonCartridgeFileBuilder, elements: BoardElementDto[]): Promise { + private async addColumnBoards( + builder: CommonCartridgeFileBuilder, + elements: BoardElementDto[], + exportedColumnBoards: string[] + ): Promise { const columnBoards = this.filterColumnBoardFromBoardElement(elements); - const columnBoardsIds = columnBoards.map((element) => element.columnBoardId); + const columnBoardsIds = columnBoards + .filter((columBoard) => exportedColumnBoards.includes(columBoard.columnBoardId)) + .map((columBoard) => columBoard.columnBoardId); + + if (!columnBoardsIds) { + return; + } - // get board skeleton of columnm boards from the server const boardSkeletons: BoardSkeletonDto[] = await Promise.all( columnBoardsIds.map((elementId) => this.findBoardSkeletonById(elementId)) ); @@ -196,7 +218,6 @@ export class CommonCartridgeExportService { identifier: createIdentifier(columnId), }); - // get cards ids by every column const cardsIds = column.cards.map((card) => card.cardId); const listOfCards: CardListResponseDto = await this.findAllCardsByIds(cardsIds); diff --git a/apps/server/src/modules/common-cartridge/uc/common-cartridge.uc.ts b/apps/server/src/modules/common-cartridge/uc/common-cartridge.uc.ts index 89903c8bea8..07d140461f4 100644 --- a/apps/server/src/modules/common-cartridge/uc/common-cartridge.uc.ts +++ b/apps/server/src/modules/common-cartridge/uc/common-cartridge.uc.ts @@ -24,8 +24,14 @@ export class CommonCartridgeUc { return response; } - public async exportCourseToCommonCartridge(courseId: EntityId, version: CommonCartridgeVersion): Promise { - const exportedCourse = await this.exportService.exportCourse(courseId, version); + public async exportCourseToCommonCartridge( + courseId: EntityId, + version: CommonCartridgeVersion, + topics: string[], + tasks: string[], + columnBoards: string[] + ): Promise { + const exportedCourse = await this.exportService.exportCourse(courseId, version, topics, tasks, columnBoards); return exportedCourse; } From d12111c79b534ed2aa85bfd404d19e7cec8aa3da Mon Sep 17 00:00:00 2001 From: Firas Shmit Date: Thu, 14 Nov 2024 14:55:44 +0100 Subject: [PATCH 17/61] EW-1060 changed endpoint name of new export --- .../common-cartridge/controller/common-cartridge.controller.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/server/src/modules/common-cartridge/controller/common-cartridge.controller.ts b/apps/server/src/modules/common-cartridge/controller/common-cartridge.controller.ts index a5b8209e241..3b36e4c888d 100644 --- a/apps/server/src/modules/common-cartridge/controller/common-cartridge.controller.ts +++ b/apps/server/src/modules/common-cartridge/controller/common-cartridge.controller.ts @@ -17,7 +17,7 @@ export class CommonCartridgeController { return this.commonCartridgeUC.exportCourse(exportCourseParams.parentId); } - @Get('testexport/:parentId') + @Get('newexport/:parentId') public async exportCourseToCommonCartridge( @Param() exportCourseParams: ExportCourseParams, @Query() queryParams: CourseQueryParams, From 8f7f5b88fa5e6a83aef8ab938f071ce3834934fe Mon Sep 17 00:00:00 2001 From: Firas Shmit Date: Fri, 15 Nov 2024 11:04:10 +0100 Subject: [PATCH 18/61] EW-1060 changed export endpoint to POST --- .../controller/common-cartridge.controller.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/server/src/modules/common-cartridge/controller/common-cartridge.controller.ts b/apps/server/src/modules/common-cartridge/controller/common-cartridge.controller.ts index 3b36e4c888d..8ef36c54800 100644 --- a/apps/server/src/modules/common-cartridge/controller/common-cartridge.controller.ts +++ b/apps/server/src/modules/common-cartridge/controller/common-cartridge.controller.ts @@ -1,4 +1,4 @@ -import { Body, Controller, Get, Param, Query, Res, StreamableFile } from '@nestjs/common'; +import { Body, Controller, Get, Param, Post, Query, Res, StreamableFile } from '@nestjs/common'; import { ApiTags } from '@nestjs/swagger'; import { Response } from 'express'; import { CommonCartridgeUc } from '../uc/common-cartridge.uc'; @@ -17,7 +17,7 @@ export class CommonCartridgeController { return this.commonCartridgeUC.exportCourse(exportCourseParams.parentId); } - @Get('newexport/:parentId') + @Post('newexport/:parentId') public async exportCourseToCommonCartridge( @Param() exportCourseParams: ExportCourseParams, @Query() queryParams: CourseQueryParams, From 794c806687b276a2d417a999eadbab13c5754818 Mon Sep 17 00:00:00 2001 From: Firas Shmit Date: Fri, 15 Nov 2024 13:20:56 +0100 Subject: [PATCH 19/61] EW-1060 modified mapping of some cc elements --- .../lesson-client/dto/component-text-props.dto.ts | 2 +- .../service/common-cartridge-export.service.ts | 2 +- .../common-cartridge/service/common-cartridge.mapper.ts | 4 +++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-text-props.dto.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-text-props.dto.ts index be7a16bdd41..69176b55ae5 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-text-props.dto.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-text-props.dto.ts @@ -1,7 +1,7 @@ import { ComponentTextPropsImpl } from '../lessons-api-client'; export class ComponentTextPropsDto { - text!: string; + text: string; constructor(textContent: ComponentTextPropsImpl) { this.text = textContent.text; diff --git a/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts b/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts index c7be8361898..163701888db 100644 --- a/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts +++ b/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts @@ -162,7 +162,7 @@ export class CommonCartridgeExportService { exportedTasks.includes(task.id) ); - if (!tasks) { + if (tasks.length === 0) { return; } diff --git a/apps/server/src/modules/common-cartridge/service/common-cartridge.mapper.ts b/apps/server/src/modules/common-cartridge/service/common-cartridge.mapper.ts index 9463ade1a19..31812f3d3b3 100644 --- a/apps/server/src/modules/common-cartridge/service/common-cartridge.mapper.ts +++ b/apps/server/src/modules/common-cartridge/service/common-cartridge.mapper.ts @@ -62,7 +62,9 @@ export class CommonCartridgeExportMapper { type: CommonCartridgeResourceType.WEB_CONTENT, identifier: createIdentifier(lessonContent.id), title: lessonContent.title, - html: `

${lessonContent.title}

${(lessonContent.content as ComponentTextPropsDto).text}

`, + html: `

${lessonContent.title ?? ''}

${ + (lessonContent.content as ComponentTextPropsDto).text ?? '' + }

`, intendedUse: CommonCartridgeIntendedUseType.UNSPECIFIED, }; case LessonContentDtoComponentValues.GEO_GEBRA: From 02cc85c056b3177109a4bfb9c814fb19445aeb7c Mon Sep 17 00:00:00 2001 From: Firas Shmit Date: Fri, 15 Nov 2024 14:44:58 +0100 Subject: [PATCH 20/61] EW-1060 deleted the old export endpoint of cc- microservice --- .../controller/common-cartridge.controller.ts | 14 ++++---------- .../uc/common-cartridge.uc.ts | 19 +------------------ 2 files changed, 5 insertions(+), 28 deletions(-) diff --git a/apps/server/src/modules/common-cartridge/controller/common-cartridge.controller.ts b/apps/server/src/modules/common-cartridge/controller/common-cartridge.controller.ts index 8ef36c54800..548103a2b6d 100644 --- a/apps/server/src/modules/common-cartridge/controller/common-cartridge.controller.ts +++ b/apps/server/src/modules/common-cartridge/controller/common-cartridge.controller.ts @@ -1,9 +1,8 @@ -import { Body, Controller, Get, Param, Post, Query, Res, StreamableFile } from '@nestjs/common'; +import { Body, Controller, Param, Post, Query, Res, StreamableFile } from '@nestjs/common'; import { ApiTags } from '@nestjs/swagger'; import { Response } from 'express'; import { CommonCartridgeUc } from '../uc/common-cartridge.uc'; import { ExportCourseParams } from './dto'; -import { CourseExportBodyResponse } from './dto/course-export-body.response'; import { CourseQueryParams } from './dto/course.query.params'; import { CourseExportBodyParams } from './dto/course-export.body.params'; @@ -12,19 +11,14 @@ import { CourseExportBodyParams } from './dto/course-export.body.params'; export class CommonCartridgeController { constructor(private readonly commonCartridgeUC: CommonCartridgeUc) {} - @Get('export/:parentId') - public async exportCourse(@Param() exportCourseParams: ExportCourseParams): Promise { - return this.commonCartridgeUC.exportCourse(exportCourseParams.parentId); - } - - @Post('newexport/:parentId') - public async exportCourseToCommonCartridge( + @Post('export/:parentId') + public async exportCourse( @Param() exportCourseParams: ExportCourseParams, @Query() queryParams: CourseQueryParams, @Body() bodyParams: CourseExportBodyParams, @Res({ passthrough: true }) response: Response ): Promise { - const result = await this.commonCartridgeUC.exportCourseToCommonCartridge( + const result = await this.commonCartridgeUC.exportCourse( exportCourseParams.parentId, queryParams.version, bodyParams.topics, diff --git a/apps/server/src/modules/common-cartridge/uc/common-cartridge.uc.ts b/apps/server/src/modules/common-cartridge/uc/common-cartridge.uc.ts index 07d140461f4..d7d00e6e02e 100644 --- a/apps/server/src/modules/common-cartridge/uc/common-cartridge.uc.ts +++ b/apps/server/src/modules/common-cartridge/uc/common-cartridge.uc.ts @@ -1,30 +1,13 @@ import { Injectable } from '@nestjs/common'; import { EntityId } from '@shared/domain/types'; -import { CourseFileIdsResponse } from '../controller/dto'; import { CommonCartridgeExportService } from '../service/common-cartridge-export.service'; -import { CourseExportBodyResponse } from '../controller/dto/course-export-body.response'; -import { CourseCommonCartridgeMetadataDto } from '../common-cartridge-client/course-client'; import { CommonCartridgeVersion } from '../export/common-cartridge.enums'; @Injectable() export class CommonCartridgeUc { constructor(private readonly exportService: CommonCartridgeExportService) {} - public async exportCourse(courseId: EntityId): Promise { - const files = await this.exportService.findCourseFileRecords(courseId); - const courseFileIds = new CourseFileIdsResponse(files.map((file) => file.id)); - const courseCommonCartridgeMetadata: CourseCommonCartridgeMetadataDto = - await this.exportService.findCourseCommonCartridgeMetadata(courseId); - - const response = new CourseExportBodyResponse({ - courseFileIds, - courseCommonCartridgeMetadata, - }); - - return response; - } - - public async exportCourseToCommonCartridge( + public async exportCourse( courseId: EntityId, version: CommonCartridgeVersion, topics: string[], From e81ff227edd6384214a8c8f687e23e38243d691c Mon Sep 17 00:00:00 2001 From: Firas Shmit Date: Tue, 19 Nov 2024 11:19:54 +0100 Subject: [PATCH 21/61] EW-1060 fixed export of cards --- .../board-client/dto/column-skeleton.dto.ts | 2 +- .../service/common-cartridge-export.service.ts | 15 ++++++++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/board-client/dto/column-skeleton.dto.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/board-client/dto/column-skeleton.dto.ts index 1094edefbc4..806e0517fec 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/board-client/dto/column-skeleton.dto.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/board-client/dto/column-skeleton.dto.ts @@ -5,7 +5,7 @@ export class ColumnSkeletonDto { title: string; - cards: CardSkeletonDto[]; + cards?: CardSkeletonDto[]; constructor(props: ColumnSkeletonDto) { this.columnId = props.columnId; diff --git a/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts b/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts index 163701888db..916e8b2ab14 100644 --- a/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts +++ b/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts @@ -71,7 +71,6 @@ export class CommonCartridgeExportService { return lesson; } - // export course to common cartridge public async exportCourse( courseId: string, version: CommonCartridgeVersion, @@ -191,7 +190,7 @@ export class CommonCartridgeExportService { } const boardSkeletons: BoardSkeletonDto[] = await Promise.all( - columnBoardsIds.map((elementId) => this.findBoardSkeletonById(elementId)) + columnBoardsIds.map((columnBoardId) => this.findBoardSkeletonById(columnBoardId)) ); await Promise.all( @@ -218,12 +217,14 @@ export class CommonCartridgeExportService { identifier: createIdentifier(columnId), }); - const cardsIds = column.cards.map((card) => card.cardId); - const listOfCards: CardListResponseDto = await this.findAllCardsByIds(cardsIds); + if (column.cards?.length) { + const cardsIds = column.cards.map((card) => card.cardId); + const listOfCards: CardListResponseDto = await this.findAllCardsByIds(cardsIds); - listOfCards.data.forEach((card) => { - this.addCardToOrganization(card, columnOrganization); - }); + listOfCards.data.forEach((card) => { + this.addCardToOrganization(card, columnOrganization); + }); + } } private addCardToOrganization(card: CardResponseDto, columnOrganization: CommonCartridgeOrganizationNode): void { From ae156b7ee472cdffe9e8c808ba5eb79b8ec5c4d2 Mon Sep 17 00:00:00 2001 From: Firas Shmit Date: Thu, 21 Nov 2024 10:13:57 +0100 Subject: [PATCH 22/61] EW-1060 changed showen title of a card --- .../common-cartridge/service/common-cartridge.mapper.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/server/src/modules/common-cartridge/service/common-cartridge.mapper.ts b/apps/server/src/modules/common-cartridge/service/common-cartridge.mapper.ts index 31812f3d3b3..5fb4b22ad5f 100644 --- a/apps/server/src/modules/common-cartridge/service/common-cartridge.mapper.ts +++ b/apps/server/src/modules/common-cartridge/service/common-cartridge.mapper.ts @@ -172,8 +172,8 @@ export class CommonCartridgeExportMapper { const title = sanitizeHtml(text, { allowedTags: [], allowedAttributes: {}, - }).slice(0, 50); + }).slice(0, 20); - return title; + return `${title}...`; } } From 62fa3b6e573ced5252c5ac2a4000c2d8dea2d896 Mon Sep 17 00:00:00 2001 From: Firas Shmit Date: Fri, 22 Nov 2024 11:08:28 +0100 Subject: [PATCH 23/61] EW-1060 modified test of export uc --- .../common-cartridge-export.service.ts | 8 ++--- .../uc/common-cartridge.uc.spec.ts | 31 ++++++------------- 2 files changed, 14 insertions(+), 25 deletions(-) diff --git a/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts b/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts index 916e8b2ab14..e6089eaf24b 100644 --- a/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts +++ b/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts @@ -41,25 +41,25 @@ export class CommonCartridgeExportService { private readonly mapper: CommonCartridgeExportMapper ) {} - public async findCourseCommonCartridgeMetadata(courseId: string): Promise { + private async findCourseCommonCartridgeMetadata(courseId: string): Promise { const courseCommonCartridgeMetadata = await this.coursesClientAdapter.getCourseCommonCartridgeMetadata(courseId); return courseCommonCartridgeMetadata; } - public async findRoomBoardByCourseId(courseId: string): Promise { + private async findRoomBoardByCourseId(courseId: string): Promise { const courseRooms = await this.courseRoomsClientAdapter.getRoomBoardByCourseId(courseId); return courseRooms; } - public async findBoardSkeletonById(boardId: string): Promise { + private async findBoardSkeletonById(boardId: string): Promise { const boardSkeleton = await this.boardClientAdapter.getBoardSkeletonById(boardId); return boardSkeleton; } - public async findAllCardsByIds(ids: Array): Promise { + private async findAllCardsByIds(ids: Array): Promise { const cards = await this.cardClientAdapter.getAllBoardCardsByIds(ids); return cards; diff --git a/apps/server/src/modules/common-cartridge/uc/common-cartridge.uc.spec.ts b/apps/server/src/modules/common-cartridge/uc/common-cartridge.uc.spec.ts index 8fc9bcba92b..2d3e0dcfca3 100644 --- a/apps/server/src/modules/common-cartridge/uc/common-cartridge.uc.spec.ts +++ b/apps/server/src/modules/common-cartridge/uc/common-cartridge.uc.spec.ts @@ -1,10 +1,9 @@ import { faker } from '@faker-js/faker'; import { DeepMocked, createMock } from '@golevelup/ts-jest'; import { Test, TestingModule } from '@nestjs/testing'; -import { CourseFileIdsResponse } from '../controller/dto'; import { CommonCartridgeExportService } from '../service/common-cartridge-export.service'; import { CommonCartridgeUc } from './common-cartridge.uc'; -import { CourseExportBodyResponse } from '../controller/dto/course-export-body.response'; +import { CommonCartridgeVersion } from '../export/common-cartridge.enums'; describe('CommonCartridgeUc', () => { let module: TestingModule; @@ -37,31 +36,21 @@ describe('CommonCartridgeUc', () => { describe('exportCourse', () => { const setup = () => { const courseId = faker.string.uuid(); - const expected = new CourseExportBodyResponse({ - courseFileIds: new CourseFileIdsResponse([]), - courseCommonCartridgeMetadata: { - id: courseId, - title: faker.lorem.sentence(), - copyRightOwners: [], - }, - }); + const version = CommonCartridgeVersion.V_1_1_0; + const topics = [faker.lorem.sentence(), faker.lorem.sentence()]; + const tasks = [faker.lorem.sentence(), faker.lorem.sentence()]; + const columnBoards = [faker.lorem.sentence(), faker.lorem.sentence()]; + const expected = Buffer.alloc(0); - commonCartridgeExportServiceMock.findCourseFileRecords.mockResolvedValue([]); - commonCartridgeExportServiceMock.findCourseCommonCartridgeMetadata.mockResolvedValue({ - id: expected.courseCommonCartridgeMetadata?.id ?? '', - title: expected.courseCommonCartridgeMetadata?.title ?? '', - copyRightOwners: expected.courseCommonCartridgeMetadata?.copyRightOwners ?? [], - }); + commonCartridgeExportServiceMock.exportCourse.mockResolvedValue(expected); - return { courseId, expected }; + return { courseId, version, topics, tasks, columnBoards, expected }; }; it('should return a course export response with file IDs and metadata of a course', async () => { - const { courseId, expected } = setup(); - - const result = await sut.exportCourse(courseId); + const { courseId, expected, version, tasks, columnBoards, topics } = setup(); - expect(result).toEqual(expected); + expect(await sut.exportCourse(courseId, version, topics, tasks, columnBoards)).toEqual(expected); }); }); }); From 1f133535d5c5b06e3f0d7e8e1a9dd7897de93459 Mon Sep 17 00:00:00 2001 From: Firas Shmit Date: Fri, 22 Nov 2024 13:45:20 +0100 Subject: [PATCH 24/61] EW-1060 added some logs --- .../common-cartridge-export.service.ts | 89 ++++++++++++++++--- 1 file changed, 75 insertions(+), 14 deletions(-) diff --git a/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts b/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts index e6089eaf24b..2d2af0dfe83 100644 --- a/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts +++ b/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts @@ -1,5 +1,6 @@ import { FileDto, FilesStorageClientAdapterService } from '@modules/files-storage-client'; import { Injectable } from '@nestjs/common'; +import { ErrorLogger } from '@src/core/logger'; import { BoardClientAdapter, BoardSkeletonDto, ColumnSkeletonDto } from '../common-cartridge-client/board-client'; import { CourseCommonCartridgeMetadataDto, CoursesClientAdapter } from '../common-cartridge-client/course-client'; import { CourseRoomsClientAdapter } from '../common-cartridge-client/room-client'; @@ -38,39 +39,105 @@ export class CommonCartridgeExportService { private readonly coursesClientAdapter: CoursesClientAdapter, private readonly courseRoomsClientAdapter: CourseRoomsClientAdapter, private readonly lessonClinetAdapter: LessonClientAdapter, - private readonly mapper: CommonCartridgeExportMapper + private readonly mapper: CommonCartridgeExportMapper, + private readonly erorrLogger: ErrorLogger ) {} private async findCourseCommonCartridgeMetadata(courseId: string): Promise { - const courseCommonCartridgeMetadata = await this.coursesClientAdapter.getCourseCommonCartridgeMetadata(courseId); + let courseCommonCartridgeMetadata: CourseCommonCartridgeMetadataDto = {} as CourseCommonCartridgeMetadataDto; + try { + courseCommonCartridgeMetadata = await this.coursesClientAdapter.getCourseCommonCartridgeMetadata(courseId); + } catch (error: unknown) { + this.erorrLogger.error({ + getLogMessage() { + return { + message: 'Error while fetching course common cartridge metadata', + error, + }; + }, + }); + } return courseCommonCartridgeMetadata; } private async findRoomBoardByCourseId(courseId: string): Promise { - const courseRooms = await this.courseRoomsClientAdapter.getRoomBoardByCourseId(courseId); - - return courseRooms; + let roomBoardDto: RoomBoardDto = {} as RoomBoardDto; + try { + roomBoardDto = await this.courseRoomsClientAdapter.getRoomBoardByCourseId(courseId); + } catch (error: unknown) { + this.erorrLogger.error({ + getLogMessage() { + return { + message: 'Error while fetching room board by course ID', + error, + }; + }, + }); + } + return roomBoardDto; } private async findBoardSkeletonById(boardId: string): Promise { - const boardSkeleton = await this.boardClientAdapter.getBoardSkeletonById(boardId); + let boardSkeleton: BoardSkeletonDto = {} as BoardSkeletonDto; + try { + boardSkeleton = await this.boardClientAdapter.getBoardSkeletonById(boardId); + } catch (error: unknown) { + this.erorrLogger.error({ + getLogMessage() { + return { + message: 'Error while fetching board skeleton by course ID', + error, + }; + }, + }); + } return boardSkeleton; } private async findAllCardsByIds(ids: Array): Promise { - const cards = await this.cardClientAdapter.getAllBoardCardsByIds(ids); + let cards: CardListResponseDto = {} as CardListResponseDto; + try { + cards = await this.cardClientAdapter.getAllBoardCardsByIds(ids); + } catch (error: unknown) { + this.erorrLogger.error({ + getLogMessage() { + return { + message: 'Error while fetching all board cards by IDs', + error, + }; + }, + }); + } return cards; } private async findLessonById(lessonId: string): Promise { - const lesson = await this.lessonClinetAdapter.getLessonById(lessonId); + let lesson: LessonDto = {} as LessonDto; + try { + lesson = await this.lessonClinetAdapter.getLessonById(lessonId); + } catch (error: unknown) { + this.erorrLogger.error({ + getLogMessage() { + return { + message: 'Error while fetching lesson by ID', + error, + }; + }, + }); + } return lesson; } + private async findCourseFileRecords(courseId: string): Promise { + const courseFiles = await this.filesService.listFilesOfParent(courseId); + + return courseFiles; + } + public async exportCourse( courseId: string, version: CommonCartridgeVersion, @@ -100,12 +167,6 @@ export class CommonCartridgeExportService { return builder.build(); } - public async findCourseFileRecords(courseId: string): Promise { - const courseFiles = await this.filesService.listFilesOfParent(courseId); - - return courseFiles; - } - private addComponentToOrganization( component: LessonContentDto, lessonOrganization: CommonCartridgeOrganizationNode From f799b1dcb99d37e7f0ee0aa8409418b72292dfd3 Mon Sep 17 00:00:00 2001 From: Firas Shmit Date: Mon, 25 Nov 2024 10:49:13 +0100 Subject: [PATCH 25/61] EW-1060 added test for cc controller --- .../common-cartridge.controller.spec.ts | 43 +++++++++++-------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/apps/server/src/modules/common-cartridge/controller/common-cartridge.controller.spec.ts b/apps/server/src/modules/common-cartridge/controller/common-cartridge.controller.spec.ts index a274eff5f7c..7851657abd5 100644 --- a/apps/server/src/modules/common-cartridge/controller/common-cartridge.controller.spec.ts +++ b/apps/server/src/modules/common-cartridge/controller/common-cartridge.controller.spec.ts @@ -1,10 +1,14 @@ import { faker } from '@faker-js/faker'; import { DeepMocked, createMock } from '@golevelup/ts-jest'; import { Test, TestingModule } from '@nestjs/testing'; +import { Response } from 'express'; +import { StreamableFile } from '@nestjs/common'; import { CommonCartridgeUc } from '../uc/common-cartridge.uc'; import { CommonCartridgeController } from './common-cartridge.controller'; -import { CourseFileIdsResponse, ExportCourseParams } from './dto'; -import { CourseExportBodyResponse } from './dto/course-export-body.response'; +import { ExportCourseParams } from './dto'; +import { CourseQueryParams } from './dto/course.query.params'; +import { CourseExportBodyParams } from './dto/course-export.body.params'; +import { CommonCartridgeVersion } from '../export/common-cartridge.enums'; describe('CommonCartridgeController', () => { let module: TestingModule; @@ -37,28 +41,33 @@ describe('CommonCartridgeController', () => { describe('exportCourse', () => { const setup = () => { const courseId = faker.string.uuid(); - const request = new ExportCourseParams(); - const expected = new CourseExportBodyResponse({ - courseFileIds: new CourseFileIdsResponse([]), - courseCommonCartridgeMetadata: { - id: courseId, - title: faker.lorem.sentence(), - copyRightOwners: [faker.lorem.words()], - }, - }); + const params = { parentId: courseId } as ExportCourseParams; + const query = { version: CommonCartridgeVersion.V_1_1_0 } as CourseQueryParams; + const body = { + topics: [faker.string.uuid(), faker.string.uuid()], + tasks: [faker.string.uuid()], + columnBoards: [faker.string.uuid(), faker.string.uuid()], + } as CourseExportBodyParams; + const expected = Buffer.from(faker.lorem.paragraphs(100)); + const mockResponse = { + set: jest.fn(), + } as unknown as Response; - Reflect.set(request, 'parentId', courseId); commonCartridgeUcMock.exportCourse.mockResolvedValue(expected); - return { request, expected }; + return { params, expected, query, body, mockResponse }; }; - it('should return a list of found FileRecords', async () => { - const { request, expected } = setup(); + it('should return a streamable file', async () => { + const { params, query, body, mockResponse } = setup(); - const result = await sut.exportCourse(request); + const result = await sut.exportCourse(params, query, body, mockResponse); - expect(result).toEqual(expected); + expect(mockResponse.set).toHaveBeenCalledWith({ + 'Content-Type': 'application/zip', + 'Content-Disposition': `attachment; filename=course_${params.parentId}.zip`, + }); + expect(result).toBeInstanceOf(StreamableFile); }); }); }); From d6102efa57864dd022db344e618ec1586cbe3ec2 Mon Sep 17 00:00:00 2001 From: Firas Shmit Date: Wed, 27 Nov 2024 11:55:22 +0100 Subject: [PATCH 26/61] EW-1060 changed some variables name --- .../card-client/dto/timestamp-response.dto.ts | 2 +- .../course-client/courses-client.adapter.spec.ts | 2 +- .../course-client/courses-client.adapter.ts | 2 +- .../course-client/dto/course-common-cartridge-metadata.dto.ts | 4 ++-- .../service/common-cartridge-export.service.ts | 2 +- .../common-cartridge/service/common-cartridge.mapper.ts | 4 ++-- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/timestamp-response.dto.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/timestamp-response.dto.ts index a75998154b1..1fc934e4599 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/timestamp-response.dto.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/timestamp-response.dto.ts @@ -5,7 +5,7 @@ export class TimestampResponseDto { deletedAt?: string; - constructor(lastUpdatedAt: string, createdAt: string, deletedAt: string) { + constructor(lastUpdatedAt: string, createdAt: string, deletedAt?: string) { this.lastUpdatedAt = lastUpdatedAt; this.createdAt = createdAt; this.deletedAt = deletedAt; diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/courses-client.adapter.spec.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/courses-client.adapter.spec.ts index 058a7517f98..abd0d86d4a7 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/courses-client.adapter.spec.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/courses-client.adapter.spec.ts @@ -74,7 +74,7 @@ describe(CoursesClientAdapter.name, () => { expect(coursesApi.courseControllerGetCourseCcMetadataById).toHaveBeenCalledWith(courseId, expectedOptions); expect(result.id).toBeDefined(); - expect(result.title).toBeDefined(); + expect(result.courseName).toBeDefined(); expect(result.creationDate).toBeDefined(); expect(result.copyRightOwners).toBeDefined(); }); diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/courses-client.adapter.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/courses-client.adapter.ts index 324f907f06f..5b6955bb36b 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/courses-client.adapter.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/courses-client.adapter.ts @@ -15,7 +15,7 @@ export class CoursesClientAdapter { const response = await this.coursesApi.courseControllerGetCourseCcMetadataById(courseId, options); const courseCommonCartridgeMetadata: CourseCommonCartridgeMetadataDto = new CourseCommonCartridgeMetadataDto({ id: response.data.id, - title: response.data.title, + courseName: response.data.title, creationDate: response.data.creationDate, copyRightOwners: response.data.copyRightOwners, }); diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/dto/course-common-cartridge-metadata.dto.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/dto/course-common-cartridge-metadata.dto.ts index 117963823ca..179bb62e7b4 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/dto/course-common-cartridge-metadata.dto.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/dto/course-common-cartridge-metadata.dto.ts @@ -1,7 +1,7 @@ export class CourseCommonCartridgeMetadataDto { id: string; - title: string; + courseName: string; creationDate?: string; @@ -9,7 +9,7 @@ export class CourseCommonCartridgeMetadataDto { constructor(props: CourseCommonCartridgeMetadataDto) { this.id = props.id; - this.title = props.title; + this.courseName = props.courseName; this.creationDate = props.creationDate; this.copyRightOwners = props.copyRightOwners; } diff --git a/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts b/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts index 2d2af0dfe83..3c6ce211ea7 100644 --- a/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts +++ b/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts @@ -145,7 +145,7 @@ export class CommonCartridgeExportService { exportedTasks: string[], exportedColumnBoards: string[] ): Promise { - const builder = new CommonCartridgeFileBuilder(this.mapper.mapCourseToManifestNew(version, courseId)); + const builder = new CommonCartridgeFileBuilder(this.mapper.mapCourseToManifest(version, courseId)); const courseCommonCartridgeMetadata: CourseCommonCartridgeMetadataDto = await this.findCourseCommonCartridgeMetadata(courseId); diff --git a/apps/server/src/modules/common-cartridge/service/common-cartridge.mapper.ts b/apps/server/src/modules/common-cartridge/service/common-cartridge.mapper.ts index 5fb4b22ad5f..cfef1d43d26 100644 --- a/apps/server/src/modules/common-cartridge/service/common-cartridge.mapper.ts +++ b/apps/server/src/modules/common-cartridge/service/common-cartridge.mapper.ts @@ -27,7 +27,7 @@ import { ComponentEtherpadPropsDto } from '../common-cartridge-client/lesson-cli export class CommonCartridgeExportMapper { private static readonly GEOGEBRA_BASE_URL: string = 'https://geogebra.org'; - public mapCourseToManifestNew( + public mapCourseToManifest( version: CommonCartridgeVersion, courseId: string ): { version: CommonCartridgeVersion; identifier: string } { @@ -40,7 +40,7 @@ export class CommonCartridgeExportMapper { public mapCourseToMetadata(courseMetadata: CourseCommonCartridgeMetadataDto): CommonCartridgeElementProps { return { type: CommonCartridgeElementType.METADATA, - title: courseMetadata.title, + title: courseMetadata.courseName, copyrightOwners: courseMetadata.copyRightOwners, creationDate: courseMetadata.creationDate ? new Date(courseMetadata.creationDate) : new Date(), }; From e50495d50efa8427db50c6bf0f5d80da4fbde1fd Mon Sep 17 00:00:00 2001 From: Firas Shmit Date: Wed, 27 Nov 2024 12:16:27 +0100 Subject: [PATCH 27/61] EW-1060 added logger module to imports --- .../src/modules/common-cartridge/common-cartridge.module.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/server/src/modules/common-cartridge/common-cartridge.module.ts b/apps/server/src/modules/common-cartridge/common-cartridge.module.ts index ab1cfbd8d68..0baa7a31515 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge.module.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge.module.ts @@ -5,6 +5,7 @@ import { Module } from '@nestjs/common'; import { ALL_ENTITIES } from '@shared/domain/entity'; import { DB_PASSWORD, DB_URL, DB_USERNAME } from '@src/config'; import { RabbitMQWrapperModule } from '@src/infra/rabbitmq'; +import { LoggerModule } from '@src/core/logger'; import { defaultMikroOrmOptions } from '../server'; import { BoardClientModule } from './common-cartridge-client/board-client'; import { CoursesClientModule } from './common-cartridge-client/course-client'; @@ -19,6 +20,7 @@ import { CommonCartridgeExportMapper } from './service/common-cartridge.mapper'; imports: [ RabbitMQWrapperModule, FilesStorageClientModule, + LoggerModule, MikroOrmModule.forRoot({ ...defaultMikroOrmOptions, type: 'mongo', From 0599ed3c8305fbe166263efcfc8dbcd46bb4739f Mon Sep 17 00:00:00 2001 From: Firas Shmit Date: Wed, 27 Nov 2024 18:00:15 +0100 Subject: [PATCH 28/61] EW-1060 added tests for cc export service --- .../dto/link-element-content.dto.ts | 2 +- .../common-cartridge-export.service.spec.ts | 503 ++++++++++++++---- 2 files changed, 410 insertions(+), 95 deletions(-) diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/link-element-content.dto.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/link-element-content.dto.ts index 6b257248f30..6b9737b21d0 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/link-element-content.dto.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/link-element-content.dto.ts @@ -7,7 +7,7 @@ export class LinkElementContentDto { imageUrl?: string; - constructor(url: string, title: string, description: string, imageUrl: string) { + constructor(url: string, title: string, description: string, imageUrl?: string) { this.url = url; this.title = title; this.description = description; diff --git a/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.spec.ts b/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.spec.ts index f6d1066f5b0..22ef8094aa8 100644 --- a/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.spec.ts +++ b/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.spec.ts @@ -1,28 +1,269 @@ -import { faker } from '@faker-js/faker'; import { DeepMocked, createMock } from '@golevelup/ts-jest'; import { FilesStorageClientAdapterService } from '@modules/files-storage-client'; +import { faker } from '@faker-js/faker'; import { Test, TestingModule } from '@nestjs/testing'; -import { BoardClientAdapter } from '../common-cartridge-client/board-client'; +import AdmZip from 'adm-zip'; +import { ErrorLogger } from '@src/core/logger'; +import { + BoardClientAdapter, + BoardSkeletonDto, + CardSkeletonDto, + ColumnSkeletonDto, +} from '../common-cartridge-client/board-client'; import { CommonCartridgeExportService } from './common-cartridge-export.service'; -import { CoursesClientAdapter } from '../common-cartridge-client/course-client'; +import { CourseCommonCartridgeMetadataDto, CoursesClientAdapter } from '../common-cartridge-client/course-client'; import { CourseRoomsClientAdapter } from '../common-cartridge-client/room-client'; import { CardClientAdapter } from '../common-cartridge-client/card-client/card-client.adapter'; -import { CardListResponseDto } from '../common-cartridge-client/card-client/dto/card-list-response.dto'; +import { LessonClientAdapter } from '../common-cartridge-client/lesson-client/lesson-client.adapter'; +import { CommonCartridgeExportMapper } from './common-cartridge.mapper'; +import { CommonCartridgeVersion } from '../export/common-cartridge.enums'; +import { RoomBoardDto } from '../common-cartridge-client/room-client/dto/room-board.dto'; +import { LessonDto, LessonLinkedTaskDto } from '../common-cartridge-client/lesson-client/dto'; import { CardResponseDto } from '../common-cartridge-client/card-client/dto/card-response.dto'; +import { VisibilitySettingsResponseDto } from '../common-cartridge-client/card-client/dto/visibility-settings-response.dto'; +import { TimestampResponseDto } from '../common-cartridge-client/card-client/dto/timestamp-response.dto'; +import { CardListResponseDto } from '../common-cartridge-client/card-client/dto/card-list-response.dto'; +import { BoardElementDtoType } from '../common-cartridge-client/room-client/enums/board-element.enum'; +import { BoardLayout } from '../common-cartridge-client/room-client/enums/board-layout.enum'; +import { BoardTaskDto } from '../common-cartridge-client/room-client/dto/board-task.dto'; +import { BoardTaskStatusDto } from '../common-cartridge-client/room-client/dto/board-task-status.dto'; +import { RichTextElementResponseDto } from '../common-cartridge-client/card-client/dto/rich-text-element-response.dto'; import { ContentElementType } from '../common-cartridge-client/card-client/enums/content-element-type.enum'; +import { RichTextElementContentDto } from '../common-cartridge-client/card-client/dto/rich-text-element-content.dto'; +import { LinkElementResponseDto } from '../common-cartridge-client/card-client/dto/link-element-response.dto'; +import { LinkElementContentDto } from '../common-cartridge-client/card-client/dto/link-element-content.dto'; describe('CommonCartridgeExportService', () => { let module: TestingModule; let sut: CommonCartridgeExportService; - let filesStorageServiceMock: DeepMocked; let coursesClientAdapterMock: DeepMocked; let courseRoomsClientAdapterMock: DeepMocked; let cardClientAdapterMock: DeepMocked; + let boardClientAdapterMock: DeepMocked; + let lessonClientAdapterMock: DeepMocked; + let errorLogger: DeepMocked; + + const dummyCourseId = faker.string.uuid(); + const createXmlString = (nodeName: string, value: boolean | number | string): string => + `<${nodeName}>${value.toString()}`; + const getFileContent = (archive: AdmZip, filePath: string): string | undefined => + archive.getEntry(filePath)?.getData().toString(); + + const setupParams = async ( + version: CommonCartridgeVersion, + exportTopics: boolean, + exportTasks: boolean, + exportColumnBoards: boolean + ) => { + const courseMetadata = new CourseCommonCartridgeMetadataDto({ + id: dummyCourseId, + courseName: 'TEST COURSE', + creationDate: faker.date.recent().toISOString(), + copyRightOwners: [faker.person.fullName()], + }); + + const lessonLinkedTask: LessonLinkedTaskDto = { + name: 'TEST LINKED TASK', + description: faker.lorem.paragraph(), + descriptionInputFormat: 'plainText', + availableDate: faker.date.recent().toISOString(), + dueDate: faker.date.future().toISOString(), + private: false, + publicSubmissions: false, + teamSubmissions: false, + creator: faker.internet.email(), + courseId: dummyCourseId, + submissionIds: [], + finishedIds: [], + }; + + const lessons: LessonDto[] = [ + { + lessonId: faker.string.uuid(), + name: 'TEST LESSON 1', + courseId: dummyCourseId, + courseGroupId: faker.string.uuid(), + hidden: false, + position: faker.number.int(), + contents: [ + { + id: faker.string.uuid(), + content: { + text: 'text', + }, + title: faker.lorem.sentence(), + component: 'text', + hidden: false, + }, + ], + materials: [], + linkedTasks: [lessonLinkedTask], + }, + { + lessonId: faker.string.uuid(), + name: 'TEST LESSON 2', + courseId: dummyCourseId, + courseGroupId: faker.string.uuid(), + hidden: false, + position: faker.number.int(), + contents: [ + { + id: faker.string.uuid(), + content: { + text: 'text', + }, + title: faker.lorem.sentence(), + component: 'text', + hidden: false, + }, + ], + materials: [], + }, + ]; + + const boardSkeleton: BoardSkeletonDto = { + boardId: faker.string.uuid(), + title: 'TEST BOARD SKELETON', + columns: [ + new ColumnSkeletonDto({ + columnId: faker.string.uuid(), + title: faker.lorem.sentence(), + cards: [ + new CardSkeletonDto({ + cardId: faker.string.uuid(), + height: faker.number.int(), + }), + new CardSkeletonDto({ + cardId: faker.string.uuid(), + height: faker.number.int(), + }), + ], + }), + new ColumnSkeletonDto({ + columnId: faker.string.uuid(), + title: faker.lorem.sentence(), + cards: [], + }), + ], + isVisible: true, + layout: 'columns', + }; + + const listOfCardsResponse: CardListResponseDto = { + data: [ + new CardResponseDto( + boardSkeleton.columns[0].cards?.[0].cardId ?? '', + 'TEST CARD 1', + faker.number.int(), + [ + new RichTextElementResponseDto( + faker.string.uuid(), + ContentElementType.RICH_TEXT, + new RichTextElementContentDto('dummy rich text', 'plainText'), + new TimestampResponseDto(faker.date.recent().toISOString(), faker.date.recent().toISOString(), undefined) + ), + ], + new VisibilitySettingsResponseDto('public'), + new TimestampResponseDto(faker.date.recent().toISOString(), faker.date.recent().toISOString(), undefined) + ), + new CardResponseDto( + boardSkeleton.columns[0].cards?.[1].cardId ?? '', + 'TEST CARD 2', + faker.number.int(), + [ + new LinkElementResponseDto( + faker.string.uuid(), + ContentElementType.LINK, + new LinkElementContentDto('dummy url', 'dummy title of the link', 'dummy description'), + new TimestampResponseDto(faker.date.recent().toISOString(), faker.date.recent().toISOString(), undefined) + ), + ], + new VisibilitySettingsResponseDto('public'), + new TimestampResponseDto(faker.date.recent().toISOString(), faker.date.recent().toISOString(), undefined) + ), + ], + }; + + const boardTask: BoardTaskDto = { + id: faker.string.uuid(), + name: 'TEST TASK', + availableDate: faker.date.recent().toISOString(), + dueDate: faker.date.future().toISOString(), + courseName: courseMetadata.courseName, + description: faker.lorem.paragraph(), + displayColor: faker.internet.color(), + createdAt: faker.date.recent().toISOString(), + updatedAt: faker.date.recent().toISOString(), + status: new BoardTaskStatusDto({ + submitted: faker.number.int(), + maxSubmissions: faker.number.int(), + graded: faker.number.int(), + isDraft: faker.datatype.boolean(), + isSubstitutionTeacher: faker.datatype.boolean(), + isFinished: faker.datatype.boolean(), + }), + }; + + const room: RoomBoardDto = { + roomId: faker.string.uuid(), + title: courseMetadata.courseName, + displayColor: faker.internet.color(), + elements: [ + { + type: BoardElementDtoType.TASK, + content: { ...boardTask, status: { ...boardTask.status } }, + }, + { + type: BoardElementDtoType.COLUMN_BOARD, + content: { + id: boardSkeleton.boardId, + title: 'TEST BOARD COLUMN BOARD', + published: faker.datatype.boolean(), + createdAt: faker.date.recent().toISOString(), + updatedAt: faker.date.recent().toISOString(), + columnBoardId: boardSkeleton.boardId, + layout: BoardLayout.COLUMNS, + }, + }, + ], + isArchived: false, + isSynchronized: false, + }; + + coursesClientAdapterMock.getCourseCommonCartridgeMetadata.mockResolvedValue(courseMetadata); + courseRoomsClientAdapterMock.getRoomBoardByCourseId.mockResolvedValue(room); + lessonClientAdapterMock.getLessonById.mockResolvedValue(lessons[0]); + lessonClientAdapterMock.getLessonTasks.mockResolvedValue([lessonLinkedTask]); + boardClientAdapterMock.getBoardSkeletonById.mockResolvedValue(boardSkeleton); + cardClientAdapterMock.getAllBoardCardsByIds.mockResolvedValue(listOfCardsResponse); + + const buffer = await sut.exportCourse( + dummyCourseId, + version, + exportTopics ? [lessons[0].lessonId, lessons[1].lessonId] : [], + exportTasks ? [room.elements[0].content.id] : [], + exportColumnBoards ? [room.elements[1].content.id] : [] + ); + + const archive = new AdmZip(buffer); + + return { + courseMetadata, + archive, + version, + room, + lessons, + boardTask, + boardSkeleton, + listOfCardsResponse, + }; + }; beforeAll(async () => { module = await Test.createTestingModule({ providers: [ CommonCartridgeExportService, + CommonCartridgeExportMapper, { provide: FilesStorageClientAdapterService, useValue: createMock(), @@ -43,14 +284,24 @@ describe('CommonCartridgeExportService', () => { provide: CardClientAdapter, useValue: createMock(), }, + { + provide: LessonClientAdapter, + useValue: createMock(), + }, + { + provide: ErrorLogger, + useValue: createMock(), + }, ], }).compile(); sut = module.get(CommonCartridgeExportService); - filesStorageServiceMock = module.get(FilesStorageClientAdapterService); coursesClientAdapterMock = module.get(CoursesClientAdapter); courseRoomsClientAdapterMock = module.get(CourseRoomsClientAdapter); cardClientAdapterMock = module.get(CardClientAdapter); + boardClientAdapterMock = module.get(BoardClientAdapter); + lessonClientAdapterMock = module.get(LessonClientAdapter); + errorLogger = module.get(ErrorLogger); }); afterAll(async () => { @@ -61,115 +312,179 @@ describe('CommonCartridgeExportService', () => { expect(sut).toBeDefined(); }); - describe('findCourseFileRecords', () => { - const setup = () => { - const courseId = faker.string.uuid(); - const expected = []; + describe('exportCourse', () => { + describe('when using version 1.1', () => { + const setup = async () => setupParams(CommonCartridgeVersion.V_1_1_0, true, true, true); - filesStorageServiceMock.listFilesOfParent.mockResolvedValue([]); + it('should use schema version 1.1.0', async () => { + const { archive } = await setup(); - return { courseId, expected }; - }; + expect(getFileContent(archive, 'imsmanifest.xml')).toContain(createXmlString('schemaversion', '1.1.0')); + }); + + it('should add course', async () => { + const { archive, courseMetadata } = await setup(); + + expect(getFileContent(archive, 'imsmanifest.xml')).toContain( + createXmlString('mnf:string', courseMetadata.courseName) + ); + }); + + it('should add lessons', async () => { + const { archive, lessons } = await setup(); + + lessons.forEach((lesson) => { + expect(getFileContent(archive, 'imsmanifest.xml')).toContain(createXmlString('title', lesson.name)); + }); + }); + + it('should add task', async () => { + const { archive, boardTask } = await setup(); + + expect(getFileContent(archive, 'imsmanifest.xml')).toContain(createXmlString('title', boardTask.name)); + + expect(getFileContent(archive, 'imsmanifest.xml')).toContain(` { + // const { archive, lessons } = await setup(); + // const manifest = archive.getEntry('imsmanifest.xml')?.getData().toString(); + + // lessons[0].linkedTasks?.forEach((linkedTask) => { + // expect(manifest).toContain(`${linkedTask.name}`); + // }); + // }); + + it('should add column boards', async () => { + const { archive, boardSkeleton } = await setup(); + const manifest = getFileContent(archive, 'imsmanifest.xml'); + + expect(manifest).toContain(createXmlString('title', boardSkeleton.title)); + }); - it('should return a list of FileRecords', async () => { - const { courseId, expected } = setup(); + it('should add column', async () => { + const { archive, boardSkeleton } = await setup(); + const manifest = getFileContent(archive, 'imsmanifest.xml'); - const result = await sut.findCourseFileRecords(courseId); + expect(manifest).toContain(createXmlString('title', boardSkeleton.columns[0].title ?? '')); + }); - expect(result).toEqual(expected); + it('should add card', async () => { + const { archive, listOfCardsResponse } = await setup(); + const manifest = getFileContent(archive, 'imsmanifest.xml'); + + expect(manifest).toContain(createXmlString('title', listOfCardsResponse.data[0].title ?? '')); + }); }); - }); - describe('findCourseCcMetadata', () => { - const setup = () => { - const courseId = faker.string.uuid(); - const expected = { - id: courseId, - title: faker.lorem.sentence(), - copyRightOwners: [faker.lorem.word()], - }; + describe('when using version 1.3', () => { + const setup = async () => setupParams(CommonCartridgeVersion.V_1_3_0, true, true, true); - coursesClientAdapterMock.getCourseCommonCartridgeMetadata.mockResolvedValue(expected); + it('should use schema version 1.3.0', async () => { + const { archive } = await setup(); - return { courseId, expected }; - }; + expect(getFileContent(archive, 'imsmanifest.xml')).toContain(createXmlString('schemaversion', '1.3.0')); + }); + + it('should add course', async () => { + const { archive, courseMetadata } = await setup(); + + expect(getFileContent(archive, 'imsmanifest.xml')).toContain( + createXmlString('mnf:string', courseMetadata.courseName) + ); + }); + + it('should add lessons', async () => { + const { archive, lessons } = await setup(); + + lessons.forEach((lesson) => { + expect(getFileContent(archive, 'imsmanifest.xml')).toContain(createXmlString('title', lesson.name)); + }); + }); + + it('should add tasks', async () => { + const { archive, boardTask } = await setup(); + + expect(getFileContent(archive, 'imsmanifest.xml')).toContain(` { + const { archive, lessons } = await setup(); + const manifest = archive.getEntry('imsmanifest.xml')?.getData().toString(); + + lessons[0].linkedTasks?.forEach((linkedTask) => { + expect(manifest).toContain(`${linkedTask.name}`); + }); + }); - it('should return a CourseCommonCartridgeMetadataDto', async () => { - const { courseId, expected } = setup(); + it('should add column boards', async () => { + const { archive, boardSkeleton } = await setup(); + const manifest = getFileContent(archive, 'imsmanifest.xml'); - const result = await sut.findCourseCommonCartridgeMetadata(courseId); + expect(manifest).toContain(createXmlString('title', boardSkeleton.title)); + }); - expect(result).toEqual(expected); + it('should add column', async () => { + const { archive, boardSkeleton } = await setup(); + const manifest = getFileContent(archive, 'imsmanifest.xml'); + + expect(manifest).toContain(createXmlString('title', boardSkeleton.columns[0].title ?? '')); + }); + + it('should add card', async () => { + const { archive, listOfCardsResponse } = await setup(); + const manifest = getFileContent(archive, 'imsmanifest.xml'); + + expect(manifest).toContain(createXmlString('title', listOfCardsResponse.data[0].title ?? '')); + }); + + // it('should add content element of cards', async () => { + // const { archive, textCardElement } = await setup(); + // const manifest = getFileContent(archive, 'imsmanifest.xml'); + + // expect(manifest).toContain(` { + // const { archive, linkElement } = await setup(); + // const manifest = getFileContent(archive, 'imsmanifest.xml'); + + // expect(manifest).toContain(` { - const setup = () => { - const roomId = faker.string.uuid(); - const expected = { - roomId, - title: faker.lorem.word(), - displayColor: faker.date.recent().toString(), - isSynchronized: faker.datatype.boolean(), - elements: [], - isArchived: faker.datatype.boolean(), - }; - - courseRoomsClientAdapterMock.getRoomBoardByCourseId.mockResolvedValue(expected); - - return { roomId, expected }; - }; + describe('When topics array is empty', () => { + const setup = async () => setupParams(CommonCartridgeVersion.V_1_1_0, false, true, true); + + it("shouldn't add lessons", async () => { + const { archive, lessons } = await setup(); + + lessons.forEach((lesson) => { + expect(getFileContent(archive, 'imsmanifest.xml')).not.toContain(createXmlString('title', lesson.name)); + }); + }); + }); - it('should return a room board', async () => { - const { roomId, expected } = setup(); + describe('When tasks array is empty', () => { + const setup = async () => setupParams(CommonCartridgeVersion.V_1_1_0, true, false, true); - const result = await sut.findRoomBoardByCourseId(roomId); + it("shouldn't add tasks", async () => { + const { archive, boardTask } = await setup(); - expect(result).toEqual(expected); + expect(getFileContent(archive, 'imsmanifest.xml')).not.toContain(` { - const setup = () => { - const cardsIds: Array = new Array(faker.string.uuid()); - const mockCard: CardResponseDto = { - id: cardsIds[0], - title: faker.lorem.word(), - height: faker.number.int(), - elements: [ - { - id: 'element-1', - type: ContentElementType.RICH_TEXT, - content: { - text: faker.string.alphanumeric.toString(), - inputFormat: 'HTML', - }, - timestamps: { - lastUpdatedAt: faker.date.anytime.toString(), - createdAt: faker.date.anytime.toString(), - deletedAt: '', - }, - }, - ], - visibilitySettings: { - publishedAt: '2024-10-01T12:00:00Z', - }, - timeStamps: { - lastUpdatedAt: '2024-10-01T11:00:00Z', - createdAt: faker.date.anytime.toString(), - deletedAt: faker.date.anytime.toString(), - }, - }; - const expected: CardListResponseDto = new CardListResponseDto(new Array(mockCard)); - cardClientAdapterMock.getAllBoardCardsByIds.mockResolvedValue(expected); + describe('When columnBoards array is empty', () => { + const setup = async () => setupParams(CommonCartridgeVersion.V_1_1_0, true, true, false); - return { cardsIds, expected }; - }; - it('should return a card', async () => { - const { cardsIds, expected } = setup(); - const result = await sut.findAllCardsByIds(cardsIds); + it("shouldn't add column boards", async () => { + const { archive, boardSkeleton } = await setup(); - expect(result).toEqual(expected); + expect(getFileContent(archive, 'imsmanifest.xml')).not.toContain( + createXmlString('title', boardSkeleton.columns[0].title) + ); + }); }); }); }); From 0dc4646fb38ca482e5c83b35dc3009a1af9b3d98 Mon Sep 17 00:00:00 2001 From: Firas Shmit Date: Thu, 28 Nov 2024 12:05:34 +0100 Subject: [PATCH 29/61] EW-1060 removed files client from cc service --- .../common-cartridge/common-cartridge.module.ts | 2 -- .../service/common-cartridge-export.service.ts | 11 ++--------- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/apps/server/src/modules/common-cartridge/common-cartridge.module.ts b/apps/server/src/modules/common-cartridge/common-cartridge.module.ts index 3c85a1c7d8d..c562da864eb 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge.module.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge.module.ts @@ -1,6 +1,5 @@ import { Configuration } from '@hpi-schul-cloud/commons'; import { MikroOrmModule } from '@mikro-orm/nestjs'; -import { FilesStorageClientModule } from '@modules/files-storage-client'; import { Module } from '@nestjs/common'; import { ALL_ENTITIES } from '@shared/domain/entity'; import { DB_PASSWORD, DB_URL, DB_USERNAME } from '@src/config'; @@ -19,7 +18,6 @@ import { CommonCartridgeExportMapper } from './service/common-cartridge.mapper'; @Module({ imports: [ RabbitMQWrapperModule, - FilesStorageClientModule, LoggerModule, MikroOrmModule.forRoot({ ...defaultMikroOrmOptions, diff --git a/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts b/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts index 3c6ce211ea7..1d6896fad45 100644 --- a/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts +++ b/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts @@ -33,7 +33,6 @@ const isLinkElement = (reference: unknown): reference is LinkElementResponseDto @Injectable() export class CommonCartridgeExportService { constructor( - private readonly filesService: FilesStorageClientAdapterService, private readonly boardClientAdapter: BoardClientAdapter, private readonly cardClientAdapter: CardClientAdapter, private readonly coursesClientAdapter: CoursesClientAdapter, @@ -132,12 +131,6 @@ export class CommonCartridgeExportService { return lesson; } - private async findCourseFileRecords(courseId: string): Promise { - const courseFiles = await this.filesService.listFilesOfParent(courseId); - - return courseFiles; - } - public async exportCourse( courseId: string, version: CommonCartridgeVersion, @@ -193,7 +186,7 @@ export class CommonCartridgeExportService { const filteredLessons = this.filterLessonFromBoardElements(elements); const lessonsIds = filteredLessons.filter((lesson) => topics.includes(lesson.id)).map((lesson) => lesson.id); - if (!lessonsIds) { + if (lessonsIds.length === 0) { return; } @@ -246,7 +239,7 @@ export class CommonCartridgeExportService { .filter((columBoard) => exportedColumnBoards.includes(columBoard.columnBoardId)) .map((columBoard) => columBoard.columnBoardId); - if (!columnBoardsIds) { + if (columnBoardsIds.length === 0) { return; } From 436f23e64b491802ff91cd0e8efc8b69714cf895 Mon Sep 17 00:00:00 2001 From: Firas Shmit Date: Thu, 28 Nov 2024 16:00:22 +0100 Subject: [PATCH 30/61] EW-1060 removed error logger from cc service --- .../common-cartridge.module.ts | 2 - .../common-cartridge-export.service.ts | 76 +++---------------- 2 files changed, 12 insertions(+), 66 deletions(-) diff --git a/apps/server/src/modules/common-cartridge/common-cartridge.module.ts b/apps/server/src/modules/common-cartridge/common-cartridge.module.ts index c562da864eb..5997ab8f977 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge.module.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge.module.ts @@ -5,7 +5,6 @@ import { ALL_ENTITIES } from '@shared/domain/entity'; import { DB_PASSWORD, DB_URL, DB_USERNAME } from '@src/config'; import { RabbitMQWrapperModule } from '@src/infra/rabbitmq'; import { defaultMikroOrmOptions } from '@shared/common/defaultMikroOrmOptions'; -import { LoggerModule } from '@src/core/logger'; import { BoardClientModule } from './common-cartridge-client/board-client'; import { CoursesClientModule } from './common-cartridge-client/course-client'; import { CommonCartridgeExportService } from './service/common-cartridge-export.service'; @@ -18,7 +17,6 @@ import { CommonCartridgeExportMapper } from './service/common-cartridge.mapper'; @Module({ imports: [ RabbitMQWrapperModule, - LoggerModule, MikroOrmModule.forRoot({ ...defaultMikroOrmOptions, type: 'mongo', diff --git a/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts b/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts index 1d6896fad45..1bdcbc013f7 100644 --- a/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts +++ b/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts @@ -1,6 +1,4 @@ -import { FileDto, FilesStorageClientAdapterService } from '@modules/files-storage-client'; import { Injectable } from '@nestjs/common'; -import { ErrorLogger } from '@src/core/logger'; import { BoardClientAdapter, BoardSkeletonDto, ColumnSkeletonDto } from '../common-cartridge-client/board-client'; import { CourseCommonCartridgeMetadataDto, CoursesClientAdapter } from '../common-cartridge-client/course-client'; import { CourseRoomsClientAdapter } from '../common-cartridge-client/room-client'; @@ -38,95 +36,45 @@ export class CommonCartridgeExportService { private readonly coursesClientAdapter: CoursesClientAdapter, private readonly courseRoomsClientAdapter: CourseRoomsClientAdapter, private readonly lessonClinetAdapter: LessonClientAdapter, - private readonly mapper: CommonCartridgeExportMapper, - private readonly erorrLogger: ErrorLogger + private readonly mapper: CommonCartridgeExportMapper ) {} private async findCourseCommonCartridgeMetadata(courseId: string): Promise { let courseCommonCartridgeMetadata: CourseCommonCartridgeMetadataDto = {} as CourseCommonCartridgeMetadataDto; - try { - courseCommonCartridgeMetadata = await this.coursesClientAdapter.getCourseCommonCartridgeMetadata(courseId); - } catch (error: unknown) { - this.erorrLogger.error({ - getLogMessage() { - return { - message: 'Error while fetching course common cartridge metadata', - error, - }; - }, - }); - } + + courseCommonCartridgeMetadata = await this.coursesClientAdapter.getCourseCommonCartridgeMetadata(courseId); return courseCommonCartridgeMetadata; } private async findRoomBoardByCourseId(courseId: string): Promise { let roomBoardDto: RoomBoardDto = {} as RoomBoardDto; - try { - roomBoardDto = await this.courseRoomsClientAdapter.getRoomBoardByCourseId(courseId); - } catch (error: unknown) { - this.erorrLogger.error({ - getLogMessage() { - return { - message: 'Error while fetching room board by course ID', - error, - }; - }, - }); - } + + roomBoardDto = await this.courseRoomsClientAdapter.getRoomBoardByCourseId(courseId); + return roomBoardDto; } private async findBoardSkeletonById(boardId: string): Promise { let boardSkeleton: BoardSkeletonDto = {} as BoardSkeletonDto; - try { - boardSkeleton = await this.boardClientAdapter.getBoardSkeletonById(boardId); - } catch (error: unknown) { - this.erorrLogger.error({ - getLogMessage() { - return { - message: 'Error while fetching board skeleton by course ID', - error, - }; - }, - }); - } + + boardSkeleton = await this.boardClientAdapter.getBoardSkeletonById(boardId); return boardSkeleton; } private async findAllCardsByIds(ids: Array): Promise { let cards: CardListResponseDto = {} as CardListResponseDto; - try { - cards = await this.cardClientAdapter.getAllBoardCardsByIds(ids); - } catch (error: unknown) { - this.erorrLogger.error({ - getLogMessage() { - return { - message: 'Error while fetching all board cards by IDs', - error, - }; - }, - }); - } + + cards = await this.cardClientAdapter.getAllBoardCardsByIds(ids); return cards; } private async findLessonById(lessonId: string): Promise { let lesson: LessonDto = {} as LessonDto; - try { - lesson = await this.lessonClinetAdapter.getLessonById(lessonId); - } catch (error: unknown) { - this.erorrLogger.error({ - getLogMessage() { - return { - message: 'Error while fetching lesson by ID', - error, - }; - }, - }); - } + + lesson = await this.lessonClinetAdapter.getLessonById(lessonId); return lesson; } From 5f48ca9ffa019a1752db9068df4eff25ea5dd3b3 Mon Sep 17 00:00:00 2001 From: Firas Shmit Date: Thu, 28 Nov 2024 17:14:15 +0100 Subject: [PATCH 31/61] EW-1060 added axios error to global filter --- .../core/error/domain/domainErrorHandler.ts | 5 +- .../error/filter/global-error.filter.spec.ts | 21 +++ .../common-cartridge-export.service.spec.ts | 173 ++++++++++++------ 3 files changed, 137 insertions(+), 62 deletions(-) diff --git a/apps/server/src/core/error/domain/domainErrorHandler.ts b/apps/server/src/core/error/domain/domainErrorHandler.ts index 778dd48026b..ef5748ed600 100644 --- a/apps/server/src/core/error/domain/domainErrorHandler.ts +++ b/apps/server/src/core/error/domain/domainErrorHandler.ts @@ -4,7 +4,8 @@ import { ErrorLogger, Loggable, LoggingUtils, LogMessageDataObject } from '@src/ import { ICurrentUser } from '@src/infra/auth-guard'; import { Request } from 'express'; import util from 'util'; -import { ErrorLoggable } from '../loggable'; +import axios from 'axios'; +import { AxiosErrorLoggable, ErrorLoggable } from '../loggable'; @Injectable() export class DomainErrorHandler { @@ -37,6 +38,8 @@ export class DomainErrorHandler { if (LoggingUtils.isInstanceOfLoggable(error)) { loggable = error; + } else if (axios.isAxiosError(error)) { + loggable = new AxiosErrorLoggable(error, 'AXIOS_REQUEST_ERROR'); } else if (error instanceof Error) { loggable = new ErrorLoggable(error, data); } else { diff --git a/apps/server/src/core/error/filter/global-error.filter.spec.ts b/apps/server/src/core/error/filter/global-error.filter.spec.ts index 31ce2b9f04f..2900d76b3d9 100644 --- a/apps/server/src/core/error/filter/global-error.filter.spec.ts +++ b/apps/server/src/core/error/filter/global-error.filter.spec.ts @@ -7,6 +7,7 @@ import { WsException } from '@nestjs/websockets'; import { BusinessError } from '@shared/common'; import { ErrorLogMessage, Loggable } from '@src/core/logger'; import { Response } from 'express'; +import { AxiosError } from 'axios'; import { DomainErrorHandler } from '../domain'; import { ErrorResponse } from '../dto'; import { ErrorUtils } from '../utils'; @@ -102,6 +103,26 @@ describe('GlobalErrorFilter', () => { }); }); + describe('given context is axios', () => { + const setup = () => { + const argumentsHost = createMock(); + argumentsHost.getType.mockReturnValueOnce(UseableContextType.http); + + const error = new AxiosError('test'); + + return { error, argumentsHost }; + }; + + it('should call exec on axios error handler', () => { + const { error, argumentsHost } = setup(); + + service.catch(error, argumentsHost); + + expect(domainErrorHandler.execHttpContext).toBeCalledWith(error, {}); + expect(domainErrorHandler.execHttpContext).toBeCalledTimes(1); + }); + }); + describe('given context is http', () => { const mockHttpArgumentsHost = () => { const argumentsHost = createMock(); diff --git a/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.spec.ts b/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.spec.ts index 22ef8094aa8..aa69045f0a2 100644 --- a/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.spec.ts +++ b/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.spec.ts @@ -3,7 +3,6 @@ import { FilesStorageClientAdapterService } from '@modules/files-storage-client' import { faker } from '@faker-js/faker'; import { Test, TestingModule } from '@nestjs/testing'; import AdmZip from 'adm-zip'; -import { ErrorLogger } from '@src/core/logger'; import { BoardClientAdapter, BoardSkeletonDto, @@ -18,7 +17,7 @@ import { LessonClientAdapter } from '../common-cartridge-client/lesson-client/le import { CommonCartridgeExportMapper } from './common-cartridge.mapper'; import { CommonCartridgeVersion } from '../export/common-cartridge.enums'; import { RoomBoardDto } from '../common-cartridge-client/room-client/dto/room-board.dto'; -import { LessonDto, LessonLinkedTaskDto } from '../common-cartridge-client/lesson-client/dto'; +import { LessonContentDto, LessonDto, LessonLinkedTaskDto } from '../common-cartridge-client/lesson-client/dto'; import { CardResponseDto } from '../common-cartridge-client/card-client/dto/card-response.dto'; import { VisibilitySettingsResponseDto } from '../common-cartridge-client/card-client/dto/visibility-settings-response.dto'; import { TimestampResponseDto } from '../common-cartridge-client/card-client/dto/timestamp-response.dto'; @@ -32,6 +31,9 @@ import { ContentElementType } from '../common-cartridge-client/card-client/enums import { RichTextElementContentDto } from '../common-cartridge-client/card-client/dto/rich-text-element-content.dto'; import { LinkElementResponseDto } from '../common-cartridge-client/card-client/dto/link-element-response.dto'; import { LinkElementContentDto } from '../common-cartridge-client/card-client/dto/link-element-content.dto'; +import { ComponentTextPropsDto } from '../common-cartridge-client/lesson-client/dto/component-text-props.dto'; +import { BoardLessonDto } from '../common-cartridge-client/room-client/dto/board-lesson.dto'; +import { ComponentGeogebraPropsDto } from '../common-cartridge-client/lesson-client/dto/component-geogebra-props.dto'; describe('CommonCartridgeExportService', () => { let module: TestingModule; @@ -41,7 +43,6 @@ describe('CommonCartridgeExportService', () => { let cardClientAdapterMock: DeepMocked; let boardClientAdapterMock: DeepMocked; let lessonClientAdapterMock: DeepMocked; - let errorLogger: DeepMocked; const dummyCourseId = faker.string.uuid(); const createXmlString = (nodeName: string, value: boolean | number | string): string => @@ -62,20 +63,36 @@ describe('CommonCartridgeExportService', () => { copyRightOwners: [faker.person.fullName()], }); - const lessonLinkedTask: LessonLinkedTaskDto = { - name: 'TEST LINKED TASK', - description: faker.lorem.paragraph(), - descriptionInputFormat: 'plainText', - availableDate: faker.date.recent().toISOString(), - dueDate: faker.date.future().toISOString(), - private: false, - publicSubmissions: false, - teamSubmissions: false, - creator: faker.internet.email(), - courseId: dummyCourseId, - submissionIds: [], - finishedIds: [], - }; + const lessonLinkedTask: LessonLinkedTaskDto[] = [ + { + name: 'First linked Task', + description: faker.lorem.paragraph(), + descriptionInputFormat: 'plainText', + availableDate: faker.date.recent().toISOString(), + dueDate: faker.date.future().toISOString(), + private: false, + publicSubmissions: false, + teamSubmissions: false, + creator: faker.internet.email(), + courseId: dummyCourseId, + submissionIds: [], + finishedIds: [], + }, + { + name: 'second linked Task', + description: faker.lorem.paragraph(), + descriptionInputFormat: 'plainText', + availableDate: faker.date.recent().toISOString(), + dueDate: faker.date.future().toISOString(), + private: false, + publicSubmissions: false, + teamSubmissions: false, + creator: faker.internet.email(), + courseId: dummyCourseId, + submissionIds: [], + finishedIds: [], + }, + ]; const lessons: LessonDto[] = [ { @@ -86,18 +103,27 @@ describe('CommonCartridgeExportService', () => { hidden: false, position: faker.number.int(), contents: [ - { + new LessonContentDto({ id: faker.string.uuid(), - content: { + content: new ComponentTextPropsDto({ text: 'text', - }, + }), title: faker.lorem.sentence(), component: 'text', hidden: false, - }, + }), + new LessonContentDto({ + id: faker.string.uuid(), + content: new ComponentGeogebraPropsDto({ + materialId: faker.string.uuid(), + }), + title: faker.lorem.sentence(), + component: 'geoGebra', + hidden: false, + }), ], materials: [], - linkedTasks: [lessonLinkedTask], + linkedTasks: [lessonLinkedTask[0]], }, { lessonId: faker.string.uuid(), @@ -107,15 +133,15 @@ describe('CommonCartridgeExportService', () => { hidden: false, position: faker.number.int(), contents: [ - { + new LessonContentDto({ id: faker.string.uuid(), - content: { + content: new ComponentTextPropsDto({ text: 'text', - }, + }), title: faker.lorem.sentence(), component: 'text', hidden: false, - }, + }), ], materials: [], }, @@ -153,7 +179,7 @@ describe('CommonCartridgeExportService', () => { data: [ new CardResponseDto( boardSkeleton.columns[0].cards?.[0].cardId ?? '', - 'TEST CARD 1', + 'Text card', faker.number.int(), [ new RichTextElementResponseDto( @@ -168,7 +194,7 @@ describe('CommonCartridgeExportService', () => { ), new CardResponseDto( boardSkeleton.columns[0].cards?.[1].cardId ?? '', - 'TEST CARD 2', + 'link card', faker.number.int(), [ new LinkElementResponseDto( @@ -225,6 +251,34 @@ describe('CommonCartridgeExportService', () => { layout: BoardLayout.COLUMNS, }, }, + { + type: BoardElementDtoType.LESSON, + content: new BoardLessonDto({ + id: lessons[0].lessonId, + name: lessons[0].name, + courseName: courseMetadata.courseName, + numberOfPublishedTasks: lessons[0].linkedTasks?.length ?? 0, + numberOfDraftTasks: 0, + numberOfPlannedTasks: 0, + createdAt: faker.date.recent().toISOString(), + updatedAt: faker.date.recent().toISOString(), + hidden: lessons[0].hidden, + }), + }, + { + type: BoardElementDtoType.LESSON, + content: new BoardLessonDto({ + id: lessons[1].lessonId, + name: lessons[1].name, + courseName: courseMetadata.courseName, + numberOfPublishedTasks: lessons[1].linkedTasks?.length ?? 0, + numberOfDraftTasks: 0, + numberOfPlannedTasks: 0, + createdAt: faker.date.recent().toISOString(), + updatedAt: faker.date.recent().toISOString(), + hidden: lessons[1].hidden, + }), + }, ], isArchived: false, isSynchronized: false, @@ -233,14 +287,14 @@ describe('CommonCartridgeExportService', () => { coursesClientAdapterMock.getCourseCommonCartridgeMetadata.mockResolvedValue(courseMetadata); courseRoomsClientAdapterMock.getRoomBoardByCourseId.mockResolvedValue(room); lessonClientAdapterMock.getLessonById.mockResolvedValue(lessons[0]); - lessonClientAdapterMock.getLessonTasks.mockResolvedValue([lessonLinkedTask]); + lessonClientAdapterMock.getLessonTasks.mockResolvedValue(lessonLinkedTask); boardClientAdapterMock.getBoardSkeletonById.mockResolvedValue(boardSkeleton); cardClientAdapterMock.getAllBoardCardsByIds.mockResolvedValue(listOfCardsResponse); const buffer = await sut.exportCourse( dummyCourseId, version, - exportTopics ? [lessons[0].lessonId, lessons[1].lessonId] : [], + exportTopics ? [room.elements[2].content.id, room.elements[3].content.id] : [], exportTasks ? [room.elements[0].content.id] : [], exportColumnBoards ? [room.elements[1].content.id] : [] ); @@ -256,6 +310,8 @@ describe('CommonCartridgeExportService', () => { boardTask, boardSkeleton, listOfCardsResponse, + textElement: listOfCardsResponse.data[0].elements[0].content as RichTextElementContentDto, + linkElement: listOfCardsResponse.data[1].elements[0].content as LinkElementContentDto, }; }; @@ -288,10 +344,6 @@ describe('CommonCartridgeExportService', () => { provide: LessonClientAdapter, useValue: createMock(), }, - { - provide: ErrorLogger, - useValue: createMock(), - }, ], }).compile(); @@ -301,7 +353,6 @@ describe('CommonCartridgeExportService', () => { cardClientAdapterMock = module.get(CardClientAdapter); boardClientAdapterMock = module.get(BoardClientAdapter); lessonClientAdapterMock = module.get(LessonClientAdapter); - errorLogger = module.get(ErrorLogger); }); afterAll(async () => { @@ -330,12 +381,12 @@ describe('CommonCartridgeExportService', () => { ); }); - it('should add lessons', async () => { - const { archive, lessons } = await setup(); + it('should add lesson', async () => { + const { archive, room } = await setup(); - lessons.forEach((lesson) => { - expect(getFileContent(archive, 'imsmanifest.xml')).toContain(createXmlString('title', lesson.name)); - }); + expect(getFileContent(archive, 'imsmanifest.xml')).toContain( + createXmlString('title', (room.elements[2].content as BoardLessonDto).name) + ); }); it('should add task', async () => { @@ -346,14 +397,14 @@ describe('CommonCartridgeExportService', () => { expect(getFileContent(archive, 'imsmanifest.xml')).toContain(` { - // const { archive, lessons } = await setup(); - // const manifest = archive.getEntry('imsmanifest.xml')?.getData().toString(); + it('should add tasks of lesson to manifest file', async () => { + const { archive, lessons } = await setup(); + const manifest = archive.getEntry('imsmanifest.xml')?.getData().toString(); - // lessons[0].linkedTasks?.forEach((linkedTask) => { - // expect(manifest).toContain(`${linkedTask.name}`); - // }); - // }); + lessons[0].linkedTasks?.forEach((linkedTask) => { + expect(manifest).toContain(`${linkedTask.name}`); + }); + }); it('should add column boards', async () => { const { archive, boardSkeleton } = await setup(); @@ -395,11 +446,11 @@ describe('CommonCartridgeExportService', () => { }); it('should add lessons', async () => { - const { archive, lessons } = await setup(); + const { archive, room } = await setup(); - lessons.forEach((lesson) => { - expect(getFileContent(archive, 'imsmanifest.xml')).toContain(createXmlString('title', lesson.name)); - }); + expect(getFileContent(archive, 'imsmanifest.xml')).toContain( + createXmlString('title', (room.elements[2].content as BoardLessonDto).name) + ); }); it('should add tasks', async () => { @@ -438,19 +489,19 @@ describe('CommonCartridgeExportService', () => { expect(manifest).toContain(createXmlString('title', listOfCardsResponse.data[0].title ?? '')); }); - // it('should add content element of cards', async () => { - // const { archive, textCardElement } = await setup(); - // const manifest = getFileContent(archive, 'imsmanifest.xml'); + it('should add content element of cards', async () => { + const { archive, listOfCardsResponse } = await setup(); + const manifest = getFileContent(archive, 'imsmanifest.xml'); - // expect(manifest).toContain(` { - // const { archive, linkElement } = await setup(); - // const manifest = getFileContent(archive, 'imsmanifest.xml'); + it('should add link element of card', async () => { + const { archive, linkElement } = await setup(); + const manifest = getFileContent(archive, 'imsmanifest.xml'); - // expect(manifest).toContain(` { From 584956153e8a5534bea324c035925ea0e46b51e4 Mon Sep 17 00:00:00 2001 From: Firas Shmit Date: Thu, 28 Nov 2024 17:50:09 +0100 Subject: [PATCH 32/61] EW-1060 added test for axios loggable --- .../error/domain/domainErrorHandler.spec.ts | 19 +++++++++++++++++++ .../error/filter/global-error.filter.spec.ts | 2 +- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/apps/server/src/core/error/domain/domainErrorHandler.spec.ts b/apps/server/src/core/error/domain/domainErrorHandler.spec.ts index d253593efb5..baefa7797c9 100644 --- a/apps/server/src/core/error/domain/domainErrorHandler.spec.ts +++ b/apps/server/src/core/error/domain/domainErrorHandler.spec.ts @@ -4,9 +4,11 @@ import { Test, TestingModule } from '@nestjs/testing'; import { BusinessError } from '@shared/common'; import { ErrorLogger, ErrorLogMessage, Loggable, LogMessage, ValidationErrorLogMessage } from '@src/core/logger'; import util from 'util'; +import { AxiosError } from 'axios'; import { ErrorLoggable } from '../loggable/error.loggable'; import { ErrorUtils } from '../utils'; import { DomainErrorHandler } from './domainErrorHandler'; +import { AxiosErrorLoggable } from '../loggable'; class SampleLoggableException extends BadRequestException implements Loggable { constructor(private testData: string) { @@ -201,5 +203,22 @@ describe('GlobalErrorFilter', () => { expect(logger.error).toBeCalledWith(loggable); }); }); + + describe('when error is a axios error', () => { + const setup = () => { + const error = new AxiosError('test'); + const axiosLoggable = new AxiosErrorLoggable(error, 'AXIOS_REQUEST_ERROR'); + + return { axiosLoggable }; + }; + + it('should call logger with axios error', () => { + const { axiosLoggable } = setup(); + + domainErrorHandler.exec(axiosLoggable); + + expect(logger.error).toBeCalledWith(axiosLoggable); + }); + }); }); }); diff --git a/apps/server/src/core/error/filter/global-error.filter.spec.ts b/apps/server/src/core/error/filter/global-error.filter.spec.ts index 2900d76b3d9..4e99f0ca396 100644 --- a/apps/server/src/core/error/filter/global-error.filter.spec.ts +++ b/apps/server/src/core/error/filter/global-error.filter.spec.ts @@ -113,7 +113,7 @@ describe('GlobalErrorFilter', () => { return { error, argumentsHost }; }; - it('should call exec on axios error handler', () => { + it('should call exec on domain error handler', () => { const { error, argumentsHost } = setup(); service.catch(error, argumentsHost); From ea64b51af703f68e21c0bc1cd415bb8e9c070956 Mon Sep 17 00:00:00 2001 From: Firas Shmit Date: Fri, 29 Nov 2024 09:19:52 +0100 Subject: [PATCH 33/61] EW-1060 fixed cc service test --- .../service/common-cartridge-export.service.spec.ts | 7 ------- 1 file changed, 7 deletions(-) diff --git a/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.spec.ts b/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.spec.ts index aa69045f0a2..e460e01f2f7 100644 --- a/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.spec.ts +++ b/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.spec.ts @@ -489,13 +489,6 @@ describe('CommonCartridgeExportService', () => { expect(manifest).toContain(createXmlString('title', listOfCardsResponse.data[0].title ?? '')); }); - it('should add content element of cards', async () => { - const { archive, listOfCardsResponse } = await setup(); - const manifest = getFileContent(archive, 'imsmanifest.xml'); - - expect(manifest).toContain(` { const { archive, linkElement } = await setup(); const manifest = getFileContent(archive, 'imsmanifest.xml'); From ee6937cbc4791072328c54585021cded2f3aaaf7 Mon Sep 17 00:00:00 2001 From: Firas Shmit Date: Fri, 29 Nov 2024 10:17:38 +0100 Subject: [PATCH 34/61] EW-1060 fixed mapping of lernstore component --- .../service/common-cartridge.mapper.ts | 38 +++++++++++++++---- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/apps/server/src/modules/common-cartridge/service/common-cartridge.mapper.ts b/apps/server/src/modules/common-cartridge/service/common-cartridge.mapper.ts index cfef1d43d26..73a5e8b65b3 100644 --- a/apps/server/src/modules/common-cartridge/service/common-cartridge.mapper.ts +++ b/apps/server/src/modules/common-cartridge/service/common-cartridge.mapper.ts @@ -85,18 +85,42 @@ export class CommonCartridgeExportMapper { }`, url: (lessonContent.content as ComponentEtherpadPropsDto).url, }; - case LessonContentDtoComponentValues.LERNSTORE: - return { - type: CommonCartridgeResourceType.WEB_LINK, - identifier: createIdentifier(lessonContent.id), - title: (lessonContent.content as ComponentLernstorePropsDto).resources.join(', '), - url: (lessonContent.content as ComponentLernstorePropsDto & { url: string }).url, - }; + case LessonContentDtoComponentValues.LERNSTORE: { + const { resources } = lessonContent.content as ComponentLernstorePropsDto; + const extractedResources = this.extractResources(resources); + return ( + extractedResources.map((resource) => { + return { + type: CommonCartridgeResourceType.WEB_LINK, + identifier: createIdentifier(), + title: resource.title, + url: resource.url, + }; + }) || [] + ); + } default: return []; } } + // should be removed after fixing the issue with the Lernstore component + private extractResources(resources: string[]): { title: string; url: string }[] { + return resources.map((resource) => { + const fields = resource.split(',').map((field) => field.trim()); + let title = ''; + let url = ''; + + fields.forEach((field) => { + const [key, value] = field.split('=').map((part) => part.trim()); + if (key === 'title') title = value; + if (key === 'url') url = value; + }); + + return { title, url }; + }); + } + public mapContentToOrganization(content: LessonContentDto): CommonCartridgeOrganizationProps { return { identifier: createIdentifier(content.id), From b8db89158155956f9ba3d7a24ede774a4bd43cd8 Mon Sep 17 00:00:00 2001 From: Firas Shmit Date: Fri, 29 Nov 2024 11:07:19 +0100 Subject: [PATCH 35/61] EW-1060 changed some variables to constants --- .../common-cartridge-export.service.ts | 20 +++++-------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts b/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts index 1bdcbc013f7..1f4fc9cc9d7 100644 --- a/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts +++ b/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts @@ -40,41 +40,31 @@ export class CommonCartridgeExportService { ) {} private async findCourseCommonCartridgeMetadata(courseId: string): Promise { - let courseCommonCartridgeMetadata: CourseCommonCartridgeMetadataDto = {} as CourseCommonCartridgeMetadataDto; - - courseCommonCartridgeMetadata = await this.coursesClientAdapter.getCourseCommonCartridgeMetadata(courseId); + const courseCommonCartridgeMetadata = await this.coursesClientAdapter.getCourseCommonCartridgeMetadata(courseId); return courseCommonCartridgeMetadata; } private async findRoomBoardByCourseId(courseId: string): Promise { - let roomBoardDto: RoomBoardDto = {} as RoomBoardDto; - - roomBoardDto = await this.courseRoomsClientAdapter.getRoomBoardByCourseId(courseId); + const roomBoardDto = await this.courseRoomsClientAdapter.getRoomBoardByCourseId(courseId); return roomBoardDto; } private async findBoardSkeletonById(boardId: string): Promise { - let boardSkeleton: BoardSkeletonDto = {} as BoardSkeletonDto; - - boardSkeleton = await this.boardClientAdapter.getBoardSkeletonById(boardId); + const boardSkeleton = await this.boardClientAdapter.getBoardSkeletonById(boardId); return boardSkeleton; } private async findAllCardsByIds(ids: Array): Promise { - let cards: CardListResponseDto = {} as CardListResponseDto; - - cards = await this.cardClientAdapter.getAllBoardCardsByIds(ids); + const cards = await this.cardClientAdapter.getAllBoardCardsByIds(ids); return cards; } private async findLessonById(lessonId: string): Promise { - let lesson: LessonDto = {} as LessonDto; - - lesson = await this.lessonClinetAdapter.getLessonById(lessonId); + const lesson = await this.lessonClinetAdapter.getLessonById(lessonId); return lesson; } From 346cabab6c8962624c66fd9226f9cbb44eebb42f Mon Sep 17 00:00:00 2001 From: Firas Shmit Date: Fri, 29 Nov 2024 11:24:13 +0100 Subject: [PATCH 36/61] EW-1060 covered lernstore elements of a lesson by a test --- .../common-cartridge-export.service.spec.ts | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.spec.ts b/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.spec.ts index e460e01f2f7..5d4eadb4595 100644 --- a/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.spec.ts +++ b/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.spec.ts @@ -34,6 +34,7 @@ import { LinkElementContentDto } from '../common-cartridge-client/card-client/dt import { ComponentTextPropsDto } from '../common-cartridge-client/lesson-client/dto/component-text-props.dto'; import { BoardLessonDto } from '../common-cartridge-client/room-client/dto/board-lesson.dto'; import { ComponentGeogebraPropsDto } from '../common-cartridge-client/lesson-client/dto/component-geogebra-props.dto'; +import { ComponentLernstorePropsDto } from '../common-cartridge-client/lesson-client/dto/component-lernstore-props.dto'; describe('CommonCartridgeExportService', () => { let module: TestingModule; @@ -121,6 +122,15 @@ describe('CommonCartridgeExportService', () => { component: 'geoGebra', hidden: false, }), + new LessonContentDto({ + id: faker.string.uuid(), + content: new ComponentLernstorePropsDto({ + resources: ['{title: resource1, url: https:test.de}', '{title: resource2, url: https:test.de}'], + }), + title: faker.lorem.sentence(), + component: 'resources', + hidden: false, + }), ], materials: [], linkedTasks: [lessonLinkedTask[0]], @@ -406,6 +416,15 @@ describe('CommonCartridgeExportService', () => { }); }); + it('should add lernstore element of lesson to manifest file', async () => { + const { archive, lessons } = await setup(); + const manifest = archive.getEntry('imsmanifest.xml')?.getData().toString(); + + lessons[0].contents.forEach((content) => { + expect(manifest).toContain(`${content.title}`); + }); + }); + it('should add column boards', async () => { const { archive, boardSkeleton } = await setup(); const manifest = getFileContent(archive, 'imsmanifest.xml'); @@ -468,6 +487,15 @@ describe('CommonCartridgeExportService', () => { }); }); + it('should add lernstore element of lesson to manifest file', async () => { + const { archive, lessons } = await setup(); + const manifest = archive.getEntry('imsmanifest.xml')?.getData().toString(); + + lessons[0].contents.forEach((content) => { + expect(manifest).toContain(`${content.title}`); + }); + }); + it('should add column boards', async () => { const { archive, boardSkeleton } = await setup(); const manifest = getFileContent(archive, 'imsmanifest.xml'); From 2583f286125c66396e9408bd224bcb5c553137b9 Mon Sep 17 00:00:00 2001 From: Firas Shmit Date: Fri, 29 Nov 2024 12:46:18 +0100 Subject: [PATCH 37/61] EW-1060 modified test of lesson client adapter --- .../lesson-client.adapter.spec.ts | 90 ++++--------------- 1 file changed, 18 insertions(+), 72 deletions(-) diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lesson-client.adapter.spec.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lesson-client.adapter.spec.ts index fef7a941220..50590bb8f59 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lesson-client.adapter.spec.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lesson-client.adapter.spec.ts @@ -52,10 +52,26 @@ describe(LessonClientAdapter.name, () => { describe('getLessonById', () => { describe('When getLessonById is called', () => { const setup = () => { + const lessonId = faker.string.uuid(); + const linkedTasks = createMock>({ + data: [ + { + name: faker.lorem.sentence(), + description: faker.lorem.sentence(), + descriptionInputFormat: faker.helpers.arrayElement(['plainText', 'richTextCk4', 'richTextCk5Simple']), + availableDate: faker.date.recent().toString(), + dueDate: faker.date.future().toString(), + private: faker.datatype.boolean(), + publicSubmissions: faker.datatype.boolean(), + teamSubmissions: faker.datatype.boolean(), + }, + ], + }); + const response = createMock>({ data: { _id: faker.string.uuid(), - id: faker.string.uuid(), + id: lessonId, name: faker.lorem.sentence(), courseId: faker.string.uuid(), courseGroupId: faker.string.uuid(), @@ -86,6 +102,7 @@ describe(LessonClientAdapter.name, () => { }, }); + lessonApiMock.lessonControllerGetLessonTasks.mockResolvedValue(linkedTasks); lessonApiMock.lessonControllerGetLesson.mockResolvedValue(response); return { lessonId: response.data.id }; @@ -137,75 +154,4 @@ describe(LessonClientAdapter.name, () => { }); }); }); - - describe('getLessonTasks', () => { - describe('When getLessonTasks is called', () => { - const setup = () => { - const lessonId = faker.string.uuid(); - const response = createMock>({ - data: [ - { - name: faker.lorem.sentence(), - description: faker.lorem.sentence(), - descriptionInputFormat: faker.helpers.arrayElement(['plainText', 'richTextCk4', 'richTextCk5Simple']), - availableDate: faker.date.recent().toString(), - dueDate: faker.date.future().toString(), - private: faker.datatype.boolean(), - publicSubmissions: faker.datatype.boolean(), - teamSubmissions: faker.datatype.boolean(), - }, - ], - }); - - lessonApiMock.lessonControllerGetLessonTasks.mockResolvedValue(response); - - return { lessonId }; - }; - - it('should call lessonControllerGetLessonTasks', async () => { - const { lessonId } = setup(); - - await sut.getLessonTasks(lessonId); - - expect(lessonApiMock.lessonControllerGetLessonTasks).toHaveBeenCalled(); - }); - }); - - describe('When getLessonTasks is called with invalid id', () => { - const setup = () => { - const lessonResponseId = faker.string.uuid(); - - lessonApiMock.lessonControllerGetLessonTasks.mockRejectedValueOnce(new Error('error')); - - return { lessonResponseId }; - }; - - it('should throw an error', async () => { - const { lessonResponseId } = setup(); - - const result = sut.getLessonTasks(lessonResponseId); - - await expect(result).rejects.toThrowError('error'); - }); - }); - - describe('When no JWT token is found', () => { - const setup = () => { - const lessonResponseId = faker.string.uuid(); - const request = createMock({ - headers: {}, - }) as Request; - - const adapter: LessonClientAdapter = new LessonClientAdapter(lessonApiMock, request); - - return { lessonResponseId, adapter }; - }; - - it('should throw an UnauthorizedError', async () => { - const { lessonResponseId, adapter } = setup(); - - await expect(adapter.getLessonTasks(lessonResponseId)).rejects.toThrowError(UnauthorizedException); - }); - }); - }); }); From d82f0eb3a766a8729731ac1c1c65fd4a7d608884 Mon Sep 17 00:00:00 2001 From: Firas Shmit Date: Mon, 2 Dec 2024 17:29:43 +0100 Subject: [PATCH 38/61] EW-1060 added dtos fatory for cc & modified card response --- .../card-client/dto/card-response.dto.ts | 6 +- .../mapper/card-response.mapper.ts | 4 +- .../testing/common-cartridge-dtos.factory.ts | 214 ++++++++++++++++++ 3 files changed, 219 insertions(+), 5 deletions(-) create mode 100644 apps/server/src/modules/common-cartridge/testing/common-cartridge-dtos.factory.ts diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/card-response.dto.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/card-response.dto.ts index 2139dfcbd1e..a307d0fe3d1 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/card-response.dto.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/card-response.dto.ts @@ -17,14 +17,14 @@ export class CardResponseDto { constructor( id: string, - title: string, height: number, elements: CardResponseElementsInnerDto[], visibilitySettings: VisibilitySettingsResponseDto, - timestamps: TimestampResponseDto + timestamps: TimestampResponseDto, + title?: string ) { this.id = id; - this.title = title; + this.title = title ?? ''; this.height = height; this.elements = elements; this.visibilitySettings = visibilitySettings; diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/mapper/card-response.mapper.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/mapper/card-response.mapper.ts index ecf86629756..107ff340fa2 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/mapper/card-response.mapper.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/mapper/card-response.mapper.ts @@ -47,11 +47,11 @@ export class CardResponseMapper { private static mapToCardResponseDto(cardResponse: CardResponse): CardResponseDto { return new CardResponseDto( cardResponse.id, - cardResponse.title ?? '', cardResponse.height, this.mapToCardResponseElementsInnerDto(cardResponse.elements), this.mapToVisibilitySettingsDto(cardResponse.visibilitySettings), - this.mapToTimestampDto(cardResponse.timestamps) + this.mapToTimestampDto(cardResponse.timestamps), + cardResponse.title ?? '' ); } diff --git a/apps/server/src/modules/common-cartridge/testing/common-cartridge-dtos.factory.ts b/apps/server/src/modules/common-cartridge/testing/common-cartridge-dtos.factory.ts new file mode 100644 index 00000000000..dedfd1673b4 --- /dev/null +++ b/apps/server/src/modules/common-cartridge/testing/common-cartridge-dtos.factory.ts @@ -0,0 +1,214 @@ +import { faker } from '@faker-js/faker'; +import { Factory } from 'fishery'; +import { CourseCommonCartridgeMetadataDto } from '../common-cartridge-client/course-client'; +import { LessonContentDto, LessonDto, LessonLinkedTaskDto } from '../common-cartridge-client/lesson-client/dto'; +import { BoardSkeletonDto, CardSkeletonDto, ColumnSkeletonDto } from '../common-cartridge-client/board-client'; +import { CardListResponseDto } from '../common-cartridge-client/card-client/dto/card-list-response.dto'; +import { CardResponseDto } from '../common-cartridge-client/card-client/dto/card-response.dto'; +import { ContentElementType } from '../common-cartridge-client/card-client/enums/content-element-type.enum'; +import { BoardTaskDto } from '../common-cartridge-client/room-client/dto/board-task.dto'; +import { BoardTaskStatusDto } from '../common-cartridge-client/room-client/dto/board-task-status.dto'; +import { RoomBoardDto } from '../common-cartridge-client/room-client/dto/room-board.dto'; +import { BoardElementDtoType } from '../common-cartridge-client/room-client/enums/board-element.enum'; +import { BoardLessonDto } from '../common-cartridge-client/room-client/dto/board-lesson.dto'; +import { BoardColumnBoardDto } from '../common-cartridge-client/room-client/dto/board-column-board.dto'; +import { BoardLayout } from '../common-cartridge-client/room-client/enums/board-layout.enum'; + +export const courseMetadataFactory = Factory.define(({ sequence }) => { + return { + id: sequence.toString(), + courseName: faker.lorem.sentence(), + creationDate: faker.date.recent().toISOString(), + copyRightOwners: [faker.person.fullName(), faker.person.fullName()], + }; +}); + +export const cardFactory = Factory.define(({ sequence }) => { + return { + cardId: sequence.toString(), + height: faker.number.int(), + }; +}); + +export const columnFactory = Factory.define(({ sequence }) => { + return { + columnId: sequence.toString(), + title: faker.lorem.sentence(), + cards: [cardFactory.build(), cardFactory.build()], + }; +}); + +export const columnBoardFactory = Factory.define(({ sequence }) => { + return { + boardId: sequence.toString(), + title: faker.lorem.sentence(), + columns: [columnFactory.build(), columnFactory.build()], + isVisible: faker.datatype.boolean(), + layout: faker.lorem.word(), + }; +}); + +export const cardResponseFactory = Factory.define(({ sequence }) => { + return { + id: sequence.toString(), + height: faker.number.int(), + elements: [ + { + id: faker.string.uuid(), + type: ContentElementType.RICH_TEXT, + content: { + text: 'text', + inputFormat: 'plainText', + }, + timestamps: { + lastUpdatedAt: faker.date.recent().toISOString(), + createdAt: faker.date.recent().toISOString(), + deletedAt: undefined, + }, + }, + { + id: faker.string.uuid(), + type: ContentElementType.LINK, + content: { + url: faker.internet.url(), + title: faker.lorem.word(), + description: faker.lorem.sentence(), + }, + timestamps: { + lastUpdatedAt: faker.date.recent().toISOString(), + createdAt: faker.date.recent().toISOString(), + deletedAt: undefined, + }, + }, + ], + visibilitySettings: { + publishedAt: faker.date.recent().toISOString(), + }, + timeStamps: { + lastUpdatedAt: faker.date.recent().toISOString(), + createdAt: faker.date.recent().toISOString(), + deletedAt: undefined, + }, + title: faker.lorem.sentence(), + }; +}); + +export const listOfCardResponseFactory = Factory.define(() => { + return { + data: [cardResponseFactory.build(), cardResponseFactory.build()], + }; +}); + +export const lessonLinkedTaskFactory = Factory.define(() => { + return { + name: faker.lorem.word(), + description: faker.lorem.paragraph(), + descriptionInputFormat: 'plainText', + availableDate: faker.date.recent().toISOString(), + dueDate: faker.date.future().toISOString(), + private: faker.datatype.boolean(), + publicSubmissions: faker.datatype.boolean(), + teamSubmissions: faker.datatype.boolean(), + creator: faker.internet.email(), + courseId: null, + submissionIds: [faker.string.uuid(), faker.string.uuid()], + finishedIds: [faker.string.uuid(), faker.string.uuid()], + }; +}); + +export const lessonContentFactory = Factory.define(({ sequence }) => { + return { + id: sequence.toString(), + type: faker.lorem.word(), + content: { text: 'text' }, + title: faker.lorem.word(), + component: 'text', + hidden: faker.datatype.boolean(), + }; +}); + +export const lessonFactory = Factory.define(({ sequence }) => { + return { + lessonId: sequence.toString(), + name: faker.lorem.word(), + courseId: undefined, + courseGroupId: faker.string.uuid(), + hidden: faker.datatype.boolean(), + position: faker.number.int(), + contents: lessonContentFactory.buildList(2), + materials: [], + linkedTasks: [lessonLinkedTaskFactory.build(), lessonLinkedTaskFactory.build()], + }; +}); + +export const boardLessonFactory = Factory.define(() => { + return { + id: faker.string.uuid(), + name: faker.lorem.word(), + courseName: undefined, + hidden: faker.datatype.boolean(), + numberOfPublishedTasks: faker.number.int(), + numberOfDraftTasks: faker.number.int(), + numberOfPlannedTasks: faker.number.int(), + createdAt: faker.date.recent().toISOString(), + updatedAt: faker.date.recent().toISOString(), + }; +}); + +export const boardTaskFactory = Factory.define(({ sequence }) => { + return { + id: sequence.toString(), + name: faker.lorem.word(), + createdAt: faker.date.recent().toISOString(), + updatedAt: faker.date.recent().toISOString(), + availableDate: faker.date.recent().toISOString(), + courseName: undefined, + description: faker.lorem.word(), + displayColor: faker.lorem.word(), + dueDate: faker.date.recent().toISOString(), + status: new BoardTaskStatusDto({ + submitted: faker.number.int(), + maxSubmissions: faker.number.int(), + graded: faker.number.int(), + isDraft: faker.datatype.boolean(), + isSubstitutionTeacher: faker.datatype.boolean(), + isFinished: faker.datatype.boolean(), + }), + }; +}); + +export const boardCloumnBoardFactory = Factory.define(({ sequence }) => { + return { + id: sequence.toString(), + title: faker.lorem.word(), + published: faker.datatype.boolean(), + createdAt: faker.date.recent().toISOString(), + updatedAt: faker.date.recent().toISOString(), + columnBoardId: faker.string.uuid(), + layout: BoardLayout.COLUMNS, + }; +}); + +export const roomFactory = Factory.define(({ sequence }) => { + return { + roomId: sequence.toString(), + title: faker.lorem.word(), + displayColor: faker.lorem.word(), + elements: [ + { + type: BoardElementDtoType.TASK, + content: boardTaskFactory.build(), + }, + { + type: BoardElementDtoType.LESSON, + content: boardLessonFactory.build(), + }, + { + type: BoardElementDtoType.COLUMN_BOARD, + content: boardCloumnBoardFactory.build(), + }, + ], + isArchived: faker.datatype.boolean(), + isSynchronized: faker.datatype.boolean(), + }; +}); From f03855f763d87d0a9a5e02da3db3a9f6fa44cb7a Mon Sep 17 00:00:00 2001 From: Firas Shmit Date: Tue, 3 Dec 2024 17:04:03 +0100 Subject: [PATCH 39/61] EW-1060 added test factories for cc export --- .../dto/link-element-response.dto.ts | 10 +- .../dto/rich-text-element-response.dto.ts | 15 +- .../mapper/card-response.mapper.ts | 24 +- .../common-cartridge-export.service.spec.ts | 351 ++++-------------- .../common-cartridge-export.service.ts | 8 +- .../service/common-cartridge.mapper.ts | 2 +- .../testing/common-cartridge-dtos.factory.ts | 82 ++-- 7 files changed, 142 insertions(+), 350 deletions(-) diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/link-element-response.dto.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/link-element-response.dto.ts index 4c4fa40a48a..a203e076720 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/link-element-response.dto.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/link-element-response.dto.ts @@ -11,10 +11,10 @@ export class LinkElementResponseDto { timestamps: TimestampResponseDto; - constructor(id: string, type: ContentElementType, content: LinkElementContentDto, timestamps: TimestampResponseDto) { - this.id = id; - this.type = type; - this.content = content; - this.timestamps = timestamps; + constructor(props: LinkElementResponseDto) { + this.id = props.id; + this.type = props.type; + this.content = props.content; + this.timestamps = props.timestamps; } } diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/rich-text-element-response.dto.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/rich-text-element-response.dto.ts index b8e5c3811b5..978e70ebc11 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/rich-text-element-response.dto.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/rich-text-element-response.dto.ts @@ -11,15 +11,10 @@ export class RichTextElementResponseDto { timestamps: TimestampResponseDto; - constructor( - id: string, - type: ContentElementType, - content: RichTextElementContentDto, - timestamps: TimestampResponseDto - ) { - this.id = id; - this.type = type; - this.content = content; - this.timestamps = timestamps; + constructor(props: RichTextElementResponseDto) { + this.id = props.id; + this.type = props.type; + this.content = props.content; + this.timestamps = props.timestamps; } } diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/mapper/card-response.mapper.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/mapper/card-response.mapper.ts index 107ff340fa2..f8b1acc76dd 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/mapper/card-response.mapper.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/mapper/card-response.mapper.ts @@ -135,24 +135,24 @@ export class CardResponseMapper { case ContentElementType.LINK: { const content: LinkElementContent = element.content as LinkElementContent; elements.push( - new LinkElementResponseDto( - element.id, - ContentElementType.LINK, - new LinkElementContentDto(content.url, content.title, content.description ?? '', content.imageUrl ?? ''), - this.mapToTimestampDto(element.timestamps) - ) + new LinkElementResponseDto({ + id: element.id, + type: ContentElementType.LINK, + content: new LinkElementContentDto(content.url, content.title, content.description ?? ''), + timestamps: this.mapToTimestampDto(element.timestamps), + }) ); break; } case ContentElementType.RICH_TEXT: { const content: RichTextElementContent = element.content as RichTextElementContent; elements.push( - new RichTextElementResponseDto( - element.id, - ContentElementType.RICH_TEXT, - new RichTextElementContentDto(content.text, content.inputFormat), - this.mapToTimestampDto(element.timestamps) - ) + new RichTextElementResponseDto({ + id: element.id, + type: ContentElementType.RICH_TEXT, + content: new RichTextElementContentDto(content.text, content.inputFormat), + timestamps: this.mapToTimestampDto(element.timestamps), + }) ); break; } diff --git a/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.spec.ts b/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.spec.ts index 5d4eadb4595..dc55f0e47be 100644 --- a/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.spec.ts +++ b/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.spec.ts @@ -3,12 +3,7 @@ import { FilesStorageClientAdapterService } from '@modules/files-storage-client' import { faker } from '@faker-js/faker'; import { Test, TestingModule } from '@nestjs/testing'; import AdmZip from 'adm-zip'; -import { - BoardClientAdapter, - BoardSkeletonDto, - CardSkeletonDto, - ColumnSkeletonDto, -} from '../common-cartridge-client/board-client'; +import { BoardClientAdapter, BoardSkeletonDto } from '../common-cartridge-client/board-client'; import { CommonCartridgeExportService } from './common-cartridge-export.service'; import { CourseCommonCartridgeMetadataDto, CoursesClientAdapter } from '../common-cartridge-client/course-client'; import { CourseRoomsClientAdapter } from '../common-cartridge-client/room-client'; @@ -17,24 +12,23 @@ import { LessonClientAdapter } from '../common-cartridge-client/lesson-client/le import { CommonCartridgeExportMapper } from './common-cartridge.mapper'; import { CommonCartridgeVersion } from '../export/common-cartridge.enums'; import { RoomBoardDto } from '../common-cartridge-client/room-client/dto/room-board.dto'; -import { LessonContentDto, LessonDto, LessonLinkedTaskDto } from '../common-cartridge-client/lesson-client/dto'; -import { CardResponseDto } from '../common-cartridge-client/card-client/dto/card-response.dto'; -import { VisibilitySettingsResponseDto } from '../common-cartridge-client/card-client/dto/visibility-settings-response.dto'; -import { TimestampResponseDto } from '../common-cartridge-client/card-client/dto/timestamp-response.dto'; -import { CardListResponseDto } from '../common-cartridge-client/card-client/dto/card-list-response.dto'; -import { BoardElementDtoType } from '../common-cartridge-client/room-client/enums/board-element.enum'; -import { BoardLayout } from '../common-cartridge-client/room-client/enums/board-layout.enum'; -import { BoardTaskDto } from '../common-cartridge-client/room-client/dto/board-task.dto'; -import { BoardTaskStatusDto } from '../common-cartridge-client/room-client/dto/board-task-status.dto'; -import { RichTextElementResponseDto } from '../common-cartridge-client/card-client/dto/rich-text-element-response.dto'; -import { ContentElementType } from '../common-cartridge-client/card-client/enums/content-element-type.enum'; +import { LessonDto } from '../common-cartridge-client/lesson-client/dto'; import { RichTextElementContentDto } from '../common-cartridge-client/card-client/dto/rich-text-element-content.dto'; -import { LinkElementResponseDto } from '../common-cartridge-client/card-client/dto/link-element-response.dto'; import { LinkElementContentDto } from '../common-cartridge-client/card-client/dto/link-element-content.dto'; -import { ComponentTextPropsDto } from '../common-cartridge-client/lesson-client/dto/component-text-props.dto'; +import { + boardCloumnBoardFactory, + boardLessonFactory, + boardTaskFactory, + columnBoardFactory, + courseMetadataFactory, + lessonFactory, + listOfCardResponseFactory, + roomFactory, +} from '../testing/common-cartridge-dtos.factory'; +import { CardListResponseDto } from '../common-cartridge-client/card-client/dto/card-list-response.dto'; +import { BoardTaskDto } from '../common-cartridge-client/room-client/dto/board-task.dto'; import { BoardLessonDto } from '../common-cartridge-client/room-client/dto/board-lesson.dto'; -import { ComponentGeogebraPropsDto } from '../common-cartridge-client/lesson-client/dto/component-geogebra-props.dto'; -import { ComponentLernstorePropsDto } from '../common-cartridge-client/lesson-client/dto/component-lernstore-props.dto'; +import { BoardColumnBoardDto } from '../common-cartridge-client/room-client/dto/board-column-board.dto'; describe('CommonCartridgeExportService', () => { let module: TestingModule; @@ -57,256 +51,36 @@ describe('CommonCartridgeExportService', () => { exportTasks: boolean, exportColumnBoards: boolean ) => { - const courseMetadata = new CourseCommonCartridgeMetadataDto({ - id: dummyCourseId, - courseName: 'TEST COURSE', - creationDate: faker.date.recent().toISOString(), - copyRightOwners: [faker.person.fullName()], - }); - - const lessonLinkedTask: LessonLinkedTaskDto[] = [ - { - name: 'First linked Task', - description: faker.lorem.paragraph(), - descriptionInputFormat: 'plainText', - availableDate: faker.date.recent().toISOString(), - dueDate: faker.date.future().toISOString(), - private: false, - publicSubmissions: false, - teamSubmissions: false, - creator: faker.internet.email(), - courseId: dummyCourseId, - submissionIds: [], - finishedIds: [], - }, - { - name: 'second linked Task', - description: faker.lorem.paragraph(), - descriptionInputFormat: 'plainText', - availableDate: faker.date.recent().toISOString(), - dueDate: faker.date.future().toISOString(), - private: false, - publicSubmissions: false, - teamSubmissions: false, - creator: faker.internet.email(), - courseId: dummyCourseId, - submissionIds: [], - finishedIds: [], - }, - ]; - - const lessons: LessonDto[] = [ - { - lessonId: faker.string.uuid(), - name: 'TEST LESSON 1', - courseId: dummyCourseId, - courseGroupId: faker.string.uuid(), - hidden: false, - position: faker.number.int(), - contents: [ - new LessonContentDto({ - id: faker.string.uuid(), - content: new ComponentTextPropsDto({ - text: 'text', - }), - title: faker.lorem.sentence(), - component: 'text', - hidden: false, - }), - new LessonContentDto({ - id: faker.string.uuid(), - content: new ComponentGeogebraPropsDto({ - materialId: faker.string.uuid(), - }), - title: faker.lorem.sentence(), - component: 'geoGebra', - hidden: false, - }), - new LessonContentDto({ - id: faker.string.uuid(), - content: new ComponentLernstorePropsDto({ - resources: ['{title: resource1, url: https:test.de}', '{title: resource2, url: https:test.de}'], - }), - title: faker.lorem.sentence(), - component: 'resources', - hidden: false, - }), - ], - materials: [], - linkedTasks: [lessonLinkedTask[0]], - }, - { - lessonId: faker.string.uuid(), - name: 'TEST LESSON 2', - courseId: dummyCourseId, - courseGroupId: faker.string.uuid(), - hidden: false, - position: faker.number.int(), - contents: [ - new LessonContentDto({ - id: faker.string.uuid(), - content: new ComponentTextPropsDto({ - text: 'text', - }), - title: faker.lorem.sentence(), - component: 'text', - hidden: false, - }), - ], - materials: [], - }, - ]; - - const boardSkeleton: BoardSkeletonDto = { - boardId: faker.string.uuid(), - title: 'TEST BOARD SKELETON', - columns: [ - new ColumnSkeletonDto({ - columnId: faker.string.uuid(), - title: faker.lorem.sentence(), - cards: [ - new CardSkeletonDto({ - cardId: faker.string.uuid(), - height: faker.number.int(), - }), - new CardSkeletonDto({ - cardId: faker.string.uuid(), - height: faker.number.int(), - }), - ], - }), - new ColumnSkeletonDto({ - columnId: faker.string.uuid(), - title: faker.lorem.sentence(), - cards: [], - }), - ], - isVisible: true, - layout: 'columns', - }; - - const listOfCardsResponse: CardListResponseDto = { - data: [ - new CardResponseDto( - boardSkeleton.columns[0].cards?.[0].cardId ?? '', - 'Text card', - faker.number.int(), - [ - new RichTextElementResponseDto( - faker.string.uuid(), - ContentElementType.RICH_TEXT, - new RichTextElementContentDto('dummy rich text', 'plainText'), - new TimestampResponseDto(faker.date.recent().toISOString(), faker.date.recent().toISOString(), undefined) - ), - ], - new VisibilitySettingsResponseDto('public'), - new TimestampResponseDto(faker.date.recent().toISOString(), faker.date.recent().toISOString(), undefined) - ), - new CardResponseDto( - boardSkeleton.columns[0].cards?.[1].cardId ?? '', - 'link card', - faker.number.int(), - [ - new LinkElementResponseDto( - faker.string.uuid(), - ContentElementType.LINK, - new LinkElementContentDto('dummy url', 'dummy title of the link', 'dummy description'), - new TimestampResponseDto(faker.date.recent().toISOString(), faker.date.recent().toISOString(), undefined) - ), - ], - new VisibilitySettingsResponseDto('public'), - new TimestampResponseDto(faker.date.recent().toISOString(), faker.date.recent().toISOString(), undefined) - ), - ], - }; - - const boardTask: BoardTaskDto = { - id: faker.string.uuid(), - name: 'TEST TASK', - availableDate: faker.date.recent().toISOString(), - dueDate: faker.date.future().toISOString(), - courseName: courseMetadata.courseName, - description: faker.lorem.paragraph(), - displayColor: faker.internet.color(), - createdAt: faker.date.recent().toISOString(), - updatedAt: faker.date.recent().toISOString(), - status: new BoardTaskStatusDto({ - submitted: faker.number.int(), - maxSubmissions: faker.number.int(), - graded: faker.number.int(), - isDraft: faker.datatype.boolean(), - isSubstitutionTeacher: faker.datatype.boolean(), - isFinished: faker.datatype.boolean(), - }), - }; - - const room: RoomBoardDto = { - roomId: faker.string.uuid(), - title: courseMetadata.courseName, - displayColor: faker.internet.color(), - elements: [ - { - type: BoardElementDtoType.TASK, - content: { ...boardTask, status: { ...boardTask.status } }, - }, - { - type: BoardElementDtoType.COLUMN_BOARD, - content: { - id: boardSkeleton.boardId, - title: 'TEST BOARD COLUMN BOARD', - published: faker.datatype.boolean(), - createdAt: faker.date.recent().toISOString(), - updatedAt: faker.date.recent().toISOString(), - columnBoardId: boardSkeleton.boardId, - layout: BoardLayout.COLUMNS, - }, - }, - { - type: BoardElementDtoType.LESSON, - content: new BoardLessonDto({ - id: lessons[0].lessonId, - name: lessons[0].name, - courseName: courseMetadata.courseName, - numberOfPublishedTasks: lessons[0].linkedTasks?.length ?? 0, - numberOfDraftTasks: 0, - numberOfPlannedTasks: 0, - createdAt: faker.date.recent().toISOString(), - updatedAt: faker.date.recent().toISOString(), - hidden: lessons[0].hidden, - }), - }, - { - type: BoardElementDtoType.LESSON, - content: new BoardLessonDto({ - id: lessons[1].lessonId, - name: lessons[1].name, - courseName: courseMetadata.courseName, - numberOfPublishedTasks: lessons[1].linkedTasks?.length ?? 0, - numberOfDraftTasks: 0, - numberOfPlannedTasks: 0, - createdAt: faker.date.recent().toISOString(), - updatedAt: faker.date.recent().toISOString(), - hidden: lessons[1].hidden, - }), - }, - ], - isArchived: false, - isSynchronized: false, - }; + const courseMetadata: CourseCommonCartridgeMetadataDto = courseMetadataFactory.build(); + const lesson: LessonDto = lessonFactory.build(); + lesson.courseId = courseMetadata.id; + + const boardSkeleton: BoardSkeletonDto = columnBoardFactory.build(); + const listOfCardsResponse: CardListResponseDto = listOfCardResponseFactory.build(); + const boardTask: BoardTaskDto = boardTaskFactory.build(); + boardTask.courseName = courseMetadata.courseName; + + const room: RoomBoardDto = roomFactory.build(); + room.title = courseMetadata.courseName; + room.elements[0].content = boardTask; + room.elements[1].content = new BoardLessonDto(boardLessonFactory.build()); + room.elements[1].content.id = lesson.lessonId; + room.elements[1].content.name = lesson.name; + room.elements[2].content = new BoardColumnBoardDto(boardCloumnBoardFactory.build()); coursesClientAdapterMock.getCourseCommonCartridgeMetadata.mockResolvedValue(courseMetadata); - courseRoomsClientAdapterMock.getRoomBoardByCourseId.mockResolvedValue(room); - lessonClientAdapterMock.getLessonById.mockResolvedValue(lessons[0]); - lessonClientAdapterMock.getLessonTasks.mockResolvedValue(lessonLinkedTask); + lessonClientAdapterMock.getLessonById.mockResolvedValue(lesson); + lessonClientAdapterMock.getLessonTasks.mockResolvedValue(lesson.linkedTasks ?? []); boardClientAdapterMock.getBoardSkeletonById.mockResolvedValue(boardSkeleton); cardClientAdapterMock.getAllBoardCardsByIds.mockResolvedValue(listOfCardsResponse); + courseRoomsClientAdapterMock.getRoomBoardByCourseId.mockResolvedValue(room); const buffer = await sut.exportCourse( dummyCourseId, version, - exportTopics ? [room.elements[2].content.id, room.elements[3].content.id] : [], + exportTopics ? [room.elements[1].content.id] : [], exportTasks ? [room.elements[0].content.id] : [], - exportColumnBoards ? [room.elements[1].content.id] : [] + exportColumnBoards ? [room.elements[2].content.id] : [] ); const archive = new AdmZip(buffer); @@ -316,12 +90,12 @@ describe('CommonCartridgeExportService', () => { archive, version, room, - lessons, + lesson, boardTask, boardSkeleton, listOfCardsResponse, textElement: listOfCardsResponse.data[0].elements[0].content as RichTextElementContentDto, - linkElement: listOfCardsResponse.data[1].elements[0].content as LinkElementContentDto, + linkElement: listOfCardsResponse.data[0].elements[1].content as LinkElementContentDto, }; }; @@ -392,11 +166,9 @@ describe('CommonCartridgeExportService', () => { }); it('should add lesson', async () => { - const { archive, room } = await setup(); + const { archive, lesson } = await setup(); - expect(getFileContent(archive, 'imsmanifest.xml')).toContain( - createXmlString('title', (room.elements[2].content as BoardLessonDto).name) - ); + expect(getFileContent(archive, 'imsmanifest.xml')).toContain(createXmlString('title', lesson.name)); }); it('should add task', async () => { @@ -408,19 +180,19 @@ describe('CommonCartridgeExportService', () => { }); it('should add tasks of lesson to manifest file', async () => { - const { archive, lessons } = await setup(); + const { archive, lesson } = await setup(); const manifest = archive.getEntry('imsmanifest.xml')?.getData().toString(); - lessons[0].linkedTasks?.forEach((linkedTask) => { + lesson.linkedTasks?.forEach((linkedTask) => { expect(manifest).toContain(`${linkedTask.name}`); }); }); it('should add lernstore element of lesson to manifest file', async () => { - const { archive, lessons } = await setup(); + const { archive, lesson } = await setup(); const manifest = archive.getEntry('imsmanifest.xml')?.getData().toString(); - lessons[0].contents.forEach((content) => { + lesson.contents.forEach((content) => { expect(manifest).toContain(`${content.title}`); }); }); @@ -464,13 +236,13 @@ describe('CommonCartridgeExportService', () => { ); }); - it('should add lessons', async () => { - const { archive, room } = await setup(); + // it('should add lessons', async () => { + // const { archive, room } = await setup(); - expect(getFileContent(archive, 'imsmanifest.xml')).toContain( - createXmlString('title', (room.elements[2].content as BoardLessonDto).name) - ); - }); + // expect(getFileContent(archive, 'imsmanifest.xml')).toContain( + // createXmlString('title', (room.elements[1].content as BoardLessonDto).name) + // ); + // }); it('should add tasks', async () => { const { archive, boardTask } = await setup(); @@ -479,19 +251,19 @@ describe('CommonCartridgeExportService', () => { }); it('should add tasks of lesson to manifest file', async () => { - const { archive, lessons } = await setup(); + const { archive, lesson } = await setup(); const manifest = archive.getEntry('imsmanifest.xml')?.getData().toString(); - lessons[0].linkedTasks?.forEach((linkedTask) => { + lesson.linkedTasks?.forEach((linkedTask) => { expect(manifest).toContain(`${linkedTask.name}`); }); }); it('should add lernstore element of lesson to manifest file', async () => { - const { archive, lessons } = await setup(); + const { archive, lesson } = await setup(); const manifest = archive.getEntry('imsmanifest.xml')?.getData().toString(); - lessons[0].contents.forEach((content) => { + lesson.contents.forEach((content) => { expect(manifest).toContain(`${content.title}`); }); }); @@ -523,17 +295,22 @@ describe('CommonCartridgeExportService', () => { expect(manifest).toContain(createXmlString('title', linkElement.title)); }); + + it('should add text element of card', async () => { + const { archive, textElement } = await setup(); + const manifest = getFileContent(archive, 'imsmanifest.xml'); + + expect(manifest).toContain(createXmlString('title', textElement.text)); + }); }); describe('When topics array is empty', () => { const setup = async () => setupParams(CommonCartridgeVersion.V_1_1_0, false, true, true); it("shouldn't add lessons", async () => { - const { archive, lessons } = await setup(); + const { archive, lesson } = await setup(); - lessons.forEach((lesson) => { - expect(getFileContent(archive, 'imsmanifest.xml')).not.toContain(createXmlString('title', lesson.name)); - }); + expect(getFileContent(archive, 'imsmanifest.xml')).not.toContain(createXmlString('title', lesson.name)); }); }); @@ -543,7 +320,7 @@ describe('CommonCartridgeExportService', () => { it("shouldn't add tasks", async () => { const { archive, boardTask } = await setup(); - expect(getFileContent(archive, 'imsmanifest.xml')).not.toContain(` { const columnBoards = this.filterColumnBoardFromBoardElement(elements); const columnBoardsIds = columnBoards - .filter((columBoard) => exportedColumnBoards.includes(columBoard.columnBoardId)) + .filter((columnBoard) => exportedColumnBoards.includes(columnBoard.id)) .map((columBoard) => columBoard.columnBoardId); if (columnBoardsIds.length === 0) { @@ -248,7 +248,7 @@ export class CommonCartridgeExportService { } private filterTasksFromBoardElements(elements: BoardElementDto[]): BoardTaskDto[] { - const tasks: BoardTaskDto[] = elements + const tasks = elements .filter((element) => element.type === BoardElementDtoType.TASK) .map((element) => element.content as BoardTaskDto); @@ -256,7 +256,7 @@ export class CommonCartridgeExportService { } private filterLessonFromBoardElements(elements: BoardElementDto[]): BoardLessonDto[] { - const lessons: BoardLessonDto[] = elements + const lessons = elements .filter((element) => element.content instanceof BoardLessonDto) .map((element) => element.content as BoardLessonDto); @@ -264,7 +264,7 @@ export class CommonCartridgeExportService { } private filterColumnBoardFromBoardElement(elements: BoardElementDto[]): BoardColumnBoardDto[] { - const columnBoard: BoardColumnBoardDto[] = elements + const columnBoard = elements .filter((element) => element.type === BoardElementDtoType.COLUMN_BOARD) .map((element) => element.content as BoardColumnBoardDto); diff --git a/apps/server/src/modules/common-cartridge/service/common-cartridge.mapper.ts b/apps/server/src/modules/common-cartridge/service/common-cartridge.mapper.ts index 73a5e8b65b3..660c4af6fb3 100644 --- a/apps/server/src/modules/common-cartridge/service/common-cartridge.mapper.ts +++ b/apps/server/src/modules/common-cartridge/service/common-cartridge.mapper.ts @@ -198,6 +198,6 @@ export class CommonCartridgeExportMapper { allowedAttributes: {}, }).slice(0, 20); - return `${title}...`; + return title.length > 20 ? `${title}...` : title; } } diff --git a/apps/server/src/modules/common-cartridge/testing/common-cartridge-dtos.factory.ts b/apps/server/src/modules/common-cartridge/testing/common-cartridge-dtos.factory.ts index dedfd1673b4..2354d8b5727 100644 --- a/apps/server/src/modules/common-cartridge/testing/common-cartridge-dtos.factory.ts +++ b/apps/server/src/modules/common-cartridge/testing/common-cartridge-dtos.factory.ts @@ -1,5 +1,6 @@ import { faker } from '@faker-js/faker'; import { Factory } from 'fishery'; +import { BaseFactory } from '@shared/testing'; import { CourseCommonCartridgeMetadataDto } from '../common-cartridge-client/course-client'; import { LessonContentDto, LessonDto, LessonLinkedTaskDto } from '../common-cartridge-client/lesson-client/dto'; import { BoardSkeletonDto, CardSkeletonDto, ColumnSkeletonDto } from '../common-cartridge-client/board-client'; @@ -13,6 +14,10 @@ import { BoardElementDtoType } from '../common-cartridge-client/room-client/enum import { BoardLessonDto } from '../common-cartridge-client/room-client/dto/board-lesson.dto'; import { BoardColumnBoardDto } from '../common-cartridge-client/room-client/dto/board-column-board.dto'; import { BoardLayout } from '../common-cartridge-client/room-client/enums/board-layout.enum'; +import { RichTextElementContentDto } from '../common-cartridge-client/card-client/dto/rich-text-element-content.dto'; +import { LinkElementContentDto } from '../common-cartridge-client/card-client/dto/link-element-content.dto'; +import { RichTextElementResponseDto } from '../common-cartridge-client/card-client/dto/rich-text-element-response.dto'; +import { LinkElementResponseDto } from '../common-cartridge-client/card-client/dto/link-element-response.dto'; export const courseMetadataFactory = Factory.define(({ sequence }) => { return { @@ -48,39 +53,54 @@ export const columnBoardFactory = Factory.define(({ sequence } }; }); +export const richTextElementContentFactory = Factory.define(() => { + return { + text: faker.lorem.word(), + inputFormat: 'plainText', + }; +}); + +class RichTextElement extends BaseFactory> {} +export const richTextElementFactroy = RichTextElement.define(RichTextElementResponseDto, () => { + return { + id: faker.string.uuid(), + type: ContentElementType.RICH_TEXT, + content: richTextElementContentFactory.build(), + timestamps: { + lastUpdatedAt: faker.date.recent().toISOString(), + createdAt: faker.date.recent().toISOString(), + deletedAt: undefined, + }, + }; +}); + +export const linkElementContentFactory = Factory.define(() => { + return { + url: faker.internet.url(), + title: faker.lorem.word(), + description: faker.lorem.sentence(), + }; +}); + +class LinkElementFactory extends BaseFactory> {} +export const linkElementFactory = LinkElementFactory.define(LinkElementResponseDto, () => { + return { + id: faker.string.uuid(), + type: ContentElementType.LINK, + content: linkElementContentFactory.build(), + timestamps: { + lastUpdatedAt: faker.date.recent().toISOString(), + createdAt: faker.date.recent().toISOString(), + deletedAt: undefined, + }, + }; +}); + export const cardResponseFactory = Factory.define(({ sequence }) => { return { id: sequence.toString(), height: faker.number.int(), - elements: [ - { - id: faker.string.uuid(), - type: ContentElementType.RICH_TEXT, - content: { - text: 'text', - inputFormat: 'plainText', - }, - timestamps: { - lastUpdatedAt: faker.date.recent().toISOString(), - createdAt: faker.date.recent().toISOString(), - deletedAt: undefined, - }, - }, - { - id: faker.string.uuid(), - type: ContentElementType.LINK, - content: { - url: faker.internet.url(), - title: faker.lorem.word(), - description: faker.lorem.sentence(), - }, - timestamps: { - lastUpdatedAt: faker.date.recent().toISOString(), - createdAt: faker.date.recent().toISOString(), - deletedAt: undefined, - }, - }, - ], + elements: [richTextElementFactroy.build(), linkElementFactory.build()], visibilitySettings: { publishedAt: faker.date.recent().toISOString(), }, @@ -177,9 +197,9 @@ export const boardTaskFactory = Factory.define(({ sequence }) => { }; }); -export const boardCloumnBoardFactory = Factory.define(({ sequence }) => { +export const boardCloumnBoardFactory = Factory.define(() => { return { - id: sequence.toString(), + id: faker.string.uuid(), title: faker.lorem.word(), published: faker.datatype.boolean(), createdAt: faker.date.recent().toISOString(), From 056869ef726c4530c07b585fa229ac5fafa6d984 Mon Sep 17 00:00:00 2001 From: Firas Shmit Date: Tue, 3 Dec 2024 17:21:27 +0100 Subject: [PATCH 40/61] EW-1060 some changes --- .../card-client/dto/card-response.dto.ts | 2 +- .../common-cartridge.controller.spec.ts | 4 ++-- .../controller/common-cartridge.controller.ts | 6 +++--- .../controller/dto/common-cartridge.params.ts | 2 +- .../common-cartridge-export.service.spec.ts | 15 +++++++-------- .../service/common-cartridge-export.service.ts | 4 ++-- 6 files changed, 16 insertions(+), 17 deletions(-) diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/card-response.dto.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/card-response.dto.ts index a307d0fe3d1..94e94786a99 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/card-response.dto.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/card-response.dto.ts @@ -24,7 +24,7 @@ export class CardResponseDto { title?: string ) { this.id = id; - this.title = title ?? ''; + this.title = title; this.height = height; this.elements = elements; this.visibilitySettings = visibilitySettings; diff --git a/apps/server/src/modules/common-cartridge/controller/common-cartridge.controller.spec.ts b/apps/server/src/modules/common-cartridge/controller/common-cartridge.controller.spec.ts index 7851657abd5..11fceb8135c 100644 --- a/apps/server/src/modules/common-cartridge/controller/common-cartridge.controller.spec.ts +++ b/apps/server/src/modules/common-cartridge/controller/common-cartridge.controller.spec.ts @@ -41,7 +41,7 @@ describe('CommonCartridgeController', () => { describe('exportCourse', () => { const setup = () => { const courseId = faker.string.uuid(); - const params = { parentId: courseId } as ExportCourseParams; + const params = { courseId: courseId } as ExportCourseParams; const query = { version: CommonCartridgeVersion.V_1_1_0 } as CourseQueryParams; const body = { topics: [faker.string.uuid(), faker.string.uuid()], @@ -65,7 +65,7 @@ describe('CommonCartridgeController', () => { expect(mockResponse.set).toHaveBeenCalledWith({ 'Content-Type': 'application/zip', - 'Content-Disposition': `attachment; filename=course_${params.parentId}.zip`, + 'Content-Disposition': `attachment; filename=course_${params.courseId}.zip`, }); expect(result).toBeInstanceOf(StreamableFile); }); diff --git a/apps/server/src/modules/common-cartridge/controller/common-cartridge.controller.ts b/apps/server/src/modules/common-cartridge/controller/common-cartridge.controller.ts index 548103a2b6d..f0a62fafe5f 100644 --- a/apps/server/src/modules/common-cartridge/controller/common-cartridge.controller.ts +++ b/apps/server/src/modules/common-cartridge/controller/common-cartridge.controller.ts @@ -11,7 +11,7 @@ import { CourseExportBodyParams } from './dto/course-export.body.params'; export class CommonCartridgeController { constructor(private readonly commonCartridgeUC: CommonCartridgeUc) {} - @Post('export/:parentId') + @Post('export/:courseId') public async exportCourse( @Param() exportCourseParams: ExportCourseParams, @Query() queryParams: CourseQueryParams, @@ -19,7 +19,7 @@ export class CommonCartridgeController { @Res({ passthrough: true }) response: Response ): Promise { const result = await this.commonCartridgeUC.exportCourse( - exportCourseParams.parentId, + exportCourseParams.courseId, queryParams.version, bodyParams.topics, bodyParams.tasks, @@ -28,7 +28,7 @@ export class CommonCartridgeController { response.set({ 'Content-Type': 'application/zip', - 'Content-Disposition': `attachment; filename=course_${exportCourseParams.parentId}.zip`, + 'Content-Disposition': `attachment; filename=course_${exportCourseParams.courseId}.zip`, }); return new StreamableFile(result); diff --git a/apps/server/src/modules/common-cartridge/controller/dto/common-cartridge.params.ts b/apps/server/src/modules/common-cartridge/controller/dto/common-cartridge.params.ts index a93c604f793..59f13b82182 100644 --- a/apps/server/src/modules/common-cartridge/controller/dto/common-cartridge.params.ts +++ b/apps/server/src/modules/common-cartridge/controller/dto/common-cartridge.params.ts @@ -5,5 +5,5 @@ import { IsMongoId } from 'class-validator'; export class ExportCourseParams { @IsMongoId() @ApiProperty() - public readonly parentId!: EntityId; + public readonly courseId!: EntityId; } diff --git a/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.spec.ts b/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.spec.ts index dc55f0e47be..6ad82ec65e8 100644 --- a/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.spec.ts +++ b/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.spec.ts @@ -39,7 +39,6 @@ describe('CommonCartridgeExportService', () => { let boardClientAdapterMock: DeepMocked; let lessonClientAdapterMock: DeepMocked; - const dummyCourseId = faker.string.uuid(); const createXmlString = (nodeName: string, value: boolean | number | string): string => `<${nodeName}>${value.toString()}`; const getFileContent = (archive: AdmZip, filePath: string): string | undefined => @@ -76,7 +75,7 @@ describe('CommonCartridgeExportService', () => { courseRoomsClientAdapterMock.getRoomBoardByCourseId.mockResolvedValue(room); const buffer = await sut.exportCourse( - dummyCourseId, + courseMetadata.id, version, exportTopics ? [room.elements[1].content.id] : [], exportTasks ? [room.elements[0].content.id] : [], @@ -236,13 +235,13 @@ describe('CommonCartridgeExportService', () => { ); }); - // it('should add lessons', async () => { - // const { archive, room } = await setup(); + it('should add lessons', async () => { + const { archive, lesson } = await setup(); - // expect(getFileContent(archive, 'imsmanifest.xml')).toContain( - // createXmlString('title', (room.elements[1].content as BoardLessonDto).name) - // ); - // }); + expect(getFileContent(archive, 'imsmanifest.xml')).toContain( + createXmlString('title', lesson.name) + ); + }); it('should add tasks', async () => { const { archive, boardTask } = await setup(); diff --git a/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts b/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts index 9ecd25afac6..31a13309688 100644 --- a/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts +++ b/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts @@ -35,7 +35,7 @@ export class CommonCartridgeExportService { private readonly cardClientAdapter: CardClientAdapter, private readonly coursesClientAdapter: CoursesClientAdapter, private readonly courseRoomsClientAdapter: CourseRoomsClientAdapter, - private readonly lessonClinetAdapter: LessonClientAdapter, + private readonly lessonClientAdapter: LessonClientAdapter, private readonly mapper: CommonCartridgeExportMapper ) {} @@ -64,7 +64,7 @@ export class CommonCartridgeExportService { } private async findLessonById(lessonId: string): Promise { - const lesson = await this.lessonClinetAdapter.getLessonById(lessonId); + const lesson = await this.lessonClientAdapter.getLessonById(lessonId); return lesson; } From 451b7e0e2610099a38406910cdeadc6e73435a7d Mon Sep 17 00:00:00 2001 From: Firas Shmit Date: Wed, 4 Dec 2024 10:38:03 +0100 Subject: [PATCH 41/61] EW-1060 some changes --- .../card-client/dto/card-response.dto.ts | 21 +++++---------- .../dto/link-element-content.dto.ts | 10 +++---- .../dto/rich-text-element-response.dto.ts | 2 +- .../card-client/dto/timestamp-response.dto.ts | 8 +++--- .../mapper/card-response.mapper.ts | 26 ++++++++++++------- .../uc/common-cartridge.uc.spec.ts | 4 ++- 6 files changed, 36 insertions(+), 35 deletions(-) diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/card-response.dto.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/card-response.dto.ts index 94e94786a99..8bfff069b92 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/card-response.dto.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/card-response.dto.ts @@ -15,19 +15,12 @@ export class CardResponseDto { timeStamps: TimestampResponseDto; - constructor( - id: string, - height: number, - elements: CardResponseElementsInnerDto[], - visibilitySettings: VisibilitySettingsResponseDto, - timestamps: TimestampResponseDto, - title?: string - ) { - this.id = id; - this.title = title; - this.height = height; - this.elements = elements; - this.visibilitySettings = visibilitySettings; - this.timeStamps = timestamps; + constructor(props: Readonly) { + this.id = props.id; + this.title = props.title; + this.height = props.height; + this.elements = props.elements; + this.visibilitySettings = props.visibilitySettings; + this.timeStamps = props.timeStamps; } } diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/link-element-content.dto.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/link-element-content.dto.ts index 6b9737b21d0..0b1d2c14348 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/link-element-content.dto.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/link-element-content.dto.ts @@ -7,10 +7,10 @@ export class LinkElementContentDto { imageUrl?: string; - constructor(url: string, title: string, description: string, imageUrl?: string) { - this.url = url; - this.title = title; - this.description = description; - this.imageUrl = imageUrl; + constructor(props: Readonly) { + this.url = props.url; + this.title = props.title; + this.description = props.description; + this.imageUrl = props.imageUrl; } } diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/rich-text-element-response.dto.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/rich-text-element-response.dto.ts index 978e70ebc11..66f75d4dce9 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/rich-text-element-response.dto.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/rich-text-element-response.dto.ts @@ -11,7 +11,7 @@ export class RichTextElementResponseDto { timestamps: TimestampResponseDto; - constructor(props: RichTextElementResponseDto) { + constructor(props: Readonly) { this.id = props.id; this.type = props.type; this.content = props.content; diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/timestamp-response.dto.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/timestamp-response.dto.ts index 1fc934e4599..902897ed23f 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/timestamp-response.dto.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/timestamp-response.dto.ts @@ -5,9 +5,9 @@ export class TimestampResponseDto { deletedAt?: string; - constructor(lastUpdatedAt: string, createdAt: string, deletedAt?: string) { - this.lastUpdatedAt = lastUpdatedAt; - this.createdAt = createdAt; - this.deletedAt = deletedAt; + constructor(props: Readonly) { + this.lastUpdatedAt = props.lastUpdatedAt; + this.createdAt = props.createdAt; + this.deletedAt = props.deletedAt; } } diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/mapper/card-response.mapper.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/mapper/card-response.mapper.ts index f8b1acc76dd..e187b79ba6c 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/mapper/card-response.mapper.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/mapper/card-response.mapper.ts @@ -45,14 +45,14 @@ export class CardResponseMapper { } private static mapToCardResponseDto(cardResponse: CardResponse): CardResponseDto { - return new CardResponseDto( - cardResponse.id, - cardResponse.height, - this.mapToCardResponseElementsInnerDto(cardResponse.elements), - this.mapToVisibilitySettingsDto(cardResponse.visibilitySettings), - this.mapToTimestampDto(cardResponse.timestamps), - cardResponse.title ?? '' - ); + return new CardResponseDto({ + id: cardResponse.id, + title: cardResponse.title, + height: cardResponse.height, + elements: this.mapToCardResponseElementsInnerDto(cardResponse.elements), + visibilitySettings: this.mapToVisibilitySettingsDto(cardResponse.visibilitySettings), + timeStamps: this.mapToTimestampDto(cardResponse.timestamps), + }); } private static mapToCardResponseElementsInnerDto( @@ -138,7 +138,10 @@ export class CardResponseMapper { new LinkElementResponseDto({ id: element.id, type: ContentElementType.LINK, - content: new LinkElementContentDto(content.url, content.title, content.description ?? ''), + content: new LinkElementContentDto({ + url: content.url, + title: content.title, + description: content.description}), timestamps: this.mapToTimestampDto(element.timestamps), }) ); @@ -170,6 +173,9 @@ export class CardResponseMapper { } private static mapToTimestampDto(timestamp: TimestampsResponse): TimestampResponseDto { - return new TimestampResponseDto(timestamp.lastUpdatedAt, timestamp.createdAt, timestamp.deletedAt ?? ''); + return new TimestampResponseDto({ + lastUpdatedAt: timestamp.lastUpdatedAt, + createdAt: timestamp.createdAt, + deletedAt: timestamp.deletedAt}); } } diff --git a/apps/server/src/modules/common-cartridge/uc/common-cartridge.uc.spec.ts b/apps/server/src/modules/common-cartridge/uc/common-cartridge.uc.spec.ts index 2d3e0dcfca3..2e7aee0e2e5 100644 --- a/apps/server/src/modules/common-cartridge/uc/common-cartridge.uc.spec.ts +++ b/apps/server/src/modules/common-cartridge/uc/common-cartridge.uc.spec.ts @@ -49,8 +49,10 @@ describe('CommonCartridgeUc', () => { it('should return a course export response with file IDs and metadata of a course', async () => { const { courseId, expected, version, tasks, columnBoards, topics } = setup(); - + expect(await sut.exportCourse(courseId, version, topics, tasks, columnBoards)).toEqual(expected); + expect(commonCartridgeExportServiceMock.exportCourse).toHaveBeenCalledWith(courseId, version, topics, tasks, columnBoards); + }); }); }); From afc4f7890e1ecf47bbf995f9d0c9f44044071333 Mon Sep 17 00:00:00 2001 From: Firas Shmit Date: Wed, 4 Dec 2024 11:30:54 +0100 Subject: [PATCH 42/61] EW-1060 review changes --- .../dto/component-etherpad-props.dto.ts | 6 +- .../dto/component-geogebra-props.dto.ts | 2 +- .../dto/component-internal-props.dto.ts | 2 +- .../dto/component-lernstore-props.dto.ts | 2 +- .../dto/component-nexboard-props-dto.ts | 8 +-- .../common-cartridge-export.service.ts | 60 +++++++++---------- .../dto/course-export.body.params.ts | 6 +- 7 files changed, 44 insertions(+), 42 deletions(-) diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-etherpad-props.dto.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-etherpad-props.dto.ts index 998a10a2538..8330d28546d 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-etherpad-props.dto.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-etherpad-props.dto.ts @@ -1,11 +1,11 @@ import { ComponentEtherpadPropsImpl } from '../lessons-api-client'; export class ComponentEtherpadPropsDto { - description!: string; + description: string; - title!: string; + title: string; - url!: string; + url: string; constructor(etherpadContent: ComponentEtherpadPropsImpl) { this.description = etherpadContent.description; diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-geogebra-props.dto.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-geogebra-props.dto.ts index 3caaef9d602..02d9e69dbfe 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-geogebra-props.dto.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-geogebra-props.dto.ts @@ -1,7 +1,7 @@ import { ComponentGeogebraPropsImpl } from '../lessons-api-client'; export class ComponentGeogebraPropsDto { - materialId!: string; + materialId: string; constructor(geogebraContent: ComponentGeogebraPropsImpl) { this.materialId = geogebraContent.materialId; diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-internal-props.dto.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-internal-props.dto.ts index f6982b5b4d5..c7890bddf19 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-internal-props.dto.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-internal-props.dto.ts @@ -1,7 +1,7 @@ import { ComponentInternalPropsImpl } from '../lessons-api-client'; export class ComponentInternalPropsDto { - url!: string; + url: string; constructor(internalContent: ComponentInternalPropsImpl) { this.url = internalContent.url; diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-lernstore-props.dto.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-lernstore-props.dto.ts index 0392f05052a..f2b1ab5de7c 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-lernstore-props.dto.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-lernstore-props.dto.ts @@ -1,7 +1,7 @@ import { ComponentLernstorePropsImpl } from '../lessons-api-client'; export class ComponentLernstorePropsDto { - resources!: string[]; + resources: string[]; constructor(lernstoreContent: ComponentLernstorePropsImpl) { this.resources = lernstoreContent.resources; diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-nexboard-props-dto.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-nexboard-props-dto.ts index 100a51c5348..1031af3511f 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-nexboard-props-dto.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-nexboard-props-dto.ts @@ -1,13 +1,13 @@ import { ComponentNexboardPropsImpl } from '../lessons-api-client'; export class ComponentNexboardPropsDto { - board!: string; + board: string; - description!: string; + description: string; - title!: string; + title: string; - url!: string; + url: string; constructor(nexboardContent: ComponentNexboardPropsImpl) { this.board = nexboardContent.board; diff --git a/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts b/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts index 31a13309688..5935478b1ee 100644 --- a/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts +++ b/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts @@ -39,36 +39,6 @@ export class CommonCartridgeExportService { private readonly mapper: CommonCartridgeExportMapper ) {} - private async findCourseCommonCartridgeMetadata(courseId: string): Promise { - const courseCommonCartridgeMetadata = await this.coursesClientAdapter.getCourseCommonCartridgeMetadata(courseId); - - return courseCommonCartridgeMetadata; - } - - private async findRoomBoardByCourseId(courseId: string): Promise { - const roomBoardDto = await this.courseRoomsClientAdapter.getRoomBoardByCourseId(courseId); - - return roomBoardDto; - } - - private async findBoardSkeletonById(boardId: string): Promise { - const boardSkeleton = await this.boardClientAdapter.getBoardSkeletonById(boardId); - - return boardSkeleton; - } - - private async findAllCardsByIds(ids: Array): Promise { - const cards = await this.cardClientAdapter.getAllBoardCardsByIds(ids); - - return cards; - } - - private async findLessonById(lessonId: string): Promise { - const lesson = await this.lessonClientAdapter.getLessonById(lessonId); - - return lesson; - } - public async exportCourse( courseId: string, version: CommonCartridgeVersion, @@ -270,4 +240,34 @@ export class CommonCartridgeExportService { return columnBoard; } + + private async findCourseCommonCartridgeMetadata(courseId: string): Promise { + const courseCommonCartridgeMetadata = await this.coursesClientAdapter.getCourseCommonCartridgeMetadata(courseId); + + return courseCommonCartridgeMetadata; + } + + private async findRoomBoardByCourseId(courseId: string): Promise { + const roomBoardDto = await this.courseRoomsClientAdapter.getRoomBoardByCourseId(courseId); + + return roomBoardDto; + } + + private async findBoardSkeletonById(boardId: string): Promise { + const boardSkeleton = await this.boardClientAdapter.getBoardSkeletonById(boardId); + + return boardSkeleton; + } + + private async findAllCardsByIds(ids: Array): Promise { + const cards = await this.cardClientAdapter.getAllBoardCardsByIds(ids); + + return cards; + } + + private async findLessonById(lessonId: string): Promise { + const lesson = await this.lessonClientAdapter.getLessonById(lessonId); + + return lesson; + } } diff --git a/apps/server/src/modules/learnroom/controller/dto/course-export.body.params.ts b/apps/server/src/modules/learnroom/controller/dto/course-export.body.params.ts index 1edbcf7869e..a2e86355e8a 100644 --- a/apps/server/src/modules/learnroom/controller/dto/course-export.body.params.ts +++ b/apps/server/src/modules/learnroom/controller/dto/course-export.body.params.ts @@ -1,8 +1,9 @@ import { ApiProperty } from '@nestjs/swagger'; -import { IsArray } from 'class-validator'; +import { IsArray, IsString } from 'class-validator'; export class CourseExportBodyParams { @IsArray() + @IsString({ each: true }) @ApiProperty({ description: 'The list of ids of topics which should be exported. If empty no topics are exported.', type: [String], @@ -10,14 +11,15 @@ export class CourseExportBodyParams { public readonly topics!: string[]; @IsArray() + @IsString({ each: true }) @ApiProperty({ description: 'The list of ids of tasks which should be exported. If empty no tasks are exported.', type: [String], }) public readonly tasks!: string[]; - // AI next 6 lines @IsArray() + @IsString({ each: true }) @ApiProperty({ description: 'The list of ids of column boards which should be exported. If empty no column boards are exported.', type: [String], From 892d7292cfd3372822ced9cc7b699a17b1e69c1f Mon Sep 17 00:00:00 2001 From: Firas Shmit Date: Wed, 4 Dec 2024 11:37:49 +0100 Subject: [PATCH 43/61] EW-1060 deleted checks of exported elements --- .../common-cartridge-export.service.ts | 35 +++---------------- 1 file changed, 5 insertions(+), 30 deletions(-) diff --git a/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts b/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts index 5935478b1ee..2d029fcb75c 100644 --- a/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts +++ b/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts @@ -93,11 +93,6 @@ export class CommonCartridgeExportService { ): Promise { const filteredLessons = this.filterLessonFromBoardElements(elements); const lessonsIds = filteredLessons.filter((lesson) => topics.includes(lesson.id)).map((lesson) => lesson.id); - - if (lessonsIds.length === 0) { - return; - } - const lessons = await Promise.all(lessonsIds.map((elementId) => this.findLessonById(elementId))); lessons.forEach((lesson) => { @@ -122,11 +117,6 @@ export class CommonCartridgeExportService { const tasks: BoardTaskDto[] = this.filterTasksFromBoardElements(elements).filter((task) => exportedTasks.includes(task.id) ); - - if (tasks.length === 0) { - return; - } - const tasksOrganization = builder.createOrganization({ title: 'Aufgaben', identifier: createIdentifier(), @@ -146,11 +136,6 @@ export class CommonCartridgeExportService { const columnBoardsIds = columnBoards .filter((columnBoard) => exportedColumnBoards.includes(columnBoard.id)) .map((columBoard) => columBoard.columnBoardId); - - if (columnBoardsIds.length === 0) { - return; - } - const boardSkeletons: BoardSkeletonDto[] = await Promise.all( columnBoardsIds.map((columnBoardId) => this.findBoardSkeletonById(columnBoardId)) ); @@ -242,32 +227,22 @@ export class CommonCartridgeExportService { } private async findCourseCommonCartridgeMetadata(courseId: string): Promise { - const courseCommonCartridgeMetadata = await this.coursesClientAdapter.getCourseCommonCartridgeMetadata(courseId); - - return courseCommonCartridgeMetadata; + return await this.coursesClientAdapter.getCourseCommonCartridgeMetadata(courseId); } private async findRoomBoardByCourseId(courseId: string): Promise { - const roomBoardDto = await this.courseRoomsClientAdapter.getRoomBoardByCourseId(courseId); - - return roomBoardDto; + return await this.courseRoomsClientAdapter.getRoomBoardByCourseId(courseId); } private async findBoardSkeletonById(boardId: string): Promise { - const boardSkeleton = await this.boardClientAdapter.getBoardSkeletonById(boardId); - - return boardSkeleton; + return await this.boardClientAdapter.getBoardSkeletonById(boardId); } private async findAllCardsByIds(ids: Array): Promise { - const cards = await this.cardClientAdapter.getAllBoardCardsByIds(ids); - - return cards; + return await this.cardClientAdapter.getAllBoardCardsByIds(ids); } private async findLessonById(lessonId: string): Promise { - const lesson = await this.lessonClientAdapter.getLessonById(lessonId); - - return lesson; + return await this.lessonClientAdapter.getLessonById(lessonId); } } From 341aff948c9237d544b6942a40d468c8cf0d4a26 Mon Sep 17 00:00:00 2001 From: Firas Shmit Date: Wed, 4 Dec 2024 14:16:00 +0100 Subject: [PATCH 44/61] EW-1060 fixed lint errors --- .../card-client/mapper/card-response.mapper.ts | 14 ++++++++------ .../common-cartridge-export.service.spec.ts | 2 +- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/mapper/card-response.mapper.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/mapper/card-response.mapper.ts index e187b79ba6c..4a8746a884c 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/mapper/card-response.mapper.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/mapper/card-response.mapper.ts @@ -139,9 +139,10 @@ export class CardResponseMapper { id: element.id, type: ContentElementType.LINK, content: new LinkElementContentDto({ - url: content.url, - title: content.title, - description: content.description}), + url: content.url, + title: content.title, + description: content.description + }), timestamps: this.mapToTimestampDto(element.timestamps), }) ); @@ -174,8 +175,9 @@ export class CardResponseMapper { private static mapToTimestampDto(timestamp: TimestampsResponse): TimestampResponseDto { return new TimestampResponseDto({ - lastUpdatedAt: timestamp.lastUpdatedAt, - createdAt: timestamp.createdAt, - deletedAt: timestamp.deletedAt}); + lastUpdatedAt: timestamp.lastUpdatedAt, + createdAt: timestamp.createdAt, + deletedAt: timestamp.deletedAt + }); } } diff --git a/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.spec.ts b/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.spec.ts index 6ad82ec65e8..45d5832a502 100644 --- a/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.spec.ts +++ b/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.spec.ts @@ -308,7 +308,7 @@ describe('CommonCartridgeExportService', () => { it("shouldn't add lessons", async () => { const { archive, lesson } = await setup(); - + expect(getFileContent(archive, 'imsmanifest.xml')).not.toContain(createXmlString('title', lesson.name)); }); }); From e1a6c9960540833a8a8aa948a366f638d903b79e Mon Sep 17 00:00:00 2001 From: Firas Shmit Date: Wed, 4 Dec 2024 15:09:04 +0100 Subject: [PATCH 45/61] EW-1060 fixed lint errors --- .../common-cartridge-export.service.spec.ts | 7 ++----- .../common-cartridge-export.service.ts | 20 ++++++++++++++----- .../uc/common-cartridge.uc.spec.ts | 11 +++++++--- 3 files changed, 25 insertions(+), 13 deletions(-) diff --git a/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.spec.ts b/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.spec.ts index 45d5832a502..1a9553024a2 100644 --- a/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.spec.ts +++ b/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.spec.ts @@ -1,6 +1,5 @@ import { DeepMocked, createMock } from '@golevelup/ts-jest'; import { FilesStorageClientAdapterService } from '@modules/files-storage-client'; -import { faker } from '@faker-js/faker'; import { Test, TestingModule } from '@nestjs/testing'; import AdmZip from 'adm-zip'; import { BoardClientAdapter, BoardSkeletonDto } from '../common-cartridge-client/board-client'; @@ -238,9 +237,7 @@ describe('CommonCartridgeExportService', () => { it('should add lessons', async () => { const { archive, lesson } = await setup(); - expect(getFileContent(archive, 'imsmanifest.xml')).toContain( - createXmlString('title', lesson.name) - ); + expect(getFileContent(archive, 'imsmanifest.xml')).toContain(createXmlString('title', lesson.name)); }); it('should add tasks', async () => { @@ -308,7 +305,7 @@ describe('CommonCartridgeExportService', () => { it("shouldn't add lessons", async () => { const { archive, lesson } = await setup(); - + expect(getFileContent(archive, 'imsmanifest.xml')).not.toContain(createXmlString('title', lesson.name)); }); }); diff --git a/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts b/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts index 2d029fcb75c..96be753b89b 100644 --- a/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts +++ b/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts @@ -227,22 +227,32 @@ export class CommonCartridgeExportService { } private async findCourseCommonCartridgeMetadata(courseId: string): Promise { - return await this.coursesClientAdapter.getCourseCommonCartridgeMetadata(courseId); + const courseMetadata = await this.coursesClientAdapter.getCourseCommonCartridgeMetadata(courseId); + + return courseMetadata; } private async findRoomBoardByCourseId(courseId: string): Promise { - return await this.courseRoomsClientAdapter.getRoomBoardByCourseId(courseId); + const roomBoardDto = await this.courseRoomsClientAdapter.getRoomBoardByCourseId(courseId); + + return roomBoardDto; } private async findBoardSkeletonById(boardId: string): Promise { - return await this.boardClientAdapter.getBoardSkeletonById(boardId); + const boardSkeletonDto = await this.boardClientAdapter.getBoardSkeletonById(boardId); + + return boardSkeletonDto; } private async findAllCardsByIds(ids: Array): Promise { - return await this.cardClientAdapter.getAllBoardCardsByIds(ids); + const cardListResponseDto = await this.cardClientAdapter.getAllBoardCardsByIds(ids); + + return cardListResponseDto; } private async findLessonById(lessonId: string): Promise { - return await this.lessonClientAdapter.getLessonById(lessonId); + const lessonDto = await this.lessonClientAdapter.getLessonById(lessonId); + + return lessonDto; } } diff --git a/apps/server/src/modules/common-cartridge/uc/common-cartridge.uc.spec.ts b/apps/server/src/modules/common-cartridge/uc/common-cartridge.uc.spec.ts index 2e7aee0e2e5..f047c162ef2 100644 --- a/apps/server/src/modules/common-cartridge/uc/common-cartridge.uc.spec.ts +++ b/apps/server/src/modules/common-cartridge/uc/common-cartridge.uc.spec.ts @@ -49,10 +49,15 @@ describe('CommonCartridgeUc', () => { it('should return a course export response with file IDs and metadata of a course', async () => { const { courseId, expected, version, tasks, columnBoards, topics } = setup(); - - expect(await sut.exportCourse(courseId, version, topics, tasks, columnBoards)).toEqual(expected); - expect(commonCartridgeExportServiceMock.exportCourse).toHaveBeenCalledWith(courseId, version, topics, tasks, columnBoards); + expect(await sut.exportCourse(courseId, version, topics, tasks, columnBoards)).toEqual(expected); + expect(commonCartridgeExportServiceMock.exportCourse).toHaveBeenCalledWith( + courseId, + version, + topics, + tasks, + columnBoards + ); }); }); }); From 1876734c26de12da30e4369192b2ed89e61d6cd3 Mon Sep 17 00:00:00 2001 From: Firas Shmit Date: Wed, 4 Dec 2024 15:23:20 +0100 Subject: [PATCH 46/61] EW-1060 fixed more lint errors --- .../card-client/mapper/card-response.mapper.ts | 4 ++-- .../controller/common-cartridge.controller.spec.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/mapper/card-response.mapper.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/mapper/card-response.mapper.ts index 4a8746a884c..fa8743fe5f6 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/mapper/card-response.mapper.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/mapper/card-response.mapper.ts @@ -141,7 +141,7 @@ export class CardResponseMapper { content: new LinkElementContentDto({ url: content.url, title: content.title, - description: content.description + description: content.description, }), timestamps: this.mapToTimestampDto(element.timestamps), }) @@ -177,7 +177,7 @@ export class CardResponseMapper { return new TimestampResponseDto({ lastUpdatedAt: timestamp.lastUpdatedAt, createdAt: timestamp.createdAt, - deletedAt: timestamp.deletedAt + deletedAt: timestamp.deletedAt, }); } } diff --git a/apps/server/src/modules/common-cartridge/controller/common-cartridge.controller.spec.ts b/apps/server/src/modules/common-cartridge/controller/common-cartridge.controller.spec.ts index 11fceb8135c..245579d7364 100644 --- a/apps/server/src/modules/common-cartridge/controller/common-cartridge.controller.spec.ts +++ b/apps/server/src/modules/common-cartridge/controller/common-cartridge.controller.spec.ts @@ -41,7 +41,7 @@ describe('CommonCartridgeController', () => { describe('exportCourse', () => { const setup = () => { const courseId = faker.string.uuid(); - const params = { courseId: courseId } as ExportCourseParams; + const params = { courseId } as ExportCourseParams; const query = { version: CommonCartridgeVersion.V_1_1_0 } as CourseQueryParams; const body = { topics: [faker.string.uuid(), faker.string.uuid()], From 68c3dc4679f971210bbf8be37988a61ecc584083 Mon Sep 17 00:00:00 2001 From: Firas Shmit Date: Wed, 4 Dec 2024 16:07:40 +0100 Subject: [PATCH 47/61] EW-1060 fixed card mapper test --- .../card-client/mapper/card-response.mapper.spec.ts | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/mapper/card-response.mapper.spec.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/mapper/card-response.mapper.spec.ts index 29052e30911..3b88164ada3 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/mapper/card-response.mapper.spec.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/mapper/card-response.mapper.spec.ts @@ -172,17 +172,5 @@ describe('CardResponseMapper', () => { expect(cardResponse.visibilitySettings.publishedAt).toBe(''); }); }); - - describe('when deletedAt in TimestampsResponse is null', () => { - const mockList: CardListResponse = setup([]); - mockList.data[0].timestamps.deletedAt = undefined; - - it('should return an empty string', () => { - const mapperResult = CardResponseMapper.mapToCardListResponseDto(mockList); - const cardResponse: CardResponseDto = mapperResult.data[0]; - - expect(cardResponse.timeStamps.deletedAt).toBe(''); - }); - }); }); }); From dc1589fae73455e153a0e7875cfb55cb6919d2d0 Mon Sep 17 00:00:00 2001 From: Firas Shmit Date: Thu, 5 Dec 2024 11:40:34 +0100 Subject: [PATCH 48/61] EW-1060 modifed test of lesson dto mapper --- .../dto/component-etherpad-props.dto.ts | 10 +- .../mapper/lesson-dto.mapper.spec.ts | 293 +++++++++++++++--- .../lesson-client/mapper/lesson-dto.mapper.ts | 8 +- 3 files changed, 264 insertions(+), 47 deletions(-) diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-etherpad-props.dto.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-etherpad-props.dto.ts index 8330d28546d..085219a56c5 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-etherpad-props.dto.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-etherpad-props.dto.ts @@ -1,5 +1,3 @@ -import { ComponentEtherpadPropsImpl } from '../lessons-api-client'; - export class ComponentEtherpadPropsDto { description: string; @@ -7,9 +5,9 @@ export class ComponentEtherpadPropsDto { url: string; - constructor(etherpadContent: ComponentEtherpadPropsImpl) { - this.description = etherpadContent.description; - this.title = etherpadContent.title; - this.url = etherpadContent.url; + constructor(props: Readonly) { + this.description = props.description; + this.title = props.title; + this.url = props.url; } } diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/mapper/lesson-dto.mapper.spec.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/mapper/lesson-dto.mapper.spec.ts index 3b294527520..03402407a43 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/mapper/lesson-dto.mapper.spec.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/mapper/lesson-dto.mapper.spec.ts @@ -5,30 +5,78 @@ import { LessonResponse, LessonLinkedTaskResponse, LessonLinkedTaskResponseDescriptionInputFormat, + ComponentEtherpadPropsImpl, + ComponentGeogebraPropsImpl, + ComponentInternalPropsImpl, + ComponentTextPropsImpl, + ComponentLernstorePropsImpl, + ComponentNexboardPropsImpl, + LessonContentResponseComponent, } from '../lessons-api-client'; import { LessonDtoMapper } from './lesson-dto.mapper'; +import { LessonDto } from '../dto'; +import { ComponentGeogebraPropsDto } from '../dto/component-geogebra-props.dto'; +import { ComponentTextPropsDto } from '../dto/component-text-props.dto'; +import { ComponentInternalPropsDto } from '../dto/component-internal-props.dto'; +import { ComponentLernstorePropsDto } from '../dto/component-lernstore-props.dto'; +import { ComponentNexboardPropsDto } from '../dto/component-nexboard-props-dto'; describe('LessonDtoMapper', () => { describe('mapToLessonDto', () => { - describe('when mapping to LessonResponse', () => { + const materialResponse: MaterialResponse = { + _id: faker.string.uuid(), + id: faker.string.uuid(), + title: faker.lorem.sentence(), + relatedResources: [faker.lorem.sentence()], + url: faker.internet.url(), + client: faker.lorem.sentence(), + license: [faker.lorem.sentence()], + merlinReference: faker.lorem.sentence(), + }; + + describe('when mapping LessonResponse to lesson DTO with etherpad contnet', () => { const setup = () => { - const materialResponse: MaterialResponse = { + const lessonContentResponse: LessonContentResponse = { + content: { title: faker.lorem.sentence() } as ComponentEtherpadPropsImpl, _id: faker.string.uuid(), id: faker.string.uuid(), title: faker.lorem.sentence(), - relatedResources: [faker.lorem.sentence()], - url: faker.internet.url(), - client: faker.lorem.sentence(), - license: [faker.lorem.sentence()], - merlinReference: faker.lorem.sentence(), + component: faker.helpers.arrayElement(['Etherpad']), + hidden: faker.datatype.boolean(), + }; + + const lessonResponse: LessonResponse = { + _id: faker.string.uuid(), + id: faker.string.uuid(), + name: faker.lorem.sentence(), + courseId: faker.string.uuid(), + courseGroupId: faker.string.uuid(), + hidden: faker.datatype.boolean(), + position: faker.number.int(), + contents: [lessonContentResponse], + materials: [materialResponse], }; + return { lessonResponse, lessonContentResponse }; + }; + + it('should return LessonDto with etherpad content', () => { + const { lessonResponse } = setup(); + + const result = LessonDtoMapper.mapToLessonDto(lessonResponse); + + expect(result).toBeInstanceOf(LessonDto); + }); + }); + + describe('when mapping LessonResponse to lesson DTO with GeoGebra content', () => { + const setup = () => { const lessonContentResponse: LessonContentResponse = { - content: { text: faker.lorem.sentence() }, + content: { materialId: faker.string.uuid() } as ComponentGeogebraPropsImpl, _id: faker.string.uuid(), id: faker.string.uuid(), title: faker.lorem.sentence(), - component: faker.helpers.arrayElement(['Etherpad', 'neXboard', 'geoGebra']), + component: faker.helpers.arrayElement(['geoGebra']), hidden: faker.datatype.boolean(), }; @@ -44,41 +92,210 @@ describe('LessonDtoMapper', () => { materials: [materialResponse], }; - return { lessonResponse }; + return { lessonResponse, lessonContentResponse }; }; - it('should return LessonDto', () => { + it('should return LessonDto with GeoGebra content', () => { const { lessonResponse } = setup(); const result = LessonDtoMapper.mapToLessonDto(lessonResponse); - expect(result).toEqual({ - lessonId: lessonResponse.id, - name: lessonResponse.name, - courseId: lessonResponse.courseId, - courseGroupId: lessonResponse.courseGroupId, - hidden: lessonResponse.hidden, - position: lessonResponse.position, - contents: [ - { - content: lessonResponse.contents[0].content, - title: lessonResponse.contents[0].title, - component: lessonResponse.contents[0].component, - hidden: lessonResponse.contents[0].hidden, - }, - ], - materials: [ - { - materialsId: lessonResponse.materials[0].id, - title: lessonResponse.materials[0].title, - relatedResources: [lessonResponse.materials[0].relatedResources[0]], - url: lessonResponse.materials[0].url, - client: lessonResponse.materials[0].client, - license: lessonResponse.materials[0].license, - merlinReference: lessonResponse.materials[0].merlinReference, - }, - ], - }); + expect(result).toBeInstanceOf(LessonDto); + expect(result.contents[0].component).toEqual('geoGebra'); + expect(result.contents[0].content).toBeInstanceOf(ComponentGeogebraPropsDto); + }); + }); + + describe('when mapping LessonResponse to lesson DTO with Text content', () => { + const setup = () => { + const lessonContentResponse: LessonContentResponse = { + content: { text: faker.lorem.sentence() } as ComponentTextPropsImpl, + _id: faker.string.uuid(), + id: faker.string.uuid(), + title: faker.lorem.sentence(), + component: faker.helpers.arrayElement(['text']), + hidden: faker.datatype.boolean(), + }; + + const lessonResponse: LessonResponse = { + _id: faker.string.uuid(), + id: faker.string.uuid(), + name: faker.lorem.sentence(), + courseId: faker.string.uuid(), + courseGroupId: faker.string.uuid(), + hidden: faker.datatype.boolean(), + position: faker.number.int(), + contents: [lessonContentResponse], + materials: [materialResponse], + }; + + return { lessonResponse, lessonContentResponse }; + }; + + it('should return LessonDto with text content', () => { + const { lessonResponse } = setup(); + + const result = LessonDtoMapper.mapToLessonDto(lessonResponse); + + expect(result).toBeInstanceOf(LessonDto); + expect(result.contents[0].component).toEqual('text'); + expect(result.contents[0].content).toBeInstanceOf(ComponentTextPropsDto); + }); + }); + + describe('when mapping LessonResponse to lesson DTO with internal content', () => { + const setup = () => { + const lessonContentResponse: LessonContentResponse = { + content: { url: faker.internet.url() } as ComponentInternalPropsImpl, + _id: faker.string.uuid(), + id: faker.string.uuid(), + title: faker.lorem.sentence(), + component: faker.helpers.arrayElement(['internal']), + hidden: faker.datatype.boolean(), + }; + + const lessonResponse: LessonResponse = { + _id: faker.string.uuid(), + id: faker.string.uuid(), + name: faker.lorem.sentence(), + courseId: faker.string.uuid(), + courseGroupId: faker.string.uuid(), + hidden: faker.datatype.boolean(), + position: faker.number.int(), + contents: [lessonContentResponse], + materials: [materialResponse], + }; + + return { lessonResponse, lessonContentResponse }; + }; + + it('should return LessonDto with internal content', () => { + const { lessonResponse } = setup(); + + const result = LessonDtoMapper.mapToLessonDto(lessonResponse); + + expect(result).toBeInstanceOf(LessonDto); + expect(result.contents[0].component).toEqual('internal'); + expect(result.contents[0].content).toBeInstanceOf(ComponentInternalPropsDto); + }); + }); + + describe('when mapping LessonResponse to lesson DTO with lernstore content', () => { + const setup = () => { + const lessonContentResponse: LessonContentResponse = { + content: { resources: [faker.internet.url(), faker.lorem.text()] } as ComponentLernstorePropsImpl, + _id: faker.string.uuid(), + id: faker.string.uuid(), + title: faker.lorem.sentence(), + component: faker.helpers.arrayElement(['resources']), + hidden: faker.datatype.boolean(), + }; + + const lessonResponse: LessonResponse = { + _id: faker.string.uuid(), + id: faker.string.uuid(), + name: faker.lorem.sentence(), + courseId: faker.string.uuid(), + courseGroupId: faker.string.uuid(), + hidden: faker.datatype.boolean(), + position: faker.number.int(), + contents: [lessonContentResponse], + materials: [materialResponse], + }; + + return { lessonResponse, lessonContentResponse }; + }; + + it('should return LessonDto with lernstore content', () => { + const { lessonResponse } = setup(); + + const result = LessonDtoMapper.mapToLessonDto(lessonResponse); + + expect(result).toBeInstanceOf(LessonDto); + expect(result.contents[0].component).toEqual('resources'); + expect(result.contents[0].content).toBeInstanceOf(ComponentLernstorePropsDto); + }); + }); + + describe('when mapping LessonResponse to lesson DTO with next board content', () => { + const setup = () => { + const lessonContentResponse: LessonContentResponse = { + content: { + board: faker.lorem.text(), + description: faker.lorem.word(), + title: faker.lorem.text(), + url: faker.internet.url(), + } as ComponentNexboardPropsImpl, + _id: faker.string.uuid(), + id: faker.string.uuid(), + title: faker.lorem.sentence(), + component: faker.helpers.arrayElement(['neXboard']), + hidden: faker.datatype.boolean(), + }; + + const lessonResponse: LessonResponse = { + _id: faker.string.uuid(), + id: faker.string.uuid(), + name: faker.lorem.sentence(), + courseId: faker.string.uuid(), + courseGroupId: faker.string.uuid(), + hidden: faker.datatype.boolean(), + position: faker.number.int(), + contents: [lessonContentResponse], + materials: [materialResponse], + }; + + return { lessonResponse, lessonContentResponse }; + }; + + it('should return LessonDto with nexboard content', () => { + const { lessonResponse } = setup(); + + const result = LessonDtoMapper.mapToLessonDto(lessonResponse); + + expect(result).toBeInstanceOf(LessonDto); + expect(result.contents[0].component).toEqual('neXboard'); + expect(result.contents[0].content).toBeInstanceOf(ComponentNexboardPropsDto); + }); + }); + + describe('when mapping LessonResponse to lesson DTO with an empty content', () => { + const setup = () => { + const lessonContentResponse: LessonContentResponse = { + content: { + board: faker.lorem.text(), + description: faker.lorem.word(), + title: faker.lorem.text(), + url: faker.internet.url(), + } as ComponentNexboardPropsImpl, + _id: faker.string.uuid(), + id: faker.string.uuid(), + title: faker.lorem.sentence(), + component: faker.helpers.arrayElement(['unknown']) as unknown as LessonContentResponseComponent, + hidden: faker.datatype.boolean(), + }; + + const lessonResponse: LessonResponse = { + _id: faker.string.uuid(), + id: faker.string.uuid(), + name: faker.lorem.sentence(), + courseId: faker.string.uuid(), + courseGroupId: faker.string.uuid(), + hidden: faker.datatype.boolean(), + position: faker.number.int(), + contents: [lessonContentResponse], + materials: [], + }; + + return { lessonResponse }; + }; + it('should return an empty array of contents', () => { + const { lessonResponse } = setup(); + + const result = LessonDtoMapper.mapToLessonDto(lessonResponse); + + expect(result).toBeInstanceOf(LessonDto); + expect(result.contents).toEqual([]); }); }); }); diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/mapper/lesson-dto.mapper.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/mapper/lesson-dto.mapper.ts index a2fbff7354d..b479aa77115 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/mapper/lesson-dto.mapper.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/mapper/lesson-dto.mapper.ts @@ -47,7 +47,9 @@ export class LessonDtoMapper { courseGroupId: lessonResponse.courseGroupId, hidden: lessonResponse.hidden, position: lessonResponse.position, - contents: lessonResponse.contents.map((content) => this.mapToLessenContentDto(content)), + contents: lessonResponse.contents + .map((content) => this.mapToLessenContentDto(content)) + .filter((contetnDto) => contetnDto !== null), materials: lessonResponse.materials.map((material) => this.mapToLessonMaterialDto(material)), }); @@ -68,7 +70,7 @@ export class LessonDtoMapper { return lessonMaterialsDto; } - private static mapToLessenContentDto(lessonContentResponse: LessonContentResponse): LessonContentDto { + private static mapToLessenContentDto(lessonContentResponse: LessonContentResponse): LessonContentDto | null { switch (lessonContentResponse.component) { case LessonContentResponseComponent.TEXT: return new LessonContentDto({ @@ -119,7 +121,7 @@ export class LessonDtoMapper { content: new ComponentNexboardPropsDto(lessonContentResponse.content as ComponentNexboardPropsImpl), }); default: - throw new Error(`Unknown component type of lesson content`); + return null; } } } From 43fbd5ad3062cf71c116d1fd27efcb7689f24bd8 Mon Sep 17 00:00:00 2001 From: Firas Shmit Date: Thu, 5 Dec 2024 14:02:26 +0100 Subject: [PATCH 49/61] EW-1060 added common cartridge export mapper --- .../service/common-cartridge.mapper.spec.ts | 287 ++++++++++++++++++ .../service/common-cartridge.mapper.ts | 2 +- 2 files changed, 288 insertions(+), 1 deletion(-) create mode 100644 apps/server/src/modules/common-cartridge/service/common-cartridge.mapper.spec.ts diff --git a/apps/server/src/modules/common-cartridge/service/common-cartridge.mapper.spec.ts b/apps/server/src/modules/common-cartridge/service/common-cartridge.mapper.spec.ts new file mode 100644 index 00000000000..53a5a7fd9b3 --- /dev/null +++ b/apps/server/src/modules/common-cartridge/service/common-cartridge.mapper.spec.ts @@ -0,0 +1,287 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { faker } from '@faker-js/faker'; +import { CommonCartridgeExportMapper } from './common-cartridge.mapper'; +import { + boardTaskFactory, + lessonContentFactory, + lessonLinkedTaskFactory, + linkElementFactory, + richTextElementFactroy, +} from '../testing/common-cartridge-dtos.factory'; +import { LessonContentDtoComponentValues } from '../common-cartridge-client/lesson-client/dto'; +import { + CommonCartridgeIntendedUseType, + CommonCartridgeResourceType, + CommonCartridgeVersion, +} from '../export/common-cartridge.enums'; +import { ComponentGeogebraPropsDto } from '../common-cartridge-client/lesson-client/dto/component-geogebra-props.dto'; +import { ComponentEtherpadPropsDto } from '../common-cartridge-client/lesson-client/dto/component-etherpad-props.dto'; +import { createIdentifier } from '../export/utils'; + +const GEOGEBRA_BASE_URL = 'https://geogebra.org'; + +describe('CommonCartridgeExportMapper', () => { + let module: TestingModule; + let sut: CommonCartridgeExportMapper; + + beforeAll(async () => { + module = await Test.createTestingModule({ + providers: [CommonCartridgeExportMapper], + }).compile(); + + sut = module.get(CommonCartridgeExportMapper); + }); + + afterAll(async () => { + await module.close(); + }); + it('should be defined', () => { + expect(sut).toBeDefined(); + }); + + describe('mapContentToResources', () => { + describe('when lesson content is GeoGebra', () => { + const setup = () => { + const lessonContent = lessonContentFactory.build(); + lessonContent.component = LessonContentDtoComponentValues.GEO_GEBRA; + lessonContent.content = { + materialId: faker.string.uuid(), + }; + return { lessonContent }; + }; + it('should map lesson content to GeoGebra resources', () => { + const { lessonContent } = setup(); + const result = sut.mapContentToResources(lessonContent); + + expect(result).toEqual({ + type: CommonCartridgeResourceType.WEB_LINK, + identifier: `i${lessonContent.id ?? ''}`, + title: lessonContent.title, + url: `${GEOGEBRA_BASE_URL}/m/${(lessonContent.content as ComponentGeogebraPropsDto).materialId}`, + }); + }); + }); + + describe('when lesson content is Etherpad', () => { + const setup = () => { + const lessonContent = lessonContentFactory.build(); + lessonContent.component = LessonContentDtoComponentValues.ETHERPAD; + lessonContent.content = { + description: faker.lorem.sentence(), + title: faker.lorem.sentence(), + url: faker.internet.url(), + }; + return { lessonContent }; + }; + + it('should map lesson content to Etherpad resources', () => { + const { lessonContent } = setup(); + const result = sut.mapContentToResources(lessonContent); + + expect(result).toEqual({ + type: CommonCartridgeResourceType.WEB_LINK, + identifier: `i${lessonContent.id ?? ''}`, + title: `${(lessonContent.content as ComponentEtherpadPropsDto).title} - ${ + (lessonContent.content as ComponentEtherpadPropsDto).description + }`, + url: (lessonContent.content as ComponentEtherpadPropsDto).url, + }); + }); + }); + + describe('when lesson content is Lernstore', () => { + const setup = () => { + const lessonContent = lessonContentFactory.build(); + lessonContent.component = LessonContentDtoComponentValues.LERNSTORE; + lessonContent.content = { + resources: [faker.internet.url(), faker.internet.url()], + }; + return { lessonContent }; + }; + + it('should map lesson content to Lernstore resources', () => { + const { lessonContent } = setup(); + const result = sut.mapContentToResources(lessonContent); + + expect(result[0]).toEqual({ + type: CommonCartridgeResourceType.WEB_LINK, + identifier: `i${lessonContent.id ?? ''}`, + title: '', + url: '', + }); + }); + }); + }); + + describe('mapContentToOrganization', () => { + const setup = () => { + const lessonContent = lessonContentFactory.build(); + return { lessonContent }; + }; + describe('when mapping lesson to organization', () => { + it('should map lesson identifier and title to organization', () => { + const { lessonContent } = setup(); + const result = sut.mapContentToOrganization(lessonContent); + + expect(result).toEqual({ + identifier: `i${lessonContent.id ?? ''}`, + title: lessonContent.title, + }); + }); + }); + }); + + describe('mapTaskToResources', () => { + const setup = () => { + const task = boardTaskFactory.build(); + + return { task }; + }; + + describe('when mapping task to resources with version 1.1.0', () => { + const { task } = setup(); + it('should map task to resources with version 1.1.0', () => { + const result = sut.mapTaskToResource(task, CommonCartridgeVersion.V_1_1_0); + + expect(result).toEqual({ + identifier: `i${task.id}`, + title: task.name, + html: `

${task.name}

${task.description ?? ''}

`, + intendedUse: CommonCartridgeIntendedUseType.UNSPECIFIED, + type: CommonCartridgeResourceType.WEB_CONTENT, + }); + }); + }); + + describe('when mapping task to resources with version 1.3.0', () => { + const { task } = setup(); + it('should map task to resources with version 1.3.0', () => { + const result = sut.mapTaskToResource(task, CommonCartridgeVersion.V_1_3_0); + + expect(result).toEqual({ + identifier: `i${task.id}`, + title: task.name, + html: `

${task.name}

${task.description ?? ''}

`, + intendedUse: CommonCartridgeIntendedUseType.ASSIGNMENT, + type: CommonCartridgeResourceType.WEB_CONTENT, + }); + }); + }); + + describe('when mapping task to resources with not supported version', () => { + const { task } = setup(); + it('should map task to resources with version 1.1.0 as default', () => { + const result = sut.mapTaskToResource(task, CommonCartridgeVersion.V_1_4_0); + + expect(result).toEqual({ + identifier: `i${task.id}`, + title: task.name, + html: `

${task.name}

${task.description ?? ''}

`, + intendedUse: CommonCartridgeIntendedUseType.UNSPECIFIED, + type: CommonCartridgeResourceType.WEB_CONTENT, + }); + }); + }); + }); + + describe('mapLinkedTaskToResource', () => { + const setup = () => { + const linkedTask = lessonLinkedTaskFactory.build(); + + return { linkedTask }; + }; + + describe('when mapping linked task to resources with version 1.1.0', () => { + const { linkedTask } = setup(); + it('should map linked task to resources with version 1.1.0', () => { + const result = sut.mapLinkedTaskToResource(linkedTask, CommonCartridgeVersion.V_1_1_0); + + expect(result).toStrictEqual( + expect.objectContaining({ + type: CommonCartridgeResourceType.WEB_CONTENT, + title: linkedTask.name, + html: `

${linkedTask.name}

${linkedTask.description}

`, + intendedUse: CommonCartridgeIntendedUseType.UNSPECIFIED, + }) + ); + }); + }); + + describe('when mapping linked task to resources with version 1.3.0', () => { + const { linkedTask } = setup(); + it('should map linked task to resources with version 1.3.0', () => { + const result = sut.mapLinkedTaskToResource(linkedTask, CommonCartridgeVersion.V_1_3_0); + + expect(result).toStrictEqual( + expect.objectContaining({ + type: CommonCartridgeResourceType.WEB_CONTENT, + title: linkedTask.name, + html: `

${linkedTask.name}

${linkedTask.description}

`, + intendedUse: CommonCartridgeIntendedUseType.ASSIGNMENT, + }) + ); + }); + }); + + describe('when mapping linked task to resources with not supported version', () => { + const { linkedTask } = setup(); + it('should map linked task to resources with version 1.1.0 as default', () => { + const result = sut.mapLinkedTaskToResource(linkedTask, CommonCartridgeVersion.V_1_4_0); + + expect(result).toStrictEqual( + expect.objectContaining({ + type: CommonCartridgeResourceType.WEB_CONTENT, + title: linkedTask.name, + html: `

${linkedTask.name}

${linkedTask.description}

`, + intendedUse: CommonCartridgeIntendedUseType.UNSPECIFIED, + }) + ); + }); + }); + }); + + describe('mapRichTextElementToResource', () => { + const setup = () => { + const richTextElement = richTextElementFactroy.build(); + + return { richTextElement }; + }; + + describe('when mapping rich text element to resources', () => { + const { richTextElement } = setup(); + it('should map rich text element to resources', () => { + const result = sut.mapRichTextElementToResource(richTextElement); + + expect(result).toEqual({ + type: CommonCartridgeResourceType.WEB_CONTENT, + identifier: createIdentifier(richTextElement.id), + title: richTextElement.content.text, + html: `

${richTextElement.content.text}

`, + intendedUse: CommonCartridgeIntendedUseType.UNSPECIFIED, + }); + }); + }); + }); + + describe('mapLinkElementToResource', () => { + const setup = () => { + const linkElement = linkElementFactory.build(); + + return { linkElement }; + }; + + describe('when mapping link element to resources', () => { + const { linkElement } = setup(); + it('should map link element to resources', () => { + const result = sut.mapLinkElementToResource(linkElement); + + expect(result).toEqual({ + type: CommonCartridgeResourceType.WEB_LINK, + identifier: createIdentifier(linkElement.id), + title: linkElement.content.title, + url: linkElement.content.url, + }); + }); + }); + }); +}); diff --git a/apps/server/src/modules/common-cartridge/service/common-cartridge.mapper.ts b/apps/server/src/modules/common-cartridge/service/common-cartridge.mapper.ts index 660c4af6fb3..0d6ff8f7441 100644 --- a/apps/server/src/modules/common-cartridge/service/common-cartridge.mapper.ts +++ b/apps/server/src/modules/common-cartridge/service/common-cartridge.mapper.ts @@ -92,7 +92,7 @@ export class CommonCartridgeExportMapper { extractedResources.map((resource) => { return { type: CommonCartridgeResourceType.WEB_LINK, - identifier: createIdentifier(), + identifier: createIdentifier(lessonContent.id), title: resource.title, url: resource.url, }; From 7accdc570eab4da49cf88c54f79761dd0e1d1c06 Mon Sep 17 00:00:00 2001 From: Firas Shmit Date: Fri, 6 Dec 2024 13:02:04 +0100 Subject: [PATCH 50/61] EW-1060 completed test coverage for cc mapper --- .../service/common-cartridge.mapper.spec.ts | 90 ++++++++++++++++++- 1 file changed, 89 insertions(+), 1 deletion(-) diff --git a/apps/server/src/modules/common-cartridge/service/common-cartridge.mapper.spec.ts b/apps/server/src/modules/common-cartridge/service/common-cartridge.mapper.spec.ts index 53a5a7fd9b3..33b675071c4 100644 --- a/apps/server/src/modules/common-cartridge/service/common-cartridge.mapper.spec.ts +++ b/apps/server/src/modules/common-cartridge/service/common-cartridge.mapper.spec.ts @@ -3,13 +3,15 @@ import { faker } from '@faker-js/faker'; import { CommonCartridgeExportMapper } from './common-cartridge.mapper'; import { boardTaskFactory, + courseMetadataFactory, lessonContentFactory, + lessonFactory, lessonLinkedTaskFactory, linkElementFactory, richTextElementFactroy, } from '../testing/common-cartridge-dtos.factory'; -import { LessonContentDtoComponentValues } from '../common-cartridge-client/lesson-client/dto'; import { + CommonCartridgeElementType, CommonCartridgeIntendedUseType, CommonCartridgeResourceType, CommonCartridgeVersion, @@ -17,6 +19,11 @@ import { import { ComponentGeogebraPropsDto } from '../common-cartridge-client/lesson-client/dto/component-geogebra-props.dto'; import { ComponentEtherpadPropsDto } from '../common-cartridge-client/lesson-client/dto/component-etherpad-props.dto'; import { createIdentifier } from '../export/utils'; +import { LessonContentResponseContentInnerDto } from '../common-cartridge-client/lesson-client/dto/lesson-content-response-inner.dto'; +import { + LessonContentDtoComponent, + LessonContentDtoComponentValues, +} from '../common-cartridge-client/lesson-client/dto'; const GEOGEBRA_BASE_URL = 'https://geogebra.org'; @@ -35,10 +42,73 @@ describe('CommonCartridgeExportMapper', () => { afterAll(async () => { await module.close(); }); + it('should be defined', () => { expect(sut).toBeDefined(); }); + describe('mapCourseToManifest', () => { + const setup = () => { + const courseId = faker.string.uuid(); + const version = CommonCartridgeVersion.V_1_1_0; + return { courseId, version }; + }; + + describe('when mapping course to manifest', () => { + const { courseId, version } = setup(); + it('should map course to manifest', () => { + const result = sut.mapCourseToManifest(version, courseId); + + expect(result).toEqual({ + version, + identifier: createIdentifier(courseId), + }); + }); + }); + }); + + describe('mapCourseToMetadata', () => { + const setup = () => { + const courseMetadata = courseMetadataFactory.build(); + return { courseMetadata }; + }; + + describe('when mapping metadata of a course to DTO', () => { + const { courseMetadata } = setup(); + it('should map metadata to a CourseCommonCartridgeMetadataDto', () => { + const result = sut.mapCourseToMetadata(courseMetadata); + + expect(result).toEqual({ + type: CommonCartridgeElementType.METADATA, + title: courseMetadata.courseName, + copyrightOwners: courseMetadata.copyRightOwners, + creationDate: courseMetadata.creationDate ? new Date(courseMetadata.creationDate) : new Date(), + }); + }); + }); + }); + + describe('mapLessonToOrganization', () => { + const setup = () => { + const lesson = lessonFactory.build(); + + return { lesson }; + }; + + describe('when mapping lesson to organization', () => { + const { lesson } = setup(); + + it('should map lesson identifier and title to organization', () => { + const result = sut.mapLessonToOrganization(lesson); + + expect(result).toEqual({ + identifier: createIdentifier(lesson.lessonId), + title: lesson.name, + }); + }); + }); + }); + describe('mapContentToResources', () => { describe('when lesson content is GeoGebra', () => { const setup = () => { @@ -49,6 +119,7 @@ describe('CommonCartridgeExportMapper', () => { }; return { lessonContent }; }; + it('should map lesson content to GeoGebra resources', () => { const { lessonContent } = setup(); const result = sut.mapContentToResources(lessonContent); @@ -111,6 +182,23 @@ describe('CommonCartridgeExportMapper', () => { }); }); }); + + describe('when lesson has no content', () => { + const setup = () => { + const lessonContent = lessonContentFactory.build(); + lessonContent.content = {} as unknown as LessonContentResponseContentInnerDto; + lessonContent.component = {} as unknown as LessonContentDtoComponent; + + return { lessonContent }; + }; + + it('should return an empty array of contents', () => { + const { lessonContent } = setup(); + const result = sut.mapContentToResources(lessonContent); + + expect(result).toBeInstanceOf(Array); + }); + }); }); describe('mapContentToOrganization', () => { From 2de9df63b6b003de6871cf3b2167b3cfbb3d408b Mon Sep 17 00:00:00 2001 From: Firas Shmit Date: Tue, 10 Dec 2024 12:23:30 +0100 Subject: [PATCH 51/61] EW-1060 coverage of tests --- .../common-cartridge-export.service.spec.ts | 14 ++++++++------ .../testing/common-cartridge-dtos.factory.ts | 15 +++++++++++++-- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.spec.ts b/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.spec.ts index 1a9553024a2..276f38b75d8 100644 --- a/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.spec.ts +++ b/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.spec.ts @@ -11,7 +11,6 @@ import { LessonClientAdapter } from '../common-cartridge-client/lesson-client/le import { CommonCartridgeExportMapper } from './common-cartridge.mapper'; import { CommonCartridgeVersion } from '../export/common-cartridge.enums'; import { RoomBoardDto } from '../common-cartridge-client/room-client/dto/room-board.dto'; -import { LessonDto } from '../common-cartridge-client/lesson-client/dto'; import { RichTextElementContentDto } from '../common-cartridge-client/card-client/dto/rich-text-element-content.dto'; import { LinkElementContentDto } from '../common-cartridge-client/card-client/dto/link-element-content.dto'; import { @@ -42,7 +41,6 @@ describe('CommonCartridgeExportService', () => { `<${nodeName}>${value.toString()}`; const getFileContent = (archive: AdmZip, filePath: string): string | undefined => archive.getEntry(filePath)?.getData().toString(); - const setupParams = async ( version: CommonCartridgeVersion, exportTopics: boolean, @@ -50,7 +48,8 @@ describe('CommonCartridgeExportService', () => { exportColumnBoards: boolean ) => { const courseMetadata: CourseCommonCartridgeMetadataDto = courseMetadataFactory.build(); - const lesson: LessonDto = lessonFactory.build(); + const lessons = lessonFactory.buildList(2); + const [lesson] = lessons; lesson.courseId = courseMetadata.id; const boardSkeleton: BoardSkeletonDto = columnBoardFactory.build(); @@ -89,6 +88,7 @@ describe('CommonCartridgeExportService', () => { version, room, lesson, + lessons, boardTask, boardSkeleton, listOfCardsResponse, @@ -234,7 +234,7 @@ describe('CommonCartridgeExportService', () => { ); }); - it('should add lessons', async () => { + it('should add lesson', async () => { const { archive, lesson } = await setup(); expect(getFileContent(archive, 'imsmanifest.xml')).toContain(createXmlString('title', lesson.name)); @@ -304,9 +304,11 @@ describe('CommonCartridgeExportService', () => { const setup = async () => setupParams(CommonCartridgeVersion.V_1_1_0, false, true, true); it("shouldn't add lessons", async () => { - const { archive, lesson } = await setup(); + const { archive, lessons } = await setup(); - expect(getFileContent(archive, 'imsmanifest.xml')).not.toContain(createXmlString('title', lesson.name)); + lessons.forEach((lesson) => { + expect(getFileContent(archive, 'imsmanifest.xml')).not.toContain(createXmlString('title', lesson.name)); + }); }); }); diff --git a/apps/server/src/modules/common-cartridge/testing/common-cartridge-dtos.factory.ts b/apps/server/src/modules/common-cartridge/testing/common-cartridge-dtos.factory.ts index 2354d8b5727..cf8805c4182 100644 --- a/apps/server/src/modules/common-cartridge/testing/common-cartridge-dtos.factory.ts +++ b/apps/server/src/modules/common-cartridge/testing/common-cartridge-dtos.factory.ts @@ -136,12 +136,23 @@ export const lessonLinkedTaskFactory = Factory.define(() => }; }); +export const lernstoreContentFactory = Factory.define(({ sequence }) => { + return { + id: sequence.toString(), + type: 'lernstore', + content: { resources: [faker.internet.url(), faker.internet.url(), faker.internet.url()] }, + title: faker.lorem.sentence(), + component: 'lernstore', + hidden: faker.datatype.boolean(), + }; +}); + export const lessonContentFactory = Factory.define(({ sequence }) => { return { id: sequence.toString(), type: faker.lorem.word(), content: { text: 'text' }, - title: faker.lorem.word(), + title: faker.lorem.sentence(), component: 'text', hidden: faker.datatype.boolean(), }; @@ -155,7 +166,7 @@ export const lessonFactory = Factory.define(({ sequence }) => { courseGroupId: faker.string.uuid(), hidden: faker.datatype.boolean(), position: faker.number.int(), - contents: lessonContentFactory.buildList(2), + contents: [lessonContentFactory.build(), lernstoreContentFactory.build()], materials: [], linkedTasks: [lessonLinkedTaskFactory.build(), lessonLinkedTaskFactory.build()], }; From d243f2d33ea5c4c2efcccf77ea2fcb235f326a57 Mon Sep 17 00:00:00 2001 From: Firas Shmit Date: Tue, 10 Dec 2024 12:59:33 +0100 Subject: [PATCH 52/61] EW-1060 deleted check for axios error from domain handelr --- apps/server/src/core/error/domain/domain-error-handler.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/apps/server/src/core/error/domain/domain-error-handler.ts b/apps/server/src/core/error/domain/domain-error-handler.ts index ef5748ed600..778dd48026b 100644 --- a/apps/server/src/core/error/domain/domain-error-handler.ts +++ b/apps/server/src/core/error/domain/domain-error-handler.ts @@ -4,8 +4,7 @@ import { ErrorLogger, Loggable, LoggingUtils, LogMessageDataObject } from '@src/ import { ICurrentUser } from '@src/infra/auth-guard'; import { Request } from 'express'; import util from 'util'; -import axios from 'axios'; -import { AxiosErrorLoggable, ErrorLoggable } from '../loggable'; +import { ErrorLoggable } from '../loggable'; @Injectable() export class DomainErrorHandler { @@ -38,8 +37,6 @@ export class DomainErrorHandler { if (LoggingUtils.isInstanceOfLoggable(error)) { loggable = error; - } else if (axios.isAxiosError(error)) { - loggable = new AxiosErrorLoggable(error, 'AXIOS_REQUEST_ERROR'); } else if (error instanceof Error) { loggable = new ErrorLoggable(error, data); } else { From e2d3e0be2eabcb3d2e87d57f0ced5cfe44bde809 Mon Sep 17 00:00:00 2001 From: Firas Shmit Date: Wed, 11 Dec 2024 08:59:17 +0100 Subject: [PATCH 53/61] EW-1060 review changes --- .../board-client/dto/column-skeleton.dto.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/board-client/dto/column-skeleton.dto.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/board-client/dto/column-skeleton.dto.ts index 806e0517fec..1094edefbc4 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/board-client/dto/column-skeleton.dto.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/board-client/dto/column-skeleton.dto.ts @@ -5,7 +5,7 @@ export class ColumnSkeletonDto { title: string; - cards?: CardSkeletonDto[]; + cards: CardSkeletonDto[]; constructor(props: ColumnSkeletonDto) { this.columnId = props.columnId; From 2b389b6c4aa9bb3d64d5b3952da3d2b9cc6c2b8a Mon Sep 17 00:00:00 2001 From: Firas Shmit Date: Wed, 11 Dec 2024 09:09:39 +0100 Subject: [PATCH 54/61] EW-1060 fixed typo --- .../lessons-api-client/models/lesson-content-response.ts | 2 +- .../lesson-client/mapper/lesson-dto.mapper.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lessons-api-client/models/lesson-content-response.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lessons-api-client/models/lesson-content-response.ts index 542789dc1b1..668e233e326 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lessons-api-client/models/lesson-content-response.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/lessons-api-client/models/lesson-content-response.ts @@ -68,7 +68,7 @@ export const LessonContentResponseComponent = { INTERNAL: 'internal', RESOURCES: 'resources', TEXT: 'text', - NE_XBOARD: 'neXboard' + NEX_BOARD: 'neXboard' } as const; export type LessonContentResponseComponent = typeof LessonContentResponseComponent[keyof typeof LessonContentResponseComponent]; diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/mapper/lesson-dto.mapper.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/mapper/lesson-dto.mapper.ts index b479aa77115..a587c984590 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/mapper/lesson-dto.mapper.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/mapper/lesson-dto.mapper.ts @@ -112,7 +112,7 @@ export class LessonDtoMapper { hidden: lessonContentResponse.hidden, content: new ComponentLernstorePropsDto(lessonContentResponse.content as ComponentLernstorePropsImpl), }); - case LessonContentResponseComponent.NE_XBOARD: + case LessonContentResponseComponent.NEX_BOARD: return new LessonContentDto({ id: lessonContentResponse.id, title: lessonContentResponse.title, From 70ab327eb23bdf9f784922ea34646de497d71819 Mon Sep 17 00:00:00 2001 From: Firas Shmit Date: Fri, 13 Dec 2024 10:25:36 +0100 Subject: [PATCH 55/61] EW-1060 added accessibility modifier --- .../card-client/dto/card-list-response.dto.ts | 2 +- .../card-client/dto/card-response.dto.ts | 12 ++++++------ ...orative-text-editor-element-response.dto.ts | 8 ++++---- .../dto/link-element-content.dto.ts | 8 ++++---- .../dto/link-element-response.dto.ts | 8 ++++---- .../dto/rich-text-element-content.dto.ts | 4 ++-- .../dto/rich-text-element-response.dto.ts | 8 ++++---- .../card-client/dto/timestamp-response.dto.ts | 6 +++--- .../dto/component-etherpad-props.dto.ts | 6 +++--- .../dto/component-geogebra-props.dto.ts | 2 +- .../dto/component-internal-props.dto.ts | 2 +- .../dto/component-lernstore-props.dto.ts | 2 +- .../dto/component-nexboard-props-dto.ts | 8 ++++---- .../dto/component-text-props.dto.ts | 2 +- .../lesson-client/dto/lesson-contents.dto.ts | 10 +++++----- .../lesson-client/dto/lesson.dto.ts | 18 +++++++++--------- .../controller/dto/course.query.params.ts | 1 - .../service/common-cartridge.mapper.ts | 4 ++-- 18 files changed, 55 insertions(+), 56 deletions(-) diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/card-list-response.dto.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/card-list-response.dto.ts index ce011649d1b..0d71a967efa 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/card-list-response.dto.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/card-list-response.dto.ts @@ -1,7 +1,7 @@ import { CardResponseDto } from './card-response.dto'; export class CardListResponseDto { - data: CardResponseDto[]; + public data: CardResponseDto[]; constructor(data: CardResponseDto[]) { this.data = data; diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/card-response.dto.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/card-response.dto.ts index 8bfff069b92..c08d4f134ad 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/card-response.dto.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/card-response.dto.ts @@ -3,17 +3,17 @@ import { TimestampResponseDto } from './timestamp-response.dto'; import { VisibilitySettingsResponseDto } from './visibility-settings-response.dto'; export class CardResponseDto { - id: string; + public id: string; - title?: string; + public title?: string; - height: number; + public height: number; - elements: Array; + public elements: Array; - visibilitySettings: VisibilitySettingsResponseDto; + public visibilitySettings: VisibilitySettingsResponseDto; - timeStamps: TimestampResponseDto; + public timeStamps: TimestampResponseDto; constructor(props: Readonly) { this.id = props.id; diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/collaborative-text-editor-element-response.dto.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/collaborative-text-editor-element-response.dto.ts index 7d864480759..b950d0f383d 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/collaborative-text-editor-element-response.dto.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/collaborative-text-editor-element-response.dto.ts @@ -2,13 +2,13 @@ import { ContentElementType } from '../cards-api-client'; import { TimestampResponseDto } from './timestamp-response.dto'; export class CollaborativeTextEditorElementResponseDto { - id: string; + public id: string; - type: ContentElementType; + public type: ContentElementType; - timestamps: TimestampResponseDto; + public timestamps: TimestampResponseDto; - content: object; + public content: object; constructor(id: string, type: ContentElementType, content: object, timestamps: TimestampResponseDto) { this.id = id; diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/link-element-content.dto.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/link-element-content.dto.ts index 0b1d2c14348..1783f4b8def 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/link-element-content.dto.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/link-element-content.dto.ts @@ -1,11 +1,11 @@ export class LinkElementContentDto { - url: string; + public url: string; - title: string; + public title: string; - description?: string; + public description?: string; - imageUrl?: string; + public imageUrl?: string; constructor(props: Readonly) { this.url = props.url; diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/link-element-response.dto.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/link-element-response.dto.ts index a203e076720..589a81945fb 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/link-element-response.dto.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/link-element-response.dto.ts @@ -3,13 +3,13 @@ import { LinkElementContentDto } from './link-element-content.dto'; import { TimestampResponseDto } from './timestamp-response.dto'; export class LinkElementResponseDto { - id: string; + public id: string; - type: ContentElementType; + public type: ContentElementType; - content: LinkElementContentDto; + public content: LinkElementContentDto; - timestamps: TimestampResponseDto; + public timestamps: TimestampResponseDto; constructor(props: LinkElementResponseDto) { this.id = props.id; diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/rich-text-element-content.dto.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/rich-text-element-content.dto.ts index 7726852b1dd..b5649341f87 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/rich-text-element-content.dto.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/rich-text-element-content.dto.ts @@ -1,7 +1,7 @@ export class RichTextElementContentDto { - text: string; + public text: string; - inputFormat: string; + public inputFormat: string; constructor(text: string, inputFormat: string) { this.text = text; diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/rich-text-element-response.dto.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/rich-text-element-response.dto.ts index 66f75d4dce9..9a0ed16f329 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/rich-text-element-response.dto.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/rich-text-element-response.dto.ts @@ -3,13 +3,13 @@ import { RichTextElementContentDto } from './rich-text-element-content.dto'; import { TimestampResponseDto } from './timestamp-response.dto'; export class RichTextElementResponseDto { - id: string; + public id: string; - type: ContentElementType; + public type: ContentElementType; - content: RichTextElementContentDto; + public content: RichTextElementContentDto; - timestamps: TimestampResponseDto; + public timestamps: TimestampResponseDto; constructor(props: Readonly) { this.id = props.id; diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/timestamp-response.dto.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/timestamp-response.dto.ts index 902897ed23f..dcf83d2e696 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/timestamp-response.dto.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/timestamp-response.dto.ts @@ -1,9 +1,9 @@ export class TimestampResponseDto { - lastUpdatedAt: string; + public lastUpdatedAt: string; - createdAt: string; + public createdAt: string; - deletedAt?: string; + public deletedAt?: string; constructor(props: Readonly) { this.lastUpdatedAt = props.lastUpdatedAt; diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-etherpad-props.dto.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-etherpad-props.dto.ts index 085219a56c5..085dcb12af5 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-etherpad-props.dto.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-etherpad-props.dto.ts @@ -1,9 +1,9 @@ export class ComponentEtherpadPropsDto { - description: string; + public description: string; - title: string; + public title: string; - url: string; + public url: string; constructor(props: Readonly) { this.description = props.description; diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-geogebra-props.dto.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-geogebra-props.dto.ts index 02d9e69dbfe..2688370b192 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-geogebra-props.dto.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-geogebra-props.dto.ts @@ -1,7 +1,7 @@ import { ComponentGeogebraPropsImpl } from '../lessons-api-client'; export class ComponentGeogebraPropsDto { - materialId: string; + public materialId: string; constructor(geogebraContent: ComponentGeogebraPropsImpl) { this.materialId = geogebraContent.materialId; diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-internal-props.dto.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-internal-props.dto.ts index c7890bddf19..d896caeee76 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-internal-props.dto.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-internal-props.dto.ts @@ -1,7 +1,7 @@ import { ComponentInternalPropsImpl } from '../lessons-api-client'; export class ComponentInternalPropsDto { - url: string; + public url: string; constructor(internalContent: ComponentInternalPropsImpl) { this.url = internalContent.url; diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-lernstore-props.dto.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-lernstore-props.dto.ts index f2b1ab5de7c..10895739f98 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-lernstore-props.dto.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-lernstore-props.dto.ts @@ -1,7 +1,7 @@ import { ComponentLernstorePropsImpl } from '../lessons-api-client'; export class ComponentLernstorePropsDto { - resources: string[]; + public resources: string[]; constructor(lernstoreContent: ComponentLernstorePropsImpl) { this.resources = lernstoreContent.resources; diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-nexboard-props-dto.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-nexboard-props-dto.ts index 1031af3511f..7115667cffc 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-nexboard-props-dto.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-nexboard-props-dto.ts @@ -1,13 +1,13 @@ import { ComponentNexboardPropsImpl } from '../lessons-api-client'; export class ComponentNexboardPropsDto { - board: string; + public board: string; - description: string; + public description: string; - title: string; + public title: string; - url: string; + public url: string; constructor(nexboardContent: ComponentNexboardPropsImpl) { this.board = nexboardContent.board; diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-text-props.dto.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-text-props.dto.ts index 69176b55ae5..8e5eb7f8493 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-text-props.dto.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/component-text-props.dto.ts @@ -1,7 +1,7 @@ import { ComponentTextPropsImpl } from '../lessons-api-client'; export class ComponentTextPropsDto { - text: string; + public text: string; constructor(textContent: ComponentTextPropsImpl) { this.text = textContent.text; diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/lesson-contents.dto.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/lesson-contents.dto.ts index ce45a7772df..78e5e97e5d3 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/lesson-contents.dto.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/lesson-contents.dto.ts @@ -1,15 +1,15 @@ import { LessonContentResponseContentInnerDto } from './lesson-content-response-inner.dto'; export class LessonContentDto { - id: string | undefined; + public id: string | undefined; - content: LessonContentResponseContentInnerDto; + public content: LessonContentResponseContentInnerDto; - title: string; + public title: string; - component: LessonContentDtoComponent; + public component: LessonContentDtoComponent; - hidden: boolean; + public hidden: boolean; constructor(props: LessonContentDto) { this.content = props.content; diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/lesson.dto.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/lesson.dto.ts index 00dc9c9cb76..69935291c5d 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/lesson.dto.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/lesson.dto.ts @@ -3,23 +3,23 @@ import { LessonLinkedTaskDto } from './lesson-linked-task.dto'; import { LessonMaterialsDto } from './lesson-materials.dto'; export class LessonDto { - lessonId: string; + public lessonId: string; - name: string; + public name: string; - courseId?: string; + public courseId?: string; - courseGroupId?: string; + public courseGroupId?: string; - hidden: boolean; + public hidden: boolean; - position: number; + public position: number; - contents: LessonContentDto[]; + public contents: LessonContentDto[]; - materials: LessonMaterialsDto[]; + public materials: LessonMaterialsDto[]; - linkedTasks?: LessonLinkedTaskDto[]; + public linkedTasks?: LessonLinkedTaskDto[]; constructor(props: LessonDto) { this.lessonId = props.lessonId; diff --git a/apps/server/src/modules/common-cartridge/controller/dto/course.query.params.ts b/apps/server/src/modules/common-cartridge/controller/dto/course.query.params.ts index 6ca66a57442..aa0a1b8bd2b 100644 --- a/apps/server/src/modules/common-cartridge/controller/dto/course.query.params.ts +++ b/apps/server/src/modules/common-cartridge/controller/dto/course.query.params.ts @@ -7,7 +7,6 @@ export class CourseQueryParams { @Matches(Object.values(CommonCartridgeVersion).join('|')) @ApiProperty({ description: 'The version of CC export', - required: true, nullable: false, enum: CommonCartridgeVersion, }) diff --git a/apps/server/src/modules/common-cartridge/service/common-cartridge.mapper.ts b/apps/server/src/modules/common-cartridge/service/common-cartridge.mapper.ts index 0d6ff8f7441..7e594081f99 100644 --- a/apps/server/src/modules/common-cartridge/service/common-cartridge.mapper.ts +++ b/apps/server/src/modules/common-cartridge/service/common-cartridge.mapper.ts @@ -129,7 +129,7 @@ export class CommonCartridgeExportMapper { } public mapTaskToResource(task: BoardTaskDto, version: CommonCartridgeVersion): CommonCartridgeResourceProps { - const intendedUse = (() => { + const intendedUse = ((): CommonCartridgeIntendedUseType => { switch (version) { case CommonCartridgeVersion.V_1_1_0: return CommonCartridgeIntendedUseType.UNSPECIFIED; @@ -153,7 +153,7 @@ export class CommonCartridgeExportMapper { task: LessonLinkedTaskDto, version: CommonCartridgeVersion ): CommonCartridgeResourceProps { - const intendedUse = (() => { + const intendedUse = ((): CommonCartridgeIntendedUseType => { switch (version) { case CommonCartridgeVersion.V_1_1_0: return CommonCartridgeIntendedUseType.UNSPECIFIED; From 5de498b4947c2c3d28d97078f53f886bbb09dddd Mon Sep 17 00:00:00 2001 From: Firas Shmit Date: Fri, 13 Dec 2024 12:39:45 +0100 Subject: [PATCH 56/61] EW-1060 fixed deep imports and add separate factories --- .../room-client/dto/index.ts | 6 ++ .../board-task-status-dto.mapper.spec.ts | 2 +- .../mapper/board-task-status-dto.mapper.ts | 2 +- .../mapper/room-board-dto.mapper.spec.ts | 2 +- .../mapper/room-board-dto.mapper.ts | 6 +- .../room-client/room-client.adapter.spec.ts | 2 +- .../room-client/room-client.adapter.ts | 2 +- .../controller/common-cartridge.controller.ts | 4 +- .../common-cartridge/controller/dto/index.ts | 2 + .../common-cartridge-export.service.spec.ts | 10 +-- .../common-cartridge-export.service.ts | 12 ++-- .../testing/common-cartridge-dtos.factory.ts | 63 +++---------------- .../testing/link-element.factory.ts | 28 +++++++++ .../testing/rich-text-element.factory.ts | 27 ++++++++ 14 files changed, 92 insertions(+), 76 deletions(-) create mode 100644 apps/server/src/modules/common-cartridge/common-cartridge-client/room-client/dto/index.ts create mode 100644 apps/server/src/modules/common-cartridge/testing/link-element.factory.ts create mode 100644 apps/server/src/modules/common-cartridge/testing/rich-text-element.factory.ts diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/room-client/dto/index.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/room-client/dto/index.ts new file mode 100644 index 00000000000..eff692a98e4 --- /dev/null +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/room-client/dto/index.ts @@ -0,0 +1,6 @@ +export { RoomBoardDto } from './room-board.dto'; +export { BoardElementDto } from './board-element.dto'; +export { BoardTaskDto } from './board-task.dto'; +export { BoardTaskStatusDto } from './board-task-status.dto'; +export { BoardLessonDto } from './board-lesson.dto'; +export { BoardColumnBoardDto } from './board-column-board.dto'; diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/room-client/mapper/board-task-status-dto.mapper.spec.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/room-client/mapper/board-task-status-dto.mapper.spec.ts index f38859c9bad..aabb717c7aa 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/room-client/mapper/board-task-status-dto.mapper.spec.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/room-client/mapper/board-task-status-dto.mapper.spec.ts @@ -1,7 +1,7 @@ import { faker } from '@faker-js/faker'; import { BoardTaskStatusResponse } from '../room-api-client'; import { BoardTaskStatusMapper } from './board-task-status-dto.mapper'; -import { BoardTaskStatusDto } from '../dto/board-task-status.dto'; +import { BoardTaskStatusDto } from '../dto'; describe(BoardTaskStatusMapper.name, () => { describe('mapBoardTaskStatusToDto', () => { diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/room-client/mapper/board-task-status-dto.mapper.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/room-client/mapper/board-task-status-dto.mapper.ts index c4834f148f9..709533afaeb 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/room-client/mapper/board-task-status-dto.mapper.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/room-client/mapper/board-task-status-dto.mapper.ts @@ -1,4 +1,4 @@ -import { BoardTaskStatusDto } from '../dto/board-task-status.dto'; +import { BoardTaskStatusDto } from '../dto'; import { BoardTaskStatusResponse } from '../room-api-client'; export class BoardTaskStatusMapper { diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/room-client/mapper/room-board-dto.mapper.spec.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/room-client/mapper/room-board-dto.mapper.spec.ts index 037ba49cae7..f1fc542b2b0 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/room-client/mapper/room-board-dto.mapper.spec.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/room-client/mapper/room-board-dto.mapper.spec.ts @@ -8,7 +8,7 @@ import { SingleColumnBoardResponse, } from '../room-api-client'; import { RoomBoardDtoMapper } from './room-board-dto.mapper'; -import { BoardTaskStatusDto } from '../dto/board-task-status.dto'; +import { BoardTaskStatusDto } from '../dto'; describe(RoomBoardDtoMapper.name, () => { describe('mapResponseToRoomBoardDto', () => { diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/room-client/mapper/room-board-dto.mapper.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/room-client/mapper/room-board-dto.mapper.ts index 6bacca7eff6..5074e143e98 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/room-client/mapper/room-board-dto.mapper.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/room-client/mapper/room-board-dto.mapper.ts @@ -1,8 +1,4 @@ -import { BoardColumnBoardDto } from '../dto/board-column-board.dto'; -import { BoardElementDto } from '../dto/board-element.dto'; -import { BoardLessonDto } from '../dto/board-lesson.dto'; -import { BoardTaskDto } from '../dto/board-task.dto'; -import { RoomBoardDto } from '../dto/room-board.dto'; +import { RoomBoardDto, BoardTaskDto, BoardLessonDto, BoardElementDto, BoardColumnBoardDto } from '../dto'; import { BoardElementDtoType } from '../enums/board-element.enum'; import { BoardColumnBoardResponse, diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/room-client/room-client.adapter.spec.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/room-client/room-client.adapter.spec.ts index 63ff0dbf697..56264183d89 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/room-client/room-client.adapter.spec.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/room-client/room-client.adapter.spec.ts @@ -8,7 +8,7 @@ import { jest } from '@jest/globals'; import { CourseRoomsApi, SingleColumnBoardResponse } from './room-api-client'; import { CourseRoomsClientAdapter } from './room-client.adapter'; import { RoomBoardDtoMapper } from './mapper/room-board-dto.mapper'; -import { RoomBoardDto } from './dto/room-board.dto'; +import { RoomBoardDto } from './dto'; const jwtToken = 'dummyJwtToken'; diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/room-client/room-client.adapter.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/room-client/room-client.adapter.ts index b53c3932334..b11354c8d4d 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/room-client/room-client.adapter.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/room-client/room-client.adapter.ts @@ -4,7 +4,7 @@ import { Request } from 'express'; import { extractJwtFromHeader } from '@shared/common'; import { RawAxiosRequestConfig } from 'axios'; import { CourseRoomsApi } from './room-api-client'; -import { RoomBoardDto } from './dto/room-board.dto'; +import { RoomBoardDto } from './dto'; import { RoomBoardDtoMapper } from './mapper/room-board-dto.mapper'; @Injectable() diff --git a/apps/server/src/modules/common-cartridge/controller/common-cartridge.controller.ts b/apps/server/src/modules/common-cartridge/controller/common-cartridge.controller.ts index f0a62fafe5f..80e1e5d10ea 100644 --- a/apps/server/src/modules/common-cartridge/controller/common-cartridge.controller.ts +++ b/apps/server/src/modules/common-cartridge/controller/common-cartridge.controller.ts @@ -2,9 +2,7 @@ import { Body, Controller, Param, Post, Query, Res, StreamableFile } from '@nest import { ApiTags } from '@nestjs/swagger'; import { Response } from 'express'; import { CommonCartridgeUc } from '../uc/common-cartridge.uc'; -import { ExportCourseParams } from './dto'; -import { CourseQueryParams } from './dto/course.query.params'; -import { CourseExportBodyParams } from './dto/course-export.body.params'; +import { ExportCourseParams, CourseQueryParams, CourseExportBodyParams } from './dto'; @ApiTags('common-cartridge') @Controller('common-cartridge') diff --git a/apps/server/src/modules/common-cartridge/controller/dto/index.ts b/apps/server/src/modules/common-cartridge/controller/dto/index.ts index e93173f89f7..6f0d5c3e079 100644 --- a/apps/server/src/modules/common-cartridge/controller/dto/index.ts +++ b/apps/server/src/modules/common-cartridge/controller/dto/index.ts @@ -1,2 +1,4 @@ export * from './common-cartridge.params'; export * from './common-cartridge.response'; +export * from './course.query.params'; +export * from './course-export.body.params'; diff --git a/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.spec.ts b/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.spec.ts index 276f38b75d8..8dd4f206d43 100644 --- a/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.spec.ts +++ b/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.spec.ts @@ -10,7 +10,12 @@ import { CardClientAdapter } from '../common-cartridge-client/card-client/card-c import { LessonClientAdapter } from '../common-cartridge-client/lesson-client/lesson-client.adapter'; import { CommonCartridgeExportMapper } from './common-cartridge.mapper'; import { CommonCartridgeVersion } from '../export/common-cartridge.enums'; -import { RoomBoardDto } from '../common-cartridge-client/room-client/dto/room-board.dto'; +import { + RoomBoardDto, + BoardTaskDto, + BoardLessonDto, + BoardColumnBoardDto, +} from '../common-cartridge-client/room-client/dto'; import { RichTextElementContentDto } from '../common-cartridge-client/card-client/dto/rich-text-element-content.dto'; import { LinkElementContentDto } from '../common-cartridge-client/card-client/dto/link-element-content.dto'; import { @@ -24,9 +29,6 @@ import { roomFactory, } from '../testing/common-cartridge-dtos.factory'; import { CardListResponseDto } from '../common-cartridge-client/card-client/dto/card-list-response.dto'; -import { BoardTaskDto } from '../common-cartridge-client/room-client/dto/board-task.dto'; -import { BoardLessonDto } from '../common-cartridge-client/room-client/dto/board-lesson.dto'; -import { BoardColumnBoardDto } from '../common-cartridge-client/room-client/dto/board-column-board.dto'; describe('CommonCartridgeExportService', () => { let module: TestingModule; diff --git a/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts b/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts index 96be753b89b..c61bf7a16e1 100644 --- a/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts +++ b/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts @@ -2,20 +2,22 @@ import { Injectable } from '@nestjs/common'; import { BoardClientAdapter, BoardSkeletonDto, ColumnSkeletonDto } from '../common-cartridge-client/board-client'; import { CourseCommonCartridgeMetadataDto, CoursesClientAdapter } from '../common-cartridge-client/course-client'; import { CourseRoomsClientAdapter } from '../common-cartridge-client/room-client'; -import { RoomBoardDto } from '../common-cartridge-client/room-client/dto/room-board.dto'; +import { + RoomBoardDto, + BoardElementDto, + BoardColumnBoardDto, + BoardLessonDto, + BoardTaskDto, +} from '../common-cartridge-client/room-client/dto'; import { CardClientAdapter } from '../common-cartridge-client/card-client/card-client.adapter'; import { CardListResponseDto } from '../common-cartridge-client/card-client/dto/card-list-response.dto'; import { LessonClientAdapter } from '../common-cartridge-client/lesson-client/lesson-client.adapter'; -import { BoardColumnBoardDto } from '../common-cartridge-client/room-client/dto/board-column-board.dto'; -import { BoardLessonDto } from '../common-cartridge-client/room-client/dto/board-lesson.dto'; import { LessonContentDto, LessonDto } from '../common-cartridge-client/lesson-client/dto'; import { CommonCartridgeFileBuilder } from '../export/builders/common-cartridge-file-builder'; import { CommonCartridgeVersion } from '../export/common-cartridge.enums'; import { CommonCartridgeExportMapper } from './common-cartridge.mapper'; import { CommonCartridgeOrganizationNode } from '../export/builders/common-cartridge-organization-node'; -import { BoardTaskDto } from '../common-cartridge-client/room-client/dto/board-task.dto'; import { createIdentifier } from '../export/utils'; -import { BoardElementDto } from '../common-cartridge-client/room-client/dto/board-element.dto'; import { BoardElementDtoType } from '../common-cartridge-client/room-client/enums/board-element.enum'; import { CardResponseDto } from '../common-cartridge-client/card-client/dto/card-response.dto'; import { CardResponseElementsInnerDto } from '../common-cartridge-client/card-client/types/card-response-elements-inner.type'; diff --git a/apps/server/src/modules/common-cartridge/testing/common-cartridge-dtos.factory.ts b/apps/server/src/modules/common-cartridge/testing/common-cartridge-dtos.factory.ts index cf8805c4182..f4978330dc3 100644 --- a/apps/server/src/modules/common-cartridge/testing/common-cartridge-dtos.factory.ts +++ b/apps/server/src/modules/common-cartridge/testing/common-cartridge-dtos.factory.ts @@ -1,23 +1,21 @@ import { faker } from '@faker-js/faker'; import { Factory } from 'fishery'; -import { BaseFactory } from '@shared/testing'; import { CourseCommonCartridgeMetadataDto } from '../common-cartridge-client/course-client'; import { LessonContentDto, LessonDto, LessonLinkedTaskDto } from '../common-cartridge-client/lesson-client/dto'; import { BoardSkeletonDto, CardSkeletonDto, ColumnSkeletonDto } from '../common-cartridge-client/board-client'; import { CardListResponseDto } from '../common-cartridge-client/card-client/dto/card-list-response.dto'; import { CardResponseDto } from '../common-cartridge-client/card-client/dto/card-response.dto'; -import { ContentElementType } from '../common-cartridge-client/card-client/enums/content-element-type.enum'; -import { BoardTaskDto } from '../common-cartridge-client/room-client/dto/board-task.dto'; -import { BoardTaskStatusDto } from '../common-cartridge-client/room-client/dto/board-task-status.dto'; -import { RoomBoardDto } from '../common-cartridge-client/room-client/dto/room-board.dto'; +import { + RoomBoardDto, + BoardTaskStatusDto, + BoardTaskDto, + BoardLessonDto, + BoardColumnBoardDto, +} from '../common-cartridge-client/room-client/dto'; import { BoardElementDtoType } from '../common-cartridge-client/room-client/enums/board-element.enum'; -import { BoardLessonDto } from '../common-cartridge-client/room-client/dto/board-lesson.dto'; -import { BoardColumnBoardDto } from '../common-cartridge-client/room-client/dto/board-column-board.dto'; import { BoardLayout } from '../common-cartridge-client/room-client/enums/board-layout.enum'; -import { RichTextElementContentDto } from '../common-cartridge-client/card-client/dto/rich-text-element-content.dto'; -import { LinkElementContentDto } from '../common-cartridge-client/card-client/dto/link-element-content.dto'; -import { RichTextElementResponseDto } from '../common-cartridge-client/card-client/dto/rich-text-element-response.dto'; -import { LinkElementResponseDto } from '../common-cartridge-client/card-client/dto/link-element-response.dto'; +import { richTextElementFactroy } from './rich-text-element.factory'; +import { linkElementFactory } from './link-element.factory'; export const courseMetadataFactory = Factory.define(({ sequence }) => { return { @@ -53,49 +51,6 @@ export const columnBoardFactory = Factory.define(({ sequence } }; }); -export const richTextElementContentFactory = Factory.define(() => { - return { - text: faker.lorem.word(), - inputFormat: 'plainText', - }; -}); - -class RichTextElement extends BaseFactory> {} -export const richTextElementFactroy = RichTextElement.define(RichTextElementResponseDto, () => { - return { - id: faker.string.uuid(), - type: ContentElementType.RICH_TEXT, - content: richTextElementContentFactory.build(), - timestamps: { - lastUpdatedAt: faker.date.recent().toISOString(), - createdAt: faker.date.recent().toISOString(), - deletedAt: undefined, - }, - }; -}); - -export const linkElementContentFactory = Factory.define(() => { - return { - url: faker.internet.url(), - title: faker.lorem.word(), - description: faker.lorem.sentence(), - }; -}); - -class LinkElementFactory extends BaseFactory> {} -export const linkElementFactory = LinkElementFactory.define(LinkElementResponseDto, () => { - return { - id: faker.string.uuid(), - type: ContentElementType.LINK, - content: linkElementContentFactory.build(), - timestamps: { - lastUpdatedAt: faker.date.recent().toISOString(), - createdAt: faker.date.recent().toISOString(), - deletedAt: undefined, - }, - }; -}); - export const cardResponseFactory = Factory.define(({ sequence }) => { return { id: sequence.toString(), diff --git a/apps/server/src/modules/common-cartridge/testing/link-element.factory.ts b/apps/server/src/modules/common-cartridge/testing/link-element.factory.ts new file mode 100644 index 00000000000..726e711d765 --- /dev/null +++ b/apps/server/src/modules/common-cartridge/testing/link-element.factory.ts @@ -0,0 +1,28 @@ +import { faker } from '@faker-js/faker'; +import { BaseFactory } from '@shared/testing'; +import { Factory } from 'fishery'; +import { LinkElementContentDto } from '../common-cartridge-client/card-client/dto/link-element-content.dto'; +import { LinkElementResponseDto } from '../common-cartridge-client/card-client/dto/link-element-response.dto'; +import { ContentElementType } from '../common-cartridge-client/card-client/enums/content-element-type.enum'; + +export const linkElementContentFactory = Factory.define(() => { + return { + url: faker.internet.url(), + title: faker.lorem.word(), + description: faker.lorem.sentence(), + }; +}); + +class LinkElementFactory extends BaseFactory> {} +export const linkElementFactory = LinkElementFactory.define(LinkElementResponseDto, () => { + return { + id: faker.string.uuid(), + type: ContentElementType.LINK, + content: linkElementContentFactory.build(), + timestamps: { + lastUpdatedAt: faker.date.recent().toISOString(), + createdAt: faker.date.recent().toISOString(), + deletedAt: undefined, + }, + }; +}); diff --git a/apps/server/src/modules/common-cartridge/testing/rich-text-element.factory.ts b/apps/server/src/modules/common-cartridge/testing/rich-text-element.factory.ts new file mode 100644 index 00000000000..01e880ae0de --- /dev/null +++ b/apps/server/src/modules/common-cartridge/testing/rich-text-element.factory.ts @@ -0,0 +1,27 @@ +import { BaseFactory } from '@shared/testing'; +import { faker } from '@faker-js/faker'; +import { Factory } from 'fishery'; +import { RichTextElementResponseDto } from '../common-cartridge-client/card-client/dto/rich-text-element-response.dto'; +import { RichTextElementContentDto } from '../common-cartridge-client/card-client/dto/rich-text-element-content.dto'; +import { ContentElementType } from '../common-cartridge-client/card-client/enums/content-element-type.enum'; + +export const richTextElementContentFactory = Factory.define(() => { + return { + text: faker.lorem.word(), + inputFormat: 'plainText', + }; +}); + +class RichTextElement extends BaseFactory> {} +export const richTextElementFactroy = RichTextElement.define(RichTextElementResponseDto, () => { + return { + id: faker.string.uuid(), + type: ContentElementType.RICH_TEXT, + content: richTextElementContentFactory.build(), + timestamps: { + lastUpdatedAt: faker.date.recent().toISOString(), + createdAt: faker.date.recent().toISOString(), + deletedAt: undefined, + }, + }; +}); From 9b5e8f7e6499e14cbca1c6a3c05fc675ddced3b4 Mon Sep 17 00:00:00 2001 From: Firas Shmit Date: Fri, 13 Dec 2024 12:53:36 +0100 Subject: [PATCH 57/61] EW-1060 modified imports of CC mapper --- .../common-cartridge/service/common-cartridge.mapper.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/server/src/modules/common-cartridge/service/common-cartridge.mapper.spec.ts b/apps/server/src/modules/common-cartridge/service/common-cartridge.mapper.spec.ts index 33b675071c4..a4bbafa1423 100644 --- a/apps/server/src/modules/common-cartridge/service/common-cartridge.mapper.spec.ts +++ b/apps/server/src/modules/common-cartridge/service/common-cartridge.mapper.spec.ts @@ -7,9 +7,9 @@ import { lessonContentFactory, lessonFactory, lessonLinkedTaskFactory, - linkElementFactory, - richTextElementFactroy, } from '../testing/common-cartridge-dtos.factory'; +import { linkElementFactory } from '../testing/link-element.factory'; +import { richTextElementFactroy } from '../testing/rich-text-element.factory'; import { CommonCartridgeElementType, CommonCartridgeIntendedUseType, From 7ae761d7348d7a005a1c6dc4e1a3837cb1b40862 Mon Sep 17 00:00:00 2001 From: Firas Shmit Date: Fri, 13 Dec 2024 13:41:15 +0100 Subject: [PATCH 58/61] EW-1060 modified deep imports of some dtos --- .../common-cartridge-client/card-client/dto/index.ts | 8 ++++++++ .../service/common-cartridge-export.service.spec.ts | 8 +++++--- .../service/common-cartridge-export.service.ts | 10 ++++++---- .../lesson/controller/dto/lesson-content.response.ts | 1 + 4 files changed, 20 insertions(+), 7 deletions(-) create mode 100644 apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/index.ts diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/index.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/index.ts new file mode 100644 index 00000000000..64c051f06c7 --- /dev/null +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/index.ts @@ -0,0 +1,8 @@ +export { RichTextElementResponseDto } from './rich-text-element-response.dto'; +export { RichTextElementContentDto } from './rich-text-element-content.dto'; +export { LinkElementContentDto } from './link-element-content.dto'; +export { LinkElementResponseDto } from './link-element-response.dto'; +export { CardResponseDto } from './card-response.dto'; +export { CardListResponseDto } from './card-list-response.dto'; +export { TimestampResponseDto } from './timestamp-response.dto'; +export { VisibilitySettingsResponseDto } from './visibility-settings-response.dto'; diff --git a/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.spec.ts b/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.spec.ts index 8dd4f206d43..1e2d7fab28b 100644 --- a/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.spec.ts +++ b/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.spec.ts @@ -16,8 +16,11 @@ import { BoardLessonDto, BoardColumnBoardDto, } from '../common-cartridge-client/room-client/dto'; -import { RichTextElementContentDto } from '../common-cartridge-client/card-client/dto/rich-text-element-content.dto'; -import { LinkElementContentDto } from '../common-cartridge-client/card-client/dto/link-element-content.dto'; +import { + RichTextElementContentDto, + LinkElementContentDto, + CardListResponseDto, +} from '../common-cartridge-client/card-client/dto'; import { boardCloumnBoardFactory, boardLessonFactory, @@ -28,7 +31,6 @@ import { listOfCardResponseFactory, roomFactory, } from '../testing/common-cartridge-dtos.factory'; -import { CardListResponseDto } from '../common-cartridge-client/card-client/dto/card-list-response.dto'; describe('CommonCartridgeExportService', () => { let module: TestingModule; diff --git a/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts b/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts index c61bf7a16e1..586106f3308 100644 --- a/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts +++ b/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts @@ -10,7 +10,6 @@ import { BoardTaskDto, } from '../common-cartridge-client/room-client/dto'; import { CardClientAdapter } from '../common-cartridge-client/card-client/card-client.adapter'; -import { CardListResponseDto } from '../common-cartridge-client/card-client/dto/card-list-response.dto'; import { LessonClientAdapter } from '../common-cartridge-client/lesson-client/lesson-client.adapter'; import { LessonContentDto, LessonDto } from '../common-cartridge-client/lesson-client/dto'; import { CommonCartridgeFileBuilder } from '../export/builders/common-cartridge-file-builder'; @@ -19,10 +18,13 @@ import { CommonCartridgeExportMapper } from './common-cartridge.mapper'; import { CommonCartridgeOrganizationNode } from '../export/builders/common-cartridge-organization-node'; import { createIdentifier } from '../export/utils'; import { BoardElementDtoType } from '../common-cartridge-client/room-client/enums/board-element.enum'; -import { CardResponseDto } from '../common-cartridge-client/card-client/dto/card-response.dto'; import { CardResponseElementsInnerDto } from '../common-cartridge-client/card-client/types/card-response-elements-inner.type'; -import { RichTextElementResponseDto } from '../common-cartridge-client/card-client/dto/rich-text-element-response.dto'; -import { LinkElementResponseDto } from '../common-cartridge-client/card-client/dto/link-element-response.dto'; +import { + RichTextElementResponseDto, + LinkElementResponseDto, + CardListResponseDto, + CardResponseDto, +} from '../common-cartridge-client/card-client/dto'; const isRichTextElement = (reference: unknown): reference is RichTextElementResponseDto => reference instanceof RichTextElementResponseDto; diff --git a/apps/server/src/modules/lesson/controller/dto/lesson-content.response.ts b/apps/server/src/modules/lesson/controller/dto/lesson-content.response.ts index 86844f8f2c2..3a52a17b47b 100644 --- a/apps/server/src/modules/lesson/controller/dto/lesson-content.response.ts +++ b/apps/server/src/modules/lesson/controller/dto/lesson-content.response.ts @@ -11,6 +11,7 @@ import { ComponentType, } from '@shared/domain/entity/lesson.entity'; +// eslint problem will be solved in EW-1090 class ComponentTextPropsImpl implements ComponentTextProperties { @ApiProperty({ nullable: false }) text!: string; From 01d36c392ef3b7642c8aaad3f74ac3d7aa8aad1d Mon Sep 17 00:00:00 2001 From: Firas Shmit Date: Fri, 13 Dec 2024 15:19:50 +0100 Subject: [PATCH 59/61] EW-1060 covered code with tests --- .../common-cartridge-export.service.spec.ts | 30 +++++++++++++++++-- .../common-cartridge-export.service.ts | 2 +- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.spec.ts b/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.spec.ts index 1e2d7fab28b..ffc209887a4 100644 --- a/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.spec.ts +++ b/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.spec.ts @@ -304,7 +304,7 @@ describe('CommonCartridgeExportService', () => { }); }); - describe('When topics array is empty', () => { + describe('when topics array is empty', () => { const setup = async () => setupParams(CommonCartridgeVersion.V_1_1_0, false, true, true); it("shouldn't add lessons", async () => { @@ -316,7 +316,7 @@ describe('CommonCartridgeExportService', () => { }); }); - describe('When tasks array is empty', () => { + describe('when tasks array is empty', () => { const setup = async () => setupParams(CommonCartridgeVersion.V_1_1_0, true, false, true); it("shouldn't add tasks", async () => { @@ -326,7 +326,7 @@ describe('CommonCartridgeExportService', () => { }); }); - describe('When columnBoards array is empty', () => { + describe('when columnBoards array is empty', () => { const setup = async () => setupParams(CommonCartridgeVersion.V_1_1_0, true, true, false); it("shouldn't add column boards", async () => { @@ -337,5 +337,29 @@ describe('CommonCartridgeExportService', () => { ); }); }); + + describe('when topics has no linked tasks', () => { + const setup = async () => setupParams(CommonCartridgeVersion.V_1_1_0, false, true, true); + + it('should add lesson without linked tasks', async () => { + const { archive, lesson } = await setup(); + lesson.linkedTasks = undefined; + + expect(getFileContent(archive, 'imsmanifest.xml')).not.toContain(createXmlString('title', lesson.name)); + }); + }); + + describe('when columnBoards has no cards', () => { + const setup = async () => setupParams(CommonCartridgeVersion.V_1_1_0, true, true, false); + + it('should add column boards without cards', async () => { + const { archive, boardSkeleton } = await setup(); + boardSkeleton.columns[0].cards = []; + + expect(getFileContent(archive, 'imsmanifest.xml')).not.toContain( + createXmlString('title', boardSkeleton.columns[0].title) + ); + }); + }); }); }); diff --git a/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts b/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts index 586106f3308..0628e8579ba 100644 --- a/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts +++ b/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts @@ -168,7 +168,7 @@ export class CommonCartridgeExportService { identifier: createIdentifier(columnId), }); - if (column.cards?.length) { + if (column.cards.length) { const cardsIds = column.cards.map((card) => card.cardId); const listOfCards: CardListResponseDto = await this.findAllCardsByIds(cardsIds); From 2d480a29b68b4159200d1bd815e489ff7302a431 Mon Sep 17 00:00:00 2001 From: Firas Shmit Date: Fri, 13 Dec 2024 16:18:11 +0100 Subject: [PATCH 60/61] EW-1060 modified linked task of topic --- .../lesson-client/dto/lesson.dto.ts | 2 +- .../lesson-client/mapper/lesson-dto.mapper.ts | 1 + .../common-cartridge-export.service.spec.ts | 28 ++----------------- .../common-cartridge-export.service.ts | 2 +- 4 files changed, 5 insertions(+), 28 deletions(-) diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/lesson.dto.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/lesson.dto.ts index 69935291c5d..1385d6136e1 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/lesson.dto.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/dto/lesson.dto.ts @@ -19,7 +19,7 @@ export class LessonDto { public materials: LessonMaterialsDto[]; - public linkedTasks?: LessonLinkedTaskDto[]; + public linkedTasks: LessonLinkedTaskDto[]; constructor(props: LessonDto) { this.lessonId = props.lessonId; diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/mapper/lesson-dto.mapper.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/mapper/lesson-dto.mapper.ts index a587c984590..aeeeba2cf3a 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/mapper/lesson-dto.mapper.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/lesson-client/mapper/lesson-dto.mapper.ts @@ -50,6 +50,7 @@ export class LessonDtoMapper { contents: lessonResponse.contents .map((content) => this.mapToLessenContentDto(content)) .filter((contetnDto) => contetnDto !== null), + linkedTasks: [], materials: lessonResponse.materials.map((material) => this.mapToLessonMaterialDto(material)), }); diff --git a/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.spec.ts b/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.spec.ts index ffc209887a4..769de8f23ed 100644 --- a/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.spec.ts +++ b/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.spec.ts @@ -185,7 +185,7 @@ describe('CommonCartridgeExportService', () => { const { archive, lesson } = await setup(); const manifest = archive.getEntry('imsmanifest.xml')?.getData().toString(); - lesson.linkedTasks?.forEach((linkedTask) => { + lesson.linkedTasks.forEach((linkedTask) => { expect(manifest).toContain(`${linkedTask.name}`); }); }); @@ -254,7 +254,7 @@ describe('CommonCartridgeExportService', () => { const { archive, lesson } = await setup(); const manifest = archive.getEntry('imsmanifest.xml')?.getData().toString(); - lesson.linkedTasks?.forEach((linkedTask) => { + lesson.linkedTasks.forEach((linkedTask) => { expect(manifest).toContain(`${linkedTask.name}`); }); }); @@ -337,29 +337,5 @@ describe('CommonCartridgeExportService', () => { ); }); }); - - describe('when topics has no linked tasks', () => { - const setup = async () => setupParams(CommonCartridgeVersion.V_1_1_0, false, true, true); - - it('should add lesson without linked tasks', async () => { - const { archive, lesson } = await setup(); - lesson.linkedTasks = undefined; - - expect(getFileContent(archive, 'imsmanifest.xml')).not.toContain(createXmlString('title', lesson.name)); - }); - }); - - describe('when columnBoards has no cards', () => { - const setup = async () => setupParams(CommonCartridgeVersion.V_1_1_0, true, true, false); - - it('should add column boards without cards', async () => { - const { archive, boardSkeleton } = await setup(); - boardSkeleton.columns[0].cards = []; - - expect(getFileContent(archive, 'imsmanifest.xml')).not.toContain( - createXmlString('title', boardSkeleton.columns[0].title) - ); - }); - }); }); }); diff --git a/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts b/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts index 0628e8579ba..5a708fda0d3 100644 --- a/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts +++ b/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts @@ -106,7 +106,7 @@ export class CommonCartridgeExportService { this.addComponentToOrganization(content, lessonsOrganization); }); - lesson.linkedTasks?.forEach((task) => { + lesson.linkedTasks.forEach((task) => { lessonsOrganization.addResource(this.mapper.mapLinkedTaskToResource(task, version)); }); }); From 1071e4ee96f1c4fa69029b38106a65e97b6a54cb Mon Sep 17 00:00:00 2001 From: Firas Shmit Date: Wed, 18 Dec 2024 14:46:25 +0100 Subject: [PATCH 61/61] removed check of elements to dtos --- .../card-client/dto/link-element-response.dto.ts | 4 ++++ .../card-client/dto/rich-text-element-response.dto.ts | 4 ++++ .../service/common-cartridge-export.service.ts | 10 ++-------- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/link-element-response.dto.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/link-element-response.dto.ts index 589a81945fb..1e11e34450a 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/link-element-response.dto.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/link-element-response.dto.ts @@ -17,4 +17,8 @@ export class LinkElementResponseDto { this.content = props.content; this.timestamps = props.timestamps; } + + public static isLinkElement(reference: unknown): reference is LinkElementResponseDto { + return reference instanceof LinkElementResponseDto; + } } diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/rich-text-element-response.dto.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/rich-text-element-response.dto.ts index 9a0ed16f329..162575ade32 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/rich-text-element-response.dto.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-client/card-client/dto/rich-text-element-response.dto.ts @@ -17,4 +17,8 @@ export class RichTextElementResponseDto { this.content = props.content; this.timestamps = props.timestamps; } + + public static isRichTextElement(reference: unknown): reference is RichTextElementResponseDto { + return reference instanceof RichTextElementResponseDto; + } } diff --git a/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts b/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts index 5a708fda0d3..49fe182de05 100644 --- a/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts +++ b/apps/server/src/modules/common-cartridge/service/common-cartridge-export.service.ts @@ -26,12 +26,6 @@ import { CardResponseDto, } from '../common-cartridge-client/card-client/dto'; -const isRichTextElement = (reference: unknown): reference is RichTextElementResponseDto => - reference instanceof RichTextElementResponseDto; - -const isLinkElement = (reference: unknown): reference is LinkElementResponseDto => - reference instanceof LinkElementResponseDto; - @Injectable() export class CommonCartridgeExportService { constructor( @@ -193,13 +187,13 @@ export class CommonCartridgeExportService { element: CardResponseElementsInnerDto, cardOrganization: CommonCartridgeOrganizationNode ): void { - if (isRichTextElement(element)) { + if (RichTextElementResponseDto.isRichTextElement(element)) { const resource = this.mapper.mapRichTextElementToResource(element); cardOrganization.addResource(resource); } - if (isLinkElement(element)) { + if (LinkElementResponseDto.isLinkElement(element)) { const resource = this.mapper.mapLinkElementToResource(element); cardOrganization.addResource(resource);