refactor(common): Learning content

This commit is contained in:
Tibo De Peuter 2025-03-31 21:55:34 +02:00
parent 70a31a292c
commit 5a90862098
Signed by: tdpeuter
GPG key ID: 38297DE43F75FFE2
19 changed files with 36 additions and 22 deletions

View file

@ -1,12 +1,12 @@
import { Request, Response } from 'express'; import { Request, Response } from 'express';
import { FALLBACK_LANG } from '../config.js'; import { FALLBACK_LANG } from '../config.js';
import { FilteredLearningObject, LearningObjectIdentifier, LearningPathIdentifier } from '../interfaces/learning-content.js';
import learningObjectService from '../services/learning-objects/learning-object-service.js'; import learningObjectService from '../services/learning-objects/learning-object-service.js';
import { EnvVars, getEnvVar } from '../util/envvars.js'; import { EnvVars, getEnvVar } from '../util/envvars.js';
import { Language } from '../entities/content/language.js'; import { Language } from '../entities/content/language.js';
import attachmentService from '../services/learning-objects/attachment-service.js'; import attachmentService from '../services/learning-objects/attachment-service.js';
import { NotFoundError } from '@mikro-orm/core'; import { NotFoundError } from '@mikro-orm/core';
import { BadRequestException } from '../exceptions/bad-request-exception.js'; import { BadRequestException } from '../exceptions/bad-request-exception.js';
import { FilteredLearningObject, LearningObjectIdentifier, LearningPathIdentifier } from 'dwengo-1-common/src/interfaces/learning-content';
function getLearningObjectIdentifierFromRequest(req: Request): LearningObjectIdentifier { function getLearningObjectIdentifierFromRequest(req: Request): LearningObjectIdentifier {
if (!req.params.hruid) { if (!req.params.hruid) {

View file

@ -1,6 +1,12 @@
import { DWENGO_API_BASE } from '../config.js'; import { DWENGO_API_BASE } from '../config.js';
import { fetchWithLogging } from '../util/api-helper.js'; import { fetchWithLogging } from '../util/api-helper.js';
import { FilteredLearningObject, LearningObjectMetadata, LearningObjectNode, LearningPathResponse } from '../interfaces/learning-content.js';
import {
FilteredLearningObject,
LearningObjectMetadata,
LearningObjectNode,
LearningPathResponse,
} from 'dwengo-1-common/src/interfaces/learning-content';
function filterData(data: LearningObjectMetadata, htmlUrl: string): FilteredLearningObject { function filterData(data: LearningObjectMetadata, htmlUrl: string): FilteredLearningObject {
return { return {

View file

@ -1,6 +1,7 @@
import { getAttachmentRepository } from '../../data/repositories.js'; import { getAttachmentRepository } from '../../data/repositories.js';
import { Attachment } from '../../entities/content/attachment.entity.js'; import { Attachment } from '../../entities/content/attachment.entity.js';
import { LearningObjectIdentifier } from '../../interfaces/learning-content.js';
import { LearningObjectIdentifier } from 'dwengo-1-common/src/interfaces/learning-content';
const attachmentService = { const attachmentService = {
getAttachment(learningObjectId: LearningObjectIdentifier, attachmentName: string): Promise<Attachment | null> { getAttachment(learningObjectId: LearningObjectIdentifier, attachmentName: string): Promise<Attachment | null> {

View file

@ -1,5 +1,4 @@
import { LearningObjectProvider } from './learning-object-provider.js'; import { LearningObjectProvider } from './learning-object-provider.js';
import { FilteredLearningObject, LearningObjectIdentifier, LearningPathIdentifier } from '../../interfaces/learning-content.js';
import { getLearningObjectRepository, getLearningPathRepository } from '../../data/repositories.js'; import { getLearningObjectRepository, getLearningPathRepository } from '../../data/repositories.js';
import { Language } from '../../entities/content/language.js'; import { Language } from '../../entities/content/language.js';
import { LearningObject } from '../../entities/content/learning-object.entity.js'; import { LearningObject } from '../../entities/content/learning-object.entity.js';
@ -8,6 +7,7 @@ import processingService from './processing/processing-service.js';
import { NotFoundError } from '@mikro-orm/core'; import { NotFoundError } from '@mikro-orm/core';
import learningObjectService from './learning-object-service.js'; import learningObjectService from './learning-object-service.js';
import { getLogger, Logger } from '../../logging/initalize.js'; import { getLogger, Logger } from '../../logging/initalize.js';
import { FilteredLearningObject, LearningObjectIdentifier, LearningPathIdentifier } from 'dwengo-1-common/src/interfaces/learning-content';
const logger: Logger = getLogger(); const logger: Logger = getLogger();

View file

@ -1,5 +1,8 @@
import { DWENGO_API_BASE } from '../../config.js'; import { DWENGO_API_BASE } from '../../config.js';
import { fetchWithLogging } from '../../util/api-helper.js'; import { fetchWithLogging } from '../../util/api-helper.js';
import dwengoApiLearningPathProvider from '../learning-paths/dwengo-api-learning-path-provider.js';
import { LearningObjectProvider } from './learning-object-provider.js';
import { getLogger, Logger } from '../../logging/initalize.js';
import { import {
FilteredLearningObject, FilteredLearningObject,
LearningObjectIdentifier, LearningObjectIdentifier,
@ -7,10 +10,7 @@ import {
LearningObjectNode, LearningObjectNode,
LearningPathIdentifier, LearningPathIdentifier,
LearningPathResponse, LearningPathResponse,
} from '../../interfaces/learning-content.js'; } from 'dwengo-1-common/src/interfaces/learning-content';
import dwengoApiLearningPathProvider from '../learning-paths/dwengo-api-learning-path-provider.js';
import { LearningObjectProvider } from './learning-object-provider.js';
import { getLogger, Logger } from '../../logging/initalize.js';
const logger: Logger = getLogger(); const logger: Logger = getLogger();

View file

@ -1,4 +1,4 @@
import { FilteredLearningObject, LearningObjectIdentifier, LearningPathIdentifier } from '../../interfaces/learning-content.js'; import { FilteredLearningObject, LearningObjectIdentifier, LearningPathIdentifier } from 'dwengo-1-common/src/interfaces/learning-content';
export interface LearningObjectProvider { export interface LearningObjectProvider {
/** /**

View file

@ -1,8 +1,8 @@
import { FilteredLearningObject, LearningObjectIdentifier, LearningPathIdentifier } from '../../interfaces/learning-content.js';
import dwengoApiLearningObjectProvider from './dwengo-api-learning-object-provider.js'; import dwengoApiLearningObjectProvider from './dwengo-api-learning-object-provider.js';
import { LearningObjectProvider } from './learning-object-provider.js'; import { LearningObjectProvider } from './learning-object-provider.js';
import { EnvVars, getEnvVar } from '../../util/envvars.js'; import { EnvVars, getEnvVar } from '../../util/envvars.js';
import databaseLearningObjectProvider from './database-learning-object-provider.js'; import databaseLearningObjectProvider from './database-learning-object-provider.js';
import { FilteredLearningObject, LearningObjectIdentifier, LearningPathIdentifier } from 'dwengo-1-common/src/interfaces/learning-content';
function getProvider(id: LearningObjectIdentifier): LearningObjectProvider { function getProvider(id: LearningObjectIdentifier): LearningObjectProvider {
if (id.hruid.startsWith(getEnvVar(EnvVars.UserContentPrefix))) { if (id.hruid.startsWith(getEnvVar(EnvVars.UserContentPrefix))) {

View file

@ -8,13 +8,13 @@ import InlineImageProcessor from '../image/inline-image-processor.js';
import * as marked from 'marked'; import * as marked from 'marked';
import { getUrlStringForLearningObjectHTML, isValidHttpUrl } from '../../../../util/links.js'; import { getUrlStringForLearningObjectHTML, isValidHttpUrl } from '../../../../util/links.js';
import { ProcessingError } from '../processing-error.js'; import { ProcessingError } from '../processing-error.js';
import { LearningObjectIdentifier } from '../../../../interfaces/learning-content.js';
import { Language } from '../../../../entities/content/language.js'; import { Language } from '../../../../entities/content/language.js';
import Image = marked.Tokens.Image; import Image = marked.Tokens.Image;
import Heading = marked.Tokens.Heading; import Heading = marked.Tokens.Heading;
import Link = marked.Tokens.Link; import Link = marked.Tokens.Link;
import RendererObject = marked.RendererObject; import RendererObject = marked.RendererObject;
import { LearningObjectIdentifier } from 'dwengo-1-common/src/interfaces/learning-content';
const prefixes = { const prefixes = {
learningObject: '@learning-object', learningObject: '@learning-object',

View file

@ -13,9 +13,9 @@ import GiftProcessor from './gift/gift-processor.js';
import { LearningObject } from '../../../entities/content/learning-object.entity.js'; import { LearningObject } from '../../../entities/content/learning-object.entity.js';
import Processor from './processor.js'; import Processor from './processor.js';
import { DwengoContentType } from './content-type.js'; import { DwengoContentType } from './content-type.js';
import { LearningObjectIdentifier } from '../../../interfaces/learning-content.js';
import { Language } from '../../../entities/content/language.js'; import { Language } from '../../../entities/content/language.js';
import { replaceAsync } from '../../../util/async.js'; import { replaceAsync } from '../../../util/async.js';
import { LearningObjectIdentifier } from 'dwengo-1-common/src/interfaces/learning-content';
const EMBEDDED_LEARNING_OBJECT_PLACEHOLDER = /<learning-object hruid="([^"]+)" language="([^"]+)" version="([^"]+)"\/>/g; const EMBEDDED_LEARNING_OBJECT_PLACEHOLDER = /<learning-object hruid="([^"]+)" language="([^"]+)" version="([^"]+)"\/>/g;
const LEARNING_OBJECT_DOES_NOT_EXIST = "<div class='non-existing-learning-object' />"; const LEARNING_OBJECT_DOES_NOT_EXIST = "<div class='non-existing-learning-object' />";

View file

@ -1,5 +1,4 @@
import { LearningPathProvider } from './learning-path-provider.js'; import { LearningPathProvider } from './learning-path-provider.js';
import { FilteredLearningObject, LearningObjectNode, LearningPath, LearningPathResponse, Transition } from '../../interfaces/learning-content.js';
import { LearningPath as LearningPathEntity } from '../../entities/content/learning-path.entity.js'; import { LearningPath as LearningPathEntity } from '../../entities/content/learning-path.entity.js';
import { getLearningPathRepository } from '../../data/repositories.js'; import { getLearningPathRepository } from '../../data/repositories.js';
import { Language } from '../../entities/content/language.js'; import { Language } from '../../entities/content/language.js';
@ -7,6 +6,13 @@ import learningObjectService from '../learning-objects/learning-object-service.j
import { LearningPathNode } from '../../entities/content/learning-path-node.entity.js'; import { LearningPathNode } from '../../entities/content/learning-path-node.entity.js';
import { LearningPathTransition } from '../../entities/content/learning-path-transition.entity.js'; import { LearningPathTransition } from '../../entities/content/learning-path-transition.entity.js';
import { getLastSubmissionForCustomizationTarget, isTransitionPossible, PersonalizationTarget } from './learning-path-personalization-util.js'; import { getLastSubmissionForCustomizationTarget, isTransitionPossible, PersonalizationTarget } from './learning-path-personalization-util.js';
import {
FilteredLearningObject,
LearningObjectNode,
LearningPath,
LearningPathResponse,
Transition,
} from 'dwengo-1-common/src/interfaces/learning-content';
/** /**
* Fetches the corresponding learning object for each of the nodes and creates a map that maps each node to its * Fetches the corresponding learning object for each of the nodes and creates a map that maps each node to its

View file

@ -1,8 +1,8 @@
import { fetchWithLogging } from '../../util/api-helper.js'; import { fetchWithLogging } from '../../util/api-helper.js';
import { DWENGO_API_BASE } from '../../config.js'; import { DWENGO_API_BASE } from '../../config.js';
import { LearningPath, LearningPathResponse } from '../../interfaces/learning-content.js';
import { LearningPathProvider } from './learning-path-provider.js'; import { LearningPathProvider } from './learning-path-provider.js';
import { getLogger, Logger } from '../../logging/initalize.js'; import { getLogger, Logger } from '../../logging/initalize.js';
import { LearningPath, LearningPathResponse } from 'dwengo-1-common/src/interfaces/learning-content';
const logger: Logger = getLogger(); const logger: Logger = getLogger();

View file

@ -1,6 +1,6 @@
import { LearningPath, LearningPathResponse } from '../../interfaces/learning-content.js';
import { Language } from '../../entities/content/language.js'; import { Language } from '../../entities/content/language.js';
import { PersonalizationTarget } from './learning-path-personalization-util.js'; import { PersonalizationTarget } from './learning-path-personalization-util.js';
import { LearningPath, LearningPathResponse } from 'dwengo-1-common/src/interfaces/learning-content';
/** /**
* Generic interface for a service which provides access to learning paths from a data source. * Generic interface for a service which provides access to learning paths from a data source.

View file

@ -1,9 +1,9 @@
import { LearningPath, LearningPathResponse } from '../../interfaces/learning-content.js';
import dwengoApiLearningPathProvider from './dwengo-api-learning-path-provider.js'; import dwengoApiLearningPathProvider from './dwengo-api-learning-path-provider.js';
import databaseLearningPathProvider from './database-learning-path-provider.js'; import databaseLearningPathProvider from './database-learning-path-provider.js';
import { EnvVars, getEnvVar } from '../../util/envvars.js'; import { EnvVars, getEnvVar } from '../../util/envvars.js';
import { Language } from '../../entities/content/language.js'; import { Language } from '../../entities/content/language.js';
import { PersonalizationTarget } from './learning-path-personalization-util.js'; import { PersonalizationTarget } from './learning-path-personalization-util.js';
import { LearningPath, LearningPathResponse } from 'dwengo-1-common/src/interfaces/learning-content';
const userContentPrefix = getEnvVar(EnvVars.UserContentPrefix); const userContentPrefix = getEnvVar(EnvVars.UserContentPrefix);
const allProviders = [dwengoApiLearningPathProvider, databaseLearningPathProvider]; const allProviders = [dwengoApiLearningPathProvider, databaseLearningPathProvider];

View file

@ -1,4 +1,4 @@
import { LearningObjectIdentifier } from '../interfaces/learning-content'; import { LearningObjectIdentifier } from 'dwengo-1-common/src/interfaces/learning-content';
export function isValidHttpUrl(url: string): boolean { export function isValidHttpUrl(url: string): boolean {
try { try {

View file

@ -5,11 +5,11 @@ import example from '../../test-assets/learning-objects/pn-werkingnotebooks/pn-w
import { LearningObject } from '../../../src/entities/content/learning-object.entity'; import { LearningObject } from '../../../src/entities/content/learning-object.entity';
import databaseLearningObjectProvider from '../../../src/services/learning-objects/database-learning-object-provider'; import databaseLearningObjectProvider from '../../../src/services/learning-objects/database-learning-object-provider';
import { expectToBeCorrectFilteredLearningObject } from '../../test-utils/expectations'; import { expectToBeCorrectFilteredLearningObject } from '../../test-utils/expectations';
import { FilteredLearningObject } from '../../../src/interfaces/learning-content';
import { Language } from '../../../src/entities/content/language'; import { Language } from '../../../src/entities/content/language';
import learningObjectExample from '../../test-assets/learning-objects/pn-werkingnotebooks/pn-werkingnotebooks-example'; import learningObjectExample from '../../test-assets/learning-objects/pn-werkingnotebooks/pn-werkingnotebooks-example';
import learningPathExample from '../../test-assets/learning-paths/pn-werking-example'; import learningPathExample from '../../test-assets/learning-paths/pn-werking-example';
import { LearningPath } from '../../../src/entities/content/learning-path.entity'; import { LearningPath } from '../../../src/entities/content/learning-path.entity';
import {FilteredLearningObject} from "dwengo-1-common/src/interfaces/learning-content";
async function initExampleData(): Promise<{ learningObject: LearningObject; learningPath: LearningPath }> { async function initExampleData(): Promise<{ learningObject: LearningObject; learningPath: LearningPath }> {
const learningObjectRepo = getLearningObjectRepository(); const learningObjectRepo = getLearningObjectRepository();

View file

@ -4,11 +4,11 @@ import { LearningObject } from '../../../src/entities/content/learning-object.en
import { getLearningObjectRepository, getLearningPathRepository } from '../../../src/data/repositories'; import { getLearningObjectRepository, getLearningPathRepository } from '../../../src/data/repositories';
import learningObjectExample from '../../test-assets/learning-objects/pn-werkingnotebooks/pn-werkingnotebooks-example'; import learningObjectExample from '../../test-assets/learning-objects/pn-werkingnotebooks/pn-werkingnotebooks-example';
import learningObjectService from '../../../src/services/learning-objects/learning-object-service'; import learningObjectService from '../../../src/services/learning-objects/learning-object-service';
import { LearningObjectIdentifier, LearningPathIdentifier } from '../../../src/interfaces/learning-content';
import { Language } from '../../../src/entities/content/language'; import { Language } from '../../../src/entities/content/language';
import { EnvVars, getEnvVar } from '../../../src/util/envvars'; import { EnvVars, getEnvVar } from '../../../src/util/envvars';
import { LearningPath } from '../../../src/entities/content/learning-path.entity'; import { LearningPath } from '../../../src/entities/content/learning-path.entity';
import learningPathExample from '../../test-assets/learning-paths/pn-werking-example'; import learningPathExample from '../../test-assets/learning-paths/pn-werking-example';
import {LearningObjectIdentifier, LearningPathIdentifier} from "dwengo-1-common/src/interfaces/learning-content";
const EXPECTED_DWENGO_LEARNING_OBJECT_TITLE = 'Werken met notebooks'; const EXPECTED_DWENGO_LEARNING_OBJECT_TITLE = 'Werken met notebooks';
const DWENGO_TEST_LEARNING_OBJECT_ID: LearningObjectIdentifier = { const DWENGO_TEST_LEARNING_OBJECT_ID: LearningObjectIdentifier = {

View file

@ -19,7 +19,8 @@ import {
createConditionTestLearningPathAndLearningObjects, createConditionTestLearningPathAndLearningObjects,
} from '../../test-assets/learning-paths/test-conditions-example.js'; } from '../../test-assets/learning-paths/test-conditions-example.js';
import { Student } from '../../../src/entities/users/student.entity.js'; import { Student } from '../../../src/entities/users/student.entity.js';
import { LearningObjectNode, LearningPathResponse } from '../../../src/interfaces/learning-content.js';
import {LearningObjectNode, LearningPathResponse} from "dwengo-1-common/src/interfaces/learning-content";
async function initExampleData(): Promise<{ learningObject: LearningObject; learningPath: LearningPath }> { async function initExampleData(): Promise<{ learningObject: LearningObject; learningPath: LearningPath }> {
const learningObjectRepo = getLearningObjectRepository(); const learningObjectRepo = getLearningObjectRepository();

View file

@ -1,8 +1,8 @@
import { AssertionError } from 'node:assert'; import { AssertionError } from 'node:assert';
import { LearningObject } from '../../src/entities/content/learning-object.entity'; import { LearningObject } from '../../src/entities/content/learning-object.entity';
import { FilteredLearningObject, LearningPath } from '../../src/interfaces/learning-content';
import { LearningPath as LearningPathEntity } from '../../src/entities/content/learning-path.entity'; import { LearningPath as LearningPathEntity } from '../../src/entities/content/learning-path.entity';
import { expect } from 'vitest'; import { expect } from 'vitest';
import {FilteredLearningObject, LearningPath} from "dwengo-1-common/src/interfaces/learning-content";
// Ignored properties because they belang for example to the class, not to the entity itself. // Ignored properties because they belang for example to the class, not to the entity itself.
const IGNORE_PROPERTIES = ['parent']; const IGNORE_PROPERTIES = ['parent'];

View file

@ -1,4 +1,4 @@
import { Language } from '../entities/content/language'; import { Language } from 'dwengo-1-backend/src/entities/content/language.js'
export interface Transition { export interface Transition {
default: boolean; default: boolean;