diff --git a/backend/src/controllers/learningObjects.ts b/backend/src/controllers/learningObjects.ts index 4295326a..e0a7cd4a 100644 --- a/backend/src/controllers/learningObjects.ts +++ b/backend/src/controllers/learningObjects.ts @@ -3,9 +3,9 @@ import { getLearningObjectById, getLearningObjectIdsFromPath, getLearningObjectsFromPath, -} from '../services/learningObjects.js'; +} from '../services/learning-content/dwengo-api/dwengo-api-learning-object-provider.js'; import { FALLBACK_LANG } from '../config.js'; -import { FilteredLearningObject } from '../interfaces/learningPath'; +import { FilteredLearningObject } from '../interfaces/learningContent'; export async function getAllLearningObjects( req: Request, diff --git a/backend/src/controllers/learningPaths.ts b/backend/src/controllers/learningPaths.ts index 903451be..f05532d4 100644 --- a/backend/src/controllers/learningPaths.ts +++ b/backend/src/controllers/learningPaths.ts @@ -4,7 +4,7 @@ import { FALLBACK_LANG } from '../config.js'; import { fetchLearningPaths, searchLearningPaths, -} from '../services/learningPaths.js'; +} from '../services/learning-content/dwengo-api/dwengo-api-learning-path-provider.js'; /** * Fetch learning paths based on query parameters. */ diff --git a/backend/src/interfaces/learningPath.ts b/backend/src/interfaces/learningContent.ts similarity index 96% rename from backend/src/interfaces/learningPath.ts rename to backend/src/interfaces/learningContent.ts index 1e2cc6ef..9811543e 100644 --- a/backend/src/interfaces/learningPath.ts +++ b/backend/src/interfaces/learningContent.ts @@ -20,7 +20,7 @@ export interface LearningObjectNode { updatedAt: string; } -export interface LearningPath { +export interface LearningContent { _id: string; language: string; hruid: string; @@ -93,6 +93,6 @@ export interface FilteredLearningObject { export interface LearningPathResponse { success: boolean; source: string; - data: LearningPath[] | null; + data: LearningContent[] | null; message?: string; } diff --git a/backend/src/services/learningObjects.ts b/backend/src/services/learning-content/dwengo-api/dwengo-api-learning-object-provider.ts similarity index 52% rename from backend/src/services/learningObjects.ts rename to backend/src/services/learning-content/dwengo-api/dwengo-api-learning-object-provider.ts index d1d34ad2..c5e52695 100644 --- a/backend/src/services/learningObjects.ts +++ b/backend/src/services/learning-content/dwengo-api/dwengo-api-learning-object-provider.ts @@ -1,13 +1,20 @@ -import { DWENGO_API_BASE } from '../config.js'; -import { fetchWithLogging } from '../util/apiHelper.js'; +import { DWENGO_API_BASE } from '../../../config.js'; +import { fetchWithLogging } from '../../../util/apiHelper.js'; import { FilteredLearningObject, LearningObjectMetadata, LearningObjectNode, LearningPathResponse, -} from '../interfaces/learningPath.js'; -import { fetchLearningPaths } from './learningPaths.js'; +} from '../../../interfaces/learningContent.js'; +import dwengoApiLearningPathProvider from './dwengo-api-learning-path-provider.js'; +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 @@ -36,29 +43,7 @@ function filterData( } /** - * Fetches a single learning object by its HRUID - */ -export async function getLearningObjectById( - hruid: string, - language: string -): Promise { - const metadataUrl = `${DWENGO_API_BASE}/learningObject/getMetadata?hruid=${hruid}&language=${language}`; - const metadata = await fetchWithLogging( - metadataUrl, - `Metadata for Learning Object HRUID "${hruid}" (language ${language})` - ); - - if (!metadata) { - console.error(`⚠️ WARNING: Learning object "${hruid}" not found.`); - return null; - } - - const htmlUrl = `${DWENGO_API_BASE}/learningObject/getRaw?hruid=${hruid}&language=${language}`; - return filterData(metadata, htmlUrl); -} - -/** - * Generic function to fetch learning objects (full data or just HRUIDs) + * Generic helper function to fetch learning objects (full data or just HRUIDs) */ async function fetchLearningObjects( hruid: string, @@ -67,7 +52,7 @@ async function fetchLearningObjects( ): Promise { try { const learningPathResponse: LearningPathResponse = - await fetchLearningPaths( + await dwengoApiLearningPathProvider.fetchLearningPaths( [hruid], language, `Learning path for HRUID "${hruid}"` @@ -93,7 +78,7 @@ async function fetchLearningObjects( return await Promise.all( nodes.map(async (node) => { - return getLearningObjectById( + return dwengoApiLearningObjectProvider.getLearningObjectById( node.learningobject_hruid, language ); @@ -109,26 +94,52 @@ async function fetchLearningObjects( } } -/** - * Fetch full learning object data (metadata) - */ -export async function getLearningObjectsFromPath( - hruid: string, - language: string -): Promise { - return (await fetchLearningObjects( - hruid, - true, - language - )) as FilteredLearningObject[]; -} +const dwengoApiLearningObjectProvider: LearningObjectProvider = { + /** + * Fetches a single learning object by its HRUID + */ + async getLearningObjectById( + hruid: string, + language: string + ): Promise { + const metadataUrl = `${DWENGO_API_BASE}/learningObject/getMetadata?hruid=${hruid}&language=${language}`; + const metadata = await fetchWithLogging( + metadataUrl, + `Metadata for Learning Object HRUID "${hruid}" (language ${language})` + ); -/** - * Fetch only learning object HRUIDs - */ -export async function getLearningObjectIdsFromPath( - hruid: string, - language: string -): Promise { - return (await fetchLearningObjects(hruid, false, language)) as string[]; -} + if (!metadata) { + console.error(`⚠️ WARNING: Learning object "${hruid}" not found.`); + return null; + } + + const htmlUrl = `${DWENGO_API_BASE}/learningObject/getRaw?hruid=${hruid}&language=${language}`; + return filterData(metadata, htmlUrl); + }, + + /** + * Fetch full learning object data (metadata) + */ + async getLearningObjectsFromPath( + hruid: string, + language: string + ): Promise { + return (await fetchLearningObjects( + hruid, + true, + language + )) as FilteredLearningObject[]; + }, + + /** + * Fetch only learning object HRUIDs + */ + async getLearningObjectIdsFromPath( + hruid: string, + language: string + ): Promise { + return (await fetchLearningObjects(hruid, false, language)) as string[]; + } +}; + +export default dwengoApiLearningObjectProvider; 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 new file mode 100644 index 00000000..23662646 --- /dev/null +++ b/backend/src/services/learning-content/dwengo-api/dwengo-api-learning-path-provider.ts @@ -0,0 +1,65 @@ +import { fetchWithLogging } from '../../../util/apiHelper.js'; +import { DWENGO_API_BASE } from '../../../config.js'; +import { + LearningContent, + LearningPathResponse, +} from '../../../interfaces/learningContent.js'; +import {LearningPathProvider} from "../learning-path-provider"; + +const dwengoApiLearningPathProvider: LearningPathProvider = { + async fetchLearningPaths( + hruids: string[], + language: string, + source: string + ): Promise { + if (hruids.length === 0) { + return { + success: false, + source, + data: null, + message: `No HRUIDs provided for ${source}.`, + }; + } + + const apiUrl = `${DWENGO_API_BASE}/learningPath/getPathsFromIdList`; + const params = { pathIdList: JSON.stringify({ hruids }), language }; + + const learningPaths = await fetchWithLogging( + apiUrl, + `Learning paths for ${source}`, + params + ); + + if (!learningPaths || learningPaths.length === 0) { + console.error(`⚠️ WARNING: No learning paths found for ${source}.`); + return { + success: false, + source, + data: [], + message: `No learning paths found for ${source}.`, + }; + } + + return { + success: true, + source, + data: learningPaths, + }; + }, + async searchLearningPaths( + query: string, + language: string + ): Promise { + const apiUrl = `${DWENGO_API_BASE}/learningPath/search`; + const params = { all: query, language }; + + const searchResults = await fetchWithLogging( + apiUrl, + `Search learning paths with query "${query}"`, + params + ); + return searchResults ?? []; + } +}; + +export default dwengoApiLearningPathProvider; diff --git a/backend/src/services/learning-content/learning-object-provider.ts b/backend/src/services/learning-content/learning-object-provider.ts new file mode 100644 index 00000000..e37c4442 --- /dev/null +++ b/backend/src/services/learning-content/learning-object-provider.ts @@ -0,0 +1,18 @@ +import {FilteredLearningObject} from "../../interfaces/learningContent"; + +export interface LearningObjectProvider { + /** + * Fetches a single learning object by its HRUID + */ + getLearningObjectById(hruid: string, language: string): Promise; + + /** + * Fetch full learning object data (metadata) + */ + getLearningObjectsFromPath(hruid: string, language: string): Promise; + + /** + * Fetch only learning object HRUIDs + */ + getLearningObjectIdsFromPath(hruid: string, language: string): Promise; +} diff --git a/backend/src/services/learning-content/learning-object-service.ts b/backend/src/services/learning-content/learning-object-service.ts new file mode 100644 index 00000000..e0beec60 --- /dev/null +++ b/backend/src/services/learning-content/learning-object-service.ts @@ -0,0 +1,30 @@ +import {FilteredLearningObject} from "../../interfaces/learningContent"; +import dwengoApiLearningObjectProvider from "./dwengo-api/dwengo-api-learning-object-provider"; + +/** + * Service providing access to data about learning objects from the appropriate data source (database or Dwengo-api) + */ +const learningObjectService = { + /** + * Fetches a single learning object by its HRUID + */ + getLearningObjectById(hruid: string, language: string): Promise { + return dwengoApiLearningObjectProvider.getLearningObjectById(hruid, language); + }, + + /** + * Fetch full learning object data (metadata) + */ + getLearningObjectsFromPath(hruid: string, language: string): Promise { + return dwengoApiLearningObjectProvider.getLearningObjectsFromPath(hruid, language); + }, + + /** + * Fetch only learning object HRUIDs + */ + getLearningObjectIdsFromPath(hruid: string, language: string): Promise { + return dwengoApiLearningObjectProvider.getLearningObjectIdsFromPath(hruid, language); + } +}; + +export default learningObjectService; diff --git a/backend/src/services/learning-content/learning-path-provider.ts b/backend/src/services/learning-content/learning-path-provider.ts new file mode 100644 index 00000000..f236cd82 --- /dev/null +++ b/backend/src/services/learning-content/learning-path-provider.ts @@ -0,0 +1,16 @@ +import {LearningContent, LearningPathResponse} from "../../interfaces/learningContent"; + +/** + * Generic interface for a service which provides access to learning paths from a data source. + */ +export interface LearningPathProvider { + /** + * Fetch the learning paths with the given hruids from the data source. + */ + fetchLearningPaths(hruids: string[], language: string, source: string): Promise; + + /** + * Search learning paths in the data source using the given search string. + */ + searchLearningPaths(query: string, language: string): Promise; +} diff --git a/backend/src/services/learning-content/learning-path-service.ts b/backend/src/services/learning-content/learning-path-service.ts new file mode 100644 index 00000000..31e10558 --- /dev/null +++ b/backend/src/services/learning-content/learning-path-service.ts @@ -0,0 +1,23 @@ +import {LearningContent, LearningPathResponse} from "../../interfaces/learningContent"; +import dwengoApiLearningPathProvider from "./dwengo-api/dwengo-api-learning-path-provider"; + +/** + * Service providing access to data about learning paths from the appropriate data source (database or Dwengo-api) + */ +const learningPathService = { + /** + * Fetch the learning paths with the given hruids from the data source. + */ + fetchLearningPaths(hruids: string[], language: string, source: string): Promise { + return dwengoApiLearningPathProvider.fetchLearningPaths(hruids, language, source); + }, + + /** + * Search learning paths in the data source using the given search string. + */ + searchLearningPaths(query: string, language: string): Promise { + return dwengoApiLearningPathProvider.searchLearningPaths(query, language); + } +} + +export default learningPathService; diff --git a/backend/src/services/learningPaths.ts b/backend/src/services/learningPaths.ts deleted file mode 100644 index 2a9f15a3..00000000 --- a/backend/src/services/learningPaths.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { fetchWithLogging } from '../util/apiHelper.js'; -import { DWENGO_API_BASE } from '../config.js'; -import { - LearningPath, - LearningPathResponse, -} from '../interfaces/learningPath.js'; - -export async function fetchLearningPaths( - hruids: string[], - language: string, - source: string -): Promise { - if (hruids.length === 0) { - return { - success: false, - source, - data: null, - message: `No HRUIDs provided for ${source}.`, - }; - } - - const apiUrl = `${DWENGO_API_BASE}/learningPath/getPathsFromIdList`; - const params = { pathIdList: JSON.stringify({ hruids }), language }; - - const learningPaths = await fetchWithLogging( - apiUrl, - `Learning paths for ${source}`, - params - ); - - if (!learningPaths || learningPaths.length === 0) { - console.error(`⚠️ WARNING: No learning paths found for ${source}.`); - return { - success: false, - source, - data: [], - message: `No learning paths found for ${source}.`, - }; - } - - return { - success: true, - source, - data: learningPaths, - }; -} - -export async function searchLearningPaths( - query: string, - language: string -): Promise { - const apiUrl = `${DWENGO_API_BASE}/learningPath/search`; - const params = { all: query, language }; - - const searchResults = await fetchWithLogging( - apiUrl, - `Search learning paths with query "${query}"`, - params - ); - return searchResults ?? []; -}