fix: format
This commit is contained in:
		
							parent
							
								
									5da0720a08
								
							
						
					
					
						commit
						887787de05
					
				
					 8 changed files with 107 additions and 41 deletions
				
			
		|  | @ -7,4 +7,4 @@ | ||||||
| 
 | 
 | ||||||
| export const DWENGO_API_BASE = 'https://dwengo.org/backend/api'; | export const DWENGO_API_BASE = 'https://dwengo.org/backend/api'; | ||||||
| 
 | 
 | ||||||
| export const FALLBACK_LANG = "nl"; | export const FALLBACK_LANG = 'nl'; | ||||||
|  |  | ||||||
|  | @ -1,6 +1,6 @@ | ||||||
| import { Request, Response } from 'express'; | import { Request, Response } from 'express'; | ||||||
| import { getLearningObjectsFromPath } from '../services/learningObjects.js'; | import { getLearningObjectsFromPath } from '../services/learningObjects.js'; | ||||||
| import {FALLBACK_LANG} from "../config"; | import { FALLBACK_LANG } from '../config'; | ||||||
| 
 | 
 | ||||||
| export async function getAllLearningObjects( | export async function getAllLearningObjects( | ||||||
|     req: Request, |     req: Request, | ||||||
|  |  | ||||||
|  | @ -1,16 +1,19 @@ | ||||||
| import { Request, Response } from 'express'; | import { Request, Response } from 'express'; | ||||||
| import { themes } from '../data/themes.js'; | import { themes } from '../data/themes.js'; | ||||||
| import {DWENGO_API_BASE, FALLBACK_LANG} from '../config.js'; | import { DWENGO_API_BASE, FALLBACK_LANG } from '../config.js'; | ||||||
| import { fetchWithLogging } from "../util/apiHelper.js"; | import { fetchWithLogging } from '../util/apiHelper.js'; | ||||||
| import { fetchLearningPaths } from "../services/learningPaths.js"; | import { fetchLearningPaths } from '../services/learningPaths.js'; | ||||||
| import {LearningPath} from "../interfaces/learningPath"; | import { LearningPath } from '../interfaces/learningPath'; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * Fetch learning paths based on HRUIDs or return all if no HRUIDs are provided. |  * Fetch learning paths based on HRUIDs or return all if no HRUIDs are provided. | ||||||
|  * - If `hruids` are given -> fetch specific learning paths. |  * - If `hruids` are given -> fetch specific learning paths. | ||||||
|  * - If `hruids` is missing -> return all available learning paths. |  * - If `hruids` is missing -> return all available learning paths. | ||||||
|  */ |  */ | ||||||
| export async function getLearningPaths(req: Request, res: Response): Promise<void> { | export async function getLearningPaths( | ||||||
|  |     req: Request, | ||||||
|  |     res: Response | ||||||
|  | ): Promise<void> { | ||||||
|     try { |     try { | ||||||
|         const hruids = req.query.hruids; // Can be string or array
 |         const hruids = req.query.hruids; // Can be string or array
 | ||||||
|         const language = (req.query.language as string) || FALLBACK_LANG; |         const language = (req.query.language as string) || FALLBACK_LANG; | ||||||
|  | @ -18,13 +21,21 @@ export async function getLearningPaths(req: Request, res: Response): Promise<voi | ||||||
|         let hruidList: string[]; |         let hruidList: string[]; | ||||||
| 
 | 
 | ||||||
|         if (hruids) { |         if (hruids) { | ||||||
|             hruidList = Array.isArray(hruids) ? hruids.map(String) : [String(hruids)]; |             hruidList = Array.isArray(hruids) | ||||||
|  |                 ? hruids.map(String) | ||||||
|  |                 : [String(hruids)]; | ||||||
|         } else { |         } else { | ||||||
|             // If no hruids are provided, fetch ALL learning paths
 |             // If no hruids are provided, fetch ALL learning paths
 | ||||||
|             hruidList = themes.flatMap((theme) => {return theme.hruids}); |             hruidList = themes.flatMap((theme) => { | ||||||
|  |                 return theme.hruids; | ||||||
|  |             }); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         const learningPaths = await fetchLearningPaths(hruidList, language, `HRUIDs: ${hruidList.join(', ')}`); |         const learningPaths = await fetchLearningPaths( | ||||||
|  |             hruidList, | ||||||
|  |             language, | ||||||
|  |             `HRUIDs: ${hruidList.join(', ')}` | ||||||
|  |         ); | ||||||
| 
 | 
 | ||||||
|         res.json(learningPaths); |         res.json(learningPaths); | ||||||
|     } catch (error) { |     } catch (error) { | ||||||
|  | @ -33,37 +44,51 @@ export async function getLearningPaths(req: Request, res: Response): Promise<voi | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| /** | /** | ||||||
|  * Fetch all learning paths for a specific theme. |  * Fetch all learning paths for a specific theme. | ||||||
|  */ |  */ | ||||||
| export async function getLearningPathsByTheme(req: Request, res: Response): Promise<void> { | export async function getLearningPathsByTheme( | ||||||
|  |     req: Request, | ||||||
|  |     res: Response | ||||||
|  | ): Promise<void> { | ||||||
|     try { |     try { | ||||||
|         const themeKey = req.params.theme; |         const themeKey = req.params.theme; | ||||||
|         const language = (req.query.language as string) || FALLBACK_LANG; |         const language = (req.query.language as string) || FALLBACK_LANG; | ||||||
| 
 | 
 | ||||||
|         const theme = themes.find((t) => {return t.title === themeKey}); |         const theme = themes.find((t) => { | ||||||
|  |             return t.title === themeKey; | ||||||
|  |         }); | ||||||
|         if (!theme) { |         if (!theme) { | ||||||
|             console.error(`⚠️ WARNING: Theme "${themeKey}" not found.`); |             console.error(`⚠️ WARNING: Theme "${themeKey}" not found.`); | ||||||
|             res.status(404).json({ error: 'Theme not found' }); |             res.status(404).json({ error: 'Theme not found' }); | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         const response = await fetchLearningPaths(theme.hruids, language, `theme "${themeKey}"`); |         const response = await fetchLearningPaths( | ||||||
|  |             theme.hruids, | ||||||
|  |             language, | ||||||
|  |             `theme "${themeKey}"` | ||||||
|  |         ); | ||||||
|         res.json({ |         res.json({ | ||||||
|             theme: themeKey, |             theme: themeKey, | ||||||
|             hruids: theme.hruids, |             hruids: theme.hruids, | ||||||
|             ...response, |             ...response, | ||||||
|         }); |         }); | ||||||
|     } catch (error) { |     } catch (error) { | ||||||
|         console.error('❌ Unexpected error fetching learning paths by theme:', error); |         console.error( | ||||||
|  |             '❌ Unexpected error fetching learning paths by theme:', | ||||||
|  |             error | ||||||
|  |         ); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * Search learning paths by query. |  * Search learning paths by query. | ||||||
|  */ |  */ | ||||||
| export async function searchLearningPaths(req: Request, res: Response): Promise<void> { | export async function searchLearningPaths( | ||||||
|  |     req: Request, | ||||||
|  |     res: Response | ||||||
|  | ): Promise<void> { | ||||||
|     try { |     try { | ||||||
|         const query = req.query.query as string; |         const query = req.query.query as string; | ||||||
|         const language = (req.query.language as string) || FALLBACK_LANG; |         const language = (req.query.language as string) || FALLBACK_LANG; | ||||||
|  | @ -76,7 +101,11 @@ export async function searchLearningPaths(req: Request, res: Response): Promise< | ||||||
|         const apiUrl = `${DWENGO_API_BASE}/learningPath/search`; |         const apiUrl = `${DWENGO_API_BASE}/learningPath/search`; | ||||||
|         const params = { all: query, language }; |         const params = { all: query, language }; | ||||||
| 
 | 
 | ||||||
|         const searchResults = await fetchWithLogging<LearningPath[]>(apiUrl, `Search learning paths with query "${query}"`, params); |         const searchResults = await fetchWithLogging<LearningPath[]>( | ||||||
|  |             apiUrl, | ||||||
|  |             `Search learning paths with query "${query}"`, | ||||||
|  |             params | ||||||
|  |         ); | ||||||
|         res.json(searchResults ?? []); |         res.json(searchResults ?? []); | ||||||
|     } catch (error) { |     } catch (error) { | ||||||
|         console.error('❌ Unexpected error searching learning paths:', error); |         console.error('❌ Unexpected error searching learning paths:', error); | ||||||
|  |  | ||||||
|  | @ -3,7 +3,7 @@ import path from 'path'; | ||||||
| import yaml from 'js-yaml'; | import yaml from 'js-yaml'; | ||||||
| import { Request, Response } from 'express'; | import { Request, Response } from 'express'; | ||||||
| import { themes } from '../data/themes.js'; | import { themes } from '../data/themes.js'; | ||||||
| import {FALLBACK_LANG} from "../config"; | import { FALLBACK_LANG } from '../config'; | ||||||
| 
 | 
 | ||||||
| interface Translations { | interface Translations { | ||||||
|     curricula_page: { |     curricula_page: { | ||||||
|  | @ -27,7 +27,8 @@ function loadTranslations(language: string): Translations { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export function getThemes(req: Request, res: Response) { | export function getThemes(req: Request, res: Response) { | ||||||
|     const language = (req.query.language as string)?.toLowerCase() || FALLBACK_LANG; |     const language = | ||||||
|  |         (req.query.language as string)?.toLowerCase() || FALLBACK_LANG; | ||||||
|     const translations = loadTranslations(language); |     const translations = loadTranslations(language); | ||||||
| 
 | 
 | ||||||
|     const themeList = themes.map((theme) => { |     const themeList = themes.map((theme) => { | ||||||
|  |  | ||||||
|  | @ -8,7 +8,7 @@ const router = express.Router(); | ||||||
| // Arg: hruid learningPath
 | // Arg: hruid learningPath
 | ||||||
| // Query: language
 | // Query: language
 | ||||||
| // Route to fetch list of learning objects based on hruid of learning path
 | // Route to fetch list of learning objects based on hruid of learning path
 | ||||||
| // example: http://localhost:3000/learningObject/un_artificiele_intelligentie
 | // Example: http://localhost:3000/learningObject/un_artificiele_intelligentie
 | ||||||
| router.get('/:hruid', getAllLearningObjects); | router.get('/:hruid', getAllLearningObjects); | ||||||
| 
 | 
 | ||||||
| export default router; | export default router; | ||||||
|  |  | ||||||
|  | @ -1,10 +1,16 @@ | ||||||
| import { DWENGO_API_BASE } from '../config.js'; | import { DWENGO_API_BASE } from '../config.js'; | ||||||
| import { fetchWithLogging } from "../util/apiHelper.js"; | import { fetchWithLogging } from '../util/apiHelper.js'; | ||||||
| import {FilteredLearningObject, LearningObjectMetadata, LearningObjectNode} from "../interfaces/learningPath.js"; | import { | ||||||
| import {fetchLearningPaths} from "./learningPaths.js"; |     FilteredLearningObject, | ||||||
|  |     LearningObjectMetadata, | ||||||
|  |     LearningObjectNode, | ||||||
|  | } from '../interfaces/learningPath.js'; | ||||||
|  | import { fetchLearningPaths } from './learningPaths.js'; | ||||||
| 
 | 
 | ||||||
| 
 | function filterLearningObjectMetadata( | ||||||
| function filterLearningObjectMetadata(data: LearningObjectMetadata, htmlUrl: string) : FilteredLearningObject { |     data: LearningObjectMetadata, | ||||||
|  |     htmlUrl: string | ||||||
|  | ): FilteredLearningObject { | ||||||
|     return { |     return { | ||||||
|         key: data.hruid, // Hruid learningObject (not path)
 |         key: data.hruid, // Hruid learningObject (not path)
 | ||||||
|         _id: data._id, |         _id: data._id, | ||||||
|  | @ -31,12 +37,22 @@ function filterLearningObjectMetadata(data: LearningObjectMetadata, htmlUrl: str | ||||||
| export async function getLearningObjectsFromPath( | export async function getLearningObjectsFromPath( | ||||||
|     hruid: string, |     hruid: string, | ||||||
|     language: string |     language: string | ||||||
| ):  Promise<FilteredLearningObject[]> { | ): Promise<FilteredLearningObject[]> { | ||||||
|     try { |     try { | ||||||
|         const learningPathResponse = await fetchLearningPaths([hruid], language, `Learning path for HRUID "${hruid}"`); |         const learningPathResponse = await fetchLearningPaths( | ||||||
|  |             [hruid], | ||||||
|  |             language, | ||||||
|  |             `Learning path for HRUID "${hruid}"` | ||||||
|  |         ); | ||||||
| 
 | 
 | ||||||
|         if (!learningPathResponse.success || !learningPathResponse.data || learningPathResponse.data.length === 0) { |         if ( | ||||||
|             console.error(`⚠️ WARNING: Learning path "${hruid}" exists but contains no learning objects.`); |             !learningPathResponse.success || | ||||||
|  |             !learningPathResponse.data || | ||||||
|  |             learningPathResponse.data.length === 0 | ||||||
|  |         ) { | ||||||
|  |             console.error( | ||||||
|  |                 `⚠️ WARNING: Learning path "${hruid}" exists but contains no learning objects.` | ||||||
|  |             ); | ||||||
|             return []; |             return []; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | @ -50,12 +66,18 @@ export async function getLearningObjectsFromPath( | ||||||
|                     `Metadata for Learning Object HRUID "${node.learningobject_hruid}" (version ${node.version}, language ${language})` |                     `Metadata for Learning Object HRUID "${node.learningobject_hruid}" (version ${node.version}, language ${language})` | ||||||
|                 ); |                 ); | ||||||
| 
 | 
 | ||||||
|                 if (!metadata) {return null;} |                 if (!metadata) { | ||||||
|  |                     return null; | ||||||
|  |                 } | ||||||
| 
 | 
 | ||||||
|                 const htmlUrl = `${DWENGO_API_BASE}/learningObject/getRaw?hruid=${node.learningobject_hruid}&version=${node.version}&language=${language}`; |                 const htmlUrl = `${DWENGO_API_BASE}/learningObject/getRaw?hruid=${node.learningobject_hruid}&version=${node.version}&language=${language}`; | ||||||
|                 return filterLearningObjectMetadata(metadata, htmlUrl); |                 return filterLearningObjectMetadata(metadata, htmlUrl); | ||||||
|             }) |             }) | ||||||
|         ).then((objects) => {return objects.filter((obj): obj is FilteredLearningObject => {return obj !== null})}); |         ).then((objects) => { | ||||||
|  |             return objects.filter((obj): obj is FilteredLearningObject => { | ||||||
|  |                 return obj !== null; | ||||||
|  |             }); | ||||||
|  |         }); | ||||||
|     } catch (error) { |     } catch (error) { | ||||||
|         console.error('Error fetching learning objects:', error); |         console.error('Error fetching learning objects:', error); | ||||||
|         return []; |         return []; | ||||||
|  |  | ||||||
|  | @ -1,6 +1,9 @@ | ||||||
| import { fetchWithLogging } from "../util/apiHelper.js"; | import { fetchWithLogging } from '../util/apiHelper.js'; | ||||||
| import { DWENGO_API_BASE } from "../config.js"; | import { DWENGO_API_BASE } from '../config.js'; | ||||||
| import {LearningPath, LearningPathResponse} from "../interfaces/learningPath.js"; | import { | ||||||
|  |     LearningPath, | ||||||
|  |     LearningPathResponse, | ||||||
|  | } from '../interfaces/learningPath.js'; | ||||||
| 
 | 
 | ||||||
| export async function fetchLearningPaths( | export async function fetchLearningPaths( | ||||||
|     hruids: string[], |     hruids: string[], | ||||||
|  | @ -19,7 +22,11 @@ export async function fetchLearningPaths( | ||||||
|     const apiUrl = `${DWENGO_API_BASE}/learningPath/getPathsFromIdList`; |     const apiUrl = `${DWENGO_API_BASE}/learningPath/getPathsFromIdList`; | ||||||
|     const params = { pathIdList: JSON.stringify({ hruids }), language }; |     const params = { pathIdList: JSON.stringify({ hruids }), language }; | ||||||
| 
 | 
 | ||||||
|     const learningPaths = await fetchWithLogging<LearningPath[]>(apiUrl, `Learning paths for ${source}`, params); |     const learningPaths = await fetchWithLogging<LearningPath[]>( | ||||||
|  |         apiUrl, | ||||||
|  |         `Learning paths for ${source}`, | ||||||
|  |         params | ||||||
|  |     ); | ||||||
| 
 | 
 | ||||||
|     if (!learningPaths || learningPaths.length === 0) { |     if (!learningPaths || learningPaths.length === 0) { | ||||||
|         console.error(`⚠️ WARNING: No learning paths found for ${source}.`); |         console.error(`⚠️ WARNING: No learning paths found for ${source}.`); | ||||||
|  |  | ||||||
|  | @ -1,4 +1,4 @@ | ||||||
| import axios, {AxiosRequestConfig} from 'axios'; | import axios, { AxiosRequestConfig } from 'axios'; | ||||||
| 
 | 
 | ||||||
| // !!!! when logger is done -> change
 | // !!!! when logger is done -> change
 | ||||||
| 
 | 
 | ||||||
|  | @ -14,8 +14,8 @@ import axios, {AxiosRequestConfig} from 'axios'; | ||||||
| export async function fetchWithLogging<T>( | export async function fetchWithLogging<T>( | ||||||
|     url: string, |     url: string, | ||||||
|     description: string, |     description: string, | ||||||
|     params?: Record<string,any> |     params?: Record<string, any> | ||||||
| ):  Promise<T | null> { | ): Promise<T | null> { | ||||||
|     try { |     try { | ||||||
|         const config: AxiosRequestConfig = params ? { params } : {}; |         const config: AxiosRequestConfig = params ? { params } : {}; | ||||||
| 
 | 
 | ||||||
|  | @ -24,12 +24,19 @@ export async function fetchWithLogging<T>( | ||||||
|     } catch (error: any) { |     } catch (error: any) { | ||||||
|         if (error.response) { |         if (error.response) { | ||||||
|             if (error.response.status === 404) { |             if (error.response.status === 404) { | ||||||
|                 console.error(`❌ ERROR: ${description} not found (404) at "${url}".`); |                 console.error( | ||||||
|  |                     `❌ ERROR: ${description} not found (404) at "${url}".` | ||||||
|  |                 ); | ||||||
|             } else { |             } else { | ||||||
|                 console.error(`❌ ERROR: Failed to fetch ${description}. Status: ${error.response.status} - ${error.response.statusText} (URL: "${url}")`); |                 console.error( | ||||||
|  |                     `❌ ERROR: Failed to fetch ${description}. Status: ${error.response.status} - ${error.response.statusText} (URL: "${url}")` | ||||||
|  |                 ); | ||||||
|             } |             } | ||||||
|         } else { |         } else { | ||||||
|             console.error(`❌ ERROR: Network or unexpected error when fetching ${description}:`, error.message); |             console.error( | ||||||
|  |                 `❌ ERROR: Network or unexpected error when fetching ${description}:`, | ||||||
|  |                 error.message | ||||||
|  |             ); | ||||||
|         } |         } | ||||||
|         return null; |         return null; | ||||||
|     } |     } | ||||||
|  |  | ||||||
		Reference in a new issue
	
	 Gabriellvl
						Gabriellvl