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", |         "cross-env": "^7.0.3", | ||||||
|         "dotenv": "^16.4.7", |         "dotenv": "^16.4.7", | ||||||
|         "express": "^5.0.1", |         "express": "^5.0.1", | ||||||
|  |         "express-fileupload": "^1.5.1", | ||||||
|         "express-jwt": "^8.5.1", |         "express-jwt": "^8.5.1", | ||||||
|         "gift-pegjs": "^1.0.2", |         "gift-pegjs": "^1.0.2", | ||||||
|         "isomorphic-dompurify": "^2.22.0", |         "isomorphic-dompurify": "^2.22.0", | ||||||
|  | @ -51,6 +52,7 @@ | ||||||
|         "@mikro-orm/cli": "6.4.12", |         "@mikro-orm/cli": "6.4.12", | ||||||
|         "@types/cors": "^2.8.17", |         "@types/cors": "^2.8.17", | ||||||
|         "@types/express": "^5.0.0", |         "@types/express": "^5.0.0", | ||||||
|  |         "@types/express-fileupload": "^1.5.1", | ||||||
|         "@types/js-yaml": "^4.0.9", |         "@types/js-yaml": "^4.0.9", | ||||||
|         "@types/node": "^22.13.4", |         "@types/node": "^22.13.4", | ||||||
|         "@types/response-time": "^2.3.8", |         "@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 { NotFoundException } from '../exceptions/not-found-exception.js'; | ||||||
| import { envVars, getEnvVar } from '../util/envVars.js'; | import { envVars, getEnvVar } from '../util/envVars.js'; | ||||||
| import { FilteredLearningObject, LearningObjectIdentifierDTO, LearningPathIdentifier } from '@dwengo-1/common/interfaces/learning-content'; | import { FilteredLearningObject, LearningObjectIdentifierDTO, LearningPathIdentifier } from '@dwengo-1/common/interfaces/learning-content'; | ||||||
|  | import {UploadedFile} from "express-fileupload"; | ||||||
| 
 | 
 | ||||||
| function getLearningObjectIdentifierFromRequest(req: Request): LearningObjectIdentifierDTO { | function getLearningObjectIdentifierFromRequest(req: Request): LearningObjectIdentifierDTO { | ||||||
|     if (!req.params.hruid) { |     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); |     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 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 submissionRoutes from './submissions.js'; | ||||||
| import questionRoutes from './questions.js'; | import questionRoutes from './questions.js'; | ||||||
|  | import fileUpload from "express-fileupload"; | ||||||
| 
 | 
 | ||||||
| const router = express.Router(); | const router = express.Router(); | ||||||
| 
 | 
 | ||||||
|  | @ -18,6 +25,8 @@ const router = express.Router(); | ||||||
| // Example 2: http://localhost:3000/learningObject?full=true&hruid=un_artificiele_intelligentie
 | // Example 2: http://localhost:3000/learningObject?full=true&hruid=un_artificiele_intelligentie
 | ||||||
| router.get('/', getAllLearningObjects); | router.get('/', getAllLearningObjects); | ||||||
| 
 | 
 | ||||||
|  | router.post('/', fileUpload({useTempFiles: true}), handlePostLearningObject) | ||||||
|  | 
 | ||||||
| // Parameter: hruid of learning object
 | // Parameter: hruid of learning object
 | ||||||
| // Query: language
 | // Query: language
 | ||||||
| // Route to fetch data of one learning object based on its hruid
 | // Route to fetch data of one learning object based on its hruid
 | ||||||
|  |  | ||||||
|  | @ -9,6 +9,7 @@ import { | ||||||
| } from '@dwengo-1/common/interfaces/learning-content'; | } from '@dwengo-1/common/interfaces/learning-content'; | ||||||
| import {getLearningObjectRepository} from "../../data/repositories"; | import {getLearningObjectRepository} from "../../data/repositories"; | ||||||
| import {processLearningObjectZip} from "./learning-object-zip-processing-service"; | import {processLearningObjectZip} from "./learning-object-zip-processing-service"; | ||||||
|  | import {BadRequestException} from "../../exceptions/bad-request-exception"; | ||||||
| 
 | 
 | ||||||
| function getProvider(id: LearningObjectIdentifierDTO): LearningObjectProvider { | function getProvider(id: LearningObjectIdentifierDTO): LearningObjectProvider { | ||||||
|     if (id.hruid.startsWith(getEnvVar(envVars.UserContentPrefix))) { |     if (id.hruid.startsWith(getEnvVar(envVars.UserContentPrefix))) { | ||||||
|  | @ -58,7 +59,7 @@ const learningObjectService = { | ||||||
|         const learningObject = await processLearningObjectZip(learningObjectPath); |         const learningObject = await processLearningObjectZip(learningObjectPath); | ||||||
| 
 | 
 | ||||||
|         if (!learningObject.hruid.startsWith(getEnvVar(envVars.UserContentPrefix))) { |         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}); |         await learningObjectRepository.save(learningObject, {preventOverwrite: true}); | ||||||
|  |  | ||||||
|  | @ -1,8 +1,9 @@ | ||||||
| import unzipper from 'unzipper'; | import unzipper from 'unzipper'; | ||||||
| import mime from 'mime-types'; | import mime from 'mime-types'; | ||||||
| import {LearningObjectMetadata} from "@dwengo-1/common/dist/interfaces/learning-content"; |  | ||||||
| import {LearningObject} from "../../entities/content/learning-object.entity"; | import {LearningObject} from "../../entities/content/learning-object.entity"; | ||||||
| import {getAttachmentRepository, getLearningObjectRepository} from "../../data/repositories"; | 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. |  * 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) { |     for (const file of zip.files) { | ||||||
|         if (file.type === "Directory") { |         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") { |         } else if (file.path === "metadata.json") { | ||||||
|             metadata = await processMetadataJson(file); |             metadata = await processMetadataJson(file); | ||||||
|         } else if (file.path.startsWith("index.")) { |         } else if (file.path.startsWith("index.")) { | ||||||
|  | @ -34,10 +35,10 @@ export async function processLearningObjectZip(filePath: string): Promise<Learni | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (!metadata) { |     if (!metadata) { | ||||||
|         throw Error("Missing metadata.json file"); |         throw new BadRequestException("Missing metadata.json file"); | ||||||
|     } |     } | ||||||
|     if (!content) { |     if (!content) { | ||||||
|         throw Error("Missing index file"); |         throw new BadRequestException("Missing index file"); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     const learningObject = learningObjectRepo.create(metadata); |     const learningObject = learningObjectRepo.create(metadata); | ||||||
|  |  | ||||||
							
								
								
									
										54
									
								
								package-lock.json
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										54
									
								
								package-lock.json
									
										
									
										generated
									
									
									
								
							|  | @ -44,6 +44,7 @@ | ||||||
|                 "cross-env": "^7.0.3", |                 "cross-env": "^7.0.3", | ||||||
|                 "dotenv": "^16.4.7", |                 "dotenv": "^16.4.7", | ||||||
|                 "express": "^5.0.1", |                 "express": "^5.0.1", | ||||||
|  |                 "express-fileupload": "^1.5.1", | ||||||
|                 "express-jwt": "^8.5.1", |                 "express-jwt": "^8.5.1", | ||||||
|                 "gift-pegjs": "^1.0.2", |                 "gift-pegjs": "^1.0.2", | ||||||
|                 "isomorphic-dompurify": "^2.22.0", |                 "isomorphic-dompurify": "^2.22.0", | ||||||
|  | @ -64,6 +65,7 @@ | ||||||
|                 "@mikro-orm/cli": "6.4.12", |                 "@mikro-orm/cli": "6.4.12", | ||||||
|                 "@types/cors": "^2.8.17", |                 "@types/cors": "^2.8.17", | ||||||
|                 "@types/express": "^5.0.0", |                 "@types/express": "^5.0.0", | ||||||
|  |                 "@types/express-fileupload": "^1.5.1", | ||||||
|                 "@types/js-yaml": "^4.0.9", |                 "@types/js-yaml": "^4.0.9", | ||||||
|                 "@types/node": "^22.13.4", |                 "@types/node": "^22.13.4", | ||||||
|                 "@types/response-time": "^2.3.8", |                 "@types/response-time": "^2.3.8", | ||||||
|  | @ -1639,6 +1641,16 @@ | ||||||
|                 "@types/node": "*" |                 "@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": { |         "node_modules/@types/connect": { | ||||||
|             "version": "3.4.38", |             "version": "3.4.38", | ||||||
|             "license": "MIT", |             "license": "MIT", | ||||||
|  | @ -1673,6 +1685,17 @@ | ||||||
|                 "@types/serve-static": "*" |                 "@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": { |         "node_modules/@types/express-serve-static-core": { | ||||||
|             "version": "5.0.6", |             "version": "5.0.6", | ||||||
|             "dev": true, |             "dev": true, | ||||||
|  | @ -2857,6 +2880,17 @@ | ||||||
|                 "url": "https://github.com/sponsors/sindresorhus" |                 "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": { |         "node_modules/bytes": { | ||||||
|             "version": "3.1.2", |             "version": "3.1.2", | ||||||
|             "license": "MIT", |             "license": "MIT", | ||||||
|  | @ -4235,6 +4269,18 @@ | ||||||
|                 "url": "https://opencollective.com/express" |                 "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": { |         "node_modules/express-jwt": { | ||||||
|             "version": "8.5.1", |             "version": "8.5.1", | ||||||
|             "license": "MIT", |             "license": "MIT", | ||||||
|  | @ -7798,6 +7844,14 @@ | ||||||
|             "dev": true, |             "dev": true, | ||||||
|             "license": "MIT" |             "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": { |         "node_modules/string_decoder": { | ||||||
|             "version": "1.3.0", |             "version": "1.3.0", | ||||||
|             "license": "MIT", |             "license": "MIT", | ||||||
|  |  | ||||||
		Reference in a new issue
	
	 Gerald Schmittinger
						Gerald Schmittinger