feat: added learningPaths.ts
This commit is contained in:
		
							parent
							
								
									cfaae9ebe4
								
							
						
					
					
						commit
						e8e1d94e5b
					
				
					 5 changed files with 193 additions and 8 deletions
				
			
		|  | @ -18,6 +18,7 @@ | |||
|         "@mikro-orm/postgresql": "^6.4.6", | ||||
|         "@mikro-orm/reflection": "^6.4.6", | ||||
|         "@types/js-yaml": "^4.0.9", | ||||
|         "axios": "^1.8.1", | ||||
|         "dotenv": "^16.4.7", | ||||
|         "express": "^5.0.1", | ||||
|         "js-yaml": "^4.1.0" | ||||
|  |  | |||
|  | @ -1,6 +1,7 @@ | |||
| import express, { Express, Response } from 'express'; | ||||
| import initORM from './orm.js'; | ||||
| import themeRoutes from './routes/themes.js'; | ||||
| import learningPathRoutes from './routes/learningPaths.js' | ||||
| 
 | ||||
| const app: Express = express(); | ||||
| const port: string | number = process.env.PORT || 3000; | ||||
|  | @ -13,6 +14,7 @@ app.get('/', (_, res: Response) => { | |||
| }); | ||||
| 
 | ||||
| app.use('/theme', themeRoutes); | ||||
| app.use('/learningPath', learningPathRoutes); | ||||
| 
 | ||||
| async function startServer() { | ||||
|     await initORM(); | ||||
|  |  | |||
							
								
								
									
										134
									
								
								backend/src/controllers/learningPaths.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										134
									
								
								backend/src/controllers/learningPaths.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,134 @@ | |||
| import { Request, Response } from "express"; | ||||
| import axios from "axios"; | ||||
| import { themes } from "../data/themes.js"; | ||||
| import dotenv from "dotenv"; | ||||
| 
 | ||||
| // Load environment variables
 | ||||
| dotenv.config(); | ||||
| 
 | ||||
| // Get API base URL from environment variables
 | ||||
| const DWENGO_API_BASE = process.env.DWENGO_API_BASE as string; | ||||
| if (!DWENGO_API_BASE) { | ||||
|     throw new Error("DWENGO_API_BASE is not defined in the .env file"); | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Fetch learning paths for a given list of HRUIDs. | ||||
|  * This function sends a request to the Dwengo API with the provided HRUIDs. | ||||
|  */ | ||||
| export async function getLearningPathsFromIds(req: Request, res: Response): Promise<void> { | ||||
|     try { | ||||
|         const { hruids } = req.query; | ||||
|         const language = (req.query.language as string) || "nl"; // Default to Dutch
 | ||||
| 
 | ||||
|         if (!hruids) { | ||||
|             res.status(400).json({ error: "Missing required parameter: hruids" }); | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         // Convert the input to an array if it's a string
 | ||||
|         const hruidList = Array.isArray(hruids) ? hruids : [hruids]; | ||||
| 
 | ||||
|         // Request learning paths from Dwengo API
 | ||||
|         const response = await axios.get(`${DWENGO_API_BASE}/learningPath/getPathsFromIdList`, { | ||||
|             params: { | ||||
|                 pathIdList: JSON.stringify({ hruids: hruidList }), | ||||
|                 language | ||||
|             } | ||||
|         }); | ||||
| 
 | ||||
|         res.json(response.data); | ||||
|     } catch (error) { | ||||
|         console.error("Error fetching learning paths:", error); | ||||
|         res.status(500).json({ error: "Internal server error" }); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Fetch all learning paths for a specific theme. | ||||
|  * First retrieves the HRUIDs associated with the theme, | ||||
|  * then fetches the corresponding learning paths from the Dwengo API. | ||||
|  */ | ||||
| export async function getLearningPathsByTheme(req: Request, res: Response): Promise<void> { | ||||
|     try { | ||||
|         const themeKey = req.params.theme; | ||||
|         const language = (req.query.language as string) || "nl"; // Default to Dutch
 | ||||
| 
 | ||||
|         // Find the theme by its title
 | ||||
|         const theme = themes.find((t) => t.title === themeKey); | ||||
| 
 | ||||
|         if (!theme) { | ||||
|             res.status(404).json({ error: "Theme not found" }); | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         // Extract HRUIDs from the theme
 | ||||
|         const hruidList = theme.hruids; | ||||
| 
 | ||||
|         // Request learning paths from Dwengo API using the extracted HRUIDs
 | ||||
|         const response = await axios.get(`${DWENGO_API_BASE}/learningPath/getPathsFromIdList`, { | ||||
|             params: { | ||||
|                 pathIdList: JSON.stringify({ hruids: hruidList }), | ||||
|                 language | ||||
|             } | ||||
|         }); | ||||
| 
 | ||||
|         res.json({ | ||||
|             theme: themeKey, | ||||
|             hruids: hruidList, | ||||
|             learningPaths: response.data | ||||
|         }); | ||||
| 
 | ||||
|     } catch (error) { | ||||
|         console.error("Error fetching learning paths for theme:", error); | ||||
|         res.status(500).json({ error: "Internal server error" }); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| export async function searchLearningPaths(req: Request, res: Response): Promise<void> { | ||||
|     try { | ||||
|         const query = req.query.query as string; | ||||
|         const language = (req.query.language as string) || "nl"; | ||||
| 
 | ||||
|         if (!query) { | ||||
|             res.status(400).json({ error: "Missing search query" }); | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         const response = await axios.get(`${DWENGO_API_BASE}/learningPath/search`, { | ||||
|             params: { all: query, language } | ||||
|         }); | ||||
| 
 | ||||
|         res.json(response.data); | ||||
|     } catch (error) { | ||||
|         console.error("Error searching learning paths:", error); | ||||
|         res.status(500).json({ error: "Internal server error" }); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| export async function getAllLearningPaths(req: Request, res: Response): Promise<void> { | ||||
|     try { | ||||
|         const language = (req.query.language as string) || "nl"; // Default to Dutch
 | ||||
| 
 | ||||
|         // Collect all HRUIDs from all themes
 | ||||
|         const allHruids: string[] = themes.flatMap(theme => theme.hruids); | ||||
| 
 | ||||
|         if (allHruids.length === 0) { | ||||
|             res.status(404).json({ error: "No HRUIDs found in themes" }); | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         // Call the Dwengo API with all HRUIDs combined
 | ||||
|         const response = await axios.get(`${DWENGO_API_BASE}/learningPath/getPathsFromIdList`, { | ||||
|             params: { | ||||
|                 pathIdList: JSON.stringify({ hruids: allHruids }), | ||||
|                 language | ||||
|             } | ||||
|         }); | ||||
| 
 | ||||
|         res.json(response.data); | ||||
|     } catch (error) { | ||||
|         console.error("Error fetching all learning paths:", error); | ||||
|         res.status(500).json({ error: "Internal server error" }); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										18
									
								
								backend/src/routes/learningPaths.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								backend/src/routes/learningPaths.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,18 @@ | |||
| import express from "express"; | ||||
| import { getLearningPathsFromIds, getLearningPathsByTheme, getAllLearningPaths, searchLearningPaths } from "../controllers/learningPaths.js"; | ||||
| 
 | ||||
| const router = express.Router(); | ||||
| 
 | ||||
| // Route to fetch learning paths based on a list of HRUIDs
 | ||||
| router.get("/", getLearningPathsFromIds); | ||||
| 
 | ||||
| // Route to fetch all possible learning paths
 | ||||
| router.get("/all", getAllLearningPaths); | ||||
| 
 | ||||
| // Route to fetch learning paths based on a searchterm
 | ||||
| router.get("/search", searchLearningPaths); | ||||
| 
 | ||||
| // Route to fetch learning paths based on a theme
 | ||||
| router.get("/theme/:theme", getLearningPathsByTheme); | ||||
| 
 | ||||
| export default router; | ||||
							
								
								
									
										46
									
								
								package-lock.json
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										46
									
								
								package-lock.json
									
										
									
										generated
									
									
									
								
							|  | @ -35,6 +35,7 @@ | |||
|                 "@mikro-orm/postgresql": "^6.4.6", | ||||
|                 "@mikro-orm/reflection": "^6.4.6", | ||||
|                 "@types/js-yaml": "^4.0.9", | ||||
|                 "axios": "^1.8.1", | ||||
|                 "dotenv": "^16.4.7", | ||||
|                 "express": "^5.0.1", | ||||
|                 "js-yaml": "^4.1.0" | ||||
|  | @ -3152,9 +3153,19 @@ | |||
|             "version": "0.4.0", | ||||
|             "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", | ||||
|             "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", | ||||
|             "dev": true, | ||||
|             "license": "MIT" | ||||
|         }, | ||||
|         "node_modules/axios": { | ||||
|             "version": "1.8.1", | ||||
|             "resolved": "https://registry.npmjs.org/axios/-/axios-1.8.1.tgz", | ||||
|             "integrity": "sha512-NN+fvwH/kV01dYUQ3PTOZns4LWtWhOFCAhQ/pHb88WQ1hNe5V/dvFwc4VJcDL11LT9xSX0QtsR8sWUuyOuOq7g==", | ||||
|             "license": "MIT", | ||||
|             "dependencies": { | ||||
|                 "follow-redirects": "^1.15.6", | ||||
|                 "form-data": "^4.0.0", | ||||
|                 "proxy-from-env": "^1.1.0" | ||||
|             } | ||||
|         }, | ||||
|         "node_modules/balanced-match": { | ||||
|             "version": "1.0.2", | ||||
|             "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", | ||||
|  | @ -3520,7 +3531,6 @@ | |||
|             "version": "1.0.8", | ||||
|             "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", | ||||
|             "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", | ||||
|             "dev": true, | ||||
|             "license": "MIT", | ||||
|             "dependencies": { | ||||
|                 "delayed-stream": "~1.0.0" | ||||
|  | @ -3788,7 +3798,6 @@ | |||
|             "version": "1.0.0", | ||||
|             "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", | ||||
|             "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", | ||||
|             "dev": true, | ||||
|             "license": "MIT", | ||||
|             "engines": { | ||||
|                 "node": ">=0.4.0" | ||||
|  | @ -4003,7 +4012,6 @@ | |||
|             "version": "2.1.0", | ||||
|             "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", | ||||
|             "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", | ||||
|             "dev": true, | ||||
|             "license": "MIT", | ||||
|             "dependencies": { | ||||
|                 "es-errors": "^1.3.0", | ||||
|  | @ -4745,6 +4753,26 @@ | |||
|             "dev": true, | ||||
|             "license": "ISC" | ||||
|         }, | ||||
|         "node_modules/follow-redirects": { | ||||
|             "version": "1.15.9", | ||||
|             "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", | ||||
|             "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", | ||||
|             "funding": [ | ||||
|                 { | ||||
|                     "type": "individual", | ||||
|                     "url": "https://github.com/sponsors/RubenVerborgh" | ||||
|                 } | ||||
|             ], | ||||
|             "license": "MIT", | ||||
|             "engines": { | ||||
|                 "node": ">=4.0" | ||||
|             }, | ||||
|             "peerDependenciesMeta": { | ||||
|                 "debug": { | ||||
|                     "optional": true | ||||
|                 } | ||||
|             } | ||||
|         }, | ||||
|         "node_modules/foreground-child": { | ||||
|             "version": "3.3.0", | ||||
|             "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", | ||||
|  | @ -4766,7 +4794,6 @@ | |||
|             "version": "4.0.2", | ||||
|             "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz", | ||||
|             "integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==", | ||||
|             "dev": true, | ||||
|             "license": "MIT", | ||||
|             "dependencies": { | ||||
|                 "asynckit": "^0.4.0", | ||||
|  | @ -4782,7 +4809,6 @@ | |||
|             "version": "1.52.0", | ||||
|             "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", | ||||
|             "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", | ||||
|             "dev": true, | ||||
|             "license": "MIT", | ||||
|             "engines": { | ||||
|                 "node": ">= 0.6" | ||||
|  | @ -4792,7 +4818,6 @@ | |||
|             "version": "2.1.35", | ||||
|             "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", | ||||
|             "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", | ||||
|             "dev": true, | ||||
|             "license": "MIT", | ||||
|             "dependencies": { | ||||
|                 "mime-db": "1.52.0" | ||||
|  | @ -5077,7 +5102,6 @@ | |||
|             "version": "1.0.2", | ||||
|             "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", | ||||
|             "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", | ||||
|             "dev": true, | ||||
|             "license": "MIT", | ||||
|             "dependencies": { | ||||
|                 "has-symbols": "^1.0.3" | ||||
|  | @ -6772,6 +6796,12 @@ | |||
|                 "node": ">= 0.10" | ||||
|             } | ||||
|         }, | ||||
|         "node_modules/proxy-from-env": { | ||||
|             "version": "1.1.0", | ||||
|             "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", | ||||
|             "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", | ||||
|             "license": "MIT" | ||||
|         }, | ||||
|         "node_modules/punycode": { | ||||
|             "version": "2.3.1", | ||||
|             "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", | ||||
|  |  | |||
		Reference in a new issue
	
	 Gabriellvl
						Gabriellvl