feat(backend): Controller en route voor het aanmaken van leerobjecten aangemaakt.
This commit is contained in:
		
							parent
							
								
									86ba4ea11e
								
							
						
					
					
						commit
						78353d6b65
					
				
					 6 changed files with 81 additions and 6 deletions
				
			
		|  | @ -31,6 +31,7 @@ | |||
|         "cross-env": "^7.0.3", | ||||
|         "dotenv": "^16.4.7", | ||||
|         "express": "^5.0.1", | ||||
|         "express-fileupload": "^1.5.1", | ||||
|         "express-jwt": "^8.5.1", | ||||
|         "gift-pegjs": "^1.0.2", | ||||
|         "isomorphic-dompurify": "^2.22.0", | ||||
|  | @ -51,6 +52,7 @@ | |||
|         "@mikro-orm/cli": "6.4.12", | ||||
|         "@types/cors": "^2.8.17", | ||||
|         "@types/express": "^5.0.0", | ||||
|         "@types/express-fileupload": "^1.5.1", | ||||
|         "@types/js-yaml": "^4.0.9", | ||||
|         "@types/node": "^22.13.4", | ||||
|         "@types/response-time": "^2.3.8", | ||||
|  |  | |||
|  | @ -7,6 +7,7 @@ import { BadRequestException } from '../exceptions/bad-request-exception.js'; | |||
| import { NotFoundException } from '../exceptions/not-found-exception.js'; | ||||
| import { envVars, getEnvVar } from '../util/envVars.js'; | ||||
| import { FilteredLearningObject, LearningObjectIdentifierDTO, LearningPathIdentifier } from '@dwengo-1/common/interfaces/learning-content'; | ||||
| import {UploadedFile} from "express-fileupload"; | ||||
| 
 | ||||
| function getLearningObjectIdentifierFromRequest(req: Request): LearningObjectIdentifierDTO { | ||||
|     if (!req.params.hruid) { | ||||
|  | @ -72,3 +73,10 @@ export async function getAttachment(req: Request, res: Response): Promise<void> | |||
|     } | ||||
|     res.setHeader('Content-Type', attachment.mimeType).send(attachment.content); | ||||
| } | ||||
| 
 | ||||
| export async function handlePostLearningObject(req: Request, res: Response): Promise<void> { | ||||
|     if (!req.files || !req.files[0]) { | ||||
|         throw new BadRequestException('No file uploaded'); | ||||
|     } | ||||
|     await learningObjectService.storeLearningObject((req.files[0] as UploadedFile).tempFilePath); | ||||
| } | ||||
|  |  | |||
|  | @ -1,8 +1,15 @@ | |||
| import express from 'express'; | ||||
| import { getAllLearningObjects, getAttachment, getLearningObject, getLearningObjectHTML } from '../controllers/learning-objects.js'; | ||||
| import { | ||||
|     getAllLearningObjects, | ||||
|     getAttachment, | ||||
|     getLearningObject, | ||||
|     getLearningObjectHTML, | ||||
|     handlePostLearningObject | ||||
| } from '../controllers/learning-objects.js'; | ||||
| 
 | ||||
| import submissionRoutes from './submissions.js'; | ||||
| import questionRoutes from './questions.js'; | ||||
| import fileUpload from "express-fileupload"; | ||||
| 
 | ||||
| const router = express.Router(); | ||||
| 
 | ||||
|  | @ -18,6 +25,8 @@ const router = express.Router(); | |||
| // Example 2: http://localhost:3000/learningObject?full=true&hruid=un_artificiele_intelligentie
 | ||||
| router.get('/', getAllLearningObjects); | ||||
| 
 | ||||
| router.post('/', fileUpload({useTempFiles: true}), handlePostLearningObject) | ||||
| 
 | ||||
| // Parameter: hruid of learning object
 | ||||
| // Query: language
 | ||||
| // Route to fetch data of one learning object based on its hruid
 | ||||
|  |  | |||
|  | @ -9,6 +9,7 @@ import { | |||
| } from '@dwengo-1/common/interfaces/learning-content'; | ||||
| import {getLearningObjectRepository} from "../../data/repositories"; | ||||
| import {processLearningObjectZip} from "./learning-object-zip-processing-service"; | ||||
| import {BadRequestException} from "../../exceptions/bad-request-exception"; | ||||
| 
 | ||||
| function getProvider(id: LearningObjectIdentifierDTO): LearningObjectProvider { | ||||
|     if (id.hruid.startsWith(getEnvVar(envVars.UserContentPrefix))) { | ||||
|  | @ -58,7 +59,7 @@ const learningObjectService = { | |||
|         const learningObject = await processLearningObjectZip(learningObjectPath); | ||||
| 
 | ||||
|         if (!learningObject.hruid.startsWith(getEnvVar(envVars.UserContentPrefix))) { | ||||
|             throw Error("Learning object name must start with the user content prefix!"); | ||||
|             throw new BadRequestException("Learning object name must start with the user content prefix!"); | ||||
|         } | ||||
| 
 | ||||
|         await learningObjectRepository.save(learningObject, {preventOverwrite: true}); | ||||
|  |  | |||
|  | @ -1,8 +1,9 @@ | |||
| import unzipper from 'unzipper'; | ||||
| import mime from 'mime-types'; | ||||
| import {LearningObjectMetadata} from "@dwengo-1/common/dist/interfaces/learning-content"; | ||||
| import {LearningObject} from "../../entities/content/learning-object.entity"; | ||||
| import {getAttachmentRepository, getLearningObjectRepository} from "../../data/repositories"; | ||||
| import {BadRequestException} from "../../exceptions/bad-request-exception"; | ||||
| import {LearningObjectMetadata} from "@dwengo-1/common/dist/interfaces/learning-content"; | ||||
| 
 | ||||
| /** | ||||
|  * Process an uploaded zip file and construct a LearningObject from its contents. | ||||
|  | @ -20,7 +21,7 @@ export async function processLearningObjectZip(filePath: string): Promise<Learni | |||
| 
 | ||||
|     for (const file of zip.files) { | ||||
|         if (file.type === "Directory") { | ||||
|             throw Error("The learning object zip file should not contain directories."); | ||||
|             throw new BadRequestException("The learning object zip file should not contain directories."); | ||||
|         } else if (file.path === "metadata.json") { | ||||
|             metadata = await processMetadataJson(file); | ||||
|         } else if (file.path.startsWith("index.")) { | ||||
|  | @ -34,10 +35,10 @@ export async function processLearningObjectZip(filePath: string): Promise<Learni | |||
|     } | ||||
| 
 | ||||
|     if (!metadata) { | ||||
|         throw Error("Missing metadata.json file"); | ||||
|         throw new BadRequestException("Missing metadata.json file"); | ||||
|     } | ||||
|     if (!content) { | ||||
|         throw Error("Missing index file"); | ||||
|         throw new BadRequestException("Missing index file"); | ||||
|     } | ||||
| 
 | ||||
|     const learningObject = learningObjectRepo.create(metadata); | ||||
|  |  | |||
							
								
								
									
										54
									
								
								package-lock.json
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										54
									
								
								package-lock.json
									
										
									
										generated
									
									
									
								
							|  | @ -44,6 +44,7 @@ | |||
|                 "cross-env": "^7.0.3", | ||||
|                 "dotenv": "^16.4.7", | ||||
|                 "express": "^5.0.1", | ||||
|                 "express-fileupload": "^1.5.1", | ||||
|                 "express-jwt": "^8.5.1", | ||||
|                 "gift-pegjs": "^1.0.2", | ||||
|                 "isomorphic-dompurify": "^2.22.0", | ||||
|  | @ -64,6 +65,7 @@ | |||
|                 "@mikro-orm/cli": "6.4.12", | ||||
|                 "@types/cors": "^2.8.17", | ||||
|                 "@types/express": "^5.0.0", | ||||
|                 "@types/express-fileupload": "^1.5.1", | ||||
|                 "@types/js-yaml": "^4.0.9", | ||||
|                 "@types/node": "^22.13.4", | ||||
|                 "@types/response-time": "^2.3.8", | ||||
|  | @ -1639,6 +1641,16 @@ | |||
|                 "@types/node": "*" | ||||
|             } | ||||
|         }, | ||||
|         "node_modules/@types/busboy": { | ||||
|             "version": "1.5.4", | ||||
|             "resolved": "https://registry.npmjs.org/@types/busboy/-/busboy-1.5.4.tgz", | ||||
|             "integrity": "sha512-kG7WrUuAKK0NoyxfQHsVE6j1m01s6kMma64E+OZenQABMQyTJop1DumUWcLwAQ2JzpefU7PDYoRDKl8uZosFjw==", | ||||
|             "dev": true, | ||||
|             "license": "MIT", | ||||
|             "dependencies": { | ||||
|                 "@types/node": "*" | ||||
|             } | ||||
|         }, | ||||
|         "node_modules/@types/connect": { | ||||
|             "version": "3.4.38", | ||||
|             "license": "MIT", | ||||
|  | @ -1673,6 +1685,17 @@ | |||
|                 "@types/serve-static": "*" | ||||
|             } | ||||
|         }, | ||||
|         "node_modules/@types/express-fileupload": { | ||||
|             "version": "1.5.1", | ||||
|             "resolved": "https://registry.npmjs.org/@types/express-fileupload/-/express-fileupload-1.5.1.tgz", | ||||
|             "integrity": "sha512-DllImBVI1lCyjl2klky/TEwk60mbNebgXv1669h66g9TfptWSrEFq5a/raHSutaFzjSm1tmn9ypdNfu4jPSixQ==", | ||||
|             "dev": true, | ||||
|             "license": "MIT", | ||||
|             "dependencies": { | ||||
|                 "@types/busboy": "*", | ||||
|                 "@types/express": "*" | ||||
|             } | ||||
|         }, | ||||
|         "node_modules/@types/express-serve-static-core": { | ||||
|             "version": "5.0.6", | ||||
|             "dev": true, | ||||
|  | @ -2857,6 +2880,17 @@ | |||
|                 "url": "https://github.com/sponsors/sindresorhus" | ||||
|             } | ||||
|         }, | ||||
|         "node_modules/busboy": { | ||||
|             "version": "1.6.0", | ||||
|             "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", | ||||
|             "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", | ||||
|             "dependencies": { | ||||
|                 "streamsearch": "^1.1.0" | ||||
|             }, | ||||
|             "engines": { | ||||
|                 "node": ">=10.16.0" | ||||
|             } | ||||
|         }, | ||||
|         "node_modules/bytes": { | ||||
|             "version": "3.1.2", | ||||
|             "license": "MIT", | ||||
|  | @ -4235,6 +4269,18 @@ | |||
|                 "url": "https://opencollective.com/express" | ||||
|             } | ||||
|         }, | ||||
|         "node_modules/express-fileupload": { | ||||
|             "version": "1.5.1", | ||||
|             "resolved": "https://registry.npmjs.org/express-fileupload/-/express-fileupload-1.5.1.tgz", | ||||
|             "integrity": "sha512-LsYG1ALXEB7vlmjuSw8ABeOctMp8a31aUC5ZF55zuz7O2jLFnmJYrCv10py357ky48aEoBQ/9bVXgFynjvaPmA==", | ||||
|             "license": "MIT", | ||||
|             "dependencies": { | ||||
|                 "busboy": "^1.6.0" | ||||
|             }, | ||||
|             "engines": { | ||||
|                 "node": ">=12.0.0" | ||||
|             } | ||||
|         }, | ||||
|         "node_modules/express-jwt": { | ||||
|             "version": "8.5.1", | ||||
|             "license": "MIT", | ||||
|  | @ -7798,6 +7844,14 @@ | |||
|             "dev": true, | ||||
|             "license": "MIT" | ||||
|         }, | ||||
|         "node_modules/streamsearch": { | ||||
|             "version": "1.1.0", | ||||
|             "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", | ||||
|             "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", | ||||
|             "engines": { | ||||
|                 "node": ">=10.0.0" | ||||
|             } | ||||
|         }, | ||||
|         "node_modules/string_decoder": { | ||||
|             "version": "1.3.0", | ||||
|             "license": "MIT", | ||||
|  |  | |||
		Reference in a new issue
	
	 Gerald Schmittinger
						Gerald Schmittinger