diff --git a/apps/server/src/modules/learnroom/controller/rooms.controller.ts b/apps/server/src/modules/learnroom/controller/rooms.controller.ts index fe8f8d67671..0e0b2f7c7a0 100644 --- a/apps/server/src/modules/learnroom/controller/rooms.controller.ts +++ b/apps/server/src/modules/learnroom/controller/rooms.controller.ts @@ -2,7 +2,7 @@ import { Body, Controller, Get, Param, Patch, Post } from '@nestjs/common'; import { ApiTags } from '@nestjs/swagger'; import { RequestTimeout } from '@shared/common'; import { ICurrentUser, Authenticate, CurrentUser } from '@modules/authentication'; -import { CopyApiResponse, CopyElementType, CopyMapper } from '@modules/copy-helper'; +import { CopyApiResponse, CopyMapper } from '@modules/copy-helper'; import { serverConfig } from '@modules/server/server.config'; import { RoomBoardResponseMapper } from '../mapper/room-board-response.mapper'; import { CourseCopyUC } from '../uc/course-copy.uc'; diff --git a/apps/server/src/modules/lesson/service/lesson-copy.service.spec.ts b/apps/server/src/modules/lesson/service/lesson-copy.service.spec.ts index 91e20a54668..11432af777f 100644 --- a/apps/server/src/modules/lesson/service/lesson-copy.service.spec.ts +++ b/apps/server/src/modules/lesson/service/lesson-copy.service.spec.ts @@ -176,21 +176,105 @@ describe('lesson copy service', () => { expect(lesson.hidden).toEqual(true); }); - describe('the response', () => { - it('should set status title to the name of the lesson', async () => { - const { destinationCourse, originalLesson, user, copyName } = setup(); + describe('the response', () => { + it('should set status title to the name of the lesson', async () => { + const { destinationCourse, originalLesson, user, copyName } = setup(); + + const status = await copyService.copyLesson({ + originalLessonId: originalLesson.id, + destinationCourse, + user, + copyName, + }); + + expect(status.title).toEqual(copyName); + }); + + it('should set status type to lesson', async () => { + const { user, destinationCourse, originalLesson } = setup(); + + const status = await copyService.copyLesson({ + originalLessonId: originalLesson.id, + destinationCourse, + user, + }); + + expect(status.type).toEqual(CopyElementType.LESSON); + }); + + it('should set status originalEntity to original lesson', async () => { + const { user, destinationCourse, originalLesson } = setup(); + + const status = await copyService.copyLesson({ + originalLessonId: originalLesson.id, + destinationCourse, + user, + }); + + expect(status.originalEntity).toEqual(originalLesson); + }); + + it('should set lesson status', async () => { + const { user, destinationCourse, originalLesson } = setup(); + + const status = await copyService.copyLesson({ + originalLessonId: originalLesson.id, + destinationCourse, + user, + }); + + expect(status.status).toEqual(CopyStatusEnum.SUCCESS); + }); + + it('should set status of metadata', async () => { + const { user, destinationCourse, originalLesson } = setup(); + + const status = await copyService.copyLesson({ + originalLessonId: originalLesson.id, + destinationCourse, + user, + }); + + const metadataStatus = status.elements?.find((el) => el.type === CopyElementType.METADATA); + expect(metadataStatus).toBeDefined(); + expect(metadataStatus?.status).toEqual(CopyStatusEnum.SUCCESS); + }); + }); + }); + + describe('when copying into a different course', () => { + it('should set destination course as course of the copy', async () => { + const originalCourse = courseFactory.build({}); + const destinationCourse = courseFactory.buildWithId(); + const user = userFactory.build({}); + const originalLesson = lessonFactory.build({ course: originalCourse }); + lessonRepo.findById.mockResolvedValueOnce(originalLesson); const status = await copyService.copyLesson({ originalLessonId: originalLesson.id, destinationCourse, user, - copyName, }); + const lesson = status.copyEntity as LessonEntity; - expect(status.title).toEqual(copyName); + expect(lesson.course).toEqual(destinationCourse); }); + }); + + describe('when lesson contains no content', () => { + const setup = () => { + const user = userFactory.build(); + const originalCourse = courseFactory.build({ school: user.school }); + const destinationCourse = courseFactory.build({ school: user.school, teachers: [user] }); + const originalLesson = lessonFactory.build({ + course: originalCourse, + }); + lessonRepo.findById.mockResolvedValueOnce(originalLesson); + + return { user, originalCourse, destinationCourse, originalLesson }; + }; - it('should set status type to lesson', async () => { + it('contents array of copied lesson should be empty', async () => { const { user, destinationCourse, originalLesson } = setup(); const status = await copyService.copyLesson({ @@ -199,10 +283,12 @@ describe('lesson copy service', () => { user, }); - expect(status.type).toEqual(CopyElementType.LESSON); + const lesson = status.copyEntity as LessonEntity; + + expect(lesson.contents.length).toEqual(0); }); - it('should set status originalEntity to original lesson', async () => { + it('should not set contents status group', async () => { const { user, destinationCourse, originalLesson } = setup(); const status = await copyService.copyLesson({ @@ -210,11 +296,50 @@ describe('lesson copy service', () => { destinationCourse, user, }); - - expect(status.originalEntity).toEqual(originalLesson); + const contentsStatus = status.elements?.find((el) => el.type === CopyElementType.LESSON_CONTENT_GROUP); + expect(contentsStatus).not.toBeDefined(); }); + }); + + describe('when lesson contains at least one content element', () => { + const setup = () => { + const contentOne: IComponentProperties = { + title: 'title component 1', + hidden: false, + component: ComponentType.TEXT, + content: { + text: 'this is a text content', + }, + }; + const contentTwo: IComponentProperties = { + title: 'title component 2', + hidden: false, + component: ComponentType.LERNSTORE, + content: { + resources: [ + { + url: 'http://foo.bar', + title: 'foo', + description: 'bar', + client: 'client', + merlinReference: '', + }, + ], + }, + }; + const user = userFactory.build(); + const originalCourse = courseFactory.build({ school: user.school }); + const destinationCourse = courseFactory.build({ school: user.school, teachers: [user] }); + const originalLesson = lessonFactory.build({ + course: originalCourse, + contents: [contentOne, contentTwo], + }); + lessonRepo.findById.mockResolvedValueOnce(originalLesson); + copyHelperService.deriveStatusFromElements.mockReturnValue(CopyStatusEnum.SUCCESS); + return { user, originalCourse, destinationCourse, originalLesson }; + }; - it('should set lesson status', async () => { + it('contents array of copied lesson should contain content elments of original lesson', async () => { const { user, destinationCourse, originalLesson } = setup(); const status = await copyService.copyLesson({ @@ -223,11 +348,16 @@ describe('lesson copy service', () => { user, }); - expect(status.status).toEqual(CopyStatusEnum.SUCCESS); + const lesson = status.copyEntity as LessonEntity; + + expect(lesson.contents.length).toEqual(2); + expect(lesson.contents).toEqual(originalLesson.contents); }); - it('should set status of metadata', async () => { + it('copied content should persist the original hidden value', async () => { const { user, destinationCourse, originalLesson } = setup(); + originalLesson.contents[0].hidden = true; + originalLesson.contents[1].hidden = false; const status = await copyService.copyLesson({ originalLessonId: originalLesson.id, @@ -235,46 +365,66 @@ describe('lesson copy service', () => { user, }); - const metadataStatus = status.elements?.find((el) => el.type === CopyElementType.METADATA); - expect(metadataStatus).toBeDefined(); - expect(metadataStatus?.status).toEqual(CopyStatusEnum.SUCCESS); + const lesson = status.copyEntity as LessonEntity; + + expect(lesson.contents[0].hidden).toEqual(true); + expect(lesson.contents[1].hidden).toEqual(false); }); - }); - }); - describe('when copying into a different course', () => { - it('should set destination course as course of the copy', async () => { - const originalCourse = courseFactory.build({}); - const destinationCourse = courseFactory.buildWithId(); - const user = userFactory.build({}); - const originalLesson = lessonFactory.build({ course: originalCourse }); - lessonRepo.findById.mockResolvedValueOnce(originalLesson); + it('should set contents status group with correct amount of children status elements', async () => { + const { user, destinationCourse, originalLesson } = setup(); - const status = await copyService.copyLesson({ - originalLessonId: originalLesson.id, - destinationCourse, - user, + const status = await copyService.copyLesson({ + originalLessonId: originalLesson.id, + destinationCourse, + user, + }); + const contentsStatus = status.elements?.find((el) => el.type === CopyElementType.LESSON_CONTENT_GROUP); + expect(contentsStatus).toBeDefined(); + expect(contentsStatus?.elements?.length).toEqual(2); + if (contentsStatus?.elements && contentsStatus?.elements[0]) { + expect(contentsStatus?.elements[0].status).toEqual(CopyStatusEnum.SUCCESS); + } }); - const lesson = status.copyEntity as LessonEntity; - expect(lesson.course).toEqual(destinationCourse); + it('should set contents status group with correct status', async () => { + const { user, destinationCourse, originalLesson } = setup(); + + const status = await copyService.copyLesson({ + originalLessonId: originalLesson.id, + destinationCourse, + user, + }); + const contentsStatus = status.elements?.find((el) => el.type === CopyElementType.LESSON_CONTENT_GROUP); + expect(contentsStatus).toBeDefined(); + expect(contentsStatus?.status).toEqual(CopyStatusEnum.SUCCESS); + }); }); }); - describe('when lesson contains no content', () => { - const setup = () => { + describe('when lesson contains text content element', () => { + const setup = (text = 'this is a text content') => { + const textContent: IComponentProperties = { + title: 'text component 1', + hidden: false, + component: ComponentType.TEXT, + content: { + text, + }, + }; const user = userFactory.build(); const originalCourse = courseFactory.build({ school: user.school }); const destinationCourse = courseFactory.build({ school: user.school, teachers: [user] }); const originalLesson = lessonFactory.build({ course: originalCourse, + contents: [textContent], }); lessonRepo.findById.mockResolvedValueOnce(originalLesson); - return { user, originalCourse, destinationCourse, originalLesson }; + return { user, originalCourse, destinationCourse, originalLesson, textContent }; }; - it('contents array of copied lesson should be empty', async () => { + it('should set content type to LESSON_CONTENT_TEXT', async () => { const { user, destinationCourse, originalLesson } = setup(); const status = await copyService.copyLesson({ @@ -282,46 +432,57 @@ describe('lesson copy service', () => { destinationCourse, user, }); - - const lesson = status.copyEntity as LessonEntity; - - expect(lesson.contents.length).toEqual(0); + const contentsStatus = status.elements?.find((el) => el.type === CopyElementType.LESSON_CONTENT_GROUP); + expect(contentsStatus).toBeDefined(); + if (contentsStatus?.elements) { + expect(contentsStatus.elements[0].type).toEqual(CopyElementType.LESSON_CONTENT_TEXT); + expect(contentsStatus.elements[0].status).toEqual(CopyStatusEnum.SUCCESS); + } }); - it('should not set contents status group', async () => { - const { user, destinationCourse, originalLesson } = setup(); + it('should replace copied urls in lesson text', async () => { + const FILE_ID_TO_BE_REPLACED = '12837461287346091823z490812374098127340987123'; + const NEW_FILE_ID = '19843275091827465871246598716239438'; + const { user, destinationCourse, originalLesson } = setup( + `Here is a link to a file` + ); + + copyFilesService.copyFilesOfEntity.mockResolvedValue({ + fileUrlReplacements: [ + { + regex: new RegExp(FILE_ID_TO_BE_REPLACED), + replacement: NEW_FILE_ID, + }, + ], + fileCopyStatus: { type: CopyElementType.FILE_GROUP, status: CopyStatusEnum.SUCCESS }, + }); const status = await copyService.copyLesson({ originalLessonId: originalLesson.id, destinationCourse, user, }); + + const lessonCopy = status.copyEntity as LessonEntity; const contentsStatus = status.elements?.find((el) => el.type === CopyElementType.LESSON_CONTENT_GROUP); - expect(contentsStatus).not.toBeDefined(); + expect(contentsStatus).toBeDefined(); + expect((lessonCopy.contents[0].content as IComponentTextProperties).text).not.toContain(FILE_ID_TO_BE_REPLACED); }); }); - describe('when lesson contains at least one content element', () => { + describe('when lesson contains LernStore content element', () => { const setup = () => { - const contentOne: IComponentProperties = { - title: 'title component 1', - hidden: false, - component: ComponentType.TEXT, - content: { - text: 'this is a text content', - }, - }; - const contentTwo: IComponentProperties = { - title: 'title component 2', + const lernStoreContent: IComponentProperties = { + title: 'text component 1', hidden: false, component: ComponentType.LERNSTORE, content: { resources: [ { - url: 'http://foo.bar', - title: 'foo', - description: 'bar', - client: 'client', + url: 'https://foo.bar/baz', + title: 'Test title', + description: 'description', + client: 'Schul-Cloud', merlinReference: '', }, ], @@ -332,15 +493,15 @@ describe('lesson copy service', () => { const destinationCourse = courseFactory.build({ school: user.school, teachers: [user] }); const originalLesson = lessonFactory.build({ course: originalCourse, - contents: [contentOne, contentTwo], + contents: [lernStoreContent], }); lessonRepo.findById.mockResolvedValueOnce(originalLesson); - copyHelperService.deriveStatusFromElements.mockReturnValue(CopyStatusEnum.SUCCESS); - return { user, originalCourse, destinationCourse, originalLesson }; + + return { user, originalCourse, destinationCourse, originalLesson, lernStoreContent }; }; - it('contents array of copied lesson should contain content elments of original lesson', async () => { - const { user, destinationCourse, originalLesson } = setup(); + it('the content should be fully copied', async () => { + const { user, destinationCourse, originalLesson, lernStoreContent } = setup(); const status = await copyService.copyLesson({ originalLessonId: originalLesson.id, @@ -348,46 +509,60 @@ describe('lesson copy service', () => { user, }); - const lesson = status.copyEntity as LessonEntity; - - expect(lesson.contents.length).toEqual(2); - expect(lesson.contents).toEqual(originalLesson.contents); + const copiedLessonContents = (status.copyEntity as LessonEntity).contents as IComponentProperties[]; + expect(copiedLessonContents[0]).toEqual(lernStoreContent); }); - it('copied content should persist the original hidden value', async () => { + it('should set content type to LESSON_CONTENT_LERNSTORE', async () => { const { user, destinationCourse, originalLesson } = setup(); - originalLesson.contents[0].hidden = true; - originalLesson.contents[1].hidden = false; const status = await copyService.copyLesson({ originalLessonId: originalLesson.id, destinationCourse, user, }); + const contentsStatus = status.elements?.find((el) => el.type === CopyElementType.LESSON_CONTENT_GROUP); + expect(contentsStatus).toBeDefined(); + if (contentsStatus?.elements) { + expect(contentsStatus.elements[0].type).toEqual(CopyElementType.LESSON_CONTENT_LERNSTORE); + expect(contentsStatus.elements[0].status).toEqual(CopyStatusEnum.SUCCESS); + } + }); + }); - const lesson = status.copyEntity as LessonEntity; + describe('when lesson contains LernStore content element without set resource', () => { + const setup = () => { + const lernStoreContent: IComponentProperties = { + title: 'text component 1', + hidden: false, + component: ComponentType.LERNSTORE, + }; + const user = userFactory.build(); + const originalCourse = courseFactory.build({ school: user.school }); + const destinationCourse = courseFactory.build({ school: user.school, teachers: [user] }); + const originalLesson = lessonFactory.build({ + course: originalCourse, + contents: [lernStoreContent], + }); + lessonRepo.findById.mockResolvedValueOnce(originalLesson); - expect(lesson.contents[0].hidden).toEqual(true); - expect(lesson.contents[1].hidden).toEqual(false); - }); + return { user, originalCourse, destinationCourse, originalLesson, lernStoreContent }; + }; - it('should set contents status group with correct amount of children status elements', async () => { - const { user, destinationCourse, originalLesson } = setup(); + it('the content should be fully copied', async () => { + const { user, destinationCourse, originalLesson, lernStoreContent } = setup(); const status = await copyService.copyLesson({ originalLessonId: originalLesson.id, destinationCourse, user, }); - const contentsStatus = status.elements?.find((el) => el.type === CopyElementType.LESSON_CONTENT_GROUP); - expect(contentsStatus).toBeDefined(); - expect(contentsStatus?.elements?.length).toEqual(2); - if (contentsStatus?.elements && contentsStatus?.elements[0]) { - expect(contentsStatus?.elements[0].status).toEqual(CopyStatusEnum.SUCCESS); - } + + const copiedLessonContents = (status.copyEntity as LessonEntity).contents as IComponentProperties[]; + expect(copiedLessonContents[0]).toEqual(lernStoreContent); }); - it('should set contents status group with correct status', async () => { + it('should set content type to LESSON_CONTENT_LERNSTORE', async () => { const { user, destinationCourse, originalLesson } = setup(); const status = await copyService.copyLesson({ @@ -397,695 +572,385 @@ describe('lesson copy service', () => { }); const contentsStatus = status.elements?.find((el) => el.type === CopyElementType.LESSON_CONTENT_GROUP); expect(contentsStatus).toBeDefined(); - expect(contentsStatus?.status).toEqual(CopyStatusEnum.SUCCESS); - }); - }); - }); - - describe('when lesson contains text content element', () => { - const setup = (text = 'this is a text content') => { - const textContent: IComponentProperties = { - title: 'text component 1', - hidden: false, - component: ComponentType.TEXT, - content: { - text, - }, - }; - const user = userFactory.build(); - const originalCourse = courseFactory.build({ school: user.school }); - const destinationCourse = courseFactory.build({ school: user.school, teachers: [user] }); - const originalLesson = lessonFactory.build({ - course: originalCourse, - contents: [textContent], - }); - lessonRepo.findById.mockResolvedValueOnce(originalLesson); - - return { user, originalCourse, destinationCourse, originalLesson, textContent }; - }; - - it('should set content type to LESSON_CONTENT_TEXT', async () => { - const { user, destinationCourse, originalLesson } = setup(); - - const status = await copyService.copyLesson({ - originalLessonId: originalLesson.id, - destinationCourse, - user, + if (contentsStatus?.elements) { + expect(contentsStatus.elements[0].type).toEqual(CopyElementType.LESSON_CONTENT_LERNSTORE); + expect(contentsStatus.elements[0].status).toEqual(CopyStatusEnum.SUCCESS); + } }); - const contentsStatus = status.elements?.find((el) => el.type === CopyElementType.LESSON_CONTENT_GROUP); - expect(contentsStatus).toBeDefined(); - if (contentsStatus?.elements) { - expect(contentsStatus.elements[0].type).toEqual(CopyElementType.LESSON_CONTENT_TEXT); - expect(contentsStatus.elements[0].status).toEqual(CopyStatusEnum.SUCCESS); - } }); - it('should replace copied urls in lesson text', async () => { - const FILE_ID_TO_BE_REPLACED = '12837461287346091823z490812374098127340987123'; - const NEW_FILE_ID = '19843275091827465871246598716239438'; - const { user, destinationCourse, originalLesson } = setup( - `Here is a link to a file` - ); - - copyFilesService.copyFilesOfEntity.mockResolvedValue({ - fileUrlReplacements: [ - { - regex: new RegExp(FILE_ID_TO_BE_REPLACED), - replacement: NEW_FILE_ID, + describe('when lesson contains geoGebra content element', () => { + const setup = () => { + const geoGebraContent: IComponentProperties = { + title: 'text component 1', + hidden: false, + component: ComponentType.GEOGEBRA, + content: { + materialId: 'foo', }, - ], - fileCopyStatus: { type: CopyElementType.FILE_GROUP, status: CopyStatusEnum.SUCCESS }, - }); - - const status = await copyService.copyLesson({ - originalLessonId: originalLesson.id, - destinationCourse, - user, - }); - - const lessonCopy = status.copyEntity as LessonEntity; - const contentsStatus = status.elements?.find((el) => el.type === CopyElementType.LESSON_CONTENT_GROUP); - expect(contentsStatus).toBeDefined(); - expect((lessonCopy.contents[0].content as IComponentTextProperties).text).not.toContain(FILE_ID_TO_BE_REPLACED); - }); - }); + }; + const user = userFactory.build(); + const originalCourse = courseFactory.build({ school: user.school }); + const destinationCourse = courseFactory.build({ school: user.school, teachers: [user] }); + const originalLesson = lessonFactory.build({ + course: originalCourse, + contents: [geoGebraContent], + }); + lessonRepo.findById.mockResolvedValueOnce(originalLesson); - describe('when lesson contains LernStore content element', () => { - const setup = () => { - const lernStoreContent: IComponentProperties = { - title: 'text component 1', - hidden: false, - component: ComponentType.LERNSTORE, - content: { - resources: [ - { - url: 'https://foo.bar/baz', - title: 'Test title', - description: 'description', - client: 'Schul-Cloud', - merlinReference: '', - }, - ], - }, + return { user, originalCourse, destinationCourse, originalLesson }; }; - const user = userFactory.build(); - const originalCourse = courseFactory.build({ school: user.school }); - const destinationCourse = courseFactory.build({ school: user.school, teachers: [user] }); - const originalLesson = lessonFactory.build({ - course: originalCourse, - contents: [lernStoreContent], - }); - lessonRepo.findById.mockResolvedValueOnce(originalLesson); - return { user, originalCourse, destinationCourse, originalLesson, lernStoreContent }; - }; + it('geoGebra Material-ID should not be copied', async () => { + const { user, destinationCourse, originalLesson } = setup(); + + const status = await copyService.copyLesson({ + originalLessonId: originalLesson.id, + destinationCourse, + user, + }); - it('the content should be fully copied', async () => { - const { user, destinationCourse, originalLesson, lernStoreContent } = setup(); + const lessonContents = (status.copyEntity as LessonEntity).contents as IComponentProperties[]; + const geoGebraContent = lessonContents[0].content as IComponentGeogebraProperties; - const status = await copyService.copyLesson({ - originalLessonId: originalLesson.id, - destinationCourse, - user, + expect(geoGebraContent.materialId).toEqual(''); }); - const copiedLessonContents = (status.copyEntity as LessonEntity).contents as IComponentProperties[]; - expect(copiedLessonContents[0]).toEqual(lernStoreContent); - }); - - it('should set content type to LESSON_CONTENT_LERNSTORE', async () => { - const { user, destinationCourse, originalLesson } = setup(); + it('element should be hidden', async () => { + const { user, destinationCourse, originalLesson } = setup(); - const status = await copyService.copyLesson({ - originalLessonId: originalLesson.id, - destinationCourse, - user, - }); - const contentsStatus = status.elements?.find((el) => el.type === CopyElementType.LESSON_CONTENT_GROUP); - expect(contentsStatus).toBeDefined(); - if (contentsStatus?.elements) { - expect(contentsStatus.elements[0].type).toEqual(CopyElementType.LESSON_CONTENT_LERNSTORE); - expect(contentsStatus.elements[0].status).toEqual(CopyStatusEnum.SUCCESS); - } - }); - }); + const status = await copyService.copyLesson({ + originalLessonId: originalLesson.id, + destinationCourse, + user, + }); - describe('when lesson contains LernStore content element without set resource', () => { - const setup = () => { - const lernStoreContent: IComponentProperties = { - title: 'text component 1', - hidden: false, - component: ComponentType.LERNSTORE, - }; - const user = userFactory.build(); - const originalCourse = courseFactory.build({ school: user.school }); - const destinationCourse = courseFactory.build({ school: user.school, teachers: [user] }); - const originalLesson = lessonFactory.build({ - course: originalCourse, - contents: [lernStoreContent], + const lessonContents = (status.copyEntity as LessonEntity).contents as IComponentProperties[]; + expect(lessonContents[0].hidden).toEqual(true); }); - lessonRepo.findById.mockResolvedValueOnce(originalLesson); - return { user, originalCourse, destinationCourse, originalLesson, lernStoreContent }; - }; + it('content status should have correct status value', async () => { + const { user, destinationCourse, originalLesson } = setup(); - it('the content should be fully copied', async () => { - const { user, destinationCourse, originalLesson, lernStoreContent } = setup(); + const status = await copyService.copyLesson({ + originalLessonId: originalLesson.id, + destinationCourse, + user, + }); - const status = await copyService.copyLesson({ - originalLessonId: originalLesson.id, - destinationCourse, - user, + const contentsStatus = status.elements?.find((el) => el.type === CopyElementType.LESSON_CONTENT_GROUP); + expect(contentsStatus).toBeDefined(); + if (contentsStatus?.elements) { + expect(contentsStatus.elements[0].status).toEqual(CopyStatusEnum.PARTIAL); + } }); - const copiedLessonContents = (status.copyEntity as LessonEntity).contents as IComponentProperties[]; - expect(copiedLessonContents[0]).toEqual(lernStoreContent); - }); - - it('should set content type to LESSON_CONTENT_LERNSTORE', async () => { - const { user, destinationCourse, originalLesson } = setup(); + it('should set content type to LESSON_CONTENT_GEOGEBRA', async () => { + const { user, destinationCourse, originalLesson } = setup(); - const status = await copyService.copyLesson({ - originalLessonId: originalLesson.id, - destinationCourse, - user, + const status = await copyService.copyLesson({ + originalLessonId: originalLesson.id, + destinationCourse, + user, + }); + const contentsStatus = status.elements?.find((el) => el.type === CopyElementType.LESSON_CONTENT_GROUP); + expect(contentsStatus).toBeDefined(); + if (contentsStatus?.elements) { + expect(contentsStatus.elements[0].type).toEqual(CopyElementType.LESSON_CONTENT_GEOGEBRA); + } }); - const contentsStatus = status.elements?.find((el) => el.type === CopyElementType.LESSON_CONTENT_GROUP); - expect(contentsStatus).toBeDefined(); - if (contentsStatus?.elements) { - expect(contentsStatus.elements[0].type).toEqual(CopyElementType.LESSON_CONTENT_LERNSTORE); - expect(contentsStatus.elements[0].status).toEqual(CopyStatusEnum.SUCCESS); - } }); - }); - describe('when lesson contains geoGebra content element', () => { - const setup = () => { - const geoGebraContent: IComponentProperties = { - title: 'text component 1', - hidden: false, - component: ComponentType.GEOGEBRA, - content: { - materialId: 'foo', - }, - }; - const user = userFactory.build(); - const originalCourse = courseFactory.build({ school: user.school }); - const destinationCourse = courseFactory.build({ school: user.school, teachers: [user] }); - const originalLesson = lessonFactory.build({ - course: originalCourse, - contents: [geoGebraContent], - }); - lessonRepo.findById.mockResolvedValueOnce(originalLesson); + describe('when lesson contains linked tasks', () => { + describe('when no tasks are linked to the original lesson', () => { + const setup = () => { + const user = userFactory.build(); + const originalCourse = courseFactory.build({ school: user.school, teachers: [user] }); + const destinationCourse = courseFactory.build({ school: user.school, teachers: [user] }); + const originalLesson = lessonFactory.build({ + course: originalCourse, + }); - return { user, originalCourse, destinationCourse, originalLesson }; - }; + return { + user, + destinationCourse, + originalLesson, + }; + }; - it('geoGebra Material-ID should not be copied', async () => { - const { user, destinationCourse, originalLesson } = setup(); + it('should not set task status', async () => { + const { originalLesson, destinationCourse, user } = setup(); - const status = await copyService.copyLesson({ - originalLessonId: originalLesson.id, - destinationCourse, - user, + const copyStatus = await copyService.copyLesson({ + originalLessonId: originalLesson.id, + destinationCourse, + user, + }); + const tasksGroupStatus = copyStatus.elements?.find((el) => el.type === CopyElementType.TASK_GROUP); + expect(tasksGroupStatus).not.toBeDefined(); + }); }); - const lessonContents = (status.copyEntity as LessonEntity).contents as IComponentProperties[]; - const geoGebraContent = lessonContents[0].content as IComponentGeogebraProperties; - - expect(geoGebraContent.materialId).toEqual(''); - }); + describe('when a single task is linked to the original lesson', () => { + const setup = () => { + const user = userFactory.build(); + const originalCourse = courseFactory.build({ school: user.school, teachers: [user] }); + const destinationCourse = courseFactory.build({ school: user.school, teachers: [user] }); + const originalLesson = lessonFactory.build({ + course: originalCourse, + }); + lessonRepo.findById.mockResolvedValueOnce(originalLesson); + const originalTask = taskFactory.build({ + course: originalCourse, + lesson: originalLesson, + }); + const taskCopy = taskFactory.build({ name: originalTask.name }); + const mockedTaskStatus = { + title: taskCopy.name, + type: CopyElementType.TASK, + status: CopyStatusEnum.SUCCESS, + copyEntity: taskCopy, + }; + const mockedTaskGroupStatus = { + type: CopyElementType.TASK_GROUP, + status: CopyStatusEnum.SUCCESS, + elements: [mockedTaskStatus], + }; + taskCopyService.copyTask.mockResolvedValue(mockedTaskStatus); - it('element should be hidden', async () => { - const { user, destinationCourse, originalLesson } = setup(); + return { + user, + destinationCourse, + originalLesson, + originalTask, + mockedTaskStatus, + mockedTaskGroupStatus, + }; + }; - const status = await copyService.copyLesson({ - originalLessonId: originalLesson.id, - destinationCourse, - user, - }); + it('should put copy status tasks leaf', async () => { + const { originalLesson, destinationCourse, user, mockedTaskGroupStatus } = setup(); - const lessonContents = (status.copyEntity as LessonEntity).contents as IComponentProperties[]; - expect(lessonContents[0].hidden).toEqual(true); - }); + const copyStatus = await copyService.copyLesson({ + originalLessonId: originalLesson.id, + destinationCourse, + user, + }); + const tasksGroupStatus = copyStatus.elements?.find((el) => el.type === CopyElementType.TASK_GROUP); + expect(tasksGroupStatus).toBeDefined(); + expect(tasksGroupStatus).toEqual(mockedTaskGroupStatus); + }); - it('content status should have correct status value', async () => { - const { user, destinationCourse, originalLesson } = setup(); + it('should put copy status for the copied task', async () => { + const { originalLesson, originalTask, destinationCourse, user, mockedTaskStatus } = setup(); - const status = await copyService.copyLesson({ - originalLessonId: originalLesson.id, - destinationCourse, - user, + const copyStatus = await copyService.copyLesson({ + originalLessonId: originalLesson.id, + destinationCourse, + user, + }); + const tasksGroupStatus = copyStatus.elements?.find((el) => el.type === CopyElementType.TASK_GROUP); + expect(tasksGroupStatus).toBeDefined(); + const tasksStatus = tasksGroupStatus?.elements?.find( + (el) => el.type === CopyElementType.TASK && el.title === originalTask.name + ); + expect(tasksStatus).toBeDefined(); + expect(tasksStatus).toEqual(mockedTaskStatus); + }); }); - const contentsStatus = status.elements?.find((el) => el.type === CopyElementType.LESSON_CONTENT_GROUP); - expect(contentsStatus).toBeDefined(); - if (contentsStatus?.elements) { - expect(contentsStatus.elements[0].status).toEqual(CopyStatusEnum.PARTIAL); - } - }); + describe('when mupltiple tasks are linked to the original lesson', () => { + const setup = () => { + const user = userFactory.build(); + const originalCourse = courseFactory.build({ school: user.school, teachers: [user] }); + const destinationCourse = courseFactory.build({ school: user.school, teachers: [user] }); + const originalLesson = lessonFactory.build({ + course: originalCourse, + }); + lessonRepo.findById.mockResolvedValueOnce(originalLesson); + const originalTasks = taskFactory.buildList(2, { + course: originalCourse, + lesson: originalLesson, + }); + const taskCopyOne = taskFactory.build({ name: originalTasks[0].name }); + const taskCopyTwo = taskFactory.build({ name: originalTasks[1].name }); + const mockedTaskStatusOne = { + title: taskCopyOne.name, + type: CopyElementType.TASK, + status: CopyStatusEnum.SUCCESS, + copyEntity: taskCopyOne, + }; + const mockedTaskStatusTwo = { + title: taskCopyTwo.name, + type: CopyElementType.TASK, + status: CopyStatusEnum.SUCCESS, + copyEntity: taskCopyTwo, + }; + taskCopyService.copyTask + .mockResolvedValueOnce(mockedTaskStatusOne) + .mockResolvedValueOnce(mockedTaskStatusTwo); + + return { + user, + destinationCourse, + originalLesson, + mockedTaskStatusOne, + mockedTaskStatusTwo, + }; + }; - it('should set content type to LESSON_CONTENT_GEOGEBRA', async () => { - const { user, destinationCourse, originalLesson } = setup(); + it('should put copy status for each copied task under tasks', async () => { + const { originalLesson, destinationCourse, user, mockedTaskStatusOne, mockedTaskStatusTwo } = setup(); - const status = await copyService.copyLesson({ - originalLessonId: originalLesson.id, - destinationCourse, - user, + const copyStatus = await copyService.copyLesson({ + originalLessonId: originalLesson.id, + destinationCourse, + user, + }); + const tasksGroupStatus = copyStatus.elements?.find((el) => el.type === CopyElementType.TASK_GROUP); + expect(tasksGroupStatus).toBeDefined(); + expect(tasksGroupStatus?.elements).toEqual([mockedTaskStatusOne, mockedTaskStatusTwo]); + }); }); - const contentsStatus = status.elements?.find((el) => el.type === CopyElementType.LESSON_CONTENT_GROUP); - expect(contentsStatus).toBeDefined(); - if (contentsStatus?.elements) { - expect(contentsStatus.elements[0].type).toEqual(CopyElementType.LESSON_CONTENT_GEOGEBRA); - } }); - }); - describe('when lesson contains linked tasks', () => { - describe('when no tasks are linked to the original lesson', () => { + describe('when lesson contains Etherpad content element', () => { const setup = () => { + const etherpadContent: IComponentProperties = { + title: 'text', + hidden: false, + component: ComponentType.ETHERPAD, + content: { + description: 'foo', + title: 'bar', + url: 'baz', + }, + }; const user = userFactory.build(); - const originalCourse = courseFactory.build({ school: user.school, teachers: [user] }); + const originalCourse = courseFactory.build({ school: user.school }); const destinationCourse = courseFactory.build({ school: user.school, teachers: [user] }); const originalLesson = lessonFactory.build({ course: originalCourse, + contents: [etherpadContent], }); + lessonRepo.findById.mockResolvedValueOnce(originalLesson); - return { - user, - destinationCourse, - originalLesson, - }; - }; + etherpadService.createEtherpad.mockResolvedValue('abc'); - it('should not set task status', async () => { - const { originalLesson, destinationCourse, user } = setup(); + configurationSpy = jest.spyOn(Configuration, 'get').mockImplementation((config: string) => { + if (config === 'FEATURE_ETHERPAD_ENABLED') { + return true; + } + if (config === 'ETHERPAD__PAD_URI') { + return 'http://pad.uri'; + } + return null; + }); - const copyStatus = await copyService.copyLesson({ - originalLessonId: originalLesson.id, - destinationCourse, - user, - }); - const tasksGroupStatus = copyStatus.elements?.find((el) => el.type === CopyElementType.TASK_GROUP); - expect(tasksGroupStatus).not.toBeDefined(); - }); - }); - - describe('when a single task is linked to the original lesson', () => { - const setup = () => { - const user = userFactory.build(); - const originalCourse = courseFactory.build({ school: user.school, teachers: [user] }); - const destinationCourse = courseFactory.build({ school: user.school, teachers: [user] }); - const originalLesson = lessonFactory.build({ - course: originalCourse, - }); - lessonRepo.findById.mockResolvedValueOnce(originalLesson); - const originalTask = taskFactory.build({ - course: originalCourse, - lesson: originalLesson, - }); - const taskCopy = taskFactory.build({ name: originalTask.name }); - const mockedTaskStatus = { - title: taskCopy.name, - type: CopyElementType.TASK, - status: CopyStatusEnum.SUCCESS, - copyEntity: taskCopy, - }; - const mockedTaskGroupStatus = { - type: CopyElementType.TASK_GROUP, - status: CopyStatusEnum.SUCCESS, - elements: [mockedTaskStatus], - }; - taskCopyService.copyTask.mockResolvedValue(mockedTaskStatus); - - return { - user, - destinationCourse, - originalLesson, - originalTask, - mockedTaskStatus, - mockedTaskGroupStatus, - }; + return { user, originalCourse, destinationCourse, originalLesson }; }; - it('should put copy status tasks leaf', async () => { - const { originalLesson, destinationCourse, user, mockedTaskGroupStatus } = setup(); + it('should not call etherpad service, if feature flag is false', async () => { + const { user, destinationCourse, originalLesson } = setup(); + configurationSpy = jest.spyOn(Configuration, 'get').mockReturnValue(false); - const copyStatus = await copyService.copyLesson({ + const status = await copyService.copyLesson({ originalLessonId: originalLesson.id, destinationCourse, user, }); - const tasksGroupStatus = copyStatus.elements?.find((el) => el.type === CopyElementType.TASK_GROUP); - expect(tasksGroupStatus).toBeDefined(); - expect(tasksGroupStatus).toEqual(mockedTaskGroupStatus); + + const lessonContents = (status.copyEntity as LessonEntity).contents as IComponentProperties[]; + expect(configurationSpy).toHaveBeenCalledWith('FEATURE_ETHERPAD_ENABLED'); + expect(etherpadService.createEtherpad).not.toHaveBeenCalled(); + expect(lessonContents).toEqual([]); + + configurationSpy = jest.spyOn(Configuration, 'get').mockReturnValue(true); }); - it('should put copy status for the copied task', async () => { - const { originalLesson, originalTask, destinationCourse, user, mockedTaskStatus } = setup(); + it('should call etherpad service to create new etherpad', async () => { + const { user, destinationCourse, originalLesson } = setup(); - const copyStatus = await copyService.copyLesson({ + await copyService.copyLesson({ originalLessonId: originalLesson.id, destinationCourse, user, }); - const tasksGroupStatus = copyStatus.elements?.find((el) => el.type === CopyElementType.TASK_GROUP); - expect(tasksGroupStatus).toBeDefined(); - const tasksStatus = tasksGroupStatus?.elements?.find( - (el) => el.type === CopyElementType.TASK && el.title === originalTask.name - ); - expect(tasksStatus).toBeDefined(); - expect(tasksStatus).toEqual(mockedTaskStatus); - }); - }); - describe('when mupltiple tasks are linked to the original lesson', () => { - const setup = () => { - const user = userFactory.build(); - const originalCourse = courseFactory.build({ school: user.school, teachers: [user] }); - const destinationCourse = courseFactory.build({ school: user.school, teachers: [user] }); - const originalLesson = lessonFactory.build({ - course: originalCourse, - }); - lessonRepo.findById.mockResolvedValueOnce(originalLesson); - const originalTasks = taskFactory.buildList(2, { - course: originalCourse, - lesson: originalLesson, - }); - const taskCopyOne = taskFactory.build({ name: originalTasks[0].name }); - const taskCopyTwo = taskFactory.build({ name: originalTasks[1].name }); - const mockedTaskStatusOne = { - title: taskCopyOne.name, - type: CopyElementType.TASK, - status: CopyStatusEnum.SUCCESS, - copyEntity: taskCopyOne, - }; - const mockedTaskStatusTwo = { - title: taskCopyTwo.name, - type: CopyElementType.TASK, - status: CopyStatusEnum.SUCCESS, - copyEntity: taskCopyTwo, - }; - taskCopyService.copyTask.mockResolvedValueOnce(mockedTaskStatusOne).mockResolvedValueOnce(mockedTaskStatusTwo); + expect(etherpadService.createEtherpad).toHaveBeenCalled(); + }); - return { - user, - destinationCourse, - originalLesson, - mockedTaskStatusOne, - mockedTaskStatusTwo, - }; - }; + it('should not copy the etherpad content, if etherpad creation fails', async () => { + const { user, destinationCourse, originalLesson } = setup(); - it('should put copy status for each copied task under tasks', async () => { - const { originalLesson, destinationCourse, user, mockedTaskStatusOne, mockedTaskStatusTwo } = setup(); + etherpadService.createEtherpad.mockResolvedValue(false); - const copyStatus = await copyService.copyLesson({ + const status = await copyService.copyLesson({ originalLessonId: originalLesson.id, destinationCourse, user, }); - const tasksGroupStatus = copyStatus.elements?.find((el) => el.type === CopyElementType.TASK_GROUP); - expect(tasksGroupStatus).toBeDefined(); - expect(tasksGroupStatus?.elements).toEqual([mockedTaskStatusOne, mockedTaskStatusTwo]); - }); - }); - }); - - describe('when lesson contains Etherpad content element', () => { - const setup = () => { - const etherpadContent: IComponentProperties = { - title: 'text', - hidden: false, - component: ComponentType.ETHERPAD, - content: { - description: 'foo', - title: 'bar', - url: 'baz', - }, - }; - const user = userFactory.build(); - const originalCourse = courseFactory.build({ school: user.school }); - const destinationCourse = courseFactory.build({ school: user.school, teachers: [user] }); - const originalLesson = lessonFactory.build({ - course: originalCourse, - contents: [etherpadContent], - }); - lessonRepo.findById.mockResolvedValueOnce(originalLesson); - etherpadService.createEtherpad.mockResolvedValue('abc'); - - configurationSpy = jest.spyOn(Configuration, 'get').mockImplementation((config: string) => { - if (config === 'FEATURE_ETHERPAD_ENABLED') { - return true; - } - if (config === 'ETHERPAD__PAD_URI') { - return 'http://pad.uri'; + let contentStatus = CopyStatusEnum.SUCCESS; + const group = status.elements?.filter((element) => element.type === CopyElementType.LESSON_CONTENT_GROUP)[0]; + if (group && group.elements) { + contentStatus = group.elements[0].status; } - return null; - }); - - return { user, originalCourse, destinationCourse, originalLesson }; - }; - - it('should not call etherpad service, if feature flag is false', async () => { - const { user, destinationCourse, originalLesson } = setup(); - configurationSpy = jest.spyOn(Configuration, 'get').mockReturnValue(false); - - const status = await copyService.copyLesson({ - originalLessonId: originalLesson.id, - destinationCourse, - user, - }); - - const lessonContents = (status.copyEntity as LessonEntity).contents as IComponentProperties[]; - expect(configurationSpy).toHaveBeenCalledWith('FEATURE_ETHERPAD_ENABLED'); - expect(etherpadService.createEtherpad).not.toHaveBeenCalled(); - expect(lessonContents).toEqual([]); - - configurationSpy = jest.spyOn(Configuration, 'get').mockReturnValue(true); - }); + expect(contentStatus).toEqual(CopyStatusEnum.FAIL); - it('should call etherpad service to create new etherpad', async () => { - const { user, destinationCourse, originalLesson } = setup(); - - await copyService.copyLesson({ - originalLessonId: originalLesson.id, - destinationCourse, - user, - }); - - expect(etherpadService.createEtherpad).toHaveBeenCalled(); - }); - - it('should not copy the etherpad content, if etherpad creation fails', async () => { - const { user, destinationCourse, originalLesson } = setup(); - - etherpadService.createEtherpad.mockResolvedValue(false); - - const status = await copyService.copyLesson({ - originalLessonId: originalLesson.id, - destinationCourse, - user, - }); - - let contentStatus = CopyStatusEnum.SUCCESS; - const group = status.elements?.filter((element) => element.type === CopyElementType.LESSON_CONTENT_GROUP)[0]; - if (group && group.elements) { - contentStatus = group.elements[0].status; - } - expect(contentStatus).toEqual(CopyStatusEnum.FAIL); - - const lessonContents = (status.copyEntity as LessonEntity).contents as IComponentProperties[]; - expect(lessonContents.length).toEqual(0); - }); - - it('should copy etherpad correctly', async () => { - const { user, destinationCourse, originalLesson } = setup(); - - etherpadService.createEtherpad.mockResolvedValue('abc'); - - const status = await copyService.copyLesson({ - originalLessonId: originalLesson.id, - destinationCourse, - user, - }); - const copiedLessonContents = (status.copyEntity as LessonEntity).contents as IComponentProperties[]; - const copiedEtherpad = copiedLessonContents[0].content as IComponentEtherpadProperties; - expect(copiedEtherpad.url).toEqual('http://pad.uri/abc'); - }); - - it('should set content type to LESSON_CONTENT_ETHERPAD', async () => { - const { user, destinationCourse, originalLesson } = setup(); - - etherpadService.createEtherpad.mockResolvedValue('abc'); - - const status = await copyService.copyLesson({ - originalLessonId: originalLesson.id, - destinationCourse, - user, - }); - const contentsStatus = status.elements?.find((el) => el.type === CopyElementType.LESSON_CONTENT_GROUP); - expect(contentsStatus).toBeDefined(); - if (contentsStatus?.elements) { - expect(contentsStatus.elements[0].type).toEqual(CopyElementType.LESSON_CONTENT_ETHERPAD); - } - }); - }); - - describe('when lesson contains embedded task element', () => { - const setup = () => { - const user = userFactory.build(); - const originalCourse = courseFactory.build({ school: user.school, teachers: [user] }); - const destinationCourse = courseFactory.build({ school: user.school, teachers: [user] }); - const embeddedTaskContent: IComponentProperties = { - title: 'title', - hidden: false, - component: ComponentType.INTERNAL, - content: { - url: 'http://somebasedomain.de/homework/someid', - }, - }; - const originalLesson = lessonFactory.build({ - course: originalCourse, - contents: [embeddedTaskContent], - }); - lessonRepo.findById.mockResolvedValueOnce(originalLesson); - - return { - user, - destinationCourse, - originalLesson, - embeddedTaskContent, - }; - }; - - it('should add status for embedded task as SUCCESS', async () => { - const { originalLesson, destinationCourse, user } = setup(); - const copyStatus = await copyService.copyLesson({ - originalLessonId: originalLesson.id, - destinationCourse, - user, - }); - - const contentsStatus = copyStatus.elements?.find((el) => el.type === CopyElementType.LESSON_CONTENT_GROUP); - if (!contentsStatus || !contentsStatus.elements || contentsStatus.elements.length < 1) { - throw new Error('element not found'); - } - const embeddedTaskStatus = contentsStatus.elements[0]; - - expect(embeddedTaskStatus.status).toEqual(CopyStatusEnum.SUCCESS); - }); - - it('should add embedded task to copy', async () => { - const { originalLesson, destinationCourse, user, embeddedTaskContent } = setup(); - const copyStatus = await copyService.copyLesson({ - originalLessonId: originalLesson.id, - destinationCourse, - user, - }); - const lesson = copyStatus.copyEntity as LessonEntity; - const embeddedTaskLink = lesson.contents.find((el) => el.component === ComponentType.INTERNAL); - - expect(embeddedTaskLink).toEqual(embeddedTaskContent); - }); - - it('should set content type to LESSON_CONTENT_TASK', async () => { - const { user, destinationCourse, originalLesson } = setup(); - const copyStatus = await copyService.copyLesson({ - originalLessonId: originalLesson.id, - destinationCourse, - user, - }); - const contentsStatus = copyStatus.elements?.find((el) => el.type === CopyElementType.LESSON_CONTENT_GROUP); - expect(contentsStatus).toBeDefined(); - if (contentsStatus?.elements) { - expect(contentsStatus.elements[0].type).toEqual(CopyElementType.LESSON_CONTENT_TASK); - } - }); - }); - - describe('when lesson contains neXboard content element', () => { - const setup = () => { - const nexboardContent: IComponentProperties = { - title: 'text', - hidden: false, - component: ComponentType.NEXBOARD, - content: { - board: '123', - description: 'foo', - title: 'bar', - url: 'baz', - }, - }; - const user = userFactory.build(); - const originalCourse = courseFactory.build({ school: user.school }); - const destinationCourse = courseFactory.build({ school: user.school, teachers: [user] }); - const originalLesson = lessonFactory.build({ - course: originalCourse, - contents: [nexboardContent], + const lessonContents = (status.copyEntity as LessonEntity).contents as IComponentProperties[]; + expect(lessonContents.length).toEqual(0); }); - lessonRepo.findById.mockResolvedValueOnce(originalLesson); - nexboardService.createNexboard.mockResolvedValue({ board: '123', url: 'abc' }); - - configurationSpy = jest.spyOn(Configuration, 'get').mockImplementation((config: string) => { - if (config === 'FEATURE_NEXBOARD_ENABLED') { - return true; - } - return null; - }); + it('should copy etherpad correctly', async () => { + const { user, destinationCourse, originalLesson } = setup(); - return { user, originalCourse, destinationCourse, originalLesson }; - }; + etherpadService.createEtherpad.mockResolvedValue('abc'); - it('should not copy neXboard', async () => { - const { user, destinationCourse, originalLesson } = setup(); - const status = await copyService.copyLesson({ + const status = await copyService.copyLesson({ originalLessonId: originalLesson.id, destinationCourse, user, + }); + const copiedLessonContents = (status.copyEntity as LessonEntity).contents as IComponentProperties[]; + const copiedEtherpad = copiedLessonContents[0].content as IComponentEtherpadProperties; + expect(copiedEtherpad.url).toEqual('http://pad.uri/abc'); }); - const copiedLessonContents = (status.copyEntity as LessonEntity).contents as IComponentProperties[]; - const hasNexboard = copiedLessonContents.some(content => content.component === ComponentType.NEXBOARD); - expect(hasNexboard).toBe(false); - }); - it('should call neXboard service to create new neXboard', async () => { - const { user, destinationCourse, originalLesson } = setup(); + it('should set content type to LESSON_CONTENT_ETHERPAD', async () => { + const { user, destinationCourse, originalLesson } = setup(); - await copyService.copyLesson({ - originalLessonId: originalLesson.id, - destinationCourse, - user, - }); + etherpadService.createEtherpad.mockResolvedValue('abc'); - expect(nexboardService.createNexboard).toHaveBeenCalled(); - }); - - it('should not copy the neXboard content, if neXboard creation fails', async () => { - const { user, destinationCourse, originalLesson } = setup(); - nexboardService.createNexboard.mockResolvedValue(false); - const status = await copyService.copyLesson({ + const status = await copyService.copyLesson({ originalLessonId: originalLesson.id, destinationCourse, user, + }); + const contentsStatus = status.elements?.find((el) => el.type === CopyElementType.LESSON_CONTENT_GROUP); + expect(contentsStatus).toBeDefined(); + if (contentsStatus?.elements) { + expect(contentsStatus.elements[0].type).toEqual(CopyElementType.LESSON_CONTENT_ETHERPAD); + } }); - const copiedLessonContents = (status.copyEntity as LessonEntity).contents as IComponentProperties[]; - const hasNexboard = copiedLessonContents.some(content => content.component === ComponentType.NEXBOARD); - expect(hasNexboard).toBe(false); - }); - - }); + }); - describe('when lesson contains linked materials', () => { - describe('when no materials are linked to the original lesson', () => { + describe('when lesson contains embedded task element', () => { const setup = () => { const user = userFactory.build(); const originalCourse = courseFactory.build({ school: user.school, teachers: [user] }); const destinationCourse = courseFactory.build({ school: user.school, teachers: [user] }); + const embeddedTaskContent: IComponentProperties = { + title: 'title', + hidden: false, + component: ComponentType.INTERNAL, + content: { + url: 'http://somebasedomain.de/homework/someid', + }, + }; const originalLesson = lessonFactory.build({ course: originalCourse, + contents: [embeddedTaskContent], }); lessonRepo.findById.mockResolvedValueOnce(originalLesson); @@ -1093,276 +958,412 @@ describe('lesson copy service', () => { user, destinationCourse, originalLesson, + embeddedTaskContent, }; }; - it('should not set materials status', async () => { + it('should add status for embedded task as SUCCESS', async () => { const { originalLesson, destinationCourse, user } = setup(); - const copyStatus = await copyService.copyLesson({ originalLessonId: originalLesson.id, destinationCourse, user, }); - const materialsGroupStatus = copyStatus.elements?.find( - (el) => el.type === CopyElementType.LERNSTORE_MATERIAL_GROUP - ); - expect(materialsGroupStatus).not.toBeDefined(); - }); - }); - - describe('when a single material is linked to the original lesson', () => { - const setup = () => { - const user = userFactory.build(); - const originalCourse = courseFactory.build({ school: user.school, teachers: [user] }); - const destinationCourse = courseFactory.build({ school: user.school, teachers: [user] }); - const originalMaterial = materialFactory.build(); - const originalLesson = lessonFactory.build({ - course: originalCourse, - materials: [originalMaterial], - }); - lessonRepo.findById.mockResolvedValueOnce(originalLesson); - const materialCopy = materialFactory.build({ title: originalMaterial.title }); - const mockedMaterialStatus = { - title: materialCopy.title, - type: CopyElementType.LERNSTORE_MATERIAL, - status: CopyStatusEnum.SUCCESS, - copyEntity: materialCopy, - }; - const mockedMaterialGroupStatus = { - type: CopyElementType.LERNSTORE_MATERIAL_GROUP, - status: CopyStatusEnum.SUCCESS, - elements: [mockedMaterialStatus], - }; - return { - user, - destinationCourse, - originalLesson, - originalMaterial, - mockedMaterialStatus, - mockedMaterialGroupStatus, - }; - }; + const contentsStatus = copyStatus.elements?.find((el) => el.type === CopyElementType.LESSON_CONTENT_GROUP); + if (!contentsStatus || !contentsStatus.elements || contentsStatus.elements.length < 1) { + throw new Error('element not found'); + } + const embeddedTaskStatus = contentsStatus.elements[0]; - it('should put copy status materials leaf', async () => { - const { originalLesson, destinationCourse, user, mockedMaterialGroupStatus } = setup(); + expect(embeddedTaskStatus.status).toEqual(CopyStatusEnum.SUCCESS); + }); + it('should add embedded task to copy', async () => { + const { originalLesson, destinationCourse, user, embeddedTaskContent } = setup(); const copyStatus = await copyService.copyLesson({ originalLessonId: originalLesson.id, destinationCourse, user, }); - const materialsGroupStatus = copyStatus.elements?.find( - (el) => el.type === CopyElementType.LERNSTORE_MATERIAL_GROUP - ); - expect(materialsGroupStatus).toBeDefined(); - expect(materialsGroupStatus).toEqual(mockedMaterialGroupStatus); - }); + const lesson = copyStatus.copyEntity as LessonEntity; + const embeddedTaskLink = lesson.contents.find((el) => el.component === ComponentType.INTERNAL); - it('should put copy status for the copied material', async () => { - const { originalLesson, originalMaterial, destinationCourse, user, mockedMaterialStatus } = setup(); + expect(embeddedTaskLink).toEqual(embeddedTaskContent); + }); + it('should set content type to LESSON_CONTENT_TASK', async () => { + const { user, destinationCourse, originalLesson } = setup(); const copyStatus = await copyService.copyLesson({ originalLessonId: originalLesson.id, destinationCourse, user, }); - const materialsGroupStatus = copyStatus.elements?.find( - (el) => el.type === CopyElementType.LERNSTORE_MATERIAL_GROUP - ); - expect(materialsGroupStatus).toBeDefined(); - const materialStatus = materialsGroupStatus?.elements?.find( - (el) => el.type === CopyElementType.LERNSTORE_MATERIAL && el.title === originalMaterial.title - ); - expect(materialStatus).toBeDefined(); - expect(materialStatus?.title).toEqual(mockedMaterialStatus.title); - expect(materialStatus?.status).toEqual(mockedMaterialStatus.status); - const material = materialStatus?.copyEntity as Material; - expect(material?.description).toEqual(mockedMaterialStatus?.copyEntity?.description); + const contentsStatus = copyStatus.elements?.find((el) => el.type === CopyElementType.LESSON_CONTENT_GROUP); + expect(contentsStatus).toBeDefined(); + if (contentsStatus?.elements) { + expect(contentsStatus.elements[0].type).toEqual(CopyElementType.LESSON_CONTENT_TASK); + } }); }); - describe('when mupltiple materials are linked to the original lesson', () => { + describe('when lesson contains neXboard content element', () => { const setup = () => { + const nexboardContent: IComponentProperties = { + title: 'text', + hidden: false, + component: ComponentType.NEXBOARD, + content: { + board: '123', + description: 'foo', + title: 'bar', + url: 'baz', + }, + }; const user = userFactory.build(); - const originalCourse = courseFactory.build({ school: user.school, teachers: [user] }); + const originalCourse = courseFactory.build({ school: user.school }); const destinationCourse = courseFactory.build({ school: user.school, teachers: [user] }); - const originalMaterial = materialFactory.buildList(2); const originalLesson = lessonFactory.build({ course: originalCourse, - materials: originalMaterial, + contents: [nexboardContent], }); lessonRepo.findById.mockResolvedValueOnce(originalLesson); - const materialCopyOne = materialFactory.build({ title: originalMaterial[0].title }); - const materialCopyTwo = materialFactory.build({ title: originalMaterial[1].title }); - const mockedMaterialStatusOne = { - title: materialCopyOne.title, - type: CopyElementType.LERNSTORE_MATERIAL, - status: CopyStatusEnum.SUCCESS, - copyEntity: materialCopyOne, - }; - const mockedMaterialStatusTwo = { - title: materialCopyTwo.title, - type: CopyElementType.LERNSTORE_MATERIAL, - status: CopyStatusEnum.SUCCESS, - copyEntity: materialCopyTwo, - }; - return { + nexboardService.createNexboard.mockResolvedValue({ board: '123', url: 'abc' }); + + configurationSpy = jest.spyOn(Configuration, 'get').mockImplementation((config: string) => { + if (config === 'FEATURE_NEXBOARD_ENABLED') { + return true; + } + return null; + }); + + return { user, originalCourse, destinationCourse, originalLesson }; + }; + + it('should not copy neXboard', async () => { + const { user, destinationCourse, originalLesson } = setup(); + const status = await copyService.copyLesson({ + originalLessonId: originalLesson.id, + destinationCourse, user, + }); + const copiedLessonContents = (status.copyEntity as LessonEntity).contents as IComponentProperties[]; + const hasNexboard = copiedLessonContents.some((content) => content.component === ComponentType.NEXBOARD); + expect(hasNexboard).toBe(false); + }); + + it('should call neXboard service to create new neXboard', async () => { + const { user, destinationCourse, originalLesson } = setup(); + + await copyService.copyLesson({ + originalLessonId: originalLesson.id, destinationCourse, - originalLesson, - mockedMaterialStatusOne, - mockedMaterialStatusTwo, - }; - }; + user, + }); - it('should put copy status for each copied material under materials', async () => { - const { originalLesson, destinationCourse, user, mockedMaterialStatusOne, mockedMaterialStatusTwo } = setup(); + expect(nexboardService.createNexboard).toHaveBeenCalled(); + }); - const copyStatus = await copyService.copyLesson({ + it('should not copy the neXboard content, if neXboard creation fails', async () => { + const { user, destinationCourse, originalLesson } = setup(); + nexboardService.createNexboard.mockResolvedValue(false); + const status = await copyService.copyLesson({ originalLessonId: originalLesson.id, destinationCourse, user, }); - const materialsGroupStatus = copyStatus.elements?.find( - (el) => el.type === CopyElementType.LERNSTORE_MATERIAL_GROUP - ); - expect(materialsGroupStatus).toBeDefined(); - expect(materialsGroupStatus?.elements?.map((el) => el.title)).toEqual([ - mockedMaterialStatusOne.title, - mockedMaterialStatusTwo.title, - ]); + const copiedLessonContents = (status.copyEntity as LessonEntity).contents as IComponentProperties[]; + const hasNexboard = copiedLessonContents.some((content) => content.component === ComponentType.NEXBOARD); + expect(hasNexboard).toBe(false); }); }); - }); - describe('updateCopiedEmbeddedTasks', () => { - it('should leave non-lesson status as is', () => { - const status = { - type: CopyElementType.COURSE, - status: CopyStatusEnum.SUCCESS, - elements: [ - { - type: CopyElementType.TASK, - status: CopyStatusEnum.SUCCESS, - }, - ], - }; - const copyDict = copyHelperService.buildCopyEntityDict(status); - const result = copyService.updateCopiedEmbeddedTasks(status, copyDict); + describe('when lesson contains linked materials', () => { + describe('when no materials are linked to the original lesson', () => { + const setup = () => { + const user = userFactory.build(); + const originalCourse = courseFactory.build({ school: user.school, teachers: [user] }); + const destinationCourse = courseFactory.build({ school: user.school, teachers: [user] }); + const originalLesson = lessonFactory.build({ + course: originalCourse, + }); + lessonRepo.findById.mockResolvedValueOnce(originalLesson); - expect(result).toEqual(status); - }); + return { + user, + destinationCourse, + originalLesson, + }; + }; - describe('when status contains lesson with embedded tasks', () => { - const setup = () => { - const originalLesson = lessonFactory.buildWithId(); - const copiedLesson = lessonFactory.buildWithId(); - const originalTask = taskFactory.buildWithId({ lesson: originalLesson }); - const copiedTask = taskFactory.buildWithId({ lesson: copiedLesson }); - const embeddedTaskContent: IComponentProperties = { - title: 'title', - hidden: false, - component: ComponentType.INTERNAL, - content: { - url: `http://somebasedomain.de/homeworks/${originalTask.id}`, - }, + it('should not set materials status', async () => { + const { originalLesson, destinationCourse, user } = setup(); + + const copyStatus = await copyService.copyLesson({ + originalLessonId: originalLesson.id, + destinationCourse, + user, + }); + const materialsGroupStatus = copyStatus.elements?.find( + (el) => el.type === CopyElementType.LERNSTORE_MATERIAL_GROUP + ); + expect(materialsGroupStatus).not.toBeDefined(); + }); + }); + + describe('when a single material is linked to the original lesson', () => { + const setup = () => { + const user = userFactory.build(); + const originalCourse = courseFactory.build({ school: user.school, teachers: [user] }); + const destinationCourse = courseFactory.build({ school: user.school, teachers: [user] }); + const originalMaterial = materialFactory.build(); + const originalLesson = lessonFactory.build({ + course: originalCourse, + materials: [originalMaterial], + }); + lessonRepo.findById.mockResolvedValueOnce(originalLesson); + const materialCopy = materialFactory.build({ title: originalMaterial.title }); + const mockedMaterialStatus = { + title: materialCopy.title, + type: CopyElementType.LERNSTORE_MATERIAL, + status: CopyStatusEnum.SUCCESS, + copyEntity: materialCopy, + }; + const mockedMaterialGroupStatus = { + type: CopyElementType.LERNSTORE_MATERIAL_GROUP, + status: CopyStatusEnum.SUCCESS, + elements: [mockedMaterialStatus], + }; + + return { + user, + destinationCourse, + originalLesson, + originalMaterial, + mockedMaterialStatus, + mockedMaterialGroupStatus, + }; }; - const textContent: IComponentProperties = { - title: 'title component', - hidden: false, - component: ComponentType.TEXT, - content: { - text: 'this is a text content', - }, + + it('should put copy status materials leaf', async () => { + const { originalLesson, destinationCourse, user, mockedMaterialGroupStatus } = setup(); + + const copyStatus = await copyService.copyLesson({ + originalLessonId: originalLesson.id, + destinationCourse, + user, + }); + const materialsGroupStatus = copyStatus.elements?.find( + (el) => el.type === CopyElementType.LERNSTORE_MATERIAL_GROUP + ); + expect(materialsGroupStatus).toBeDefined(); + expect(materialsGroupStatus).toEqual(mockedMaterialGroupStatus); + }); + + it('should put copy status for the copied material', async () => { + const { originalLesson, originalMaterial, destinationCourse, user, mockedMaterialStatus } = setup(); + + const copyStatus = await copyService.copyLesson({ + originalLessonId: originalLesson.id, + destinationCourse, + user, + }); + const materialsGroupStatus = copyStatus.elements?.find( + (el) => el.type === CopyElementType.LERNSTORE_MATERIAL_GROUP + ); + expect(materialsGroupStatus).toBeDefined(); + const materialStatus = materialsGroupStatus?.elements?.find( + (el) => el.type === CopyElementType.LERNSTORE_MATERIAL && el.title === originalMaterial.title + ); + expect(materialStatus).toBeDefined(); + expect(materialStatus?.title).toEqual(mockedMaterialStatus.title); + expect(materialStatus?.status).toEqual(mockedMaterialStatus.status); + const material = materialStatus?.copyEntity as Material; + expect(material?.description).toEqual(mockedMaterialStatus?.copyEntity?.description); + }); + }); + + describe('when mupltiple materials are linked to the original lesson', () => { + const setup = () => { + const user = userFactory.build(); + const originalCourse = courseFactory.build({ school: user.school, teachers: [user] }); + const destinationCourse = courseFactory.build({ school: user.school, teachers: [user] }); + const originalMaterial = materialFactory.buildList(2); + const originalLesson = lessonFactory.build({ + course: originalCourse, + materials: originalMaterial, + }); + lessonRepo.findById.mockResolvedValueOnce(originalLesson); + const materialCopyOne = materialFactory.build({ title: originalMaterial[0].title }); + const materialCopyTwo = materialFactory.build({ title: originalMaterial[1].title }); + const mockedMaterialStatusOne = { + title: materialCopyOne.title, + type: CopyElementType.LERNSTORE_MATERIAL, + status: CopyStatusEnum.SUCCESS, + copyEntity: materialCopyOne, + }; + const mockedMaterialStatusTwo = { + title: materialCopyTwo.title, + type: CopyElementType.LERNSTORE_MATERIAL, + status: CopyStatusEnum.SUCCESS, + copyEntity: materialCopyTwo, + }; + + return { + user, + destinationCourse, + originalLesson, + mockedMaterialStatusOne, + mockedMaterialStatusTwo, + }; }; - copiedLesson.contents = [{ ...textContent }, embeddedTaskContent, { ...textContent }]; - const copyStatus: CopyStatus = { - type: CopyElementType.LESSON, + + it('should put copy status for each copied material under materials', async () => { + const { originalLesson, destinationCourse, user, mockedMaterialStatusOne, mockedMaterialStatusTwo } = setup(); + + const copyStatus = await copyService.copyLesson({ + originalLessonId: originalLesson.id, + destinationCourse, + user, + }); + const materialsGroupStatus = copyStatus.elements?.find( + (el) => el.type === CopyElementType.LERNSTORE_MATERIAL_GROUP + ); + expect(materialsGroupStatus).toBeDefined(); + expect(materialsGroupStatus?.elements?.map((el) => el.title)).toEqual([ + mockedMaterialStatusOne.title, + mockedMaterialStatusTwo.title, + ]); + }); + }); + }); + + describe('updateCopiedEmbeddedTasks', () => { + it('should leave non-lesson status as is', () => { + const status = { + type: CopyElementType.COURSE, status: CopyStatusEnum.SUCCESS, - originalEntity: originalLesson, - copyEntity: copiedLesson, elements: [ { type: CopyElementType.TASK, status: CopyStatusEnum.SUCCESS, - originalEntity: originalTask, - copyEntity: copiedTask, - }, - { - type: CopyElementType.LESSON_CONTENT_GROUP, - status: CopyStatusEnum.PARTIAL, - elements: [ - { - type: CopyElementType.LESSON_CONTENT_TEXT, - status: CopyStatusEnum.SUCCESS, - }, - { - type: CopyElementType.LESSON_CONTENT_TASK, - status: CopyStatusEnum.SUCCESS, - }, - { - type: CopyElementType.LESSON_CONTENT_TEXT, - status: CopyStatusEnum.SUCCESS, - }, - ], }, ], }; - const copyDict = new Map(); - copyDict.set(originalTask.id, copiedTask); - copyHelperService.buildCopyEntityDict.mockReturnValue(copyDict); - return { copyStatus, copiedTask, originalTask }; - }; + const copyDict = copyHelperService.buildCopyEntityDict(status); + const result = copyService.updateCopiedEmbeddedTasks(status, copyDict); - it('should update taskIds in lesson, if tasks were copied', () => { - const { copyStatus, originalTask, copiedTask } = setup(); - const copyDict = copyHelperService.buildCopyEntityDict(copyStatus); - const updatedCopyStatus = copyService.updateCopiedEmbeddedTasks(copyStatus, copyDict); - const lesson = updatedCopyStatus?.copyEntity as LessonEntity; - if (lesson === undefined || lesson.contents === undefined) { - throw new Error('lesson should be part of the copy'); - } - const content = lesson.contents.find((el) => el.component === ComponentType.INTERNAL); - expect((content?.content as IComponentInternalProperties).url).not.toContain(originalTask.id); - expect((content?.content as IComponentInternalProperties).url).toContain(copiedTask.id); + expect(result).toEqual(status); }); - it('should maintain order of content elements', () => { - const { copyStatus } = setup(); - const copyDict = copyHelperService.buildCopyEntityDict(copyStatus); - const updatedCopyStatus = copyService.updateCopiedEmbeddedTasks(copyStatus, copyDict); - const lesson = updatedCopyStatus?.copyEntity as LessonEntity; - if (lesson === undefined || lesson.contents === undefined) { - throw new Error('lesson should be part of the copy'); - } - expect(lesson.contents[1].component).toEqual(ComponentType.INTERNAL); - }); + describe('when status contains lesson with embedded tasks', () => { + const setup = () => { + const originalLesson = lessonFactory.buildWithId(); + const copiedLesson = lessonFactory.buildWithId(); + const originalTask = taskFactory.buildWithId({ lesson: originalLesson }); + const copiedTask = taskFactory.buildWithId({ lesson: copiedLesson }); + const embeddedTaskContent: IComponentProperties = { + title: 'title', + hidden: false, + component: ComponentType.INTERNAL, + content: { + url: `http://somebasedomain.de/homeworks/${originalTask.id}`, + }, + }; + const textContent: IComponentProperties = { + title: 'title component', + hidden: false, + component: ComponentType.TEXT, + content: { + text: 'this is a text content', + }, + }; + copiedLesson.contents = [{ ...textContent }, embeddedTaskContent, { ...textContent }]; + const copyStatus: CopyStatus = { + type: CopyElementType.LESSON, + status: CopyStatusEnum.SUCCESS, + originalEntity: originalLesson, + copyEntity: copiedLesson, + elements: [ + { + type: CopyElementType.TASK, + status: CopyStatusEnum.SUCCESS, + originalEntity: originalTask, + copyEntity: copiedTask, + }, + { + type: CopyElementType.LESSON_CONTENT_GROUP, + status: CopyStatusEnum.PARTIAL, + elements: [ + { + type: CopyElementType.LESSON_CONTENT_TEXT, + status: CopyStatusEnum.SUCCESS, + }, + { + type: CopyElementType.LESSON_CONTENT_TASK, + status: CopyStatusEnum.SUCCESS, + }, + { + type: CopyElementType.LESSON_CONTENT_TEXT, + status: CopyStatusEnum.SUCCESS, + }, + ], + }, + ], + }; + const copyDict = new Map(); + copyDict.set(originalTask.id, copiedTask); + copyHelperService.buildCopyEntityDict.mockReturnValue(copyDict); + return { copyStatus, copiedTask, originalTask }; + }; - it('should keep original url when task is not in dictionary (has not been copied)', () => { - const { copyStatus, originalTask } = setup(); - copyHelperService.buildCopyEntityDict.mockReturnValue(new Map()); - const copyDict = copyHelperService.buildCopyEntityDict(copyStatus); - const updatedCopyStatus = copyService.updateCopiedEmbeddedTasks(copyStatus, copyDict); - const lesson = updatedCopyStatus?.copyEntity as LessonEntity; - if (lesson === undefined || lesson.contents === undefined) { - throw new Error('lesson should be part of the copy'); - } - const content = lesson.contents.find((el) => el.component === ComponentType.INTERNAL); - expect((content?.content as IComponentInternalProperties).url).toEqual( - `http://somebasedomain.de/homeworks/${originalTask.id}` - ); - }); + it('should update taskIds in lesson, if tasks were copied', () => { + const { copyStatus, originalTask, copiedTask } = setup(); + const copyDict = copyHelperService.buildCopyEntityDict(copyStatus); + const updatedCopyStatus = copyService.updateCopiedEmbeddedTasks(copyStatus, copyDict); + const lesson = updatedCopyStatus?.copyEntity as LessonEntity; + if (lesson === undefined || lesson.contents === undefined) { + throw new Error('lesson should be part of the copy'); + } + const content = lesson.contents.find((el) => el.component === ComponentType.INTERNAL); + expect((content?.content as IComponentInternalProperties).url).not.toContain(originalTask.id); + expect((content?.content as IComponentInternalProperties).url).toContain(copiedTask.id); + }); + + it('should maintain order of content elements', () => { + const { copyStatus } = setup(); + const copyDict = copyHelperService.buildCopyEntityDict(copyStatus); + const updatedCopyStatus = copyService.updateCopiedEmbeddedTasks(copyStatus, copyDict); + const lesson = updatedCopyStatus?.copyEntity as LessonEntity; + if (lesson === undefined || lesson.contents === undefined) { + throw new Error('lesson should be part of the copy'); + } + expect(lesson.contents[1].component).toEqual(ComponentType.INTERNAL); + }); + + it('should keep original url when task is not in dictionary (has not been copied)', () => { + const { copyStatus, originalTask } = setup(); + copyHelperService.buildCopyEntityDict.mockReturnValue(new Map()); + const copyDict = copyHelperService.buildCopyEntityDict(copyStatus); + const updatedCopyStatus = copyService.updateCopiedEmbeddedTasks(copyStatus, copyDict); + const lesson = updatedCopyStatus?.copyEntity as LessonEntity; + if (lesson === undefined || lesson.contents === undefined) { + throw new Error('lesson should be part of the copy'); + } + const content = lesson.contents.find((el) => el.component === ComponentType.INTERNAL); + expect((content?.content as IComponentInternalProperties).url).toEqual( + `http://somebasedomain.de/homeworks/${originalTask.id}` + ); + }); - it('should use copyHelperService to build a dictionary', () => { - const { copyStatus } = setup(); - const copyDict = copyHelperService.buildCopyEntityDict(copyStatus); - copyService.updateCopiedEmbeddedTasks(copyStatus, copyDict); - expect(copyHelperService.buildCopyEntityDict).toHaveBeenCalled(); + it('should use copyHelperService to build a dictionary', () => { + const { copyStatus } = setup(); + const copyDict = copyHelperService.buildCopyEntityDict(copyStatus); + copyService.updateCopiedEmbeddedTasks(copyStatus, copyDict); + expect(copyHelperService.buildCopyEntityDict).toHaveBeenCalled(); + }); }); }); }); }); -}); diff --git a/apps/server/src/modules/lesson/service/lesson-copy.service.ts b/apps/server/src/modules/lesson/service/lesson-copy.service.ts index abc81a84736..2e3dc7db872 100644 --- a/apps/server/src/modules/lesson/service/lesson-copy.service.ts +++ b/apps/server/src/modules/lesson/service/lesson-copy.service.ts @@ -227,15 +227,18 @@ export class LessonCopyService { copiedContent.push(linkContent); copiedContentStatus.push(embeddedTaskStatus); } - if (element.component === ComponentType.NEXBOARD) { + if (element.component === ComponentType.NEXBOARD && nexboardEnabled) { // eslint-disable-next-line no-await-in-loop const nexboardContent = await this.copyNexboard(element, params); const nexboardStatus = { title: element.title, type: CopyElementType.LESSON_CONTENT_NEXBOARD, - status: nexboardContent ? CopyStatusEnum.NOT_DOING : CopyStatusEnum.FAIL, + status: CopyStatusEnum.PARTIAL, }; - copiedContentStatus.push(nexboardStatus); + if (nexboardContent) { + nexboardStatus.status = CopyStatusEnum.FAIL; + } + copiedContentStatus.push(nexboardStatus); } } const contentStatus = this.lessonStatusContent(copiedContentStatus);