From 4fb4793f185a549a7866646c32ec8ad22b96592c Mon Sep 17 00:00:00 2001 From: Patrick Sachmann <20001160+psachmann@users.noreply.github.com> Date: Wed, 4 Dec 2024 16:30:47 +0100 Subject: [PATCH 01/25] Adding new import endpoint to cc micro service --- .../common-cartridge.module.ts | 12 +++--- .../controller/common-cartridge.controller.ts | 39 +++++++++++++++++-- .../common-cartridge-import-body.params.ts | 11 ++++++ .../common-cartridge/controller/dto/index.ts | 1 + .../common-cartridge-import.service.ts | 17 ++++++++ .../modules/common-cartridge/service/index.ts | 2 + .../uc/common-cartridge.uc.ts | 14 +++++-- 7 files changed, 84 insertions(+), 12 deletions(-) create mode 100644 apps/server/src/modules/common-cartridge/controller/dto/common-cartridge-import-body.params.ts create mode 100644 apps/server/src/modules/common-cartridge/service/common-cartridge-import.service.ts create mode 100644 apps/server/src/modules/common-cartridge/service/index.ts 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 c5beb84df62..f277d3e7dcb 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge.module.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge.module.ts @@ -2,17 +2,17 @@ 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 { defaultMikroOrmOptions } from '@shared/common/defaultMikroOrmOptions'; 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 { BoardClientModule } from './common-cartridge-client/board-client'; -import { CoursesClientModule } from './common-cartridge-client/course-client'; -import { CommonCartridgeExportService } from './service/common-cartridge-export.service'; -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 { CoursesClientModule } from './common-cartridge-client/course-client'; import { LessonClientModule } from './common-cartridge-client/lesson-client/lesson-client.module'; +import { CourseRoomsModule } from './common-cartridge-client/room-client'; +import { CommonCartridgeExportService, CommonCartridgeImportService } from './service'; +import { CommonCartridgeUc } from './uc/common-cartridge.uc'; @Module({ imports: [ @@ -43,7 +43,7 @@ import { LessonClientModule } from './common-cartridge-client/lesson-client/less basePath: `${Configuration.get('API_HOST') as string}/v3/`, }), ], - providers: [CommonCartridgeUc, CommonCartridgeExportService], + providers: [CommonCartridgeUc, CommonCartridgeExportService, CommonCartridgeImportService], exports: [CommonCartridgeUc], }) export class CommonCartridgeModule {} 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..5e2423a7cf7 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,24 @@ -import { Controller, Get, Param } from '@nestjs/common'; -import { ApiTags } from '@nestjs/swagger'; +import { CurrentUser, ICurrentUser, JwtAuthentication } from '@infra/auth-guard'; +import { Controller, Get, Param, Post, UploadedFile, UseInterceptors } from '@nestjs/common'; +import { FileInterceptor } from '@nestjs/platform-express'; +import { + ApiBadRequestResponse, + ApiBody, + ApiConsumes, + ApiCreatedResponse, + ApiInternalServerErrorResponse, + ApiOperation, + ApiProduces, + ApiTags, + ApiUnauthorizedResponse, +} from '@nestjs/swagger'; +// TODO: move this into common-cartridge module +import { CommonCartridgeFileValidatorPipe } from '@src/modules/learnroom/utils'; import { CommonCartridgeUc } from '../uc/common-cartridge.uc'; -import { ExportCourseParams } from './dto'; +import { CommonCartridgeImportBodyParams, ExportCourseParams } from './dto'; import { CourseExportBodyResponse } from './dto/course-export-body.response'; +@JwtAuthentication() @ApiTags('common-cartridge') @Controller('common-cartridge') export class CommonCartridgeController { @@ -13,4 +28,22 @@ export class CommonCartridgeController { public async exportCourse(@Param() exportCourseParams: ExportCourseParams): Promise { return this.commonCartridgeUC.exportCourse(exportCourseParams.parentId); } + + @Post('import') + @UseInterceptors(FileInterceptor('file')) + @ApiOperation({ summary: 'Imports a course from a Common Cartridge file.' }) + @ApiConsumes('application/octet-stream') + @ApiProduces('application/json') + @ApiBody({ type: CommonCartridgeImportBodyParams, required: true }) + @ApiCreatedResponse({ description: 'Course was successfully imported.' }) + @ApiUnauthorizedResponse({ description: 'Request is unauthorized.' }) + @ApiBadRequestResponse({ description: 'Request data has invalid format.' }) + @ApiInternalServerErrorResponse({ description: 'Internal server error.' }) + public async importCourse( + @CurrentUser() currentUser: ICurrentUser, + @UploadedFile(CommonCartridgeFileValidatorPipe) + file: Express.Multer.File + ): Promise { + return this.commonCartridgeUC.importCourse(file); + } } diff --git a/apps/server/src/modules/common-cartridge/controller/dto/common-cartridge-import-body.params.ts b/apps/server/src/modules/common-cartridge/controller/dto/common-cartridge-import-body.params.ts new file mode 100644 index 00000000000..99e94570841 --- /dev/null +++ b/apps/server/src/modules/common-cartridge/controller/dto/common-cartridge-import-body.params.ts @@ -0,0 +1,11 @@ +import { ApiProperty } from '@nestjs/swagger'; + +export class CommonCartridgeImportBodyParams { + @ApiProperty({ + type: String, + format: 'binary', + required: true, + description: 'The Common Cartridge file to import.', + }) + file!: Express.Multer.File; +} 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..f6440953265 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,3 @@ +export { CommonCartridgeImportBodyParams } from './common-cartridge-import-body.params'; export * from './common-cartridge.params'; export * from './common-cartridge.response'; diff --git a/apps/server/src/modules/common-cartridge/service/common-cartridge-import.service.ts b/apps/server/src/modules/common-cartridge/service/common-cartridge-import.service.ts new file mode 100644 index 00000000000..f16f6e6bab9 --- /dev/null +++ b/apps/server/src/modules/common-cartridge/service/common-cartridge-import.service.ts @@ -0,0 +1,17 @@ +import { Injectable } from '@nestjs/common'; +import { CoursesClientAdapter } from '../common-cartridge-client/course-client'; +import { CommonCartridgeFileParser } from '../import/common-cartridge-file-parser'; + +@Injectable() +export class CommonCartridgeImportService { + constructor(private readonly courseClient: CoursesClientAdapter) {} + + public async importCourse(file: Express.Multer.File): Promise { + const parser = new CommonCartridgeFileParser(file.buffer); + } + + private async createCourse(parser: CommonCartridgeFileParser): Promise { + // TODO: better default name + const courseName = parser.getTitle() || 'Untitled Course'; + } +} diff --git a/apps/server/src/modules/common-cartridge/service/index.ts b/apps/server/src/modules/common-cartridge/service/index.ts new file mode 100644 index 00000000000..a84597c07d4 --- /dev/null +++ b/apps/server/src/modules/common-cartridge/service/index.ts @@ -0,0 +1,2 @@ +export { CommonCartridgeExportService } from './common-cartridge-export.service'; +export { CommonCartridgeImportService } from './common-cartridge-import.service'; 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..a7e4f92e8e9 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,13 +1,17 @@ import { Injectable } from '@nestjs/common'; import { EntityId } from '@shared/domain/types'; +import { CourseCommonCartridgeMetadataDto } from '../common-cartridge-client/course-client'; 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 { CommonCartridgeImportService } from '../service'; +import { CommonCartridgeExportService } from '../service/common-cartridge-export.service'; @Injectable() export class CommonCartridgeUc { - constructor(private readonly exportService: CommonCartridgeExportService) {} + constructor( + private readonly exportService: CommonCartridgeExportService, + private readonly importService: CommonCartridgeImportService + ) {} public async exportCourse(courseId: EntityId): Promise { const files = await this.exportService.findCourseFileRecords(courseId); @@ -22,4 +26,8 @@ export class CommonCartridgeUc { return response; } + + public async importCourse(file: Express.Multer.File): Promise { + await this.importService.importCourse(file); + } } From 2d6476be4c64ea5e349b6b462cac5ae6de0ea7dd Mon Sep 17 00:00:00 2001 From: Patrick Sachmann <20001160+psachmann@users.noreply.github.com> Date: Wed, 4 Dec 2024 17:02:18 +0100 Subject: [PATCH 02/25] Working on create course endpoint --- .../common-cartridge-import.service.ts | 4 ++ .../learnroom/controller/course.controller.ts | 44 ++++++------------- .../dto/create-course-body.params.ts | 20 +++++++++ .../modules/learnroom/controller/dto/index.ts | 9 ++-- .../src/modules/learnroom/uc/course.uc.ts | 15 +++++-- 5 files changed, 55 insertions(+), 37 deletions(-) create mode 100644 apps/server/src/modules/learnroom/controller/dto/create-course-body.params.ts diff --git a/apps/server/src/modules/common-cartridge/service/common-cartridge-import.service.ts b/apps/server/src/modules/common-cartridge/service/common-cartridge-import.service.ts index f16f6e6bab9..181055fe91b 100644 --- a/apps/server/src/modules/common-cartridge/service/common-cartridge-import.service.ts +++ b/apps/server/src/modules/common-cartridge/service/common-cartridge-import.service.ts @@ -8,10 +8,14 @@ export class CommonCartridgeImportService { public async importCourse(file: Express.Multer.File): Promise { const parser = new CommonCartridgeFileParser(file.buffer); + + await this.createCourse(parser); } private async createCourse(parser: CommonCartridgeFileParser): Promise { // TODO: better default name const courseName = parser.getTitle() || 'Untitled Course'; + + throw new Error('Not implemented'); } } diff --git a/apps/server/src/modules/learnroom/controller/course.controller.ts b/apps/server/src/modules/learnroom/controller/course.controller.ts index 8b4854622d5..da037f2c076 100644 --- a/apps/server/src/modules/learnroom/controller/course.controller.ts +++ b/apps/server/src/modules/learnroom/controller/course.controller.ts @@ -8,8 +8,6 @@ import { Param, Post, Query, - Res, - StreamableFile, UploadedFile, UseInterceptors, } from '@nestjs/common'; @@ -22,21 +20,21 @@ import { ApiInternalServerErrorResponse, ApiNoContentResponse, ApiOperation, + ApiProduces, ApiTags, ApiUnprocessableEntityResponse, } from '@nestjs/swagger'; import { PaginationParams } from '@shared/controller/'; -import { Response } from 'express'; import { CourseMapper } from '../mapper/course.mapper'; -import { CourseExportUc, CourseImportUc, CourseSyncUc, CourseUc } from '../uc'; +import { CourseImportUc, CourseSyncUc, CourseUc } from '../uc'; import { CommonCartridgeFileValidatorPipe } from '../utils'; import { CourseExportBodyParams, CourseImportBodyParams, CourseMetadataListResponse, - CourseQueryParams, CourseSyncBodyParams, CourseUrlParams, + CreateCourseBodyParams, } from './dto'; import { CourseCommonCartridgeMetadataResponse } from './dto/course-cc-metadata.response'; @@ -46,13 +44,12 @@ import { CourseCommonCartridgeMetadataResponse } from './dto/course-cc-metadata. export class CourseController { constructor( private readonly courseUc: CourseUc, - private readonly courseExportUc: CourseExportUc, private readonly courseImportUc: CourseImportUc, private readonly courseSyncUc: CourseSyncUc ) {} @Get() - async findForUser( + public async findForUser( @CurrentUser() currentUser: ICurrentUser, @Query() pagination: PaginationParams ): Promise { @@ -64,29 +61,16 @@ export class CourseController { return result; } - @Post(':courseId/export') - async exportCourse( - @CurrentUser() currentUser: ICurrentUser, - @Param() urlParams: CourseUrlParams, - @Query() queryParams: CourseQueryParams, - @Body() bodyParams: CourseExportBodyParams, - @Res({ passthrough: true }) response: Response - ): Promise { - const result = await this.courseExportUc.exportCourse( - urlParams.courseId, - currentUser.userId, - queryParams.version, - bodyParams.topics, - bodyParams.tasks, - bodyParams.columnBoards - ); - - response.set({ - 'Content-Type': 'application/zip', - 'Content-Disposition': 'attachment;', - }); - - return new StreamableFile(result); + @Post() + @ApiOperation({ summary: 'Create a new course.' }) + @ApiConsumes('application/json') + @ApiProduces('application/json') + @ApiBody({ type: CourseExportBodyParams, required: true }) + @ApiCreatedResponse({ description: 'Course was successfully created.' }) + @ApiBadRequestResponse({ description: 'Request data has invalid format.' }) + @ApiInternalServerErrorResponse({ description: 'Internal server error.' }) + public async createCourse(@CurrentUser() user: ICurrentUser, @Body() body: CreateCourseBodyParams): Promise { + await this.courseUc.createCourse(user, body); } @Post('import') diff --git a/apps/server/src/modules/learnroom/controller/dto/create-course-body.params.ts b/apps/server/src/modules/learnroom/controller/dto/create-course-body.params.ts new file mode 100644 index 00000000000..4d9869ff0cd --- /dev/null +++ b/apps/server/src/modules/learnroom/controller/dto/create-course-body.params.ts @@ -0,0 +1,20 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { IsString } from 'class-validator'; + +export class CreateCourseBodyParams { + @IsString() + @ApiProperty({ + description: 'The title of the course', + required: true, + nullable: false, + }) + public title!: string; + + @IsString() + @ApiProperty({ + description: 'The description of the course', + required: true, + nullable: false, + }) + public description!: string; +} diff --git a/apps/server/src/modules/learnroom/controller/dto/index.ts b/apps/server/src/modules/learnroom/controller/dto/index.ts index 756a0f26429..5cf8887ab55 100644 --- a/apps/server/src/modules/learnroom/controller/dto/index.ts +++ b/apps/server/src/modules/learnroom/controller/dto/index.ts @@ -1,7 +1,12 @@ +export * from './course-export.body.params'; export * from './course-import.body.params'; export * from './course-metadata.response'; +export * from './course-room-element.url.params'; +export * from './course-room.url.params'; +export * from './course-sync.body.params'; export * from './course.query.params'; export * from './course.url.params'; +export { CreateCourseBodyParams } from './create-course-body.params'; export * from './dashboard.response'; export * from './dashboard.url.params'; export * from './lesson'; @@ -9,8 +14,4 @@ export * from './move-element.body.params'; export * from './patch-group.params'; export * from './patch-order.params'; export * from './patch-visibility.params'; -export * from './course-room-element.url.params'; -export * from './course-room.url.params'; export * from './single-column-board'; -export * from './course-sync.body.params'; -export * from './course-export.body.params'; diff --git a/apps/server/src/modules/learnroom/uc/course.uc.ts b/apps/server/src/modules/learnroom/uc/course.uc.ts index 5f562c229e5..b0f29680ff8 100644 --- a/apps/server/src/modules/learnroom/uc/course.uc.ts +++ b/apps/server/src/modules/learnroom/uc/course.uc.ts @@ -2,16 +2,17 @@ import { AuthorizationService } from '@modules/authorization'; import { RoleService } from '@modules/role'; import { Injectable } from '@nestjs/common'; import { PaginationParams } from '@shared/controller/'; -import { Course } from '@shared/domain/entity'; +import { Course, CourseProperties } from '@shared/domain/entity'; import { SortOrder } from '@shared/domain/interface'; import { Counted, EntityId } from '@shared/domain/types'; import { CourseRepo } from '@shared/repo'; +import { ICurrentUser } from '@src/infra/auth-guard'; import { RoleNameMapper } from '../mapper/rolename.mapper'; import { CourseService } from '../service'; @Injectable() export class CourseUc { - public constructor( + constructor( private readonly courseRepo: CourseRepo, private readonly courseService: CourseService, private readonly authService: AuthorizationService, @@ -31,7 +32,15 @@ export class CourseUc { return role.permissions ?? []; } - public async findCourseById(courseId: EntityId): Promise { + public findCourseById(courseId: EntityId): Promise { return this.courseService.findById(courseId); } + + public async createCourse(user: ICurrentUser, props: CourseProperties): Promise { + const course = new Course({ + school: user.schoolId, + }); + + return this.courseService.create({ title, description }); + } } From 5166b6201d5b01e1ecb8f1cc76ffe3a5484dd273 Mon Sep 17 00:00:00 2001 From: Patrick Sachmann <20001160+psachmann@users.noreply.github.com> Date: Thu, 5 Dec 2024 15:41:52 +0100 Subject: [PATCH 03/25] updating and moving courses client --- .../courses-client/courses-client.adapter.ts | 18 ++ .../courses-client/courses-client.config.ts | 3 + .../courses-client/courses-client.module.ts | 31 +++ .../infra/courses-client/generated/.gitignore | 4 + .../infra/courses-client/generated/.npmignore | 1 + .../generated/.openapi-generator-ignore | 23 ++ .../generated/.openapi-generator/FILES | 13 + .../src/infra/courses-client/generated/api.ts | 18 ++ .../generated/api/courses-api.ts | 240 ++++++++++++++++++ .../infra/courses-client/generated/base.ts | 86 +++++++ .../infra/courses-client/generated/common.ts | 150 +++++++++++ .../courses-client/generated/configuration.ts | 110 ++++++++ .../courses-client/generated/git_push.sh | 57 +++++ .../infra/courses-client/generated/index.ts | 18 ++ ...urse-common-cartridge-metadata-response.ts | 48 ++++ .../models/create-course-body-params.ts | 30 +++ .../courses-client/generated/models/index.ts | 2 + apps/server/src/infra/courses-client/index.ts | 4 + .../src/modules/server/server.config.ts | 5 +- apps/server/src/shared/common/utils/jwt.ts | 15 +- openapitools.json | 24 ++ package.json | 6 +- 22 files changed, 901 insertions(+), 5 deletions(-) create mode 100644 apps/server/src/infra/courses-client/courses-client.adapter.ts create mode 100644 apps/server/src/infra/courses-client/courses-client.config.ts create mode 100644 apps/server/src/infra/courses-client/courses-client.module.ts create mode 100644 apps/server/src/infra/courses-client/generated/.gitignore create mode 100644 apps/server/src/infra/courses-client/generated/.npmignore create mode 100644 apps/server/src/infra/courses-client/generated/.openapi-generator-ignore create mode 100644 apps/server/src/infra/courses-client/generated/.openapi-generator/FILES create mode 100644 apps/server/src/infra/courses-client/generated/api.ts create mode 100644 apps/server/src/infra/courses-client/generated/api/courses-api.ts create mode 100644 apps/server/src/infra/courses-client/generated/base.ts create mode 100644 apps/server/src/infra/courses-client/generated/common.ts create mode 100644 apps/server/src/infra/courses-client/generated/configuration.ts create mode 100644 apps/server/src/infra/courses-client/generated/git_push.sh create mode 100644 apps/server/src/infra/courses-client/generated/index.ts create mode 100644 apps/server/src/infra/courses-client/generated/models/course-common-cartridge-metadata-response.ts create mode 100644 apps/server/src/infra/courses-client/generated/models/create-course-body-params.ts create mode 100644 apps/server/src/infra/courses-client/generated/models/index.ts create mode 100644 apps/server/src/infra/courses-client/index.ts diff --git a/apps/server/src/infra/courses-client/courses-client.adapter.ts b/apps/server/src/infra/courses-client/courses-client.adapter.ts new file mode 100644 index 00000000000..ba8392a4eaa --- /dev/null +++ b/apps/server/src/infra/courses-client/courses-client.adapter.ts @@ -0,0 +1,18 @@ +import { Injectable } from '@nestjs/common'; +import { CourseCommonCartridgeMetadataResponse, CoursesApi, CreateCourseBodyParams } from './generated'; + +@Injectable() +export class CoursesClientAdapter { + constructor(private readonly coursesApi: CoursesApi) {} + + public async getCourseCommonCartridgeMetadata(courseId: string): Promise { + const response = await this.coursesApi.courseControllerGetCourseCcMetadataById(courseId); + const result = response.data; + + return result; + } + + public async createCourse(params: CreateCourseBodyParams): Promise { + await this.coursesApi.courseControllerCreateCourse(params); + } +} diff --git a/apps/server/src/infra/courses-client/courses-client.config.ts b/apps/server/src/infra/courses-client/courses-client.config.ts new file mode 100644 index 00000000000..a31383b2e02 --- /dev/null +++ b/apps/server/src/infra/courses-client/courses-client.config.ts @@ -0,0 +1,3 @@ +export interface CoursesClientConfig { + API_HOST: string; +} diff --git a/apps/server/src/infra/courses-client/courses-client.module.ts b/apps/server/src/infra/courses-client/courses-client.module.ts new file mode 100644 index 00000000000..bc78f838153 --- /dev/null +++ b/apps/server/src/infra/courses-client/courses-client.module.ts @@ -0,0 +1,31 @@ +import { Module, Scope } from '@nestjs/common'; +import { ConfigService } from '@nestjs/config'; +import { REQUEST } from '@nestjs/core'; +import { extractJwtFromRequest } from '@shared/common/utils/jwt'; +import { Request } from 'express'; +import { CoursesClientAdapter } from './courses-client.adapter'; +import { CoursesClientConfig } from './courses-client.config'; +import { Configuration, CoursesApi } from './generated'; + +@Module({ + providers: [ + CoursesClientAdapter, + { + provide: CoursesApi, + scope: Scope.REQUEST, + useFactory: (configService: ConfigService, request: Request): CoursesApi => { + const basePath = configService.getOrThrow('API_HOST'); + const accessToken = extractJwtFromRequest(request); + const configuration = new Configuration({ + basePath: `${basePath}/api/v3`, + accessToken, + }); + + return new CoursesApi(configuration); + }, + inject: [ConfigService, REQUEST], + }, + ], + exports: [CoursesClientAdapter], +}) +export class CoursesClientModule {} diff --git a/apps/server/src/infra/courses-client/generated/.gitignore b/apps/server/src/infra/courses-client/generated/.gitignore new file mode 100644 index 00000000000..149b5765472 --- /dev/null +++ b/apps/server/src/infra/courses-client/generated/.gitignore @@ -0,0 +1,4 @@ +wwwroot/*.js +node_modules +typings +dist diff --git a/apps/server/src/infra/courses-client/generated/.npmignore b/apps/server/src/infra/courses-client/generated/.npmignore new file mode 100644 index 00000000000..999d88df693 --- /dev/null +++ b/apps/server/src/infra/courses-client/generated/.npmignore @@ -0,0 +1 @@ +# empty npmignore to ensure all required files (e.g., in the dist folder) are published by npm \ No newline at end of file diff --git a/apps/server/src/infra/courses-client/generated/.openapi-generator-ignore b/apps/server/src/infra/courses-client/generated/.openapi-generator-ignore new file mode 100644 index 00000000000..7484ee590a3 --- /dev/null +++ b/apps/server/src/infra/courses-client/generated/.openapi-generator-ignore @@ -0,0 +1,23 @@ +# OpenAPI Generator Ignore +# Generated by openapi-generator https://github.com/openapitools/openapi-generator + +# Use this file to prevent files from being overwritten by the generator. +# The patterns follow closely to .gitignore or .dockerignore. + +# As an example, the C# client generator defines ApiClient.cs. +# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line: +#ApiClient.cs + +# You can match any string of characters against a directory, file or extension with a single asterisk (*): +#foo/*/qux +# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux + +# You can recursively match patterns against a directory, file or extension with a double asterisk (**): +#foo/**/qux +# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux + +# You can also negate patterns with an exclamation (!). +# For example, you can ignore all files in a docs folder with the file extension .md: +#docs/*.md +# Then explicitly reverse the ignore rule for a single file: +#!docs/README.md diff --git a/apps/server/src/infra/courses-client/generated/.openapi-generator/FILES b/apps/server/src/infra/courses-client/generated/.openapi-generator/FILES new file mode 100644 index 00000000000..e10dec0e56c --- /dev/null +++ b/apps/server/src/infra/courses-client/generated/.openapi-generator/FILES @@ -0,0 +1,13 @@ +.gitignore +.npmignore +.openapi-generator-ignore +api.ts +api/courses-api.ts +base.ts +common.ts +configuration.ts +git_push.sh +index.ts +models/course-common-cartridge-metadata-response.ts +models/create-course-body-params.ts +models/index.ts diff --git a/apps/server/src/infra/courses-client/generated/api.ts b/apps/server/src/infra/courses-client/generated/api.ts new file mode 100644 index 00000000000..2a01572ebdf --- /dev/null +++ b/apps/server/src/infra/courses-client/generated/api.ts @@ -0,0 +1,18 @@ +/* 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 * from './api/courses-api'; + diff --git a/apps/server/src/infra/courses-client/generated/api/courses-api.ts b/apps/server/src/infra/courses-client/generated/api/courses-api.ts new file mode 100644 index 00000000000..9be58d522be --- /dev/null +++ b/apps/server/src/infra/courses-client/generated/api/courses-api.ts @@ -0,0 +1,240 @@ +/* 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. + */ + + +import type { Configuration } from '../configuration'; +import type { AxiosPromise, AxiosInstance, RawAxiosRequestConfig } from 'axios'; +import globalAxios from 'axios'; +// Some imports not used depending on template conditions +// @ts-ignore +import { DUMMY_BASE_URL, assertParamExists, setApiKeyToObject, setBasicAuthToObject, setBearerAuthToObject, setOAuthToObject, setSearchParams, serializeDataIfNeeded, toPathString, createRequestFunction } from '../common'; +// @ts-ignore +import { BASE_PATH, COLLECTION_FORMATS, type RequestArgs, BaseAPI, RequiredError, operationServerMap } from '../base'; +// @ts-ignore +import type { CourseCommonCartridgeMetadataResponse } from '../models'; +// @ts-ignore +import type { CreateCourseBodyParams } from '../models'; +/** + * CoursesApi - axios parameter creator + * @export + */ +export const CoursesApiAxiosParamCreator = function (configuration?: Configuration) { + return { + /** + * + * @summary Create a new course. + * @param {CreateCourseBodyParams} createCourseBodyParams + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + courseControllerCreateCourse: async (createCourseBodyParams: CreateCourseBodyParams, options: RawAxiosRequestConfig = {}): Promise => { + // verify required parameter 'createCourseBodyParams' is not null or undefined + assertParamExists('courseControllerCreateCourse', 'createCourseBodyParams', createCourseBodyParams) + const localVarPath = `/courses`; + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication bearer required + // http bearer authentication required + await setBearerAuthToObject(localVarHeaderParameter, configuration) + + + + localVarHeaderParameter['Content-Type'] = 'application/json'; + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + localVarRequestOptions.data = serializeDataIfNeeded(createCourseBodyParams, localVarRequestOptions, configuration) + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * + * @summary Get common cartridge metadata of a course by Id. + * @param {string} courseId The id of the course + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + courseControllerGetCourseCcMetadataById: async (courseId: string, options: RawAxiosRequestConfig = {}): Promise => { + // verify required parameter 'courseId' is not null or undefined + assertParamExists('courseControllerGetCourseCcMetadataById', 'courseId', courseId) + const localVarPath = `/courses/{courseId}/cc-metadata` + .replace(`{${"courseId"}}`, encodeURIComponent(String(courseId))); + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication bearer required + // http bearer authentication required + await setBearerAuthToObject(localVarHeaderParameter, configuration) + + + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + } +}; + +/** + * CoursesApi - functional programming interface + * @export + */ +export const CoursesApiFp = function(configuration?: Configuration) { + const localVarAxiosParamCreator = CoursesApiAxiosParamCreator(configuration) + return { + /** + * + * @summary Create a new course. + * @param {CreateCourseBodyParams} createCourseBodyParams + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async courseControllerCreateCourse(createCourseBodyParams: CreateCourseBodyParams, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.courseControllerCreateCourse(createCourseBodyParams, options); + const localVarOperationServerIndex = configuration?.serverIndex ?? 0; + const localVarOperationServerBasePath = operationServerMap['CoursesApi.courseControllerCreateCourse']?.[localVarOperationServerIndex]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); + }, + /** + * + * @summary Get common cartridge metadata of a course by Id. + * @param {string} courseId The id of the course + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async courseControllerGetCourseCcMetadataById(courseId: string, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.courseControllerGetCourseCcMetadataById(courseId, options); + const localVarOperationServerIndex = configuration?.serverIndex ?? 0; + const localVarOperationServerBasePath = operationServerMap['CoursesApi.courseControllerGetCourseCcMetadataById']?.[localVarOperationServerIndex]?.url; + return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); + }, + } +}; + +/** + * CoursesApi - factory interface + * @export + */ +export const CoursesApiFactory = function (configuration?: Configuration, basePath?: string, axios?: AxiosInstance) { + const localVarFp = CoursesApiFp(configuration) + return { + /** + * + * @summary Create a new course. + * @param {CreateCourseBodyParams} createCourseBodyParams + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + courseControllerCreateCourse(createCourseBodyParams: CreateCourseBodyParams, options?: any): AxiosPromise { + return localVarFp.courseControllerCreateCourse(createCourseBodyParams, options).then((request) => request(axios, basePath)); + }, + /** + * + * @summary Get common cartridge metadata of a course by Id. + * @param {string} courseId The id of the course + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + courseControllerGetCourseCcMetadataById(courseId: string, options?: any): AxiosPromise { + return localVarFp.courseControllerGetCourseCcMetadataById(courseId, options).then((request) => request(axios, basePath)); + }, + }; +}; + +/** + * CoursesApi - interface + * @export + * @interface CoursesApi + */ +export interface CoursesApiInterface { + /** + * + * @summary Create a new course. + * @param {CreateCourseBodyParams} createCourseBodyParams + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof CoursesApiInterface + */ + courseControllerCreateCourse(createCourseBodyParams: CreateCourseBodyParams, options?: RawAxiosRequestConfig): AxiosPromise; + + /** + * + * @summary Get common cartridge metadata of a course by Id. + * @param {string} courseId The id of the course + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof CoursesApiInterface + */ + courseControllerGetCourseCcMetadataById(courseId: string, options?: RawAxiosRequestConfig): AxiosPromise; + +} + +/** + * CoursesApi - object-oriented interface + * @export + * @class CoursesApi + * @extends {BaseAPI} + */ +export class CoursesApi extends BaseAPI implements CoursesApiInterface { + /** + * + * @summary Create a new course. + * @param {CreateCourseBodyParams} createCourseBodyParams + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof CoursesApi + */ + public courseControllerCreateCourse(createCourseBodyParams: CreateCourseBodyParams, options?: RawAxiosRequestConfig) { + return CoursesApiFp(this.configuration).courseControllerCreateCourse(createCourseBodyParams, options).then((request) => request(this.axios, this.basePath)); + } + + /** + * + * @summary Get common cartridge metadata of a course by Id. + * @param {string} courseId The id of the course + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof CoursesApi + */ + public courseControllerGetCourseCcMetadataById(courseId: string, options?: RawAxiosRequestConfig) { + return CoursesApiFp(this.configuration).courseControllerGetCourseCcMetadataById(courseId, options).then((request) => request(this.axios, this.basePath)); + } +} + diff --git a/apps/server/src/infra/courses-client/generated/base.ts b/apps/server/src/infra/courses-client/generated/base.ts new file mode 100644 index 00000000000..5bcf014a72f --- /dev/null +++ b/apps/server/src/infra/courses-client/generated/base.ts @@ -0,0 +1,86 @@ +/* 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. + */ + + +import type { Configuration } from './configuration'; +// Some imports not used depending on template conditions +// @ts-ignore +import type { AxiosPromise, AxiosInstance, RawAxiosRequestConfig } from 'axios'; +import globalAxios from 'axios'; + +export const BASE_PATH = "http://localhost:3030/api/v3".replace(/\/+$/, ""); + +/** + * + * @export + */ +export const COLLECTION_FORMATS = { + csv: ",", + ssv: " ", + tsv: "\t", + pipes: "|", +}; + +/** + * + * @export + * @interface RequestArgs + */ +export interface RequestArgs { + url: string; + options: RawAxiosRequestConfig; +} + +/** + * + * @export + * @class BaseAPI + */ +export class BaseAPI { + protected configuration: Configuration | undefined; + + constructor(configuration?: Configuration, protected basePath: string = BASE_PATH, protected axios: AxiosInstance = globalAxios) { + if (configuration) { + this.configuration = configuration; + this.basePath = configuration.basePath ?? basePath; + } + } +}; + +/** + * + * @export + * @class RequiredError + * @extends {Error} + */ +export class RequiredError extends Error { + constructor(public field: string, msg?: string) { + super(msg); + this.name = "RequiredError" + } +} + +interface ServerMap { + [key: string]: { + url: string, + description: string, + }[]; +} + +/** + * + * @export + */ +export const operationServerMap: ServerMap = { +} diff --git a/apps/server/src/infra/courses-client/generated/common.ts b/apps/server/src/infra/courses-client/generated/common.ts new file mode 100644 index 00000000000..6c119efb60d --- /dev/null +++ b/apps/server/src/infra/courses-client/generated/common.ts @@ -0,0 +1,150 @@ +/* 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. + */ + + +import type { Configuration } from "./configuration"; +import type { RequestArgs } from "./base"; +import type { AxiosInstance, AxiosResponse } from 'axios'; +import { RequiredError } from "./base"; + +/** + * + * @export + */ +export const DUMMY_BASE_URL = 'https://example.com' + +/** + * + * @throws {RequiredError} + * @export + */ +export const assertParamExists = function (functionName: string, paramName: string, paramValue: unknown) { + if (paramValue === null || paramValue === undefined) { + throw new RequiredError(paramName, `Required parameter ${paramName} was null or undefined when calling ${functionName}.`); + } +} + +/** + * + * @export + */ +export const setApiKeyToObject = async function (object: any, keyParamName: string, configuration?: Configuration) { + if (configuration && configuration.apiKey) { + const localVarApiKeyValue = typeof configuration.apiKey === 'function' + ? await configuration.apiKey(keyParamName) + : await configuration.apiKey; + object[keyParamName] = localVarApiKeyValue; + } +} + +/** + * + * @export + */ +export const setBasicAuthToObject = function (object: any, configuration?: Configuration) { + if (configuration && (configuration.username || configuration.password)) { + object["auth"] = { username: configuration.username, password: configuration.password }; + } +} + +/** + * + * @export + */ +export const setBearerAuthToObject = async function (object: any, configuration?: Configuration) { + if (configuration && configuration.accessToken) { + const accessToken = typeof configuration.accessToken === 'function' + ? await configuration.accessToken() + : await configuration.accessToken; + object["Authorization"] = "Bearer " + accessToken; + } +} + +/** + * + * @export + */ +export const setOAuthToObject = async function (object: any, name: string, scopes: string[], configuration?: Configuration) { + if (configuration && configuration.accessToken) { + const localVarAccessTokenValue = typeof configuration.accessToken === 'function' + ? await configuration.accessToken(name, scopes) + : await configuration.accessToken; + object["Authorization"] = "Bearer " + localVarAccessTokenValue; + } +} + +function setFlattenedQueryParams(urlSearchParams: URLSearchParams, parameter: any, key: string = ""): void { + if (parameter == null) return; + if (typeof parameter === "object") { + if (Array.isArray(parameter)) { + (parameter as any[]).forEach(item => setFlattenedQueryParams(urlSearchParams, item, key)); + } + else { + Object.keys(parameter).forEach(currentKey => + setFlattenedQueryParams(urlSearchParams, parameter[currentKey], `${key}${key !== '' ? '.' : ''}${currentKey}`) + ); + } + } + else { + if (urlSearchParams.has(key)) { + urlSearchParams.append(key, parameter); + } + else { + urlSearchParams.set(key, parameter); + } + } +} + +/** + * + * @export + */ +export const setSearchParams = function (url: URL, ...objects: any[]) { + const searchParams = new URLSearchParams(url.search); + setFlattenedQueryParams(searchParams, objects); + url.search = searchParams.toString(); +} + +/** + * + * @export + */ +export const serializeDataIfNeeded = function (value: any, requestOptions: any, configuration?: Configuration) { + const nonString = typeof value !== 'string'; + const needsSerialization = nonString && configuration && configuration.isJsonMime + ? configuration.isJsonMime(requestOptions.headers['Content-Type']) + : nonString; + return needsSerialization + ? JSON.stringify(value !== undefined ? value : {}) + : (value || ""); +} + +/** + * + * @export + */ +export const toPathString = function (url: URL) { + return url.pathname + url.search + url.hash +} + +/** + * + * @export + */ +export const createRequestFunction = function (axiosArgs: RequestArgs, globalAxios: AxiosInstance, BASE_PATH: string, configuration?: Configuration) { + return >(axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => { + const axiosRequestArgs = {...axiosArgs.options, url: (axios.defaults.baseURL ? '' : configuration?.basePath ?? basePath) + axiosArgs.url}; + return axios.request(axiosRequestArgs); + }; +} diff --git a/apps/server/src/infra/courses-client/generated/configuration.ts b/apps/server/src/infra/courses-client/generated/configuration.ts new file mode 100644 index 00000000000..8c97d307cf4 --- /dev/null +++ b/apps/server/src/infra/courses-client/generated/configuration.ts @@ -0,0 +1,110 @@ +/* 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 ConfigurationParameters { + apiKey?: string | Promise | ((name: string) => string) | ((name: string) => Promise); + username?: string; + password?: string; + accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string) | ((name?: string, scopes?: string[]) => Promise); + basePath?: string; + serverIndex?: number; + baseOptions?: any; + formDataCtor?: new () => any; +} + +export class Configuration { + /** + * parameter for apiKey security + * @param name security name + * @memberof Configuration + */ + apiKey?: string | Promise | ((name: string) => string) | ((name: string) => Promise); + /** + * parameter for basic security + * + * @type {string} + * @memberof Configuration + */ + username?: string; + /** + * parameter for basic security + * + * @type {string} + * @memberof Configuration + */ + password?: string; + /** + * parameter for oauth2 security + * @param name security name + * @param scopes oauth2 scope + * @memberof Configuration + */ + accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string) | ((name?: string, scopes?: string[]) => Promise); + /** + * override base path + * + * @type {string} + * @memberof Configuration + */ + basePath?: string; + /** + * override server index + * + * @type {number} + * @memberof Configuration + */ + serverIndex?: number; + /** + * base options for axios calls + * + * @type {any} + * @memberof Configuration + */ + baseOptions?: any; + /** + * The FormData constructor that will be used to create multipart form data + * requests. You can inject this here so that execution environments that + * do not support the FormData class can still run the generated client. + * + * @type {new () => FormData} + */ + formDataCtor?: new () => any; + + constructor(param: ConfigurationParameters = {}) { + this.apiKey = param.apiKey; + this.username = param.username; + this.password = param.password; + this.accessToken = param.accessToken; + this.basePath = param.basePath; + this.serverIndex = param.serverIndex; + this.baseOptions = param.baseOptions; + this.formDataCtor = param.formDataCtor; + } + + /** + * Check if the given MIME is a JSON MIME. + * JSON MIME examples: + * application/json + * application/json; charset=UTF8 + * APPLICATION/JSON + * application/vnd.company+json + * @param mime - MIME (Multipurpose Internet Mail Extensions) + * @return True if the given MIME is JSON, false otherwise. + */ + public isJsonMime(mime: string): boolean { + const jsonMime: RegExp = new RegExp('^(application\/json|[^;/ \t]+\/[^;/ \t]+[+]json)[ \t]*(;.*)?$', 'i'); + return mime !== null && (jsonMime.test(mime) || mime.toLowerCase() === 'application/json-patch+json'); + } +} diff --git a/apps/server/src/infra/courses-client/generated/git_push.sh b/apps/server/src/infra/courses-client/generated/git_push.sh new file mode 100644 index 00000000000..f53a75d4fab --- /dev/null +++ b/apps/server/src/infra/courses-client/generated/git_push.sh @@ -0,0 +1,57 @@ +#!/bin/sh +# ref: https://help.github.com/articles/adding-an-existing-project-to-github-using-the-command-line/ +# +# Usage example: /bin/sh ./git_push.sh wing328 openapi-petstore-perl "minor update" "gitlab.com" + +git_user_id=$1 +git_repo_id=$2 +release_note=$3 +git_host=$4 + +if [ "$git_host" = "" ]; then + git_host="github.com" + echo "[INFO] No command line input provided. Set \$git_host to $git_host" +fi + +if [ "$git_user_id" = "" ]; then + git_user_id="GIT_USER_ID" + echo "[INFO] No command line input provided. Set \$git_user_id to $git_user_id" +fi + +if [ "$git_repo_id" = "" ]; then + git_repo_id="GIT_REPO_ID" + echo "[INFO] No command line input provided. Set \$git_repo_id to $git_repo_id" +fi + +if [ "$release_note" = "" ]; then + release_note="Minor update" + echo "[INFO] No command line input provided. Set \$release_note to $release_note" +fi + +# Initialize the local directory as a Git repository +git init + +# Adds the files in the local repository and stages them for commit. +git add . + +# Commits the tracked changes and prepares them to be pushed to a remote repository. +git commit -m "$release_note" + +# Sets the new remote +git_remote=$(git remote) +if [ "$git_remote" = "" ]; then # git remote not defined + + if [ "$GIT_TOKEN" = "" ]; then + echo "[INFO] \$GIT_TOKEN (environment variable) is not set. Using the git credential in your environment." + git remote add origin https://${git_host}/${git_user_id}/${git_repo_id}.git + else + git remote add origin https://${git_user_id}:"${GIT_TOKEN}"@${git_host}/${git_user_id}/${git_repo_id}.git + fi + +fi + +git pull origin master + +# Pushes (Forces) the changes in the local repository up to the remote repository +echo "Git pushing to https://${git_host}/${git_user_id}/${git_repo_id}.git" +git push origin master 2>&1 | grep -v 'To https' diff --git a/apps/server/src/infra/courses-client/generated/index.ts b/apps/server/src/infra/courses-client/generated/index.ts new file mode 100644 index 00000000000..8b762df664e --- /dev/null +++ b/apps/server/src/infra/courses-client/generated/index.ts @@ -0,0 +1,18 @@ +/* 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 * from "./api"; +export * from "./configuration"; +export * from "./models"; diff --git a/apps/server/src/infra/courses-client/generated/models/course-common-cartridge-metadata-response.ts b/apps/server/src/infra/courses-client/generated/models/course-common-cartridge-metadata-response.ts new file mode 100644 index 00000000000..85d01bb7a85 --- /dev/null +++ b/apps/server/src/infra/courses-client/generated/models/course-common-cartridge-metadata-response.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 CourseCommonCartridgeMetadataResponse + */ +export interface CourseCommonCartridgeMetadataResponse { + /** + * The id of the course + * @type {string} + * @memberof CourseCommonCartridgeMetadataResponse + */ + 'id': string; + /** + * Title of the course + * @type {string} + * @memberof CourseCommonCartridgeMetadataResponse + */ + 'title': string; + /** + * Creation date of the course + * @type {string} + * @memberof CourseCommonCartridgeMetadataResponse + */ + 'creationDate': string; + /** + * Copy right owners of the course + * @type {Array} + * @memberof CourseCommonCartridgeMetadataResponse + */ + 'copyRightOwners': Array; +} + diff --git a/apps/server/src/infra/courses-client/generated/models/create-course-body-params.ts b/apps/server/src/infra/courses-client/generated/models/create-course-body-params.ts new file mode 100644 index 00000000000..7c27ac50eae --- /dev/null +++ b/apps/server/src/infra/courses-client/generated/models/create-course-body-params.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 CreateCourseBodyParams + */ +export interface CreateCourseBodyParams { + /** + * The title of the course + * @type {string} + * @memberof CreateCourseBodyParams + */ + 'title': string; +} + diff --git a/apps/server/src/infra/courses-client/generated/models/index.ts b/apps/server/src/infra/courses-client/generated/models/index.ts new file mode 100644 index 00000000000..3a4d2661a7c --- /dev/null +++ b/apps/server/src/infra/courses-client/generated/models/index.ts @@ -0,0 +1,2 @@ +export * from './course-common-cartridge-metadata-response'; +export * from './create-course-body-params'; diff --git a/apps/server/src/infra/courses-client/index.ts b/apps/server/src/infra/courses-client/index.ts new file mode 100644 index 00000000000..d49321c824e --- /dev/null +++ b/apps/server/src/infra/courses-client/index.ts @@ -0,0 +1,4 @@ +export { CoursesClientAdapter } from './courses-client.adapter'; +export { CoursesClientConfig } from './courses-client.config'; +export { CoursesClientModule } from './courses-client.module'; +export type * from './generated/models'; diff --git a/apps/server/src/modules/server/server.config.ts b/apps/server/src/modules/server/server.config.ts index 3c8f9d89708..fe858b67219 100644 --- a/apps/server/src/modules/server/server.config.ts +++ b/apps/server/src/modules/server/server.config.ts @@ -1,5 +1,6 @@ import { Configuration } from '@hpi-schul-cloud/commons'; import { JwtAuthGuardConfig } from '@infra/auth-guard'; +import { CoursesClientConfig } from '@infra/courses-client'; import { EncryptionConfig } from '@infra/encryption/encryption.config'; import type { IdentityManagementConfig } from '@infra/identity-management'; import type { MailConfig } from '@infra/mail/interfaces/mail-config'; @@ -75,7 +76,8 @@ export interface ServerConfig AlertConfig, ShdConfig, OauthConfig, - EncryptionConfig { + EncryptionConfig, + CoursesClientConfig { NODE_ENV: NodeEnvType; SC_DOMAIN: string; HOST: string; @@ -130,6 +132,7 @@ export interface ServerConfig } const config: ServerConfig = { + API_HOST: Configuration.get('API_HOST') as string, ACCESSIBILITY_REPORT_EMAIL: Configuration.get('ACCESSIBILITY_REPORT_EMAIL') as string, ADMIN_TABLES_DISPLAY_CONSENT_COLUMN: Configuration.get('ADMIN_TABLES_DISPLAY_CONSENT_COLUMN') as boolean, ALERT_STATUS_URL: diff --git a/apps/server/src/shared/common/utils/jwt.ts b/apps/server/src/shared/common/utils/jwt.ts index ebc589236dc..6c6ffe1b3a1 100644 --- a/apps/server/src/shared/common/utils/jwt.ts +++ b/apps/server/src/shared/common/utils/jwt.ts @@ -1,9 +1,10 @@ +import { UnauthorizedException } from '@nestjs/common'; +import cookie from 'cookie'; import { Request } from 'express'; import { ExtractJwt, JwtFromRequestFunction } from 'passport-jwt'; -import cookie from 'cookie'; export class JwtExtractor { - static fromCookie(name: string): JwtFromRequestFunction { + public static fromCookie(name: string): JwtFromRequestFunction { return (request: Request) => { let token: string | null = null; const cookies = cookie.parse(request.headers.cookie || ''); @@ -19,3 +20,13 @@ export const extractJwtFromHeader = ExtractJwt.fromExtractors([ ExtractJwt.fromAuthHeaderAsBearerToken(), JwtExtractor.fromCookie('jwt'), ]); + +export const extractJwtFromRequest = (request: Request): string => { + const jwt = extractJwtFromHeader(request); + + if (!jwt) { + throw new UnauthorizedException('No JWT token found'); + } + + return jwt; +}; diff --git a/openapitools.json b/openapitools.json index bd567305968..39cf304936d 100644 --- a/openapitools.json +++ b/openapitools.json @@ -27,6 +27,30 @@ "withInterfaces": true, "withSeparateModelsAndApi": true } + }, + "courses-api": { + "generatorName": "typescript-axios", + "inputSpec": "http://localhost:3030/api/v3/docs-json", + "output": "./apps/server/src/infra/courses-client/generated", + "skipValidateSpec": true, + "enablePostProcessFile": true, + "openapiNormalizer": { + "FILTER": "operationId:CourseController_getCourseCcMetadataById|CourseController_createCourse" + }, + "globalProperty": { + "models": "CourseCommonCartridgeMetadataResponse:CreateCourseBodyParams", + "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 21409c40dcb..e599445c9fa 100644 --- a/package.json +++ b/package.json @@ -121,7 +121,9 @@ "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", + "pregenerate-client:courses-api": "rimraf ./apps/server/src/infra/courses-client/generated", + "generate-client:courses-api": "openapi-generator-cli generate -c ./openapitools.json --generator-key courses-api" }, "dependencies": { "@aws-sdk/lib-storage": "^3.617.0", @@ -339,4 +341,4 @@ "tsconfig-paths": "^4.1.1", "typescript": "^5.5.4" } -} \ No newline at end of file +} From 21d9d871cf7b1326b3800e645e08197f8bbdb6bd Mon Sep 17 00:00:00 2001 From: Patrick Sachmann <20001160+psachmann@users.noreply.github.com> Date: Thu, 5 Dec 2024 15:42:21 +0100 Subject: [PATCH 04/25] removing old courses client --- .../course-api-client/.gitignore | 4 - .../course-api-client/.npmignore | 1 - .../.openapi-generator-ignore | 23 - .../.openapi-generator/FILES | 15 - .../course-client/course-api-client/api.ts | 18 - .../course-api-client/api/courses-api.ts | 611 ------------------ .../course-client/course-api-client/base.ts | 86 --- .../course-client/course-api-client/common.ts | 150 ----- .../course-api-client/configuration.ts | 110 ---- .../course-api-client/git_push.sh | 57 -- .../course-client/course-api-client/index.ts | 18 - ...urse-common-cartridge-metadata-response.ts | 48 -- .../models/course-export-body-params.ts | 42 -- .../models/course-metadata-list-response.ts | 51 -- .../models/course-metadata-response.ts | 66 -- .../course-api-client/models/index.ts | 4 - 16 files changed, 1304 deletions(-) delete mode 100644 apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/course-api-client/.gitignore delete mode 100644 apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/course-api-client/.npmignore delete mode 100644 apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/course-api-client/.openapi-generator-ignore delete mode 100644 apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/course-api-client/.openapi-generator/FILES delete mode 100644 apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/course-api-client/api.ts delete mode 100644 apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/course-api-client/api/courses-api.ts delete mode 100644 apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/course-api-client/base.ts delete mode 100644 apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/course-api-client/common.ts delete mode 100644 apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/course-api-client/configuration.ts delete mode 100644 apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/course-api-client/git_push.sh delete mode 100644 apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/course-api-client/index.ts delete mode 100644 apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/course-api-client/models/course-common-cartridge-metadata-response.ts delete mode 100644 apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/course-api-client/models/course-export-body-params.ts delete mode 100644 apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/course-api-client/models/course-metadata-list-response.ts delete mode 100644 apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/course-api-client/models/course-metadata-response.ts delete mode 100644 apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/course-api-client/models/index.ts diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/course-api-client/.gitignore b/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/course-api-client/.gitignore deleted file mode 100644 index 149b5765472..00000000000 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/course-api-client/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -wwwroot/*.js -node_modules -typings -dist diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/course-api-client/.npmignore b/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/course-api-client/.npmignore deleted file mode 100644 index 999d88df693..00000000000 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/course-api-client/.npmignore +++ /dev/null @@ -1 +0,0 @@ -# empty npmignore to ensure all required files (e.g., in the dist folder) are published by npm \ No newline at end of file diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/course-api-client/.openapi-generator-ignore b/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/course-api-client/.openapi-generator-ignore deleted file mode 100644 index 7484ee590a3..00000000000 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/course-api-client/.openapi-generator-ignore +++ /dev/null @@ -1,23 +0,0 @@ -# OpenAPI Generator Ignore -# Generated by openapi-generator https://github.com/openapitools/openapi-generator - -# Use this file to prevent files from being overwritten by the generator. -# The patterns follow closely to .gitignore or .dockerignore. - -# As an example, the C# client generator defines ApiClient.cs. -# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line: -#ApiClient.cs - -# You can match any string of characters against a directory, file or extension with a single asterisk (*): -#foo/*/qux -# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux - -# You can recursively match patterns against a directory, file or extension with a double asterisk (**): -#foo/**/qux -# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux - -# You can also negate patterns with an exclamation (!). -# For example, you can ignore all files in a docs folder with the file extension .md: -#docs/*.md -# Then explicitly reverse the ignore rule for a single file: -#!docs/README.md diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/course-api-client/.openapi-generator/FILES b/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/course-api-client/.openapi-generator/FILES deleted file mode 100644 index ca8e5c1e70f..00000000000 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/course-api-client/.openapi-generator/FILES +++ /dev/null @@ -1,15 +0,0 @@ -.gitignore -.npmignore -.openapi-generator-ignore -api.ts -api/courses-api.ts -base.ts -common.ts -configuration.ts -git_push.sh -index.ts -models/course-common-cartridge-metadata-response.ts -models/course-export-body-params.ts -models/course-metadata-list-response.ts -models/course-metadata-response.ts -models/index.ts diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/course-api-client/api.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/course-api-client/api.ts deleted file mode 100644 index 2a01572ebdf..00000000000 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/course-api-client/api.ts +++ /dev/null @@ -1,18 +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. - */ - - - -export * from './api/courses-api'; - diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/course-api-client/api/courses-api.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/course-api-client/api/courses-api.ts deleted file mode 100644 index 5cb342b5acc..00000000000 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/course-api-client/api/courses-api.ts +++ /dev/null @@ -1,611 +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. - */ - - -import type { Configuration } from '../configuration'; -import type { AxiosPromise, AxiosInstance, RawAxiosRequestConfig } from 'axios'; -import globalAxios from 'axios'; -// Some imports not used depending on template conditions -// @ts-ignore -import { DUMMY_BASE_URL, assertParamExists, setApiKeyToObject, setBasicAuthToObject, setBearerAuthToObject, setOAuthToObject, setSearchParams, serializeDataIfNeeded, toPathString, createRequestFunction } from '../common'; -// @ts-ignore -import { BASE_PATH, COLLECTION_FORMATS, type RequestArgs, BaseAPI, RequiredError, operationServerMap } from '../base'; -// @ts-ignore -import type { CourseCommonCartridgeMetadataResponse } from '../models'; -// @ts-ignore -import type { CourseExportBodyParams } from '../models'; -// @ts-ignore -import type { CourseMetadataListResponse } from '../models'; -/** - * CoursesApi - axios parameter creator - * @export - */ -export const CoursesApiAxiosParamCreator = function (configuration?: Configuration) { - return { - /** - * - * @param {string} courseId The id of the course - * @param {CourseControllerExportCourseVersion} version The version of CC export - * @param {CourseExportBodyParams} courseExportBodyParams - * @param {*} [options] Override http request option. - * @throws {RequiredError} - */ - courseControllerExportCourse: async (courseId: string, version: CourseControllerExportCourseVersion, courseExportBodyParams: CourseExportBodyParams, options: RawAxiosRequestConfig = {}): Promise => { - // verify required parameter 'courseId' is not null or undefined - assertParamExists('courseControllerExportCourse', 'courseId', courseId) - // verify required parameter 'version' is not null or undefined - assertParamExists('courseControllerExportCourse', 'version', version) - // verify required parameter 'courseExportBodyParams' is not null or undefined - assertParamExists('courseControllerExportCourse', 'courseExportBodyParams', courseExportBodyParams) - const localVarPath = `/courses/{courseId}/export` - .replace(`{${"courseId"}}`, encodeURIComponent(String(courseId))); - // use dummy base URL string because the URL constructor only accepts absolute URLs. - const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); - let baseOptions; - if (configuration) { - baseOptions = configuration.baseOptions; - } - - const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options}; - const localVarHeaderParameter = {} as any; - const localVarQueryParameter = {} as any; - - // authentication bearer required - // http bearer authentication required - await setBearerAuthToObject(localVarHeaderParameter, configuration) - - if (version !== undefined) { - localVarQueryParameter['version'] = version; - } - - - - localVarHeaderParameter['Content-Type'] = 'application/json'; - - setSearchParams(localVarUrlObj, localVarQueryParameter); - let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; - localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; - localVarRequestOptions.data = serializeDataIfNeeded(courseExportBodyParams, localVarRequestOptions, configuration) - - return { - url: toPathString(localVarUrlObj), - options: localVarRequestOptions, - }; - }, - /** - * - * @param {number} [skip] Number of elements (not pages) to be skipped - * @param {number} [limit] Page limit, defaults to 10. - * @param {*} [options] Override http request option. - * @throws {RequiredError} - */ - courseControllerFindForUser: async (skip?: number, limit?: number, options: RawAxiosRequestConfig = {}): Promise => { - const localVarPath = `/courses`; - // use dummy base URL string because the URL constructor only accepts absolute URLs. - const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); - let baseOptions; - if (configuration) { - baseOptions = configuration.baseOptions; - } - - const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options}; - const localVarHeaderParameter = {} as any; - const localVarQueryParameter = {} as any; - - // authentication bearer required - // http bearer authentication required - await setBearerAuthToObject(localVarHeaderParameter, configuration) - - if (skip !== undefined) { - localVarQueryParameter['skip'] = skip; - } - - if (limit !== undefined) { - localVarQueryParameter['limit'] = limit; - } - - - - setSearchParams(localVarUrlObj, localVarQueryParameter); - let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; - localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; - - return { - url: toPathString(localVarUrlObj), - options: localVarRequestOptions, - }; - }, - /** - * - * @summary Get common cartridge metadata of a course by Id. - * @param {string} courseId The id of the course - * @param {*} [options] Override http request option. - * @throws {RequiredError} - */ - courseControllerGetCourseCcMetadataById: async (courseId: string, options: RawAxiosRequestConfig = {}): Promise => { - // verify required parameter 'courseId' is not null or undefined - assertParamExists('courseControllerGetCourseCcMetadataById', 'courseId', courseId) - const localVarPath = `/courses/{courseId}/cc-metadata` - .replace(`{${"courseId"}}`, encodeURIComponent(String(courseId))); - // use dummy base URL string because the URL constructor only accepts absolute URLs. - const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); - let baseOptions; - if (configuration) { - baseOptions = configuration.baseOptions; - } - - const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options}; - const localVarHeaderParameter = {} as any; - const localVarQueryParameter = {} as any; - - // authentication bearer required - // http bearer authentication required - await setBearerAuthToObject(localVarHeaderParameter, configuration) - - - - setSearchParams(localVarUrlObj, localVarQueryParameter); - let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; - localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; - - return { - url: toPathString(localVarUrlObj), - options: localVarRequestOptions, - }; - }, - /** - * - * @summary Get permissions for a user in a course. - * @param {string} courseId The id of the course - * @param {*} [options] Override http request option. - * @throws {RequiredError} - */ - courseControllerGetUserPermissions: async (courseId: string, options: RawAxiosRequestConfig = {}): Promise => { - // verify required parameter 'courseId' is not null or undefined - assertParamExists('courseControllerGetUserPermissions', 'courseId', courseId) - const localVarPath = `/courses/{courseId}/user-permissions` - .replace(`{${"courseId"}}`, encodeURIComponent(String(courseId))); - // use dummy base URL string because the URL constructor only accepts absolute URLs. - const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); - let baseOptions; - if (configuration) { - baseOptions = configuration.baseOptions; - } - - const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options}; - const localVarHeaderParameter = {} as any; - const localVarQueryParameter = {} as any; - - // authentication bearer required - // http bearer authentication required - await setBearerAuthToObject(localVarHeaderParameter, configuration) - - - - setSearchParams(localVarUrlObj, localVarQueryParameter); - let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; - localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; - - return { - url: toPathString(localVarUrlObj), - options: localVarRequestOptions, - }; - }, - /** - * - * @summary Imports a course from a Common Cartridge file. - * @param {File} file The Common Cartridge file to import. - * @param {*} [options] Override http request option. - * @throws {RequiredError} - */ - courseControllerImportCourse: async (file: File, options: RawAxiosRequestConfig = {}): Promise => { - // verify required parameter 'file' is not null or undefined - assertParamExists('courseControllerImportCourse', 'file', file) - const localVarPath = `/courses/import`; - // use dummy base URL string because the URL constructor only accepts absolute URLs. - const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); - let baseOptions; - if (configuration) { - baseOptions = configuration.baseOptions; - } - - const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options}; - const localVarHeaderParameter = {} as any; - const localVarQueryParameter = {} as any; - const localVarFormParams = new ((configuration && configuration.formDataCtor) || FormData)(); - - // authentication bearer required - // http bearer authentication required - await setBearerAuthToObject(localVarHeaderParameter, configuration) - - - if (file !== undefined) { - localVarFormParams.append('file', file as any); - } - - - localVarHeaderParameter['Content-Type'] = 'multipart/form-data'; - - setSearchParams(localVarUrlObj, localVarQueryParameter); - let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; - localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; - localVarRequestOptions.data = localVarFormParams; - - return { - url: toPathString(localVarUrlObj), - options: localVarRequestOptions, - }; - }, - /** - * - * @summary Stop the synchronization of a course with a group. - * @param {string} courseId The id of the course - * @param {*} [options] Override http request option. - * @throws {RequiredError} - */ - courseControllerStopSynchronization: async (courseId: string, options: RawAxiosRequestConfig = {}): Promise => { - // verify required parameter 'courseId' is not null or undefined - assertParamExists('courseControllerStopSynchronization', 'courseId', courseId) - const localVarPath = `/courses/{courseId}/stop-sync` - .replace(`{${"courseId"}}`, encodeURIComponent(String(courseId))); - // use dummy base URL string because the URL constructor only accepts absolute URLs. - const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); - let baseOptions; - if (configuration) { - baseOptions = configuration.baseOptions; - } - - const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options}; - const localVarHeaderParameter = {} as any; - const localVarQueryParameter = {} as any; - - // authentication bearer required - // http bearer authentication required - await setBearerAuthToObject(localVarHeaderParameter, configuration) - - - - setSearchParams(localVarUrlObj, localVarQueryParameter); - let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; - localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; - - return { - url: toPathString(localVarUrlObj), - options: localVarRequestOptions, - }; - }, - } -}; - -/** - * CoursesApi - functional programming interface - * @export - */ -export const CoursesApiFp = function(configuration?: Configuration) { - const localVarAxiosParamCreator = CoursesApiAxiosParamCreator(configuration) - return { - /** - * - * @param {string} courseId The id of the course - * @param {CourseControllerExportCourseVersion} version The version of CC export - * @param {CourseExportBodyParams} courseExportBodyParams - * @param {*} [options] Override http request option. - * @throws {RequiredError} - */ - async courseControllerExportCourse(courseId: string, version: CourseControllerExportCourseVersion, courseExportBodyParams: CourseExportBodyParams, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { - const localVarAxiosArgs = await localVarAxiosParamCreator.courseControllerExportCourse(courseId, version, courseExportBodyParams, options); - const localVarOperationServerIndex = configuration?.serverIndex ?? 0; - const localVarOperationServerBasePath = operationServerMap['CoursesApi.courseControllerExportCourse']?.[localVarOperationServerIndex]?.url; - return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); - }, - /** - * - * @param {number} [skip] Number of elements (not pages) to be skipped - * @param {number} [limit] Page limit, defaults to 10. - * @param {*} [options] Override http request option. - * @throws {RequiredError} - */ - async courseControllerFindForUser(skip?: number, limit?: number, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { - const localVarAxiosArgs = await localVarAxiosParamCreator.courseControllerFindForUser(skip, limit, options); - const localVarOperationServerIndex = configuration?.serverIndex ?? 0; - const localVarOperationServerBasePath = operationServerMap['CoursesApi.courseControllerFindForUser']?.[localVarOperationServerIndex]?.url; - return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); - }, - /** - * - * @summary Get common cartridge metadata of a course by Id. - * @param {string} courseId The id of the course - * @param {*} [options] Override http request option. - * @throws {RequiredError} - */ - async courseControllerGetCourseCcMetadataById(courseId: string, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { - const localVarAxiosArgs = await localVarAxiosParamCreator.courseControllerGetCourseCcMetadataById(courseId, options); - const localVarOperationServerIndex = configuration?.serverIndex ?? 0; - const localVarOperationServerBasePath = operationServerMap['CoursesApi.courseControllerGetCourseCcMetadataById']?.[localVarOperationServerIndex]?.url; - return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); - }, - /** - * - * @summary Get permissions for a user in a course. - * @param {string} courseId The id of the course - * @param {*} [options] Override http request option. - * @throws {RequiredError} - */ - async courseControllerGetUserPermissions(courseId: string, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { - const localVarAxiosArgs = await localVarAxiosParamCreator.courseControllerGetUserPermissions(courseId, options); - const localVarOperationServerIndex = configuration?.serverIndex ?? 0; - const localVarOperationServerBasePath = operationServerMap['CoursesApi.courseControllerGetUserPermissions']?.[localVarOperationServerIndex]?.url; - return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); - }, - /** - * - * @summary Imports a course from a Common Cartridge file. - * @param {File} file The Common Cartridge file to import. - * @param {*} [options] Override http request option. - * @throws {RequiredError} - */ - async courseControllerImportCourse(file: File, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { - const localVarAxiosArgs = await localVarAxiosParamCreator.courseControllerImportCourse(file, options); - const localVarOperationServerIndex = configuration?.serverIndex ?? 0; - const localVarOperationServerBasePath = operationServerMap['CoursesApi.courseControllerImportCourse']?.[localVarOperationServerIndex]?.url; - return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); - }, - /** - * - * @summary Stop the synchronization of a course with a group. - * @param {string} courseId The id of the course - * @param {*} [options] Override http request option. - * @throws {RequiredError} - */ - async courseControllerStopSynchronization(courseId: string, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { - const localVarAxiosArgs = await localVarAxiosParamCreator.courseControllerStopSynchronization(courseId, options); - const localVarOperationServerIndex = configuration?.serverIndex ?? 0; - const localVarOperationServerBasePath = operationServerMap['CoursesApi.courseControllerStopSynchronization']?.[localVarOperationServerIndex]?.url; - return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); - }, - } -}; - -/** - * CoursesApi - factory interface - * @export - */ -export const CoursesApiFactory = function (configuration?: Configuration, basePath?: string, axios?: AxiosInstance) { - const localVarFp = CoursesApiFp(configuration) - return { - /** - * - * @param {string} courseId The id of the course - * @param {CourseControllerExportCourseVersion} version The version of CC export - * @param {CourseExportBodyParams} courseExportBodyParams - * @param {*} [options] Override http request option. - * @throws {RequiredError} - */ - courseControllerExportCourse(courseId: string, version: CourseControllerExportCourseVersion, courseExportBodyParams: CourseExportBodyParams, options?: any): AxiosPromise { - return localVarFp.courseControllerExportCourse(courseId, version, courseExportBodyParams, options).then((request) => request(axios, basePath)); - }, - /** - * - * @param {number} [skip] Number of elements (not pages) to be skipped - * @param {number} [limit] Page limit, defaults to 10. - * @param {*} [options] Override http request option. - * @throws {RequiredError} - */ - courseControllerFindForUser(skip?: number, limit?: number, options?: any): AxiosPromise { - return localVarFp.courseControllerFindForUser(skip, limit, options).then((request) => request(axios, basePath)); - }, - /** - * - * @summary Get common cartridge metadata of a course by Id. - * @param {string} courseId The id of the course - * @param {*} [options] Override http request option. - * @throws {RequiredError} - */ - courseControllerGetCourseCcMetadataById(courseId: string, options?: any): AxiosPromise { - return localVarFp.courseControllerGetCourseCcMetadataById(courseId, options).then((request) => request(axios, basePath)); - }, - /** - * - * @summary Get permissions for a user in a course. - * @param {string} courseId The id of the course - * @param {*} [options] Override http request option. - * @throws {RequiredError} - */ - courseControllerGetUserPermissions(courseId: string, options?: any): AxiosPromise { - return localVarFp.courseControllerGetUserPermissions(courseId, options).then((request) => request(axios, basePath)); - }, - /** - * - * @summary Imports a course from a Common Cartridge file. - * @param {File} file The Common Cartridge file to import. - * @param {*} [options] Override http request option. - * @throws {RequiredError} - */ - courseControllerImportCourse(file: File, options?: any): AxiosPromise { - return localVarFp.courseControllerImportCourse(file, options).then((request) => request(axios, basePath)); - }, - /** - * - * @summary Stop the synchronization of a course with a group. - * @param {string} courseId The id of the course - * @param {*} [options] Override http request option. - * @throws {RequiredError} - */ - courseControllerStopSynchronization(courseId: string, options?: any): AxiosPromise { - return localVarFp.courseControllerStopSynchronization(courseId, options).then((request) => request(axios, basePath)); - }, - }; -}; - -/** - * CoursesApi - interface - * @export - * @interface CoursesApi - */ -export interface CoursesApiInterface { - /** - * - * @param {string} courseId The id of the course - * @param {CourseControllerExportCourseVersion} version The version of CC export - * @param {CourseExportBodyParams} courseExportBodyParams - * @param {*} [options] Override http request option. - * @throws {RequiredError} - * @memberof CoursesApiInterface - */ - courseControllerExportCourse(courseId: string, version: CourseControllerExportCourseVersion, courseExportBodyParams: CourseExportBodyParams, options?: RawAxiosRequestConfig): AxiosPromise; - - /** - * - * @param {number} [skip] Number of elements (not pages) to be skipped - * @param {number} [limit] Page limit, defaults to 10. - * @param {*} [options] Override http request option. - * @throws {RequiredError} - * @memberof CoursesApiInterface - */ - courseControllerFindForUser(skip?: number, limit?: number, options?: RawAxiosRequestConfig): AxiosPromise; - - /** - * - * @summary Get common cartridge metadata of a course by Id. - * @param {string} courseId The id of the course - * @param {*} [options] Override http request option. - * @throws {RequiredError} - * @memberof CoursesApiInterface - */ - courseControllerGetCourseCcMetadataById(courseId: string, options?: RawAxiosRequestConfig): AxiosPromise; - - /** - * - * @summary Get permissions for a user in a course. - * @param {string} courseId The id of the course - * @param {*} [options] Override http request option. - * @throws {RequiredError} - * @memberof CoursesApiInterface - */ - courseControllerGetUserPermissions(courseId: string, options?: RawAxiosRequestConfig): AxiosPromise; - - /** - * - * @summary Imports a course from a Common Cartridge file. - * @param {File} file The Common Cartridge file to import. - * @param {*} [options] Override http request option. - * @throws {RequiredError} - * @memberof CoursesApiInterface - */ - courseControllerImportCourse(file: File, options?: RawAxiosRequestConfig): AxiosPromise; - - /** - * - * @summary Stop the synchronization of a course with a group. - * @param {string} courseId The id of the course - * @param {*} [options] Override http request option. - * @throws {RequiredError} - * @memberof CoursesApiInterface - */ - courseControllerStopSynchronization(courseId: string, options?: RawAxiosRequestConfig): AxiosPromise; - -} - -/** - * CoursesApi - object-oriented interface - * @export - * @class CoursesApi - * @extends {BaseAPI} - */ -export class CoursesApi extends BaseAPI implements CoursesApiInterface { - /** - * - * @param {string} courseId The id of the course - * @param {CourseControllerExportCourseVersion} version The version of CC export - * @param {CourseExportBodyParams} courseExportBodyParams - * @param {*} [options] Override http request option. - * @throws {RequiredError} - * @memberof CoursesApi - */ - public courseControllerExportCourse(courseId: string, version: CourseControllerExportCourseVersion, courseExportBodyParams: CourseExportBodyParams, options?: RawAxiosRequestConfig) { - return CoursesApiFp(this.configuration).courseControllerExportCourse(courseId, version, courseExportBodyParams, options).then((request) => request(this.axios, this.basePath)); - } - - /** - * - * @param {number} [skip] Number of elements (not pages) to be skipped - * @param {number} [limit] Page limit, defaults to 10. - * @param {*} [options] Override http request option. - * @throws {RequiredError} - * @memberof CoursesApi - */ - public courseControllerFindForUser(skip?: number, limit?: number, options?: RawAxiosRequestConfig) { - return CoursesApiFp(this.configuration).courseControllerFindForUser(skip, limit, options).then((request) => request(this.axios, this.basePath)); - } - - /** - * - * @summary Get common cartridge metadata of a course by Id. - * @param {string} courseId The id of the course - * @param {*} [options] Override http request option. - * @throws {RequiredError} - * @memberof CoursesApi - */ - public courseControllerGetCourseCcMetadataById(courseId: string, options?: RawAxiosRequestConfig) { - return CoursesApiFp(this.configuration).courseControllerGetCourseCcMetadataById(courseId, options).then((request) => request(this.axios, this.basePath)); - } - - /** - * - * @summary Get permissions for a user in a course. - * @param {string} courseId The id of the course - * @param {*} [options] Override http request option. - * @throws {RequiredError} - * @memberof CoursesApi - */ - public courseControllerGetUserPermissions(courseId: string, options?: RawAxiosRequestConfig) { - return CoursesApiFp(this.configuration).courseControllerGetUserPermissions(courseId, options).then((request) => request(this.axios, this.basePath)); - } - - /** - * - * @summary Imports a course from a Common Cartridge file. - * @param {File} file The Common Cartridge file to import. - * @param {*} [options] Override http request option. - * @throws {RequiredError} - * @memberof CoursesApi - */ - public courseControllerImportCourse(file: File, options?: RawAxiosRequestConfig) { - return CoursesApiFp(this.configuration).courseControllerImportCourse(file, options).then((request) => request(this.axios, this.basePath)); - } - - /** - * - * @summary Stop the synchronization of a course with a group. - * @param {string} courseId The id of the course - * @param {*} [options] Override http request option. - * @throws {RequiredError} - * @memberof CoursesApi - */ - public courseControllerStopSynchronization(courseId: string, options?: RawAxiosRequestConfig) { - return CoursesApiFp(this.configuration).courseControllerStopSynchronization(courseId, options).then((request) => request(this.axios, this.basePath)); - } -} - -/** - * @export - */ -export const CourseControllerExportCourseVersion = { - _0_0: '1.0.0', - _1_0: '1.1.0', - _2_0: '1.2.0', - _3_0: '1.3.0', - _4_0: '1.4.0' -} as const; -export type CourseControllerExportCourseVersion = typeof CourseControllerExportCourseVersion[keyof typeof CourseControllerExportCourseVersion]; diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/course-api-client/base.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/course-api-client/base.ts deleted file mode 100644 index 82686c7b81b..00000000000 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/course-api-client/base.ts +++ /dev/null @@ -1,86 +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. - */ - - -import type { Configuration } from './configuration'; -// Some imports not used depending on template conditions -// @ts-ignore -import type { AxiosPromise, AxiosInstance, RawAxiosRequestConfig } from 'axios'; -import globalAxios from 'axios'; - -export const BASE_PATH = "http://localhost/api/v3".replace(/\/+$/, ""); - -/** - * - * @export - */ -export const COLLECTION_FORMATS = { - csv: ",", - ssv: " ", - tsv: "\t", - pipes: "|", -}; - -/** - * - * @export - * @interface RequestArgs - */ -export interface RequestArgs { - url: string; - options: RawAxiosRequestConfig; -} - -/** - * - * @export - * @class BaseAPI - */ -export class BaseAPI { - protected configuration: Configuration | undefined; - - constructor(configuration?: Configuration, protected basePath: string = BASE_PATH, protected axios: AxiosInstance = globalAxios) { - if (configuration) { - this.configuration = configuration; - this.basePath = configuration.basePath ?? basePath; - } - } -}; - -/** - * - * @export - * @class RequiredError - * @extends {Error} - */ -export class RequiredError extends Error { - constructor(public field: string, msg?: string) { - super(msg); - this.name = "RequiredError" - } -} - -interface ServerMap { - [key: string]: { - url: string, - description: string, - }[]; -} - -/** - * - * @export - */ -export const operationServerMap: ServerMap = { -} diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/course-api-client/common.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/course-api-client/common.ts deleted file mode 100644 index 6c119efb60d..00000000000 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/course-api-client/common.ts +++ /dev/null @@ -1,150 +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. - */ - - -import type { Configuration } from "./configuration"; -import type { RequestArgs } from "./base"; -import type { AxiosInstance, AxiosResponse } from 'axios'; -import { RequiredError } from "./base"; - -/** - * - * @export - */ -export const DUMMY_BASE_URL = 'https://example.com' - -/** - * - * @throws {RequiredError} - * @export - */ -export const assertParamExists = function (functionName: string, paramName: string, paramValue: unknown) { - if (paramValue === null || paramValue === undefined) { - throw new RequiredError(paramName, `Required parameter ${paramName} was null or undefined when calling ${functionName}.`); - } -} - -/** - * - * @export - */ -export const setApiKeyToObject = async function (object: any, keyParamName: string, configuration?: Configuration) { - if (configuration && configuration.apiKey) { - const localVarApiKeyValue = typeof configuration.apiKey === 'function' - ? await configuration.apiKey(keyParamName) - : await configuration.apiKey; - object[keyParamName] = localVarApiKeyValue; - } -} - -/** - * - * @export - */ -export const setBasicAuthToObject = function (object: any, configuration?: Configuration) { - if (configuration && (configuration.username || configuration.password)) { - object["auth"] = { username: configuration.username, password: configuration.password }; - } -} - -/** - * - * @export - */ -export const setBearerAuthToObject = async function (object: any, configuration?: Configuration) { - if (configuration && configuration.accessToken) { - const accessToken = typeof configuration.accessToken === 'function' - ? await configuration.accessToken() - : await configuration.accessToken; - object["Authorization"] = "Bearer " + accessToken; - } -} - -/** - * - * @export - */ -export const setOAuthToObject = async function (object: any, name: string, scopes: string[], configuration?: Configuration) { - if (configuration && configuration.accessToken) { - const localVarAccessTokenValue = typeof configuration.accessToken === 'function' - ? await configuration.accessToken(name, scopes) - : await configuration.accessToken; - object["Authorization"] = "Bearer " + localVarAccessTokenValue; - } -} - -function setFlattenedQueryParams(urlSearchParams: URLSearchParams, parameter: any, key: string = ""): void { - if (parameter == null) return; - if (typeof parameter === "object") { - if (Array.isArray(parameter)) { - (parameter as any[]).forEach(item => setFlattenedQueryParams(urlSearchParams, item, key)); - } - else { - Object.keys(parameter).forEach(currentKey => - setFlattenedQueryParams(urlSearchParams, parameter[currentKey], `${key}${key !== '' ? '.' : ''}${currentKey}`) - ); - } - } - else { - if (urlSearchParams.has(key)) { - urlSearchParams.append(key, parameter); - } - else { - urlSearchParams.set(key, parameter); - } - } -} - -/** - * - * @export - */ -export const setSearchParams = function (url: URL, ...objects: any[]) { - const searchParams = new URLSearchParams(url.search); - setFlattenedQueryParams(searchParams, objects); - url.search = searchParams.toString(); -} - -/** - * - * @export - */ -export const serializeDataIfNeeded = function (value: any, requestOptions: any, configuration?: Configuration) { - const nonString = typeof value !== 'string'; - const needsSerialization = nonString && configuration && configuration.isJsonMime - ? configuration.isJsonMime(requestOptions.headers['Content-Type']) - : nonString; - return needsSerialization - ? JSON.stringify(value !== undefined ? value : {}) - : (value || ""); -} - -/** - * - * @export - */ -export const toPathString = function (url: URL) { - return url.pathname + url.search + url.hash -} - -/** - * - * @export - */ -export const createRequestFunction = function (axiosArgs: RequestArgs, globalAxios: AxiosInstance, BASE_PATH: string, configuration?: Configuration) { - return >(axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => { - const axiosRequestArgs = {...axiosArgs.options, url: (axios.defaults.baseURL ? '' : configuration?.basePath ?? basePath) + axiosArgs.url}; - return axios.request(axiosRequestArgs); - }; -} diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/course-api-client/configuration.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/course-api-client/configuration.ts deleted file mode 100644 index 8c97d307cf4..00000000000 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/course-api-client/configuration.ts +++ /dev/null @@ -1,110 +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. - */ - - -export interface ConfigurationParameters { - apiKey?: string | Promise | ((name: string) => string) | ((name: string) => Promise); - username?: string; - password?: string; - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string) | ((name?: string, scopes?: string[]) => Promise); - basePath?: string; - serverIndex?: number; - baseOptions?: any; - formDataCtor?: new () => any; -} - -export class Configuration { - /** - * parameter for apiKey security - * @param name security name - * @memberof Configuration - */ - apiKey?: string | Promise | ((name: string) => string) | ((name: string) => Promise); - /** - * parameter for basic security - * - * @type {string} - * @memberof Configuration - */ - username?: string; - /** - * parameter for basic security - * - * @type {string} - * @memberof Configuration - */ - password?: string; - /** - * parameter for oauth2 security - * @param name security name - * @param scopes oauth2 scope - * @memberof Configuration - */ - accessToken?: string | Promise | ((name?: string, scopes?: string[]) => string) | ((name?: string, scopes?: string[]) => Promise); - /** - * override base path - * - * @type {string} - * @memberof Configuration - */ - basePath?: string; - /** - * override server index - * - * @type {number} - * @memberof Configuration - */ - serverIndex?: number; - /** - * base options for axios calls - * - * @type {any} - * @memberof Configuration - */ - baseOptions?: any; - /** - * The FormData constructor that will be used to create multipart form data - * requests. You can inject this here so that execution environments that - * do not support the FormData class can still run the generated client. - * - * @type {new () => FormData} - */ - formDataCtor?: new () => any; - - constructor(param: ConfigurationParameters = {}) { - this.apiKey = param.apiKey; - this.username = param.username; - this.password = param.password; - this.accessToken = param.accessToken; - this.basePath = param.basePath; - this.serverIndex = param.serverIndex; - this.baseOptions = param.baseOptions; - this.formDataCtor = param.formDataCtor; - } - - /** - * Check if the given MIME is a JSON MIME. - * JSON MIME examples: - * application/json - * application/json; charset=UTF8 - * APPLICATION/JSON - * application/vnd.company+json - * @param mime - MIME (Multipurpose Internet Mail Extensions) - * @return True if the given MIME is JSON, false otherwise. - */ - public isJsonMime(mime: string): boolean { - const jsonMime: RegExp = new RegExp('^(application\/json|[^;/ \t]+\/[^;/ \t]+[+]json)[ \t]*(;.*)?$', 'i'); - return mime !== null && (jsonMime.test(mime) || mime.toLowerCase() === 'application/json-patch+json'); - } -} diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/course-api-client/git_push.sh b/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/course-api-client/git_push.sh deleted file mode 100644 index f53a75d4fab..00000000000 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/course-api-client/git_push.sh +++ /dev/null @@ -1,57 +0,0 @@ -#!/bin/sh -# ref: https://help.github.com/articles/adding-an-existing-project-to-github-using-the-command-line/ -# -# Usage example: /bin/sh ./git_push.sh wing328 openapi-petstore-perl "minor update" "gitlab.com" - -git_user_id=$1 -git_repo_id=$2 -release_note=$3 -git_host=$4 - -if [ "$git_host" = "" ]; then - git_host="github.com" - echo "[INFO] No command line input provided. Set \$git_host to $git_host" -fi - -if [ "$git_user_id" = "" ]; then - git_user_id="GIT_USER_ID" - echo "[INFO] No command line input provided. Set \$git_user_id to $git_user_id" -fi - -if [ "$git_repo_id" = "" ]; then - git_repo_id="GIT_REPO_ID" - echo "[INFO] No command line input provided. Set \$git_repo_id to $git_repo_id" -fi - -if [ "$release_note" = "" ]; then - release_note="Minor update" - echo "[INFO] No command line input provided. Set \$release_note to $release_note" -fi - -# Initialize the local directory as a Git repository -git init - -# Adds the files in the local repository and stages them for commit. -git add . - -# Commits the tracked changes and prepares them to be pushed to a remote repository. -git commit -m "$release_note" - -# Sets the new remote -git_remote=$(git remote) -if [ "$git_remote" = "" ]; then # git remote not defined - - if [ "$GIT_TOKEN" = "" ]; then - echo "[INFO] \$GIT_TOKEN (environment variable) is not set. Using the git credential in your environment." - git remote add origin https://${git_host}/${git_user_id}/${git_repo_id}.git - else - git remote add origin https://${git_user_id}:"${GIT_TOKEN}"@${git_host}/${git_user_id}/${git_repo_id}.git - fi - -fi - -git pull origin master - -# Pushes (Forces) the changes in the local repository up to the remote repository -echo "Git pushing to https://${git_host}/${git_user_id}/${git_repo_id}.git" -git push origin master 2>&1 | grep -v 'To https' diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/course-api-client/index.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/course-api-client/index.ts deleted file mode 100644 index 8b762df664e..00000000000 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/course-api-client/index.ts +++ /dev/null @@ -1,18 +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. - */ - - -export * from "./api"; -export * from "./configuration"; -export * from "./models"; diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/course-api-client/models/course-common-cartridge-metadata-response.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/course-api-client/models/course-common-cartridge-metadata-response.ts deleted file mode 100644 index 85d01bb7a85..00000000000 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/course-api-client/models/course-common-cartridge-metadata-response.ts +++ /dev/null @@ -1,48 +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. - */ - - - -/** - * - * @export - * @interface CourseCommonCartridgeMetadataResponse - */ -export interface CourseCommonCartridgeMetadataResponse { - /** - * The id of the course - * @type {string} - * @memberof CourseCommonCartridgeMetadataResponse - */ - 'id': string; - /** - * Title of the course - * @type {string} - * @memberof CourseCommonCartridgeMetadataResponse - */ - 'title': string; - /** - * Creation date of the course - * @type {string} - * @memberof CourseCommonCartridgeMetadataResponse - */ - 'creationDate': string; - /** - * Copy right owners of the course - * @type {Array} - * @memberof CourseCommonCartridgeMetadataResponse - */ - 'copyRightOwners': Array; -} - diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/course-api-client/models/course-export-body-params.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/course-api-client/models/course-export-body-params.ts deleted file mode 100644 index 7fe921f621c..00000000000 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/course-api-client/models/course-export-body-params.ts +++ /dev/null @@ -1,42 +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. - */ - - - -/** - * - * @export - * @interface CourseExportBodyParams - */ -export interface CourseExportBodyParams { - /** - * The list of ids of topics which should be exported. If empty no topics are exported. - * @type {Array} - * @memberof CourseExportBodyParams - */ - 'topics': Array; - /** - * The list of ids of tasks which should be exported. If empty no tasks are exported. - * @type {Array} - * @memberof CourseExportBodyParams - */ - 'tasks': Array; - /** - * The list of ids of column boards which should be exported. If empty no column boards are exported. - * @type {Array} - * @memberof CourseExportBodyParams - */ - 'columnBoards': Array; -} - diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/course-api-client/models/course-metadata-list-response.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/course-api-client/models/course-metadata-list-response.ts deleted file mode 100644 index 489f5be83ea..00000000000 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/course-api-client/models/course-metadata-list-response.ts +++ /dev/null @@ -1,51 +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 { CourseMetadataResponse } from './course-metadata-response'; - -/** - * - * @export - * @interface CourseMetadataListResponse - */ -export interface CourseMetadataListResponse { - /** - * The items for the current page. - * @type {Array} - * @memberof CourseMetadataListResponse - */ - 'data': Array; - /** - * The total amount of items. - * @type {number} - * @memberof CourseMetadataListResponse - */ - 'total': number; - /** - * The amount of items skipped from the start. - * @type {number} - * @memberof CourseMetadataListResponse - */ - 'skip': number; - /** - * The page size of the response. - * @type {number} - * @memberof CourseMetadataListResponse - */ - 'limit': number; -} - diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/course-api-client/models/course-metadata-response.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/course-api-client/models/course-metadata-response.ts deleted file mode 100644 index 0ba6eacd5a7..00000000000 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/course-api-client/models/course-metadata-response.ts +++ /dev/null @@ -1,66 +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. - */ - - - -/** - * - * @export - * @interface CourseMetadataResponse - */ -export interface CourseMetadataResponse { - /** - * The id of the Grid element - * @type {string} - * @memberof CourseMetadataResponse - */ - 'id': string; - /** - * Title of the Grid element - * @type {string} - * @memberof CourseMetadataResponse - */ - 'title': string; - /** - * Short title of the Grid element - * @type {string} - * @memberof CourseMetadataResponse - */ - 'shortTitle': string; - /** - * Color of the Grid element - * @type {string} - * @memberof CourseMetadataResponse - */ - 'displayColor': string; - /** - * Start date of the course - * @type {string} - * @memberof CourseMetadataResponse - */ - 'startDate'?: string; - /** - * End date of the course. After this the course counts as archived - * @type {string} - * @memberof CourseMetadataResponse - */ - 'untilDate'?: string; - /** - * Start of the copying process if it is still ongoing - otherwise property is not set. - * @type {string} - * @memberof CourseMetadataResponse - */ - 'copyingSince'?: string; -} - diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/course-api-client/models/index.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/course-api-client/models/index.ts deleted file mode 100644 index 2e4b620054f..00000000000 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/course-api-client/models/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from './course-common-cartridge-metadata-response'; -export * from './course-export-body-params'; -export * from './course-metadata-list-response'; -export * from './course-metadata-response'; From e50bdc34eae139c06dd327910cca5aa239e45966 Mon Sep 17 00:00:00 2001 From: Patrick Sachmann <20001160+psachmann@users.noreply.github.com> Date: Thu, 5 Dec 2024 15:49:40 +0100 Subject: [PATCH 05/25] fixing imports --- .../course-common-cartridge-metadata.dto.ts | 0 .../src/infra/courses-client/dto/index.ts | 1 + .../courses-client.adapter.spec.ts | 103 ------------------ .../course-client/courses-client.adapter.ts | 42 ------- .../course-client/courses-client.config.ts | 5 - .../courses-client.module.spec.ts | 29 ----- .../course-client/courses-client.module.ts | 26 ----- .../course-client/index.ts | 4 - .../common-cartridge.module.ts | 7 +- .../controller/common-cartridge.controller.ts | 4 +- .../common-cartridge-import-body.params.ts | 2 +- .../dto/course-export-body.response.ts | 8 +- .../common-cartridge-export.service.ts | 8 +- .../common-cartridge-import.service.ts | 10 +- .../uc/common-cartridge.uc.ts | 8 +- .../learnroom/controller/course.controller.ts | 8 +- .../dto/create-course-body.params.ts | 8 -- .../common-cartridge-import.service.ts | 4 +- .../src/modules/learnroom/uc/course.uc.ts | 16 +-- sonar-project.properties | 4 +- 20 files changed, 40 insertions(+), 257 deletions(-) rename apps/server/src/{modules/common-cartridge/common-cartridge-client/course-client => infra/courses-client}/dto/course-common-cartridge-metadata.dto.ts (100%) create mode 100644 apps/server/src/infra/courses-client/dto/index.ts delete mode 100644 apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/courses-client.adapter.spec.ts delete mode 100644 apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/courses-client.adapter.ts delete mode 100644 apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/courses-client.config.ts delete mode 100644 apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/courses-client.module.spec.ts delete mode 100644 apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/courses-client.module.ts delete mode 100644 apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/index.ts 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/infra/courses-client/dto/course-common-cartridge-metadata.dto.ts similarity index 100% rename from apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/dto/course-common-cartridge-metadata.dto.ts rename to apps/server/src/infra/courses-client/dto/course-common-cartridge-metadata.dto.ts diff --git a/apps/server/src/infra/courses-client/dto/index.ts b/apps/server/src/infra/courses-client/dto/index.ts new file mode 100644 index 00000000000..28effb98eb5 --- /dev/null +++ b/apps/server/src/infra/courses-client/dto/index.ts @@ -0,0 +1 @@ +export { CourseCommonCartridgeMetadataDto } from './course-common-cartridge-metadata.dto'; 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 deleted file mode 100644 index 058a7517f98..00000000000 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/courses-client.adapter.spec.ts +++ /dev/null @@ -1,103 +0,0 @@ -import { Test, TestingModule } from '@nestjs/testing'; -import { createMock, DeepMocked } from '@golevelup/ts-jest'; -import { REQUEST } from '@nestjs/core'; -import { Request } from 'express'; -import { faker } from '@faker-js/faker'; -import { AxiosResponse } from 'axios'; -import { CoursesClientAdapter } from './courses-client.adapter'; -import { CourseCommonCartridgeMetadataResponse, CoursesApi } from './course-api-client'; - -const jwtToken = 'dummyJwtToken'; - -describe(CoursesClientAdapter.name, () => { - let module: TestingModule; - let service: CoursesClientAdapter; - let coursesApi: DeepMocked; - - beforeAll(async () => { - module = await Test.createTestingModule({ - providers: [ - CoursesClientAdapter, - { - provide: CoursesApi, - useValue: createMock(), - }, - { - provide: REQUEST, - useValue: createMock({ - headers: { - authorization: `Bearer ${jwtToken}`, - }, - }), - }, - ], - }).compile(); - - service = module.get(CoursesClientAdapter); - coursesApi = module.get(CoursesApi); - }); - - afterAll(async () => { - await module.close(); - }); - - afterEach(() => { - jest.resetAllMocks(); - }); - - it('should be defined', () => { - expect(service).toBeDefined(); - }); - - describe('getCourseCommonCartridgeMetadata', () => { - describe('when getCourseCommonCartridgeMetadata is called', () => { - const setup = () => { - const courseId = faker.string.uuid(); - const response = createMock>({ - data: { - id: faker.string.uuid(), - title: faker.lorem.word(), - creationDate: faker.date.recent().toString(), - copyRightOwners: [faker.lorem.word(), faker.lorem.word()], - }, - }); - - coursesApi.courseControllerGetCourseCcMetadataById.mockResolvedValueOnce(response); - return { courseId }; - }; - it('should return course common cartridge metadata', async () => { - const { courseId } = setup(); - - const expectedOptions = { headers: { authorization: `Bearer ${jwtToken}` } }; - - const result = await service.getCourseCommonCartridgeMetadata(courseId); - - expect(coursesApi.courseControllerGetCourseCcMetadataById).toHaveBeenCalledWith(courseId, expectedOptions); - expect(result.id).toBeDefined(); - expect(result.title).toBeDefined(); - expect(result.creationDate).toBeDefined(); - expect(result.copyRightOwners).toBeDefined(); - }); - }); - }); - - describe('when no JWT token is found', () => { - const setup = () => { - const courseId = faker.string.uuid(); - const error = new Error('Authentication is required.'); - const request = createMock({ - headers: {}, - }); - - const adapter: CoursesClientAdapter = new CoursesClientAdapter(coursesApi, request); - - return { error, courseId, adapter }; - }; - - it('should throw an Error', async () => { - const { error, courseId, adapter } = setup(); - - await expect(adapter.getCourseCommonCartridgeMetadata(courseId)).rejects.toThrowError(error); - }); - }); -}); 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 deleted file mode 100644 index 324f907f06f..00000000000 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/courses-client.adapter.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { Inject, Injectable, UnauthorizedException } from '@nestjs/common'; -import { REQUEST } from '@nestjs/core'; -import { extractJwtFromHeader } from '@shared/common'; -import { RawAxiosRequestConfig } from 'axios'; -import { Request } from 'express'; -import { CourseCommonCartridgeMetadataDto } from './dto/course-common-cartridge-metadata.dto'; -import { CoursesApi } from './course-api-client'; - -@Injectable() -export class CoursesClientAdapter { - constructor(private readonly coursesApi: CoursesApi, @Inject(REQUEST) private request: Request) {} - - public async getCourseCommonCartridgeMetadata(courseId: string): Promise { - const options = this.createOptionParams(); - const response = await this.coursesApi.courseControllerGetCourseCcMetadataById(courseId, options); - const courseCommonCartridgeMetadata: CourseCommonCartridgeMetadataDto = new CourseCommonCartridgeMetadataDto({ - id: response.data.id, - title: response.data.title, - creationDate: response.data.creationDate, - copyRightOwners: response.data.copyRightOwners, - }); - - return courseCommonCartridgeMetadata; - } - - private createOptionParams(): RawAxiosRequestConfig { - const jwt = this.getJwt(); - const options: RawAxiosRequestConfig = { headers: { authorization: `Bearer ${jwt}` } }; - - return options; - } - - private getJwt(): string { - const jwt = extractJwtFromHeader(this.request) || this.request.headers.authorization; - - if (!jwt) { - throw new UnauthorizedException('Authentication is required.'); - } - - return jwt; - } -} diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/courses-client.config.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/courses-client.config.ts deleted file mode 100644 index 94f86ce2560..00000000000 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/courses-client.config.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { ConfigurationParameters } from './course-api-client'; - -export interface CoursesClientConfig extends ConfigurationParameters { - basePath?: string; -} diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/courses-client.module.spec.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/courses-client.module.spec.ts deleted file mode 100644 index 515b77ac509..00000000000 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/courses-client.module.spec.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { TestingModule, Test } from '@nestjs/testing'; -import { CoursesClientModule } from './courses-client.module'; -import { CoursesClientAdapter } from './courses-client.adapter'; - -describe('CommonCartridgeClientModule', () => { - let module: TestingModule; - - beforeAll(async () => { - module = await Test.createTestingModule({ - imports: [ - CoursesClientModule.register({ - basePath: 'http://localhost:3000', - }), - ], - }).compile(); - }); - - afterAll(async () => { - await module.close(); - }); - - describe('when module is initialized', () => { - it('should be defined', () => { - const coursesClientAdapter = module.get(CoursesClientAdapter); - - expect(coursesClientAdapter).toBeDefined(); - }); - }); -}); diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/courses-client.module.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/courses-client.module.ts deleted file mode 100644 index 039d58d11ca..00000000000 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/courses-client.module.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { DynamicModule, Module } from '@nestjs/common'; -import { CoursesClientAdapter } from './courses-client.adapter'; -import { Configuration, CoursesApi } from './course-api-client'; -import { CoursesClientConfig } from './courses-client.config'; - -@Module({}) -export class CoursesClientModule { - static register(config: CoursesClientConfig): DynamicModule { - const providers = [ - CoursesClientAdapter, - { - provide: CoursesApi, - useFactory: () => { - const configuration = new Configuration(config); - return new CoursesApi(configuration); - }, - }, - ]; - - return { - module: CoursesClientModule, - providers, - exports: [CoursesClientAdapter], - }; - } -} diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/index.ts b/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/index.ts deleted file mode 100644 index 501ca215cc8..00000000000 --- a/apps/server/src/modules/common-cartridge/common-cartridge-client/course-client/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export { CoursesClientModule } from './courses-client.module'; -export { CoursesClientAdapter } from './courses-client.adapter'; -export { CoursesClientConfig } from './courses-client.config'; -export { CourseCommonCartridgeMetadataDto } from './dto/course-common-cartridge-metadata.dto'; 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 f277d3e7dcb..8463e2dc3e8 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge.module.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge.module.ts @@ -1,4 +1,5 @@ import { Configuration } from '@hpi-schul-cloud/commons'; +import { CoursesClientModule } from '@infra/courses-client'; import { MikroOrmModule } from '@mikro-orm/nestjs'; import { FilesStorageClientModule } from '@modules/files-storage-client'; import { Module } from '@nestjs/common'; @@ -8,7 +9,6 @@ import { DB_PASSWORD, DB_URL, DB_USERNAME } from '@src/config'; import { RabbitMQWrapperModule } from '@src/infra/rabbitmq'; import { BoardClientModule } from './common-cartridge-client/board-client'; import { CardClientModule } from './common-cartridge-client/card-client/card-client.module'; -import { CoursesClientModule } from './common-cartridge-client/course-client'; import { LessonClientModule } from './common-cartridge-client/lesson-client/lesson-client.module'; import { CourseRoomsModule } from './common-cartridge-client/room-client'; import { CommonCartridgeExportService, CommonCartridgeImportService } from './service'; @@ -18,6 +18,7 @@ import { CommonCartridgeUc } from './uc/common-cartridge.uc'; imports: [ RabbitMQWrapperModule, FilesStorageClientModule, + CoursesClientModule, MikroOrmModule.forRoot({ ...defaultMikroOrmOptions, type: 'mongo', @@ -32,13 +33,9 @@ import { CommonCartridgeUc } from './uc/common-cartridge.uc'; CourseRoomsModule.register({ basePath: `${Configuration.get('API_HOST') as string}/v3/`, }), - CardClientModule.register({ basePath: `${Configuration.get('API_HOST') as string}/v3/`, }), - CoursesClientModule.register({ - basePath: `${Configuration.get('API_HOST') as string}/v3/`, - }), LessonClientModule.register({ basePath: `${Configuration.get('API_HOST') as string}/v3/`, }), 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 5e2423a7cf7..5f82935f0db 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 @@ -25,7 +25,7 @@ export class CommonCartridgeController { constructor(private readonly commonCartridgeUC: CommonCartridgeUc) {} @Get('export/:parentId') - public async exportCourse(@Param() exportCourseParams: ExportCourseParams): Promise { + public exportCourse(@Param() exportCourseParams: ExportCourseParams): Promise { return this.commonCartridgeUC.exportCourse(exportCourseParams.parentId); } @@ -44,6 +44,6 @@ export class CommonCartridgeController { @UploadedFile(CommonCartridgeFileValidatorPipe) file: Express.Multer.File ): Promise { - return this.commonCartridgeUC.importCourse(file); + await this.commonCartridgeUC.importCourse(file.buffer); } } diff --git a/apps/server/src/modules/common-cartridge/controller/dto/common-cartridge-import-body.params.ts b/apps/server/src/modules/common-cartridge/controller/dto/common-cartridge-import-body.params.ts index 99e94570841..e49c1edc129 100644 --- a/apps/server/src/modules/common-cartridge/controller/dto/common-cartridge-import-body.params.ts +++ b/apps/server/src/modules/common-cartridge/controller/dto/common-cartridge-import-body.params.ts @@ -7,5 +7,5 @@ export class CommonCartridgeImportBodyParams { required: true, description: 'The Common Cartridge file to import.', }) - file!: Express.Multer.File; + public file!: Express.Multer.File; } diff --git a/apps/server/src/modules/common-cartridge/controller/dto/course-export-body.response.ts b/apps/server/src/modules/common-cartridge/controller/dto/course-export-body.response.ts index 9709cbff7d1..82a51725034 100644 --- a/apps/server/src/modules/common-cartridge/controller/dto/course-export-body.response.ts +++ b/apps/server/src/modules/common-cartridge/controller/dto/course-export-body.response.ts @@ -1,12 +1,12 @@ -import { CourseCommonCartridgeMetadataDto } from '../../common-cartridge-client/course-client'; +import { CourseCommonCartridgeMetadataResponse } from '@infra/courses-client'; import { CourseFileIdsResponse } from './common-cartridge.response'; export class CourseExportBodyResponse { - courseFileIds?: CourseFileIdsResponse; + public courseFileIds?: CourseFileIdsResponse; - courseCommonCartridgeMetadata: CourseCommonCartridgeMetadataDto; + public courseCommonCartridgeMetadata: CourseCommonCartridgeMetadataResponse; - constructor(courseExportBodyResponse: CourseExportBodyResponse) { + constructor(courseExportBodyResponse: Readonly) { this.courseFileIds = courseExportBodyResponse.courseFileIds; this.courseCommonCartridgeMetadata = courseExportBodyResponse.courseCommonCartridgeMetadata; } 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..35b984b7ff9 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,11 @@ +import { CourseCommonCartridgeMetadataResponse, CoursesClientAdapter } from '@infra/courses-client'; import { FileDto, FilesStorageClientAdapterService } from '@modules/files-storage-client'; import { Injectable } from '@nestjs/common'; import { BoardClientAdapter } 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 { CourseRoomsClientAdapter } from '../common-cartridge-client/room-client'; +import { RoomBoardDto } from '../common-cartridge-client/room-client/dto/room-board.dto'; @Injectable() export class CommonCartridgeExportService { @@ -23,7 +23,7 @@ export class CommonCartridgeExportService { return courseFiles; } - public async findCourseCommonCartridgeMetadata(courseId: string): Promise { + public async findCourseCommonCartridgeMetadata(courseId: string): Promise { const courseCommonCartridgeMetadata = await this.coursesClientAdapter.getCourseCommonCartridgeMetadata(courseId); return courseCommonCartridgeMetadata; diff --git a/apps/server/src/modules/common-cartridge/service/common-cartridge-import.service.ts b/apps/server/src/modules/common-cartridge/service/common-cartridge-import.service.ts index 181055fe91b..13e47683a8b 100644 --- a/apps/server/src/modules/common-cartridge/service/common-cartridge-import.service.ts +++ b/apps/server/src/modules/common-cartridge/service/common-cartridge-import.service.ts @@ -1,19 +1,21 @@ +import { CoursesClientAdapter } from '@infra/courses-client'; import { Injectable } from '@nestjs/common'; -import { CoursesClientAdapter } from '../common-cartridge-client/course-client'; import { CommonCartridgeFileParser } from '../import/common-cartridge-file-parser'; +import { DEFAULT_FILE_PARSER_OPTIONS } from '../import/common-cartridge-import.types'; @Injectable() export class CommonCartridgeImportService { constructor(private readonly courseClient: CoursesClientAdapter) {} - public async importCourse(file: Express.Multer.File): Promise { - const parser = new CommonCartridgeFileParser(file.buffer); + public async importFile(file: Buffer): Promise { + const parser = new CommonCartridgeFileParser(file, DEFAULT_FILE_PARSER_OPTIONS); await this.createCourse(parser); } - private async createCourse(parser: CommonCartridgeFileParser): Promise { + private createCourse(parser: CommonCartridgeFileParser): Promise { // TODO: better default name + // eslint-disable-next-line @typescript-eslint/no-unused-vars const courseName = parser.getTitle() || 'Untitled Course'; throw new Error('Not implemented'); 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 a7e4f92e8e9..56517960c10 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,6 +1,5 @@ import { Injectable } from '@nestjs/common'; import { EntityId } from '@shared/domain/types'; -import { CourseCommonCartridgeMetadataDto } from '../common-cartridge-client/course-client'; import { CourseFileIdsResponse } from '../controller/dto'; import { CourseExportBodyResponse } from '../controller/dto/course-export-body.response'; import { CommonCartridgeImportService } from '../service'; @@ -16,8 +15,7 @@ export class CommonCartridgeUc { 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 courseCommonCartridgeMetadata = await this.exportService.findCourseCommonCartridgeMetadata(courseId); const response = new CourseExportBodyResponse({ courseFileIds, @@ -27,7 +25,7 @@ export class CommonCartridgeUc { return response; } - public async importCourse(file: Express.Multer.File): Promise { - await this.importService.importCourse(file); + public async importCourse(file: Buffer): Promise { + await this.importService.importFile(file); } } diff --git a/apps/server/src/modules/learnroom/controller/course.controller.ts b/apps/server/src/modules/learnroom/controller/course.controller.ts index da037f2c076..fd7d22a96fa 100644 --- a/apps/server/src/modules/learnroom/controller/course.controller.ts +++ b/apps/server/src/modules/learnroom/controller/course.controller.ts @@ -25,11 +25,11 @@ import { ApiUnprocessableEntityResponse, } from '@nestjs/swagger'; import { PaginationParams } from '@shared/controller/'; +import { SchoolService } from '@modules/school'; import { CourseMapper } from '../mapper/course.mapper'; import { CourseImportUc, CourseSyncUc, CourseUc } from '../uc'; import { CommonCartridgeFileValidatorPipe } from '../utils'; import { - CourseExportBodyParams, CourseImportBodyParams, CourseMetadataListResponse, CourseSyncBodyParams, @@ -45,7 +45,8 @@ export class CourseController { constructor( private readonly courseUc: CourseUc, private readonly courseImportUc: CourseImportUc, - private readonly courseSyncUc: CourseSyncUc + private readonly courseSyncUc: CourseSyncUc, + private readonly schoolService: SchoolService ) {} @Get() @@ -65,12 +66,11 @@ export class CourseController { @ApiOperation({ summary: 'Create a new course.' }) @ApiConsumes('application/json') @ApiProduces('application/json') - @ApiBody({ type: CourseExportBodyParams, required: true }) @ApiCreatedResponse({ description: 'Course was successfully created.' }) @ApiBadRequestResponse({ description: 'Request data has invalid format.' }) @ApiInternalServerErrorResponse({ description: 'Internal server error.' }) public async createCourse(@CurrentUser() user: ICurrentUser, @Body() body: CreateCourseBodyParams): Promise { - await this.courseUc.createCourse(user, body); + await this.courseUc.createCourse(user, body.title); } @Post('import') diff --git a/apps/server/src/modules/learnroom/controller/dto/create-course-body.params.ts b/apps/server/src/modules/learnroom/controller/dto/create-course-body.params.ts index 4d9869ff0cd..995065c2f86 100644 --- a/apps/server/src/modules/learnroom/controller/dto/create-course-body.params.ts +++ b/apps/server/src/modules/learnroom/controller/dto/create-course-body.params.ts @@ -9,12 +9,4 @@ export class CreateCourseBodyParams { nullable: false, }) public title!: string; - - @IsString() - @ApiProperty({ - description: 'The description of the course', - required: true, - nullable: false, - }) - public description!: string; } diff --git a/apps/server/src/modules/learnroom/service/common-cartridge-import.service.ts b/apps/server/src/modules/learnroom/service/common-cartridge-import.service.ts index c57b7300510..b73e90a5e90 100644 --- a/apps/server/src/modules/learnroom/service/common-cartridge-import.service.ts +++ b/apps/server/src/modules/learnroom/service/common-cartridge-import.service.ts @@ -156,7 +156,7 @@ export class CommonCartridgeImportService { column: Column, cardProps: CommonCartridgeImportOrganizationProps, organizations: CommonCartridgeImportOrganizationProps[] - ) { + ): Promise { const card = this.boardNodeFactory.buildCard(); const { title, height } = this.mapper.mapOrganizationToCard(cardProps, true); card.title = title; @@ -176,7 +176,7 @@ export class CommonCartridgeImportService { parser: CommonCartridgeFileParser, card: Card, cardElementProps: CommonCartridgeImportOrganizationProps - ) { + ): Promise { if (cardElementProps.isResource) { const resource = parser.getResource(cardElementProps); const contentElementType = this.mapper.mapResourceTypeToContentElementType(resource?.type); diff --git a/apps/server/src/modules/learnroom/uc/course.uc.ts b/apps/server/src/modules/learnroom/uc/course.uc.ts index b0f29680ff8..aa6e92846a0 100644 --- a/apps/server/src/modules/learnroom/uc/course.uc.ts +++ b/apps/server/src/modules/learnroom/uc/course.uc.ts @@ -2,8 +2,8 @@ import { AuthorizationService } from '@modules/authorization'; import { RoleService } from '@modules/role'; import { Injectable } from '@nestjs/common'; import { PaginationParams } from '@shared/controller/'; -import { Course, CourseProperties } from '@shared/domain/entity'; -import { SortOrder } from '@shared/domain/interface'; +import { Course } from '@shared/domain/entity'; +import { Permission, SortOrder } from '@shared/domain/interface'; import { Counted, EntityId } from '@shared/domain/types'; import { CourseRepo } from '@shared/repo'; import { ICurrentUser } from '@src/infra/auth-guard'; @@ -36,11 +36,13 @@ export class CourseUc { return this.courseService.findById(courseId); } - public async createCourse(user: ICurrentUser, props: CourseProperties): Promise { - const course = new Course({ - school: user.schoolId, - }); + public async createCourse(currentUser: ICurrentUser, name: string): Promise { + const user = await this.authService.getUserWithPermissions(currentUser.userId); - return this.courseService.create({ title, description }); + this.authService.checkAllPermissions(user, [Permission.COURSE_CREATE]); + + const course = new Course({ teachers: [user], school: user.school, name }); + + await this.courseService.create(course); } } diff --git a/sonar-project.properties b/sonar-project.properties index 68a946b5fac..9ec5f4c132b 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -3,8 +3,8 @@ sonar.projectKey=hpi-schul-cloud_schulcloud-server sonar.sources=. sonar.tests=. sonar.test.inclusions=**/*.spec.ts -sonar.exclusions=**/*.js,jest.config.ts,globalSetup.ts,globalTeardown.ts,**/*.app.ts,**/seed-data/*.ts,**/migrations/mikro-orm/*.ts,**/etherpad-api-client/**/*.ts,**/authorization-api-client/**/*.ts, **/course-api-client/**/*.ts,**/board-api-client/**/*.ts,**/generated/**/*.ts,**/room-api-client/**/*.ts,**/cards-api-client/**/*.ts,**/lessons-api-client/**/*.ts -sonar.coverage.exclusions=**/board-management.uc.ts,**/*.module.ts,**/*.factory.ts,**/migrations/mikro-orm/*.ts,**/globalSetup.ts,**/globalTeardown.ts,**/etherpad-api-client/**/*.ts,**/authorization-api-client/**/*.ts, **/course-api-client/**/*.ts,**/board-api-client/**/*.ts,**/generated/**/*.ts,**/room-api-client/**/*.ts,apps/server/src/console/console.ts +sonar.exclusions=**/*.js,jest.config.ts,globalSetup.ts,globalTeardown.ts,**/*.app.ts,**/seed-data/*.ts,**/migrations/mikro-orm/*.ts,**/etherpad-api-client/**/*.ts,**/authorization-api-client/**/*.ts,**/board-api-client/**/*.ts,**/generated/**/*.ts,**/room-api-client/**/*.ts,**/cards-api-client/**/*.ts,**/lessons-api-client/**/*.ts +sonar.coverage.exclusions=**/board-management.uc.ts,**/*.module.ts,**/*.factory.ts,**/migrations/mikro-orm/*.ts,**/globalSetup.ts,**/globalTeardown.ts,**/etherpad-api-client/**/*.ts,**/authorization-api-client/**/*.ts,**/board-api-client/**/*.ts,**/generated/**/*.ts,**/room-api-client/**/*.ts,apps/server/src/console/console.ts sonar.cpd.exclusions=**/controller/dto/**/*.ts,**/api/dto/**/*.ts,**/shared/testing/factory/*.factory.ts sonar.javascript.lcov.reportPaths=merged-lcov.info sonar.typescript.tsconfigPaths=tsconfig.json,src/apps/server/tsconfig.app.json From 2b5536fb82e2457ce6f2d5df83aca805b0dc711a Mon Sep 17 00:00:00 2001 From: Patrick Sachmann <20001160+psachmann@users.noreply.github.com> Date: Fri, 6 Dec 2024 10:18:56 +0100 Subject: [PATCH 06/25] removing todos --- .../service/common-cartridge-import.service.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/apps/server/src/modules/common-cartridge/service/common-cartridge-import.service.ts b/apps/server/src/modules/common-cartridge/service/common-cartridge-import.service.ts index 13e47683a8b..be14e00382b 100644 --- a/apps/server/src/modules/common-cartridge/service/common-cartridge-import.service.ts +++ b/apps/server/src/modules/common-cartridge/service/common-cartridge-import.service.ts @@ -5,7 +5,7 @@ import { DEFAULT_FILE_PARSER_OPTIONS } from '../import/common-cartridge-import.t @Injectable() export class CommonCartridgeImportService { - constructor(private readonly courseClient: CoursesClientAdapter) {} + constructor(private readonly coursesClient: CoursesClientAdapter) {} public async importFile(file: Buffer): Promise { const parser = new CommonCartridgeFileParser(file, DEFAULT_FILE_PARSER_OPTIONS); @@ -13,11 +13,9 @@ export class CommonCartridgeImportService { await this.createCourse(parser); } - private createCourse(parser: CommonCartridgeFileParser): Promise { - // TODO: better default name - // eslint-disable-next-line @typescript-eslint/no-unused-vars + private async createCourse(parser: CommonCartridgeFileParser): Promise { const courseName = parser.getTitle() || 'Untitled Course'; - throw new Error('Not implemented'); + await this.coursesClient.createCourse({ title: courseName }); } } From 54d5eb51db083fe1ee3c732749206d498a2ce4cb Mon Sep 17 00:00:00 2001 From: Patrick Sachmann <20001160+psachmann@users.noreply.github.com> Date: Fri, 6 Dec 2024 13:47:45 +0100 Subject: [PATCH 07/25] adding tests --- .../courses-client.adapter.spec.ts | 72 +++++++++++++++++++ .../courses-client/courses-client.adapter.ts | 3 +- .../courses-client.module.spec.ts | 57 +++++++++++++++ .../course-common-cartridge-metadata.dto.ts | 16 ----- .../src/infra/courses-client/dto/index.ts | 1 - apps/server/test.http | 0 6 files changed, 130 insertions(+), 19 deletions(-) create mode 100644 apps/server/src/infra/courses-client/courses-client.adapter.spec.ts create mode 100644 apps/server/src/infra/courses-client/courses-client.module.spec.ts delete mode 100644 apps/server/src/infra/courses-client/dto/course-common-cartridge-metadata.dto.ts delete mode 100644 apps/server/src/infra/courses-client/dto/index.ts create mode 100644 apps/server/test.http diff --git a/apps/server/src/infra/courses-client/courses-client.adapter.spec.ts b/apps/server/src/infra/courses-client/courses-client.adapter.spec.ts new file mode 100644 index 00000000000..da3149d8874 --- /dev/null +++ b/apps/server/src/infra/courses-client/courses-client.adapter.spec.ts @@ -0,0 +1,72 @@ +import { faker } from '@faker-js/faker'; +import { createMock, DeepMocked } from '@golevelup/ts-jest'; +import { Test, TestingModule } from '@nestjs/testing'; +import { CoursesClientAdapter } from './courses-client.adapter'; +import { CoursesApi, CreateCourseBodyParams } from './generated'; + +describe(CoursesClientAdapter.name, () => { + let module: TestingModule; + let sut: CoursesClientAdapter; + let coursesApiMock: DeepMocked; + + beforeAll(async () => { + module = await Test.createTestingModule({ + providers: [ + CoursesClientAdapter, + { + provide: CoursesApi, + useValue: createMock(), + }, + ], + }).compile(); + + sut = module.get(CoursesClientAdapter); + coursesApiMock = module.get(CoursesApi); + }); + + afterAll(async () => { + await module.close(); + }); + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('should be defined', () => { + expect(sut).toBeDefined(); + }); + + describe('getCourseCommonCartridgeMetadata', () => { + const setup = () => { + const courseId = faker.string.uuid(); + + return { courseId }; + }; + + it('should call courseControllerGetCourseCcMetadataById with the correct courseId', async () => { + const { courseId } = setup(); + + await sut.getCourseCommonCartridgeMetadata(courseId); + + expect(coursesApiMock.courseControllerGetCourseCcMetadataById).toHaveBeenCalledWith(courseId); + }); + }); + + describe('createCourse', () => { + const setup = () => { + const params: CreateCourseBodyParams = { + title: faker.word.noun(), + }; + + return { params }; + }; + + it('should call courseControllerCreateCourse with the correct params', async () => { + const { params } = setup(); + + await sut.createCourse(params); + + expect(coursesApiMock.courseControllerCreateCourse).toHaveBeenCalledWith(params); + }); + }); +}); diff --git a/apps/server/src/infra/courses-client/courses-client.adapter.ts b/apps/server/src/infra/courses-client/courses-client.adapter.ts index ba8392a4eaa..4628d93f2df 100644 --- a/apps/server/src/infra/courses-client/courses-client.adapter.ts +++ b/apps/server/src/infra/courses-client/courses-client.adapter.ts @@ -7,9 +7,8 @@ export class CoursesClientAdapter { public async getCourseCommonCartridgeMetadata(courseId: string): Promise { const response = await this.coursesApi.courseControllerGetCourseCcMetadataById(courseId); - const result = response.data; - return result; + return response.data; } public async createCourse(params: CreateCourseBodyParams): Promise { diff --git a/apps/server/src/infra/courses-client/courses-client.module.spec.ts b/apps/server/src/infra/courses-client/courses-client.module.spec.ts new file mode 100644 index 00000000000..e2332fc3c87 --- /dev/null +++ b/apps/server/src/infra/courses-client/courses-client.module.spec.ts @@ -0,0 +1,57 @@ +import { faker } from '@faker-js/faker'; +import { createMock } from '@golevelup/ts-jest'; +import { ConfigModule, ConfigService } from '@nestjs/config'; +import { REQUEST } from '@nestjs/core'; +import { Test, TestingModule } from '@nestjs/testing'; +import { Request } from 'express'; +import { CoursesClientAdapter } from './courses-client.adapter'; +import { CoursesClientModule } from './courses-client.module'; +import { CoursesApi } from './generated'; + +describe(CoursesClientModule.name, () => { + let module: TestingModule; + let sut: CoursesClientModule; + + beforeAll(async () => { + module = await Test.createTestingModule({ + imports: [CoursesClientModule, ConfigModule.forRoot({ isGlobal: true })], + }) + .overrideProvider(ConfigService) + .useValue( + createMock({ + getOrThrow: () => faker.internet.url(), + }) + ) + .overrideProvider(REQUEST) + .useValue({ headers: { authorization: `Bearer ${faker.string.alphanumeric(42)}` } } as Request) + .compile(); + + sut = module.get(CoursesClientModule); + }); + + afterAll(async () => { + await module.close(); + }); + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('should be defined', () => { + expect(sut).toBeDefined(); + }); + + describe('when requesting dependencies', () => { + it('should resolve CoursesApi', async () => { + const dependency = await module.resolve(CoursesApi); + + expect(dependency).toBeInstanceOf(CoursesApi); + }); + + it('should resolve CoursesClientAdapter', async () => { + const dependency = await module.resolve(CoursesClientAdapter); + + expect(dependency).toBeInstanceOf(CoursesClientAdapter); + }); + }); +}); diff --git a/apps/server/src/infra/courses-client/dto/course-common-cartridge-metadata.dto.ts b/apps/server/src/infra/courses-client/dto/course-common-cartridge-metadata.dto.ts deleted file mode 100644 index 117963823ca..00000000000 --- a/apps/server/src/infra/courses-client/dto/course-common-cartridge-metadata.dto.ts +++ /dev/null @@ -1,16 +0,0 @@ -export class CourseCommonCartridgeMetadataDto { - id: string; - - title: string; - - creationDate?: string; - - copyRightOwners: Array; - - constructor(props: CourseCommonCartridgeMetadataDto) { - this.id = props.id; - this.title = props.title; - this.creationDate = props.creationDate; - this.copyRightOwners = props.copyRightOwners; - } -} diff --git a/apps/server/src/infra/courses-client/dto/index.ts b/apps/server/src/infra/courses-client/dto/index.ts deleted file mode 100644 index 28effb98eb5..00000000000 --- a/apps/server/src/infra/courses-client/dto/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { CourseCommonCartridgeMetadataDto } from './course-common-cartridge-metadata.dto'; diff --git a/apps/server/test.http b/apps/server/test.http new file mode 100644 index 00000000000..e69de29bb2d From 24b2cae7fadf16d6d240aad87173169f87d293e7 Mon Sep 17 00:00:00 2001 From: Patrick Sachmann <20001160+psachmann@users.noreply.github.com> Date: Fri, 6 Dec 2024 15:10:34 +0100 Subject: [PATCH 08/25] working on tests --- .../courses-client/courses-client.module.ts | 4 +- .../uc/common-cartridge.uc.spec.ts | 34 +++++++++++--- .../modules/learnroom/uc/course.uc.spec.ts | 47 ++++++++++++++++++- .../src/modules/learnroom/uc/course.uc.ts | 6 ++- .../src/shared/common/utils/jwt.spec.ts | 18 +++++++ apps/server/src/shared/common/utils/jwt.ts | 20 ++++---- apps/server/test.http | 0 7 files changed, 108 insertions(+), 21 deletions(-) delete mode 100644 apps/server/test.http diff --git a/apps/server/src/infra/courses-client/courses-client.module.ts b/apps/server/src/infra/courses-client/courses-client.module.ts index bc78f838153..0718a7c3d81 100644 --- a/apps/server/src/infra/courses-client/courses-client.module.ts +++ b/apps/server/src/infra/courses-client/courses-client.module.ts @@ -1,7 +1,7 @@ import { Module, Scope } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; import { REQUEST } from '@nestjs/core'; -import { extractJwtFromRequest } from '@shared/common/utils/jwt'; +import { JwtExtractor } from '@shared/common/utils'; import { Request } from 'express'; import { CoursesClientAdapter } from './courses-client.adapter'; import { CoursesClientConfig } from './courses-client.config'; @@ -15,7 +15,7 @@ import { Configuration, CoursesApi } from './generated'; scope: Scope.REQUEST, useFactory: (configService: ConfigService, request: Request): CoursesApi => { const basePath = configService.getOrThrow('API_HOST'); - const accessToken = extractJwtFromRequest(request); + const accessToken = JwtExtractor.extractJwtFromRequest(request); const configuration = new Configuration({ basePath: `${basePath}/api/v3`, accessToken, 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..170e30ea09f 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 @@ -2,14 +2,16 @@ 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 { CourseExportBodyResponse } from '../controller/dto/course-export-body.response'; import { CommonCartridgeExportService } from '../service/common-cartridge-export.service'; +import { CommonCartridgeImportService } from '../service/common-cartridge-import.service'; import { CommonCartridgeUc } from './common-cartridge.uc'; -import { CourseExportBodyResponse } from '../controller/dto/course-export-body.response'; describe('CommonCartridgeUc', () => { let module: TestingModule; let sut: CommonCartridgeUc; let commonCartridgeExportServiceMock: DeepMocked; + let commonCartridgeImportServiceMock: DeepMocked; beforeAll(async () => { module = await Test.createTestingModule({ @@ -19,11 +21,16 @@ describe('CommonCartridgeUc', () => { provide: CommonCartridgeExportService, useValue: createMock(), }, + { + provide: CommonCartridgeImportService, + useValue: createMock(), + }, ], }).compile(); sut = module.get(CommonCartridgeUc); commonCartridgeExportServiceMock = module.get(CommonCartridgeExportService); + commonCartridgeImportServiceMock = module.get(CommonCartridgeImportService); }); afterAll(async () => { @@ -43,15 +50,14 @@ describe('CommonCartridgeUc', () => { id: courseId, title: faker.lorem.sentence(), copyRightOwners: [], + creationDate: faker.date.recent().toDateString(), }, }); commonCartridgeExportServiceMock.findCourseFileRecords.mockResolvedValue([]); - commonCartridgeExportServiceMock.findCourseCommonCartridgeMetadata.mockResolvedValue({ - id: expected.courseCommonCartridgeMetadata?.id ?? '', - title: expected.courseCommonCartridgeMetadata?.title ?? '', - copyRightOwners: expected.courseCommonCartridgeMetadata?.copyRightOwners ?? [], - }); + commonCartridgeExportServiceMock.findCourseCommonCartridgeMetadata.mockResolvedValue( + expected.courseCommonCartridgeMetadata + ); return { courseId, expected }; }; @@ -64,4 +70,20 @@ describe('CommonCartridgeUc', () => { expect(result).toEqual(expected); }); }); + + describe('importCourse', () => { + const setup = () => { + const file = Buffer.from(faker.lorem.paragraphs()); + + return { file }; + }; + + it('should class the import service', async () => { + const { file } = setup(); + + await sut.importCourse(file); + + expect(commonCartridgeImportServiceMock.importFile).toHaveBeenCalledWith(file); + }); + }); }); diff --git a/apps/server/src/modules/learnroom/uc/course.uc.spec.ts b/apps/server/src/modules/learnroom/uc/course.uc.spec.ts index 363fffb3c97..b4bc0c86188 100644 --- a/apps/server/src/modules/learnroom/uc/course.uc.spec.ts +++ b/apps/server/src/modules/learnroom/uc/course.uc.spec.ts @@ -1,3 +1,4 @@ +import { faker } from '@faker-js/faker'; import { createMock, DeepMocked } from '@golevelup/ts-jest'; import { ObjectId } from '@mikro-orm/mongodb'; import { AuthorizationService } from '@modules/authorization'; @@ -5,7 +6,7 @@ import { RoleDto, RoleService } from '@modules/role'; import { Test, TestingModule } from '@nestjs/testing'; import { Permission, RoleName, SortOrder } from '@shared/domain/interface'; import { CourseRepo } from '@shared/repo'; -import { courseFactory, setupEntities, UserAndAccountTestFactory } from '@shared/testing'; +import { courseFactory, currentUserFactory, setupEntities, UserAndAccountTestFactory } from '@shared/testing'; import { CourseService } from '../service'; import { CourseUc } from './course.uc'; @@ -52,6 +53,10 @@ describe('CourseUc', () => { await module.close(); }); + beforeEach(() => { + jest.clearAllMocks(); + }); + describe('findAllByUser', () => { const setup = () => { const courses = courseFactory.buildList(5); @@ -121,4 +126,44 @@ describe('CourseUc', () => { expect(courseService.findById).toHaveBeenCalledWith(course.id); }); }); + + describe('createCourse', () => { + describe('when creating a course', () => { + const setup = () => { + const { teacherUser } = UserAndAccountTestFactory.buildTeacher({}, []); + const currentUser = currentUserFactory.build({ userId: teacherUser.id }); + const courseTitle = faker.lorem.words(); + + return { currentUser, teacherUser, courseTitle }; + }; + + it('should create a course', async () => { + const { currentUser, courseTitle } = setup(); + + await expect(uc.createCourse(currentUser, courseTitle)).resolves.not.toThrow(); + expect(courseService.create).toHaveBeenCalled(); + }); + }); + + describe('when user does not have permission to create a course', () => { + const setup = () => { + const { teacherUser } = UserAndAccountTestFactory.buildTeacher({}, []); + const currentUser = currentUserFactory.build({ userId: teacherUser.id }); + const courseTitle = faker.lorem.words(); + + authorizationService.checkAllPermissions.mockImplementation(() => { + throw new Error('User does not have permission'); + }); + + return { currentUser, teacherUser, courseTitle }; + }; + + it('should throw an error', async () => { + const { currentUser, courseTitle } = setup(); + + await expect(uc.createCourse(currentUser, courseTitle)).rejects.toThrow(); + expect(courseService.create).not.toHaveBeenCalled(); + }); + }); + }); }); diff --git a/apps/server/src/modules/learnroom/uc/course.uc.ts b/apps/server/src/modules/learnroom/uc/course.uc.ts index aa6e92846a0..63ee6944304 100644 --- a/apps/server/src/modules/learnroom/uc/course.uc.ts +++ b/apps/server/src/modules/learnroom/uc/course.uc.ts @@ -32,8 +32,10 @@ export class CourseUc { return role.permissions ?? []; } - public findCourseById(courseId: EntityId): Promise { - return this.courseService.findById(courseId); + public async findCourseById(courseId: EntityId): Promise { + const course = await this.courseService.findById(courseId); + + return course; } public async createCourse(currentUser: ICurrentUser, name: string): Promise { diff --git a/apps/server/src/shared/common/utils/jwt.spec.ts b/apps/server/src/shared/common/utils/jwt.spec.ts index f0d9a74f22f..67d026a8d47 100644 --- a/apps/server/src/shared/common/utils/jwt.spec.ts +++ b/apps/server/src/shared/common/utils/jwt.spec.ts @@ -1,10 +1,13 @@ +import { faker } from '@faker-js/faker'; import { createMock, DeepMocked } from '@golevelup/ts-jest'; +import { UnauthorizedException } from '@nestjs/common'; import { Request } from 'express'; import { JwtFromRequestFunction } from 'passport-jwt'; import { JwtExtractor } from './jwt'; describe('JwtExtractor', () => { let request: DeepMocked; + beforeEach(() => { request = createMock(); }); @@ -39,4 +42,19 @@ describe('JwtExtractor', () => { expect(extractor(request)).toEqual(null); }); }); + + describe('extractJwtFromRequest', () => { + describe('when no token is found', () => { + it('should throw an UnauthorizedException', () => { + expect(() => JwtExtractor.extractJwtFromRequest(request)).toThrow(UnauthorizedException); + }); + }); + + it('should return the token if exists in cookie', () => { + const token = faker.string.alphanumeric(42); + request.headers.authorization = `Bearer ${token}`; + + expect(JwtExtractor.extractJwtFromRequest(request)).toEqual(token); + }); + }); }); diff --git a/apps/server/src/shared/common/utils/jwt.ts b/apps/server/src/shared/common/utils/jwt.ts index 6c6ffe1b3a1..d5e1f8acaed 100644 --- a/apps/server/src/shared/common/utils/jwt.ts +++ b/apps/server/src/shared/common/utils/jwt.ts @@ -14,19 +14,19 @@ export class JwtExtractor { return token; }; } + + public static extractJwtFromRequest(request: Request): string { + const jwt = ExtractJwt.fromAuthHeaderAsBearerToken()(request); + + if (!jwt) { + throw new UnauthorizedException('No JWT token found'); + } + + return jwt; + } } export const extractJwtFromHeader = ExtractJwt.fromExtractors([ ExtractJwt.fromAuthHeaderAsBearerToken(), JwtExtractor.fromCookie('jwt'), ]); - -export const extractJwtFromRequest = (request: Request): string => { - const jwt = extractJwtFromHeader(request); - - if (!jwt) { - throw new UnauthorizedException('No JWT token found'); - } - - return jwt; -}; diff --git a/apps/server/test.http b/apps/server/test.http deleted file mode 100644 index e69de29bb2d..00000000000 From 296f7170c51ae9e6ed0b725e2475e2f34629d6bf Mon Sep 17 00:00:00 2001 From: Patrick Sachmann <20001160+psachmann@users.noreply.github.com> Date: Fri, 6 Dec 2024 15:33:04 +0100 Subject: [PATCH 09/25] tests --- .../controller/api-test/course.api.spec.ts | 61 ++++++++----------- 1 file changed, 24 insertions(+), 37 deletions(-) diff --git a/apps/server/src/modules/learnroom/controller/api-test/course.api.spec.ts b/apps/server/src/modules/learnroom/controller/api-test/course.api.spec.ts index ef10c434469..3069fde5af1 100644 --- a/apps/server/src/modules/learnroom/controller/api-test/course.api.spec.ts +++ b/apps/server/src/modules/learnroom/controller/api-test/course.api.spec.ts @@ -1,7 +1,7 @@ import { faker } from '@faker-js/faker/locale/af_ZA'; import { EntityManager } from '@mikro-orm/mongodb'; import { ServerTestModule } from '@modules/server/server.module'; -import { HttpStatus, INestApplication, StreamableFile } from '@nestjs/common'; +import { HttpStatus, INestApplication } from '@nestjs/common'; import { Test, TestingModule } from '@nestjs/testing'; import { Course as CourseEntity } from '@shared/domain/entity'; import { Permission } from '@shared/domain/interface'; @@ -24,6 +24,7 @@ const createTeacher = () => { const { teacherAccount, teacherUser } = UserAndAccountTestFactory.buildTeacher({}, [ Permission.COURSE_VIEW, Permission.COURSE_EDIT, + Permission.COURSE_CREATE, ]); return { account: teacherAccount, user: teacherUser }; }; @@ -96,42 +97,6 @@ describe('Course Controller (API)', () => { }); }); - describe('[POST] /courses/:id/export', () => { - const setup = async () => { - const student1 = createStudent(); - const student2 = createStudent(); - const teacher = createTeacher(); - const substitutionTeacher = createTeacher(); - const teacherUnknownToCourse = createTeacher(); - const course = courseFactory.build({ - teachers: [teacher.user], - students: [student1.user, student2.user], - }); - - await em.persistAndFlush([teacher.account, teacher.user, course]); - em.clear(); - - const loggedInClient = await testApiClient.login(teacher.account); - - return { course, teacher, teacherUnknownToCourse, substitutionTeacher, student1, loggedInClient }; - }; - - it('should find course export', async () => { - const { course, loggedInClient } = await setup(); - - const body = { topics: [faker.string.uuid()], tasks: [faker.string.uuid()], columnBoards: [faker.string.uuid()] }; - const response = await loggedInClient.post(`${course.id}/export?version=1.1.0`, body); - - expect(response.statusCode).toEqual(201); - const file = response.body as StreamableFile; - expect(file).toBeDefined(); - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access - expect(response.header['content-type']).toBe('application/zip'); - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access - expect(response.header['content-disposition']).toBe('attachment;'); - }); - }); - describe('[POST] /courses/import', () => { const setup = async () => { const teacher = createTeacher(); @@ -413,4 +378,26 @@ describe('Course Controller (API)', () => { expect(data.id).toBe(course.id); }); }); + + describe('[POST] /courses', () => { + const setup = async () => { + const teacher = createTeacher(); + const course = courseFactory.build(); + + await em.persistAndFlush([teacher.account, teacher.user]); + em.clear(); + + const loggedInClient = await testApiClient.login(teacher.account); + + return { loggedInClient, course }; + }; + + it('should create course', async () => { + const { loggedInClient } = await setup(); + + const response = await loggedInClient.post().send({ title: faker.lorem.words() }); + + expect(response.statusCode).toEqual(201); + }); + }); }); From 0dfb6a682484b51170714bd3641f58a41c5bd78f Mon Sep 17 00:00:00 2001 From: Patrick Sachmann <20001160+psachmann@users.noreply.github.com> Date: Fri, 6 Dec 2024 15:45:15 +0100 Subject: [PATCH 10/25] working on tests --- .../common-cartridge-import.service.spec.ts | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 apps/server/src/modules/common-cartridge/service/common-cartridge-import.service.spec.ts diff --git a/apps/server/src/modules/common-cartridge/service/common-cartridge-import.service.spec.ts b/apps/server/src/modules/common-cartridge/service/common-cartridge-import.service.spec.ts new file mode 100644 index 00000000000..f144a4f5520 --- /dev/null +++ b/apps/server/src/modules/common-cartridge/service/common-cartridge-import.service.spec.ts @@ -0,0 +1,45 @@ +import { createMock, DeepMocked } from '@golevelup/ts-jest'; +import { CoursesClientAdapter } from '@infra/courses-client'; +import { Test, TestingModule } from '@nestjs/testing'; +import { CommonCartridgeImportService } from './common-cartridge-import.service'; + +describe(CommonCartridgeImportService.name, () => { + let module: TestingModule; + let sut: CommonCartridgeImportService; + let coursesClientAdapterMock: DeepMocked; + + beforeEach(async () => { + module = await Test.createTestingModule({ + providers: [ + CommonCartridgeImportService, + { + provide: CoursesClientAdapter, + useValue: createMock(), + }, + ], + }).compile(); + + sut = module.get(CommonCartridgeImportService); + coursesClientAdapterMock = module.get(CoursesClientAdapter); + }); + + afterEach(async () => { + await module.close(); + }); + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('should be defined', () => { + expect(sut).toBeDefined(); + }); + + describe('importFile', () => { + describe('when importing a file', () => { + it('should create a course', () => { + throw new Error('Test not implemented'); + }); + }); + }); +}); From d435b35b13b9563148027e454b8e1204e00298b8 Mon Sep 17 00:00:00 2001 From: Patrick Sachmann <20001160+psachmann@users.noreply.github.com> Date: Mon, 9 Dec 2024 10:27:06 +0100 Subject: [PATCH 11/25] moving pipe utils --- .../controller/common-cartridge.controller.ts | 9 +++++---- .../utils/common-cartridge-file-validator.pipe.spec.ts | 0 .../utils/common-cartridge-file-validator.pipe.ts | 2 +- .../controller}/utils/index.ts | 0 .../modules/learnroom/controller/course.controller.ts | 6 ++---- apps/server/src/modules/learnroom/learnroom.module.ts | 2 +- 6 files changed, 9 insertions(+), 10 deletions(-) rename apps/server/src/modules/{learnroom => common-cartridge/controller}/utils/common-cartridge-file-validator.pipe.spec.ts (100%) rename apps/server/src/modules/{learnroom => common-cartridge/controller}/utils/common-cartridge-file-validator.pipe.ts (91%) rename apps/server/src/modules/{learnroom => common-cartridge/controller}/utils/index.ts (100%) 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 5f82935f0db..344cc6c9cc1 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 @@ -12,11 +12,10 @@ import { ApiTags, ApiUnauthorizedResponse, } from '@nestjs/swagger'; -// TODO: move this into common-cartridge module -import { CommonCartridgeFileValidatorPipe } from '@src/modules/learnroom/utils'; import { CommonCartridgeUc } from '../uc/common-cartridge.uc'; import { CommonCartridgeImportBodyParams, ExportCourseParams } from './dto'; import { CourseExportBodyResponse } from './dto/course-export-body.response'; +import { CommonCartridgeFileValidatorPipe } from './utils'; @JwtAuthentication() @ApiTags('common-cartridge') @@ -25,8 +24,10 @@ export class CommonCartridgeController { constructor(private readonly commonCartridgeUC: CommonCartridgeUc) {} @Get('export/:parentId') - public exportCourse(@Param() exportCourseParams: ExportCourseParams): Promise { - return this.commonCartridgeUC.exportCourse(exportCourseParams.parentId); + public async exportCourse(@Param() exportCourseParams: ExportCourseParams): Promise { + const response = await this.commonCartridgeUC.exportCourse(exportCourseParams.parentId); + + return response; } @Post('import') diff --git a/apps/server/src/modules/learnroom/utils/common-cartridge-file-validator.pipe.spec.ts b/apps/server/src/modules/common-cartridge/controller/utils/common-cartridge-file-validator.pipe.spec.ts similarity index 100% rename from apps/server/src/modules/learnroom/utils/common-cartridge-file-validator.pipe.spec.ts rename to apps/server/src/modules/common-cartridge/controller/utils/common-cartridge-file-validator.pipe.spec.ts diff --git a/apps/server/src/modules/learnroom/utils/common-cartridge-file-validator.pipe.ts b/apps/server/src/modules/common-cartridge/controller/utils/common-cartridge-file-validator.pipe.ts similarity index 91% rename from apps/server/src/modules/learnroom/utils/common-cartridge-file-validator.pipe.ts rename to apps/server/src/modules/common-cartridge/controller/utils/common-cartridge-file-validator.pipe.ts index b72d27f0932..437d3b344f4 100644 --- a/apps/server/src/modules/learnroom/utils/common-cartridge-file-validator.pipe.ts +++ b/apps/server/src/modules/common-cartridge/controller/utils/common-cartridge-file-validator.pipe.ts @@ -1,6 +1,6 @@ import { BadRequestException, Injectable, PipeTransform } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; -import { LearnroomConfig } from '../learnroom.config'; +import { LearnroomConfig } from '../../../learnroom/learnroom.config'; @Injectable() export class CommonCartridgeFileValidatorPipe implements PipeTransform { diff --git a/apps/server/src/modules/learnroom/utils/index.ts b/apps/server/src/modules/common-cartridge/controller/utils/index.ts similarity index 100% rename from apps/server/src/modules/learnroom/utils/index.ts rename to apps/server/src/modules/common-cartridge/controller/utils/index.ts diff --git a/apps/server/src/modules/learnroom/controller/course.controller.ts b/apps/server/src/modules/learnroom/controller/course.controller.ts index fd7d22a96fa..f7cb1379ee9 100644 --- a/apps/server/src/modules/learnroom/controller/course.controller.ts +++ b/apps/server/src/modules/learnroom/controller/course.controller.ts @@ -1,4 +1,5 @@ import { CurrentUser, ICurrentUser, JwtAuthentication } from '@infra/auth-guard'; +import { CommonCartridgeFileValidatorPipe } from '@modules/common-cartridge/controller/utils'; import { Body, Controller, @@ -25,10 +26,8 @@ import { ApiUnprocessableEntityResponse, } from '@nestjs/swagger'; import { PaginationParams } from '@shared/controller/'; -import { SchoolService } from '@modules/school'; import { CourseMapper } from '../mapper/course.mapper'; import { CourseImportUc, CourseSyncUc, CourseUc } from '../uc'; -import { CommonCartridgeFileValidatorPipe } from '../utils'; import { CourseImportBodyParams, CourseMetadataListResponse, @@ -45,8 +44,7 @@ export class CourseController { constructor( private readonly courseUc: CourseUc, private readonly courseImportUc: CourseImportUc, - private readonly courseSyncUc: CourseSyncUc, - private readonly schoolService: SchoolService + private readonly courseSyncUc: CourseSyncUc ) {} @Get() diff --git a/apps/server/src/modules/learnroom/learnroom.module.ts b/apps/server/src/modules/learnroom/learnroom.module.ts index c06158e4a38..7f2e1437207 100644 --- a/apps/server/src/modules/learnroom/learnroom.module.ts +++ b/apps/server/src/modules/learnroom/learnroom.module.ts @@ -20,6 +20,7 @@ import { UserRepo, } from '@shared/repo'; import { LoggerModule } from '@src/core/logger'; +import { CommonCartridgeFileValidatorPipe } from '../common-cartridge/controller/utils'; import { COURSE_REPO } from './domain'; import { CommonCartridgeExportMapper } from './mapper/common-cartridge-export.mapper'; import { CommonCartridgeImportMapper } from './mapper/common-cartridge-import.mapper'; @@ -38,7 +39,6 @@ import { DashboardService, GroupDeletedHandlerService, } from './service'; -import { CommonCartridgeFileValidatorPipe } from './utils'; /** * @deprecated - the learnroom module is deprecated and will be removed in the future From eb6a12c3e51fed55e9e4d2d7d6fc49b8b11de20d Mon Sep 17 00:00:00 2001 From: Patrick Sachmann <20001160+psachmann@users.noreply.github.com> Date: Mon, 9 Dec 2024 10:39:55 +0100 Subject: [PATCH 12/25] updating config --- .../src/modules/common-cartridge/common-cartridge.config.ts | 4 ++++ .../controller/utils/common-cartridge-file-validator.pipe.ts | 4 ++-- apps/server/src/modules/common-cartridge/index.ts | 1 + apps/server/src/modules/server/server.config.ts | 4 +++- 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/apps/server/src/modules/common-cartridge/common-cartridge.config.ts b/apps/server/src/modules/common-cartridge/common-cartridge.config.ts index 724e2c558e0..75bf4ee5325 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge.config.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge.config.ts @@ -3,11 +3,15 @@ import { Configuration } from '@hpi-schul-cloud/commons'; export interface CommonCartridgeConfig { NEST_LOG_LEVEL: string; INCOMING_REQUEST_TIMEOUT: number; + FEATURE_COMMON_CARTRIDGE_COURSE_IMPORT_MAX_FILE_SIZE: number; } const commonCartridgeConfig: CommonCartridgeConfig = { NEST_LOG_LEVEL: Configuration.get('NEST_LOG_LEVEL') as string, INCOMING_REQUEST_TIMEOUT: Configuration.get('FILES_STORAGE__INCOMING_REQUEST_TIMEOUT') as number, + FEATURE_COMMON_CARTRIDGE_COURSE_IMPORT_MAX_FILE_SIZE: Configuration.get( + 'FEATURE_COMMON_CARTRIDGE_COURSE_IMPORT_MAX_FILE_SIZE' + ) as number, }; export function config(): CommonCartridgeConfig { diff --git a/apps/server/src/modules/common-cartridge/controller/utils/common-cartridge-file-validator.pipe.ts b/apps/server/src/modules/common-cartridge/controller/utils/common-cartridge-file-validator.pipe.ts index 437d3b344f4..18557abb151 100644 --- a/apps/server/src/modules/common-cartridge/controller/utils/common-cartridge-file-validator.pipe.ts +++ b/apps/server/src/modules/common-cartridge/controller/utils/common-cartridge-file-validator.pipe.ts @@ -1,12 +1,12 @@ import { BadRequestException, Injectable, PipeTransform } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; -import { LearnroomConfig } from '../../../learnroom/learnroom.config'; +import { CommonCartridgeConfig } from '../../common-cartridge.config'; @Injectable() export class CommonCartridgeFileValidatorPipe implements PipeTransform { private zipFileMagicNumber = '504b0304'; - constructor(private readonly configService: ConfigService) {} + constructor(private readonly configService: ConfigService) {} public transform(value: Express.Multer.File): Express.Multer.File { this.checkValue(value); diff --git a/apps/server/src/modules/common-cartridge/index.ts b/apps/server/src/modules/common-cartridge/index.ts index 2f177a38fb6..1673fae99bb 100644 --- a/apps/server/src/modules/common-cartridge/index.ts +++ b/apps/server/src/modules/common-cartridge/index.ts @@ -1,3 +1,4 @@ +export { CommonCartridgeConfig } from './common-cartridge.config'; export { CommonCartridgeFileBuilder, CommonCartridgeFileBuilderProps, diff --git a/apps/server/src/modules/server/server.config.ts b/apps/server/src/modules/server/server.config.ts index fe858b67219..13c5f761ee7 100644 --- a/apps/server/src/modules/server/server.config.ts +++ b/apps/server/src/modules/server/server.config.ts @@ -12,6 +12,7 @@ import { AlertConfig } from '@modules/alert'; import type { AuthenticationConfig } from '@modules/authentication'; import type { BoardConfig, MediaBoardConfig } from '@modules/board'; import type { CollaborativeTextEditorConfig } from '@modules/collaborative-text-editor'; +import { CommonCartridgeConfig } from '@modules/common-cartridge'; import type { FilesStorageClientConfig } from '@modules/files-storage-client'; import type { LearnroomConfig } from '@modules/learnroom'; import type { LessonConfig } from '@modules/lesson'; @@ -77,7 +78,8 @@ export interface ServerConfig ShdConfig, OauthConfig, EncryptionConfig, - CoursesClientConfig { + CoursesClientConfig, + CommonCartridgeConfig { NODE_ENV: NodeEnvType; SC_DOMAIN: string; HOST: string; From 7fb809745e2ba8fc47c5329f247e5164cfdd7da8 Mon Sep 17 00:00:00 2001 From: Patrick Sachmann <20001160+psachmann@users.noreply.github.com> Date: Mon, 9 Dec 2024 11:26:13 +0100 Subject: [PATCH 13/25] adding tests for import service --- .../common-cartridge-import.service.spec.ts | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/apps/server/src/modules/common-cartridge/service/common-cartridge-import.service.spec.ts b/apps/server/src/modules/common-cartridge/service/common-cartridge-import.service.spec.ts index f144a4f5520..fb771065ccb 100644 --- a/apps/server/src/modules/common-cartridge/service/common-cartridge-import.service.spec.ts +++ b/apps/server/src/modules/common-cartridge/service/common-cartridge-import.service.spec.ts @@ -1,8 +1,20 @@ +import { faker } from '@faker-js/faker'; import { createMock, DeepMocked } from '@golevelup/ts-jest'; import { CoursesClientAdapter } from '@infra/courses-client'; import { Test, TestingModule } from '@nestjs/testing'; +import type { CommonCartridgeFileParser } from '../import/common-cartridge-file-parser'; import { CommonCartridgeImportService } from './common-cartridge-import.service'; +jest.mock('../import/common-cartridge-file-parser', () => { + const fileParserMock = createMock(); + + fileParserMock.getTitle.mockReturnValue(faker.lorem.words()); + + return { + CommonCartridgeFileParser: jest.fn(() => fileParserMock), + }; +}); + describe(CommonCartridgeImportService.name, () => { let module: TestingModule; let sut: CommonCartridgeImportService; @@ -37,8 +49,10 @@ describe(CommonCartridgeImportService.name, () => { describe('importFile', () => { describe('when importing a file', () => { - it('should create a course', () => { - throw new Error('Test not implemented'); + it('should create a course', async () => { + await sut.importFile(Buffer.from('')); + + expect(coursesClientAdapterMock.createCourse).toHaveBeenCalledWith({ title: expect.any(String) }); }); }); }); From 1fa8fed37945d045b0a333612255b301718e8484 Mon Sep 17 00:00:00 2001 From: Patrick Sachmann <20001160+psachmann@users.noreply.github.com> Date: Mon, 9 Dec 2024 12:06:39 +0100 Subject: [PATCH 14/25] fixing imports --- .../service/common-cartridge-export.service.spec.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 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 f6d1066f5b0..7df015c74b2 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,15 +1,15 @@ import { faker } from '@faker-js/faker'; import { DeepMocked, createMock } from '@golevelup/ts-jest'; +import { CoursesClientAdapter } from '@infra/courses-client'; import { FilesStorageClientAdapterService } from '@modules/files-storage-client'; import { Test, TestingModule } from '@nestjs/testing'; import { BoardClientAdapter } from '../common-cartridge-client/board-client'; -import { CommonCartridgeExportService } from './common-cartridge-export.service'; -import { 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 { 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 { CourseRoomsClientAdapter } from '../common-cartridge-client/room-client'; +import { CommonCartridgeExportService } from './common-cartridge-export.service'; describe('CommonCartridgeExportService', () => { let module: TestingModule; @@ -87,6 +87,7 @@ describe('CommonCartridgeExportService', () => { id: courseId, title: faker.lorem.sentence(), copyRightOwners: [faker.lorem.word()], + creationDate: faker.date.recent().toString(), }; coursesClientAdapterMock.getCourseCommonCartridgeMetadata.mockResolvedValue(expected); From 456fd63660769f574a87a84165cb032c8c24576b Mon Sep 17 00:00:00 2001 From: Patrick Sachmann <20001160+psachmann@users.noreply.github.com> Date: Wed, 11 Dec 2024 10:09:33 +0100 Subject: [PATCH 15/25] adding api test --- .../common-cartridge.controller.api.spec.ts | 90 +++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 apps/server/src/modules/common-cartridge/controller/common-cartridge.controller.api.spec.ts diff --git a/apps/server/src/modules/common-cartridge/controller/common-cartridge.controller.api.spec.ts b/apps/server/src/modules/common-cartridge/controller/common-cartridge.controller.api.spec.ts new file mode 100644 index 00000000000..487fdf8b8d4 --- /dev/null +++ b/apps/server/src/modules/common-cartridge/controller/common-cartridge.controller.api.spec.ts @@ -0,0 +1,90 @@ +import { faker } from '@faker-js/faker'; +import { createMock } from '@golevelup/ts-jest'; +import { ICurrentUser } from '@infra/auth-guard'; +import { INestApplication } from '@nestjs/common'; +import { ConfigModule } from '@nestjs/config'; +import { Test, TestingModule } from '@nestjs/testing'; +import { axiosResponseFactory } from '@shared/testing'; +import { CoursesApi } from '@src/infra/courses-client/generated'; +import supertest from 'supertest'; +import { CommonCartridgeApiModule } from '../common-cartridge-api.module'; +import { CommonCartridgeFileBuilder } from '../export/builders/common-cartridge-file-builder'; +import { CommonCartridgeElementType, CommonCartridgeVersion } from '../export/common-cartridge.enums'; + +jest.mock('../../../infra/courses-client/generated/api/courses-api', () => { + const coursesApiMock = createMock(); + + coursesApiMock.courseControllerCreateCourse.mockResolvedValue(axiosResponseFactory.build({ status: 201 })); + + return { + CoursesApi: jest.fn(() => coursesApiMock), + }; +}); +jest.mock('../../../infra/auth-guard/decorator/jwt-auth.decorator', () => { + return { + CurrentUser: () => jest.fn(() => createMock()), + JwtAuthentication: () => jest.fn(), + }; +}); + +describe('CommonCartridgeController (API)', () => { + let module: TestingModule; + let app: INestApplication; + + beforeAll(async () => { + module = await Test.createTestingModule({ + imports: [ + CommonCartridgeApiModule, + ConfigModule.forRoot({ + isGlobal: true, + load: [ + () => { + return { API_HOST: faker.internet.url() }; + }, + ], + }), + ], + }).compile(); + app = module.createNestApplication(); + + await app.init(); + }); + + afterAll(async () => { + await module.close(); + }); + + describe('importCourse', () => { + const setup = () => { + const ccBuilder = new CommonCartridgeFileBuilder({ + identifier: 'course-1', + version: CommonCartridgeVersion.V_1_1_0, + }); + + ccBuilder.addMetadata({ + type: CommonCartridgeElementType.METADATA, + title: 'Course 1', + creationDate: new Date(), + copyrightOwners: ['Teacher 1'], + }); + + const ccFile = ccBuilder.build(); + + return { + ccFile, + }; + }; + + it('should import a course from a Common Cartridge file', async () => { + const { ccFile } = setup(); + + const response = await supertest(app.getHttpServer()) + .post('/common-cartridge/import') + .set('Authorization', `Bearer ${faker.string.alphanumeric(42)}`) + .set('Content-Type', 'application/octet-stream') + .attach('file', ccFile, 'course-1.zip'); + + expect(response.status).toBe(201); + }); + }); +}); From b15d58fe8c03408326960e0ffd48c22499fa156b Mon Sep 17 00:00:00 2001 From: Patrick Sachmann <20001160+psachmann@users.noreply.github.com> Date: Wed, 11 Dec 2024 10:23:45 +0100 Subject: [PATCH 16/25] updating test --- .../src/modules/common-cartridge/common-cartridge.config.spec.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/server/src/modules/common-cartridge/common-cartridge.config.spec.ts b/apps/server/src/modules/common-cartridge/common-cartridge.config.spec.ts index 2e15af59e9e..0926ce4b76a 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge.config.spec.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge.config.spec.ts @@ -8,6 +8,7 @@ describe('commonCartridgeConfig', () => { expect(result).toStrictEqual({ NEST_LOG_LEVEL: expect.any(String), INCOMING_REQUEST_TIMEOUT: expect.any(Number), + FEATURE_COMMON_CARTRIDGE_COURSE_IMPORT_MAX_FILE_SIZE: expect.any(Number), }); }); }); From af3c4fcafa5317698f5cf65629f0923782e4ecaf Mon Sep 17 00:00:00 2001 From: Patrick Sachmann <20001160+psachmann@users.noreply.github.com> Date: Wed, 11 Dec 2024 10:38:21 +0100 Subject: [PATCH 17/25] updating tests --- .../controller/common-cartridge.controller.spec.ts | 1 + 1 file changed, 1 insertion(+) 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..25a8ad7d939 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 @@ -44,6 +44,7 @@ describe('CommonCartridgeController', () => { id: courseId, title: faker.lorem.sentence(), copyRightOwners: [faker.lorem.words()], + creationDate: faker.date.recent().toISOString(), }, }); From 63ed335670398f6aca9253e79f43989e7833c77b Mon Sep 17 00:00:00 2001 From: Patrick Sachmann <20001160+psachmann@users.noreply.github.com> Date: Wed, 11 Dec 2024 10:56:22 +0100 Subject: [PATCH 18/25] updating tests --- .../controller/common-cartridge.controller.spec.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) 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 25a8ad7d939..b8c235083dc 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,5 +1,6 @@ import { faker } from '@faker-js/faker'; import { DeepMocked, createMock } from '@golevelup/ts-jest'; +import { ConfigModule } from '@nestjs/config'; import { Test, TestingModule } from '@nestjs/testing'; import { CommonCartridgeUc } from '../uc/common-cartridge.uc'; import { CommonCartridgeController } from './common-cartridge.controller'; @@ -13,6 +14,16 @@ describe('CommonCartridgeController', () => { beforeAll(async () => { module = await Test.createTestingModule({ + imports: [ + ConfigModule.forRoot({ + isGlobal: true, + load: [ + () => { + return { FEATURE_COMMON_CARTRIDGE_COURSE_IMPORT_MAX_FILE_SIZE: 10_000 }; + }, + ], + }), + ], controllers: [CommonCartridgeController], providers: [ { From 8d2429e89012d3c1142a7fcdf75161f3fa859cf3 Mon Sep 17 00:00:00 2001 From: Patrick Sachmann <20001160+psachmann@users.noreply.github.com> Date: Wed, 11 Dec 2024 13:28:36 +0100 Subject: [PATCH 19/25] adding cc route to ingress --- ansible/roles/common-cartridge/tasks/main.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) 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 From c5e5b79f38c3e960137de473fdd62f1026f716e9 Mon Sep 17 00:00:00 2001 From: Patrick Sachmann <20001160+psachmann@users.noreply.github.com> Date: Wed, 11 Dec 2024 13:47:17 +0100 Subject: [PATCH 20/25] testing auth-guard module --- .../common-cartridge/common-cartridge-api.module.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-api.module.ts b/apps/server/src/modules/common-cartridge/common-cartridge-api.module.ts index 317f705ec7a..556e72dc30f 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-api.module.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-api.module.ts @@ -1,3 +1,4 @@ +import { AuthGuardModule, AuthGuardOptions } from '@infra/auth-guard'; import { HttpModule } from '@nestjs/axios'; import { Module } from '@nestjs/common'; import { ConfigModule } from '@nestjs/config'; @@ -8,7 +9,13 @@ import { CommonCartridgeModule } from './common-cartridge.module'; import { CommonCartridgeController } from './controller/common-cartridge.controller'; @Module({ - imports: [CoreModule, HttpModule, ConfigModule.forRoot(createConfigModuleOptions(config)), CommonCartridgeModule], + imports: [ + CoreModule, + HttpModule, + AuthGuardModule.register([AuthGuardOptions.JWT]), + ConfigModule.forRoot(createConfigModuleOptions(config)), + CommonCartridgeModule, + ], controllers: [CommonCartridgeController], }) export class CommonCartridgeApiModule {} From 6b1b7fc871897cc24c4c3b191a6baaece8eaa5c9 Mon Sep 17 00:00:00 2001 From: Patrick Sachmann <20001160+psachmann@users.noreply.github.com> Date: Wed, 11 Dec 2024 14:03:11 +0100 Subject: [PATCH 21/25] updating imports --- .../modules/common-cartridge/common-cartridge-api.module.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/server/src/modules/common-cartridge/common-cartridge-api.module.ts b/apps/server/src/modules/common-cartridge/common-cartridge-api.module.ts index 556e72dc30f..11dab56459a 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge-api.module.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge-api.module.ts @@ -1,9 +1,11 @@ import { AuthGuardModule, AuthGuardOptions } from '@infra/auth-guard'; +import { AuthorizationClientModule } from '@infra/authorization-client'; import { HttpModule } from '@nestjs/axios'; import { Module } from '@nestjs/common'; import { ConfigModule } from '@nestjs/config'; import { createConfigModuleOptions } from '@src/config'; import { CoreModule } from '@src/core'; +import { authorizationClientConfig } from '../files-storage/files-storage.config'; import { config } from './common-cartridge.config'; import { CommonCartridgeModule } from './common-cartridge.module'; import { CommonCartridgeController } from './controller/common-cartridge.controller'; @@ -12,6 +14,7 @@ import { CommonCartridgeController } from './controller/common-cartridge.control imports: [ CoreModule, HttpModule, + AuthorizationClientModule.register(authorizationClientConfig), AuthGuardModule.register([AuthGuardOptions.JWT]), ConfigModule.forRoot(createConfigModuleOptions(config)), CommonCartridgeModule, From 09e6ba93ed6d0cbd02197b702e7919fdd5c34c40 Mon Sep 17 00:00:00 2001 From: Patrick Sachmann <20001160+psachmann@users.noreply.github.com> Date: Wed, 11 Dec 2024 14:47:04 +0100 Subject: [PATCH 22/25] updating config --- .../src/modules/common-cartridge/common-cartridge.config.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/server/src/modules/common-cartridge/common-cartridge.config.ts b/apps/server/src/modules/common-cartridge/common-cartridge.config.ts index 75bf4ee5325..bd8783e922f 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge.config.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge.config.ts @@ -4,11 +4,15 @@ export interface CommonCartridgeConfig { NEST_LOG_LEVEL: string; INCOMING_REQUEST_TIMEOUT: number; FEATURE_COMMON_CARTRIDGE_COURSE_IMPORT_MAX_FILE_SIZE: number; + JWT_PUBLIC_KEY: string; + JWT_SIGNING_ALGORITHM: Algorithm; } const commonCartridgeConfig: CommonCartridgeConfig = { NEST_LOG_LEVEL: Configuration.get('NEST_LOG_LEVEL') as string, INCOMING_REQUEST_TIMEOUT: Configuration.get('FILES_STORAGE__INCOMING_REQUEST_TIMEOUT') as number, + JWT_PUBLIC_KEY: (Configuration.get('JWT_PUBLIC_KEY') as string).replace(/\\n/g, '\n'), + JWT_SIGNING_ALGORITHM: Configuration.get('JWT_SIGNING_ALGORITHM') as Algorithm, FEATURE_COMMON_CARTRIDGE_COURSE_IMPORT_MAX_FILE_SIZE: Configuration.get( 'FEATURE_COMMON_CARTRIDGE_COURSE_IMPORT_MAX_FILE_SIZE' ) as number, From 044931f6f4466540c63316ca361164d66daf7bf1 Mon Sep 17 00:00:00 2001 From: Patrick Sachmann <20001160+psachmann@users.noreply.github.com> Date: Wed, 11 Dec 2024 15:06:00 +0100 Subject: [PATCH 23/25] changing config --- apps/server/src/modules/server/server.config.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/server/src/modules/server/server.config.ts b/apps/server/src/modules/server/server.config.ts index 13c5f761ee7..fe858b67219 100644 --- a/apps/server/src/modules/server/server.config.ts +++ b/apps/server/src/modules/server/server.config.ts @@ -12,7 +12,6 @@ import { AlertConfig } from '@modules/alert'; import type { AuthenticationConfig } from '@modules/authentication'; import type { BoardConfig, MediaBoardConfig } from '@modules/board'; import type { CollaborativeTextEditorConfig } from '@modules/collaborative-text-editor'; -import { CommonCartridgeConfig } from '@modules/common-cartridge'; import type { FilesStorageClientConfig } from '@modules/files-storage-client'; import type { LearnroomConfig } from '@modules/learnroom'; import type { LessonConfig } from '@modules/lesson'; @@ -78,8 +77,7 @@ export interface ServerConfig ShdConfig, OauthConfig, EncryptionConfig, - CoursesClientConfig, - CommonCartridgeConfig { + CoursesClientConfig { NODE_ENV: NodeEnvType; SC_DOMAIN: string; HOST: string; From 459cb2eabb11ec743ba15965f16e4eddb870343f Mon Sep 17 00:00:00 2001 From: Patrick Sachmann <20001160+psachmann@users.noreply.github.com> Date: Wed, 11 Dec 2024 15:49:03 +0100 Subject: [PATCH 24/25] fixing path --- apps/server/src/infra/courses-client/courses-client.module.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/server/src/infra/courses-client/courses-client.module.ts b/apps/server/src/infra/courses-client/courses-client.module.ts index 0718a7c3d81..a03fd839933 100644 --- a/apps/server/src/infra/courses-client/courses-client.module.ts +++ b/apps/server/src/infra/courses-client/courses-client.module.ts @@ -17,7 +17,7 @@ import { Configuration, CoursesApi } from './generated'; const basePath = configService.getOrThrow('API_HOST'); const accessToken = JwtExtractor.extractJwtFromRequest(request); const configuration = new Configuration({ - basePath: `${basePath}/api/v3`, + basePath: `${basePath}/v3`, accessToken, }); From ae0806da37494ffadb62d3ad5e5eefb31de297d5 Mon Sep 17 00:00:00 2001 From: Patrick Sachmann <20001160+psachmann@users.noreply.github.com> Date: Wed, 11 Dec 2024 16:46:01 +0100 Subject: [PATCH 25/25] fixing tests --- .../common-cartridge/common-cartridge.config.spec.ts | 2 ++ .../controller/common-cartridge.controller.api.spec.ts | 10 +++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/apps/server/src/modules/common-cartridge/common-cartridge.config.spec.ts b/apps/server/src/modules/common-cartridge/common-cartridge.config.spec.ts index 0926ce4b76a..7946ab03a32 100644 --- a/apps/server/src/modules/common-cartridge/common-cartridge.config.spec.ts +++ b/apps/server/src/modules/common-cartridge/common-cartridge.config.spec.ts @@ -9,6 +9,8 @@ describe('commonCartridgeConfig', () => { NEST_LOG_LEVEL: expect.any(String), INCOMING_REQUEST_TIMEOUT: expect.any(Number), FEATURE_COMMON_CARTRIDGE_COURSE_IMPORT_MAX_FILE_SIZE: expect.any(Number), + JWT_PUBLIC_KEY: expect.any(String), + JWT_SIGNING_ALGORITHM: expect.any(String) as unknown as Algorithm, }); }); }); diff --git a/apps/server/src/modules/common-cartridge/controller/common-cartridge.controller.api.spec.ts b/apps/server/src/modules/common-cartridge/controller/common-cartridge.controller.api.spec.ts index 487fdf8b8d4..bb2fa34132d 100644 --- a/apps/server/src/modules/common-cartridge/controller/common-cartridge.controller.api.spec.ts +++ b/apps/server/src/modules/common-cartridge/controller/common-cartridge.controller.api.spec.ts @@ -39,7 +39,15 @@ describe('CommonCartridgeController (API)', () => { isGlobal: true, load: [ () => { - return { API_HOST: faker.internet.url() }; + return { + SC_DOMAIN: faker.internet.url(), + API_HOST: faker.internet.url(), + JWT_PUBLIC_KEY: faker.string.alphanumeric(42), + JWT_SIGNING_ALGORITHM: 'RS256', + INCOMING_REQUEST_TIMEOUT: 10_000, + NEST_LOG_LEVEL: 'error', + FEATURE_COMMON_CARTRIDGE_COURSE_IMPORT_MAX_FILE_SIZE: 10_000, + }; }, ], }),