From 18ee991ce3cb6d3589d8c69f69d4acba61a98b03 Mon Sep 17 00:00:00 2001 From: Gerald Schmittinger Date: Tue, 4 Mar 2025 22:35:05 +0100 Subject: [PATCH] feat(backend): Added endpoint to fetch HTML version of learning object (from Dwengo backend) Also refactored a bit to make this easier. --- backend/src/app.ts | 4 +- backend/src/config.ts | 6 +- backend/src/controllers/learning-objects.ts | 62 +++++++++++++ backend/src/controllers/learning-paths.ts | 53 +++++++++++ backend/src/controllers/learningObjects.ts | 56 ------------ backend/src/controllers/learningPaths.ts | 59 ------------- backend/src/exceptions.ts | 21 +++++ ...learningContent.ts => learning-content.ts} | 17 +++- ...learningObjects.ts => learning-objects.ts} | 10 ++- .../{learningPaths.ts => learning-paths.ts} | 2 +- .../dwengo-api-learning-object-provider.ts | 87 +++++++++++-------- .../dwengo-api-learning-path-provider.ts | 4 +- .../learning-object-provider.ts | 17 +++- .../learning-object-service.ts | 30 +++++-- backend/src/util/apiHelper.ts | 12 ++- backend/src/util/envvars.ts | 2 + 16 files changed, 264 insertions(+), 178 deletions(-) create mode 100644 backend/src/controllers/learning-objects.ts create mode 100644 backend/src/controllers/learning-paths.ts delete mode 100644 backend/src/controllers/learningObjects.ts delete mode 100644 backend/src/controllers/learningPaths.ts create mode 100644 backend/src/exceptions.ts rename backend/src/interfaces/{learningContent.ts => learning-content.ts} (86%) rename backend/src/routes/{learningObjects.ts => learning-objects.ts} (68%) rename backend/src/routes/{learningPaths.ts => learning-paths.ts} (91%) diff --git a/backend/src/app.ts b/backend/src/app.ts index b21bb9f1..123075ea 100644 --- a/backend/src/app.ts +++ b/backend/src/app.ts @@ -3,8 +3,8 @@ import { initORM } from './orm.js'; import { EnvVars, getNumericEnvVar } from './util/envvars.js'; import themeRoutes from './routes/themes.js'; -import learningPathRoutes from './routes/learningPaths.js'; -import learningObjectRoutes from './routes/learningObjects.js'; +import learningPathRoutes from './routes/learning-paths.js'; +import learningObjectRoutes from './routes/learning-objects.js'; import studentRouter from './routes/student.js'; import groupRouter from './routes/group.js'; diff --git a/backend/src/config.ts b/backend/src/config.ts index 8fd8ec3f..2b9e67e3 100644 --- a/backend/src/config.ts +++ b/backend/src/config.ts @@ -5,6 +5,8 @@ // Load .env file // Dotenv.config(); -export const DWENGO_API_BASE = 'https://dwengo.org/backend/api'; +import {EnvVars, getEnvVar} from "./util/envvars"; -export const FALLBACK_LANG = 'nl'; +export const DWENGO_API_BASE = getEnvVar(EnvVars.LearningContentRepoApiBaseUrl); + +export const FALLBACK_LANG = getEnvVar(EnvVars.FallbackLanguage); diff --git a/backend/src/controllers/learning-objects.ts b/backend/src/controllers/learning-objects.ts new file mode 100644 index 00000000..18bf5f26 --- /dev/null +++ b/backend/src/controllers/learning-objects.ts @@ -0,0 +1,62 @@ +import { Request, Response } from 'express'; +import { FALLBACK_LANG } from '../config.js'; +import {FilteredLearningObject, LearningObjectIdentifier, LearningPathIdentifier} from '../interfaces/learning-content'; +import learningObjectService from "../services/learning-content/learning-object-service"; +import {EnvVars, getEnvVar} from "../util/envvars"; +import {Language} from "../entities/content/language"; +import {BadRequestException} from "../exceptions"; + +function getLearningObjectIdentifierFromRequest(req: Request): LearningObjectIdentifier { + if (!req.params.hruid) { + throw new BadRequestException("HRUID is required."); + } + return { + hruid: req.params.hruid as string, + language: (req.query.language || getEnvVar(EnvVars.FallbackLanguage)) as Language, + version: req.query.version as string + }; +} + +function getLearningPathIdentifierFromRequest(req: Request): LearningPathIdentifier { + if (!req.query.hruid) { + throw new BadRequestException("HRUID is required."); + } + return { + hruid: req.params.hruid as string, + language: (req.query.language as Language) || FALLBACK_LANG + } +} + +export async function getAllLearningObjects( + req: Request, + res: Response +): Promise { + const learningPathId = getLearningPathIdentifierFromRequest(req); + const full = req.query.full; + + let learningObjects: FilteredLearningObject[] | string[]; + if (full) { + learningObjects = await learningObjectService.getLearningObjectsFromPath(learningPathId); + } else { + learningObjects = await learningObjectService.getLearningObjectIdsFromPath(learningPathId); + } + + res.json(learningObjects); +} + +export async function getLearningObject( + req: Request, + res: Response +): Promise { + const learningObjectId = getLearningObjectIdentifierFromRequest(req); + + const learningObject = await learningObjectService.getLearningObjectById(learningObjectId); + res.json(learningObject); +} + +export async function getLearningObjectHTML(req: Request, res: Response): Promise { + const learningObjectId = getLearningObjectIdentifierFromRequest(req); + + const learningObject = await learningObjectService.getLearningObjectHTML(learningObjectId); + res.send(learningObject); +} diff --git a/backend/src/controllers/learning-paths.ts b/backend/src/controllers/learning-paths.ts new file mode 100644 index 00000000..593fd695 --- /dev/null +++ b/backend/src/controllers/learning-paths.ts @@ -0,0 +1,53 @@ +import { Request, Response } from 'express'; +import { themes } from '../data/themes.js'; +import { FALLBACK_LANG } from '../config.js'; +import learningPathService from "../services/learning-content/learning-path-service"; +import {NotFoundException} from "../exceptions"; + +/** + * Fetch learning paths based on query parameters. + */ +export async function getLearningPaths( + req: Request, + res: Response +): Promise { + const hruids = req.query.hruid; + const themeKey = req.query.theme as string; + const searchQuery = req.query.search as string; + const language = (req.query.language as string) || FALLBACK_LANG; + + let hruidList; + + if (hruids) { + hruidList = Array.isArray(hruids) + ? hruids.map(String) + : [String(hruids)]; + } else if (themeKey) { + const theme = themes.find((t) => { + return t.title === themeKey; + }); + if (theme) { + hruidList = theme.hruids; + } else { + throw new NotFoundException(`Theme "${themeKey}" not found.`); + } + } else if (searchQuery) { + const searchResults = await learningPathService.searchLearningPaths( + searchQuery, + language + ); + res.json(searchResults); + return; + } else { + hruidList = themes.flatMap((theme) => { + return theme.hruids; + }); + } + + const learningPaths = await learningPathService.fetchLearningPaths( + hruidList, + language, + `HRUIDs: ${hruidList.join(', ')}` + ); + res.json(learningPaths.data); +} diff --git a/backend/src/controllers/learningObjects.ts b/backend/src/controllers/learningObjects.ts deleted file mode 100644 index 2455b49c..00000000 --- a/backend/src/controllers/learningObjects.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { Request, Response } from 'express'; -import { FALLBACK_LANG } from '../config.js'; -import { FilteredLearningObject } from '../interfaces/learningContent'; -import learningObjectService from "../services/learning-content/learning-object-service"; - -export async function getAllLearningObjects( - req: Request, - res: Response -): Promise { - try { - const hruid = req.query.hruid as string; - const full = req.query.full === 'true'; - const language = (req.query.language as string) || FALLBACK_LANG; - - if (!hruid) { - res.status(400).json({ error: 'HRUID query is required.' }); - return; - } - - let learningObjects: FilteredLearningObject[] | string[]; - if (full) { - learningObjects = await learningObjectService.getLearningObjectsFromPath(hruid, language); - } else { - learningObjects = await learningObjectService.getLearningObjectIdsFromPath( - hruid, - language - ); - } - - res.json(learningObjects); - } catch (error) { - console.error('Error fetching learning objects:', error); - res.status(500).json({ error: 'Internal server error' }); - } -} - -export async function getLearningObject( - req: Request, - res: Response -): Promise { - try { - const { hruid } = req.params; - const language = (req.query.language as string) || FALLBACK_LANG; - - if (!hruid) { - res.status(400).json({ error: 'HRUID parameter is required.' }); - return; - } - - const learningObject = await learningObjectService.getLearningObjectById(hruid, language); - res.json(learningObject); - } catch (error) { - console.error('Error fetching learning object:', error); - res.status(500).json({ error: 'Internal server error' }); - } -} diff --git a/backend/src/controllers/learningPaths.ts b/backend/src/controllers/learningPaths.ts deleted file mode 100644 index af521157..00000000 --- a/backend/src/controllers/learningPaths.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { Request, Response } from 'express'; -import { themes } from '../data/themes.js'; -import { FALLBACK_LANG } from '../config.js'; -import learningPathService from "../services/learning-content/learning-path-service"; -/** - * Fetch learning paths based on query parameters. - */ -export async function getLearningPaths( - req: Request, - res: Response -): Promise { - try { - const hruids = req.query.hruid; - const themeKey = req.query.theme as string; - const searchQuery = req.query.search as string; - const language = (req.query.language as string) || FALLBACK_LANG; - - let hruidList; - - if (hruids) { - hruidList = Array.isArray(hruids) - ? hruids.map(String) - : [String(hruids)]; - } else if (themeKey) { - const theme = themes.find((t) => { - return t.title === themeKey; - }); - if (theme) { - hruidList = theme.hruids; - } else { - res.status(404).json({ - error: `Theme "${themeKey}" not found.`, - }); - return; - } - } else if (searchQuery) { - const searchResults = await learningPathService.searchLearningPaths( - searchQuery, - language - ); - res.json(searchResults); - return; - } else { - hruidList = themes.flatMap((theme) => { - return theme.hruids; - }); - } - - const learningPaths = await learningPathService.fetchLearningPaths( - hruidList, - language, - `HRUIDs: ${hruidList.join(', ')}` - ); - res.json(learningPaths.data); - } catch (error) { - console.error('❌ Unexpected error fetching learning paths:', error); - res.status(500).json({ error: 'Internal server error' }); - } -} diff --git a/backend/src/exceptions.ts b/backend/src/exceptions.ts new file mode 100644 index 00000000..993a13ba --- /dev/null +++ b/backend/src/exceptions.ts @@ -0,0 +1,21 @@ +/** + * Exception for HTTP 400 Bad Request + */ +export class BadRequestException extends Error { + public status = 400; + + constructor(error: string) { + super(error); + } +} + +/** + * Exception for HTTP 404 Not Found + */ +export class NotFoundException extends Error { + public status = 404; + + constructor(error: string) { + super(error); + } +} diff --git a/backend/src/interfaces/learningContent.ts b/backend/src/interfaces/learning-content.ts similarity index 86% rename from backend/src/interfaces/learningContent.ts rename to backend/src/interfaces/learning-content.ts index 9811543e..7fd3a55d 100644 --- a/backend/src/interfaces/learningContent.ts +++ b/backend/src/interfaces/learning-content.ts @@ -1,3 +1,5 @@ +import {Language} from "../entities/content/language"; + export interface Transition { default: boolean; _id: string; @@ -9,6 +11,12 @@ export interface Transition { }; } +export interface LearningObjectIdentifier { + hruid: string; + language: Language; + version?: string; +} + export interface LearningObjectNode { _id: string; learningobject_hruid: string; @@ -20,7 +28,7 @@ export interface LearningObjectNode { updatedAt: string; } -export interface LearningContent { +export interface LearningPath { _id: string; language: string; hruid: string; @@ -37,6 +45,11 @@ export interface LearningContent { __order: number; } +export interface LearningPathIdentifier { + hruid: string; + language: Language; +} + export interface EducationalGoal { source: string; id: string; @@ -93,6 +106,6 @@ export interface FilteredLearningObject { export interface LearningPathResponse { success: boolean; source: string; - data: LearningContent[] | null; + data: LearningPath[] | null; message?: string; } diff --git a/backend/src/routes/learningObjects.ts b/backend/src/routes/learning-objects.ts similarity index 68% rename from backend/src/routes/learningObjects.ts rename to backend/src/routes/learning-objects.ts index 416602b5..b44a6b8f 100644 --- a/backend/src/routes/learningObjects.ts +++ b/backend/src/routes/learning-objects.ts @@ -1,8 +1,8 @@ import express from 'express'; import { getAllLearningObjects, - getLearningObject, -} from '../controllers/learningObjects.js'; + getLearningObject, getLearningObjectHTML, +} from '../controllers/learning-objects.js'; const router = express.Router(); @@ -24,4 +24,10 @@ router.get('/', getAllLearningObjects); // Example: http://localhost:3000/learningObject/un_ai7 router.get('/:hruid', getLearningObject); +// Parameter: hruid of learning object +// Query: language, version (optional) +// Route to fetch the HTML rendering of one learning object based on its hruid. +// Example: http://localhost:3000/learningObject/un_ai7/html +router.get('/:hruid/html', getLearningObjectHTML); + export default router; diff --git a/backend/src/routes/learningPaths.ts b/backend/src/routes/learning-paths.ts similarity index 91% rename from backend/src/routes/learningPaths.ts rename to backend/src/routes/learning-paths.ts index ce580745..efe17312 100644 --- a/backend/src/routes/learningPaths.ts +++ b/backend/src/routes/learning-paths.ts @@ -1,5 +1,5 @@ import express from 'express'; -import { getLearningPaths } from '../controllers/learningPaths.js'; +import { getLearningPaths } from '../controllers/learning-paths.js'; const router = express.Router(); diff --git a/backend/src/services/learning-content/dwengo-api/dwengo-api-learning-object-provider.ts b/backend/src/services/learning-content/dwengo-api/dwengo-api-learning-object-provider.ts index c5e52695..981e073b 100644 --- a/backend/src/services/learning-content/dwengo-api/dwengo-api-learning-object-provider.ts +++ b/backend/src/services/learning-content/dwengo-api/dwengo-api-learning-object-provider.ts @@ -1,11 +1,11 @@ import { DWENGO_API_BASE } from '../../../config.js'; import { fetchWithLogging } from '../../../util/apiHelper.js'; import { - FilteredLearningObject, + FilteredLearningObject, LearningObjectIdentifier, LearningObjectMetadata, - LearningObjectNode, + LearningObjectNode, LearningPathIdentifier, LearningPathResponse, -} from '../../../interfaces/learningContent.js'; +} from '../../../interfaces/learning-content.js'; import dwengoApiLearningPathProvider from './dwengo-api-learning-path-provider.js'; import {LearningObjectProvider} from "../learning-object-provider"; @@ -13,11 +13,9 @@ import {LearningObjectProvider} from "../learning-object-provider"; * Helper function to convert the learning object metadata retrieved from the API to a FilteredLearningObject which * our API should return. * @param data - * @param htmlUrl */ function filterData( - data: LearningObjectMetadata, - htmlUrl: string + data: LearningObjectMetadata ): FilteredLearningObject { return { key: data.hruid, // Hruid learningObject (not path) @@ -25,7 +23,7 @@ function filterData( uuid: data.uuid, version: data.version, title: data.title, - htmlUrl, // Url to fetch html content + htmlUrl: `/learningObject/${data.hruid}/html?language=${data.language}&version=${data.version}`, // Url to fetch html content language: data.language, difficulty: data.difficulty, estimatedTime: data.estimated_time, @@ -43,19 +41,18 @@ function filterData( } /** - * Generic helper function to fetch learning objects (full data or just HRUIDs) + * Generic helper function to fetch all learning objects from a given path (full data or just HRUIDs) */ async function fetchLearningObjects( - hruid: string, - full: boolean, - language: string + learningPathId: LearningPathIdentifier, + full: boolean ): Promise { try { const learningPathResponse: LearningPathResponse = await dwengoApiLearningPathProvider.fetchLearningPaths( - [hruid], - language, - `Learning path for HRUID "${hruid}"` + [learningPathId.hruid], + learningPathId.language, + `Learning path for HRUID "${learningPathId.hruid}"` ); if ( @@ -63,7 +60,7 @@ async function fetchLearningObjects( !learningPathResponse.data?.length ) { console.error( - `⚠️ WARNING: Learning path "${hruid}" exists but contains no learning objects.` + `⚠️ WARNING: Learning path "${learningPathId.hruid}" exists but contains no learning objects.` ); return []; } @@ -78,10 +75,10 @@ async function fetchLearningObjects( return await Promise.all( nodes.map(async (node) => { - return dwengoApiLearningObjectProvider.getLearningObjectById( - node.learningobject_hruid, - language - ); + return dwengoApiLearningObjectProvider.getLearningObjectById({ + hruid: node.learningobject_hruid, + language: learningPathId.language + }); }) ).then((objects) => { return objects.filter((obj): obj is FilteredLearningObject => { @@ -99,46 +96,62 @@ const dwengoApiLearningObjectProvider: LearningObjectProvider = { * Fetches a single learning object by its HRUID */ async getLearningObjectById( - hruid: string, - language: string + id: LearningObjectIdentifier ): Promise { - const metadataUrl = `${DWENGO_API_BASE}/learningObject/getMetadata?hruid=${hruid}&language=${language}`; + let metadataUrl = `${DWENGO_API_BASE}/learningObject/getMetadata`; const metadata = await fetchWithLogging( metadataUrl, - `Metadata for Learning Object HRUID "${hruid}" (language ${language})` + `Metadata for Learning Object HRUID "${id.hruid}" (language ${id.language})`, + { + params: id + } ); if (!metadata) { - console.error(`⚠️ WARNING: Learning object "${hruid}" not found.`); + console.error(`⚠️ WARNING: Learning object "${id.hruid}" not found.`); return null; } - const htmlUrl = `${DWENGO_API_BASE}/learningObject/getRaw?hruid=${hruid}&language=${language}`; - return filterData(metadata, htmlUrl); + return filterData(metadata); }, /** * Fetch full learning object data (metadata) */ - async getLearningObjectsFromPath( - hruid: string, - language: string - ): Promise { + async getLearningObjectsFromPath(id: LearningPathIdentifier): Promise { return (await fetchLearningObjects( - hruid, + id, true, - language )) as FilteredLearningObject[]; }, /** * Fetch only learning object HRUIDs */ - async getLearningObjectIdsFromPath( - hruid: string, - language: string - ): Promise { - return (await fetchLearningObjects(hruid, false, language)) as string[]; + async getLearningObjectIdsFromPath(id: LearningPathIdentifier): Promise { + return (await fetchLearningObjects(id, false)) as string[]; + }, + + /** + * Obtain a HTML-rendering of the learning object with the given identifier (as a string). For learning objects + * from the Dwengo API, this means passing through the HTML rendering from there. + */ + async getLearningObjectHTML(id: LearningObjectIdentifier): Promise { + const htmlUrl = `${DWENGO_API_BASE}/learningObject/getRaw`; + const html = await fetchWithLogging( + htmlUrl, + `Metadata for Learning Object HRUID "${id.hruid}" (language ${id.language})`, + { + params: id + } + ); + + if (!html) { + console.error(`⚠️ WARNING: Learning object "${id.hruid}" not found.`); + return null; + } + + return html; } }; diff --git a/backend/src/services/learning-content/dwengo-api/dwengo-api-learning-path-provider.ts b/backend/src/services/learning-content/dwengo-api/dwengo-api-learning-path-provider.ts index f7b4ff7d..5811398c 100644 --- a/backend/src/services/learning-content/dwengo-api/dwengo-api-learning-path-provider.ts +++ b/backend/src/services/learning-content/dwengo-api/dwengo-api-learning-path-provider.ts @@ -27,7 +27,7 @@ const dwengoApiLearningPathProvider: LearningPathProvider = { const learningPaths = await fetchWithLogging( apiUrl, `Learning paths for ${source}`, - params + { params } ); if (!learningPaths || learningPaths.length === 0) { @@ -56,7 +56,7 @@ const dwengoApiLearningPathProvider: LearningPathProvider = { const searchResults = await fetchWithLogging( apiUrl, `Search learning paths with query "${query}"`, - params + { params } ); return searchResults ?? []; } diff --git a/backend/src/services/learning-content/learning-object-provider.ts b/backend/src/services/learning-content/learning-object-provider.ts index e37c4442..70190a1a 100644 --- a/backend/src/services/learning-content/learning-object-provider.ts +++ b/backend/src/services/learning-content/learning-object-provider.ts @@ -1,18 +1,27 @@ -import {FilteredLearningObject} from "../../interfaces/learningContent"; +import { + FilteredLearningObject, + LearningObjectIdentifier, + LearningPathIdentifier +} from "../../interfaces/learning-content"; export interface LearningObjectProvider { /** * Fetches a single learning object by its HRUID */ - getLearningObjectById(hruid: string, language: string): Promise; + getLearningObjectById(id: LearningObjectIdentifier): Promise; /** * Fetch full learning object data (metadata) */ - getLearningObjectsFromPath(hruid: string, language: string): Promise; + getLearningObjectsFromPath(id: LearningPathIdentifier): Promise; /** * Fetch only learning object HRUIDs */ - getLearningObjectIdsFromPath(hruid: string, language: string): Promise; + getLearningObjectIdsFromPath(id: LearningPathIdentifier): Promise; + + /** + * Obtain a HTML-rendering of the learning object with the given identifier (as a string). + */ + getLearningObjectHTML(id: LearningObjectIdentifier): Promise; } diff --git a/backend/src/services/learning-content/learning-object-service.ts b/backend/src/services/learning-content/learning-object-service.ts index e0beec60..4daedb79 100644 --- a/backend/src/services/learning-content/learning-object-service.ts +++ b/backend/src/services/learning-content/learning-object-service.ts @@ -1,5 +1,14 @@ -import {FilteredLearningObject} from "../../interfaces/learningContent"; +import { + FilteredLearningObject, + LearningObjectIdentifier, + LearningPathIdentifier +} from "../../interfaces/learning-content"; import dwengoApiLearningObjectProvider from "./dwengo-api/dwengo-api-learning-object-provider"; +import {LearningObjectProvider} from "./learning-object-provider"; + +function getProvider(id: LearningObjectIdentifier): LearningObjectProvider { + return dwengoApiLearningObjectProvider +} /** * Service providing access to data about learning objects from the appropriate data source (database or Dwengo-api) @@ -8,22 +17,29 @@ const learningObjectService = { /** * Fetches a single learning object by its HRUID */ - getLearningObjectById(hruid: string, language: string): Promise { - return dwengoApiLearningObjectProvider.getLearningObjectById(hruid, language); + getLearningObjectById(id: LearningObjectIdentifier): Promise { + return getProvider(id).getLearningObjectById(id); }, /** * Fetch full learning object data (metadata) */ - getLearningObjectsFromPath(hruid: string, language: string): Promise { - return dwengoApiLearningObjectProvider.getLearningObjectsFromPath(hruid, language); + getLearningObjectsFromPath(id: LearningPathIdentifier): Promise { + return getProvider(id).getLearningObjectsFromPath(id); }, /** * Fetch only learning object HRUIDs */ - getLearningObjectIdsFromPath(hruid: string, language: string): Promise { - return dwengoApiLearningObjectProvider.getLearningObjectIdsFromPath(hruid, language); + getLearningObjectIdsFromPath(id: LearningPathIdentifier): Promise { + return getProvider(id).getLearningObjectIdsFromPath(id); + }, + + /** + * Obtain a HTML-rendering of the learning object with the given identifier (as a string). + */ + getLearningObjectHTML(id: LearningObjectIdentifier): Promise { + return getProvider(id).getLearningObjectHTML(id); } }; diff --git a/backend/src/util/apiHelper.ts b/backend/src/util/apiHelper.ts index 76d166c8..8733a7a4 100644 --- a/backend/src/util/apiHelper.ts +++ b/backend/src/util/apiHelper.ts @@ -8,17 +8,21 @@ import axios, { AxiosRequestConfig } from 'axios'; * * @param url The API endpoint to fetch from. * @param description A short description of what is being fetched (for logging). - * @param params + * @param options Contains further options such as params (the query params) and responseType (whether the response + * should be parsed as JSON ("json") or whether it should be returned as plain text ("text") * @returns The response data if successful, or null if an error occurs. */ export async function fetchWithLogging( url: string, description: string, - params?: Record + options?: { + params?: Record, + query?: Record, + responseType?: "json" | "text", + } ): Promise { try { - const config: AxiosRequestConfig = params ? { params } : {}; - + const config: AxiosRequestConfig = options || {}; const response = await axios.get(url, config); return response.data; } catch (error: any) { diff --git a/backend/src/util/envvars.ts b/backend/src/util/envvars.ts index 5a06ac22..8cb82487 100644 --- a/backend/src/util/envvars.ts +++ b/backend/src/util/envvars.ts @@ -11,6 +11,8 @@ export const EnvVars: { [key: string]: EnvVar } = { DbUsername: { key: DB_PREFIX + 'USERNAME', required: true }, DbPassword: { key: DB_PREFIX + 'PASSWORD', required: true }, DbUpdate: { key: DB_PREFIX + 'UPDATE', defaultValue: false }, + LearningContentRepoApiBaseUrl: { key: PREFIX + "LEARNING_CONTENT_REPO_API_BASE_URL", defaultValue: "https://dwengo.org/backend/api"}, + FallbackLanguage: { key: PREFIX + "FALLBACK_LANGUAGE", defaultValue: "nl" }, } as const; /**