refactor(backend): Streamlining van de testdata voor leerpaden en leerobjecten + integratie in seed
Hierbij ook testdata functionaliteit toegevoegd om makkelijk nieuwe leerpaden aan te maken.
This commit is contained in:
parent
4092f1f617
commit
202cf4e33c
32 changed files with 691 additions and 493 deletions
|
@ -1,6 +1,10 @@
|
||||||
import { DwengoEntityRepository } from '../dwengo-entity-repository.js';
|
import { DwengoEntityRepository } from '../dwengo-entity-repository.js';
|
||||||
import { LearningPath } from '../../entities/content/learning-path.entity.js';
|
import { LearningPath } from '../../entities/content/learning-path.entity.js';
|
||||||
import { Language } from '@dwengo-1/common/util/language';
|
import { Language } from '@dwengo-1/common/util/language';
|
||||||
|
import {LearningPathNode} from "../../entities/content/learning-path-node.entity";
|
||||||
|
import {RequiredEntityData} from "@mikro-orm/core";
|
||||||
|
import {LearningPathTransition} from "../../entities/content/learning-path-transition.entity";
|
||||||
|
import {EntityAlreadyExistsException} from "../../exceptions/entity-already-exists-exception";
|
||||||
|
|
||||||
export class LearningPathRepository extends DwengoEntityRepository<LearningPath> {
|
export class LearningPathRepository extends DwengoEntityRepository<LearningPath> {
|
||||||
public async findByHruidAndLanguage(hruid: string, language: Language): Promise<LearningPath | null> {
|
public async findByHruidAndLanguage(hruid: string, language: Language): Promise<LearningPath | null> {
|
||||||
|
@ -23,4 +27,33 @@ export class LearningPathRepository extends DwengoEntityRepository<LearningPath>
|
||||||
populate: ['nodes', 'nodes.transitions'],
|
populate: ['nodes', 'nodes.transitions'],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public createNode(
|
||||||
|
nodeData: RequiredEntityData<LearningPathNode, never, false>
|
||||||
|
): LearningPathNode {
|
||||||
|
return this.em.create(LearningPathNode, nodeData);
|
||||||
|
}
|
||||||
|
|
||||||
|
public createTransition(
|
||||||
|
transitionData: RequiredEntityData<LearningPathTransition, never, false>
|
||||||
|
): LearningPathTransition {
|
||||||
|
return this.em.create(LearningPathTransition, transitionData)
|
||||||
|
}
|
||||||
|
|
||||||
|
public async saveLearningPathNodesAndTransitions(
|
||||||
|
path: LearningPath,
|
||||||
|
nodes: LearningPathNode[],
|
||||||
|
transitions: LearningPathTransition[],
|
||||||
|
options?: {preventOverwrite?: boolean}
|
||||||
|
): Promise<void> {
|
||||||
|
if (options?.preventOverwrite && (await this.findOne(path))) {
|
||||||
|
throw new EntityAlreadyExistsException(
|
||||||
|
"A learning path with this hruid/language combination already exists."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const em = this.getEntityManager();
|
||||||
|
await em.persistAndFlush(path);
|
||||||
|
await Promise.all(nodes.map(it => em.persistAndFlush(it)));
|
||||||
|
await Promise.all(transitions.map(it => em.persistAndFlush(it)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { Entity, Enum, ManyToOne, OneToMany, PrimaryKey, Property, Rel } from '@mikro-orm/core';
|
import {Collection, Entity, Enum, ManyToOne, OneToMany, PrimaryKey, Property, Rel} from '@mikro-orm/core';
|
||||||
import { LearningPath } from './learning-path.entity.js';
|
import { LearningPath } from './learning-path.entity.js';
|
||||||
import { LearningPathTransition } from './learning-path-transition.entity.js';
|
import { LearningPathTransition } from './learning-path-transition.entity.js';
|
||||||
import { Language } from '@dwengo-1/common/util/language';
|
import { Language } from '@dwengo-1/common/util/language';
|
||||||
|
@ -27,7 +27,7 @@ export class LearningPathNode {
|
||||||
startNode!: boolean;
|
startNode!: boolean;
|
||||||
|
|
||||||
@OneToMany({ entity: () => LearningPathTransition, mappedBy: 'node' })
|
@OneToMany({ entity: () => LearningPathTransition, mappedBy: 'node' })
|
||||||
transitions: LearningPathTransition[] = [];
|
transitions: Collection<LearningPathTransition> = new Collection<LearningPathTransition>(this);
|
||||||
|
|
||||||
@Property({ length: 3 })
|
@Property({ length: 3 })
|
||||||
createdAt: Date = new Date();
|
createdAt: Date = new Date();
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { Entity, Enum, ManyToMany, OneToMany, PrimaryKey, Property } from '@mikro-orm/core';
|
import {Collection, Entity, Enum, ManyToMany, OneToMany, PrimaryKey, Property} from '@mikro-orm/core';
|
||||||
import { Teacher } from '../users/teacher.entity.js';
|
import { Teacher } from '../users/teacher.entity.js';
|
||||||
import { LearningPathRepository } from '../../data/content/learning-path-repository.js';
|
import { LearningPathRepository } from '../../data/content/learning-path-repository.js';
|
||||||
import { LearningPathNode } from './learning-path-node.entity.js';
|
import { LearningPathNode } from './learning-path-node.entity.js';
|
||||||
|
@ -25,5 +25,5 @@ export class LearningPath {
|
||||||
image: Buffer | null = null;
|
image: Buffer | null = null;
|
||||||
|
|
||||||
@OneToMany({ entity: () => LearningPathNode, mappedBy: 'learningPath' })
|
@OneToMany({ entity: () => LearningPathNode, mappedBy: 'learningPath' })
|
||||||
nodes: LearningPathNode[] = [];
|
nodes: Collection<LearningPathNode> = new Collection<LearningPathNode>(this);
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,13 +14,14 @@ import {
|
||||||
} from '@dwengo-1/common/interfaces/learning-content';
|
} from '@dwengo-1/common/interfaces/learning-content';
|
||||||
import { Language } from '@dwengo-1/common/util/language';
|
import { Language } from '@dwengo-1/common/util/language';
|
||||||
import {Group} from "../../entities/assignments/group.entity";
|
import {Group} from "../../entities/assignments/group.entity";
|
||||||
|
import {Collection} from "@mikro-orm/core";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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
|
||||||
* corresponding learning object.
|
* corresponding learning object.
|
||||||
* @param nodes The nodes to find the learning object for.
|
* @param nodes The nodes to find the learning object for.
|
||||||
*/
|
*/
|
||||||
async function getLearningObjectsForNodes(nodes: LearningPathNode[]): Promise<Map<LearningPathNode, FilteredLearningObject>> {
|
async function getLearningObjectsForNodes(nodes: Collection<LearningPathNode>): Promise<Map<LearningPathNode, FilteredLearningObject>> {
|
||||||
// Fetching the corresponding learning object for each of the nodes and creating a map that maps each node to
|
// Fetching the corresponding learning object for each of the nodes and creating a map that maps each node to
|
||||||
// Its corresponding learning object.
|
// Its corresponding learning object.
|
||||||
const nullableNodesToLearningObjects = new Map<LearningPathNode, FilteredLearningObject | null>(
|
const nullableNodesToLearningObjects = new Map<LearningPathNode, FilteredLearningObject | null>(
|
||||||
|
@ -208,7 +209,7 @@ const databaseLearningPathProvider: LearningPathProvider = {
|
||||||
|
|
||||||
const searchResults = await learningPathRepo.findByQueryStringAndLanguage(query, language);
|
const searchResults = await learningPathRepo.findByQueryStringAndLanguage(query, language);
|
||||||
return await Promise.all(searchResults.map(async (result, index) => convertLearningPath(result, index, personalizedFor)));
|
return await Promise.all(searchResults.map(async (result, index) => convertLearningPath(result, index, personalizedFor)));
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export default databaseLearningPathProvider;
|
export default databaseLearningPathProvider;
|
||||||
|
|
|
@ -1,13 +1,79 @@
|
||||||
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 { LearningPath, LearningPathResponse } from '@dwengo-1/common/interfaces/learning-content';
|
import {LearningObjectNode, LearningPath, LearningPathResponse} from '@dwengo-1/common/interfaces/learning-content';
|
||||||
import { Language } from '@dwengo-1/common/util/language';
|
import { Language } from '@dwengo-1/common/util/language';
|
||||||
import {Group} from "../../entities/assignments/group.entity";
|
import {Group} from "../../entities/assignments/group.entity";
|
||||||
|
import {LearningPath as LearningPathEntity} from "../../entities/content/learning-path.entity";
|
||||||
|
import {getLearningPathRepository} from "../../data/repositories";
|
||||||
|
import {LearningPathNode} from "../../entities/content/learning-path-node.entity";
|
||||||
|
import {LearningPathTransition} from "../../entities/content/learning-path-transition.entity";
|
||||||
|
import {base64ToArrayBuffer} from "../../util/base64-buffer-conversion";
|
||||||
|
import {TeacherDTO} from "@dwengo-1/common/interfaces/teacher";
|
||||||
|
import {mapToTeacher} from "../../interfaces/teacher";
|
||||||
|
import {Collection} from "@mikro-orm/core";
|
||||||
|
|
||||||
const userContentPrefix = getEnvVar(envVars.UserContentPrefix);
|
const userContentPrefix = getEnvVar(envVars.UserContentPrefix);
|
||||||
const allProviders = [dwengoApiLearningPathProvider, databaseLearningPathProvider];
|
const allProviders = [dwengoApiLearningPathProvider, databaseLearningPathProvider];
|
||||||
|
|
||||||
|
export function mapToLearningPath(
|
||||||
|
dto: LearningPath, adminsDto: TeacherDTO[]
|
||||||
|
): LearningPathEntity {
|
||||||
|
const admins = adminsDto.map(admin => mapToTeacher(admin));
|
||||||
|
const repo = getLearningPathRepository();
|
||||||
|
const path = repo.create({
|
||||||
|
hruid: dto.hruid,
|
||||||
|
language: dto.language as Language,
|
||||||
|
description: dto.description,
|
||||||
|
title: dto.title,
|
||||||
|
admins,
|
||||||
|
image: dto.image ? Buffer.from(base64ToArrayBuffer(dto.image)) : null
|
||||||
|
});
|
||||||
|
const nodes = dto.nodes.map((nodeDto: LearningObjectNode, i: number) =>
|
||||||
|
repo.createNode({
|
||||||
|
learningPath: path,
|
||||||
|
learningObjectHruid: nodeDto.learningobject_hruid,
|
||||||
|
language: nodeDto.language,
|
||||||
|
version: nodeDto.version,
|
||||||
|
startNode: nodeDto.start_node ?? false,
|
||||||
|
nodeNumber: i,
|
||||||
|
createdAt: new Date(),
|
||||||
|
updatedAt: new Date()
|
||||||
|
})
|
||||||
|
);
|
||||||
|
dto.nodes.forEach(nodeDto => {
|
||||||
|
const fromNode = nodes.find(it =>
|
||||||
|
it.learningObjectHruid === nodeDto.learningobject_hruid
|
||||||
|
&& it.language === nodeDto.language
|
||||||
|
&& it.version === nodeDto.version
|
||||||
|
)!;
|
||||||
|
const transitions = nodeDto.transitions.map((transDto, i) => {
|
||||||
|
const toNode = nodes.find(it =>
|
||||||
|
it.learningObjectHruid === transDto.next.hruid
|
||||||
|
&& it.language === transDto.next.language
|
||||||
|
&& it.version === transDto.next.version
|
||||||
|
);
|
||||||
|
|
||||||
|
if (toNode) {
|
||||||
|
return repo.createTransition({
|
||||||
|
transitionNumber: i,
|
||||||
|
node: fromNode,
|
||||||
|
next: toNode,
|
||||||
|
condition: transDto.condition ?? "true"
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}).filter(it => it).map(it => it!);
|
||||||
|
|
||||||
|
fromNode.transitions = new Collection<LearningPathTransition>(transitions);
|
||||||
|
});
|
||||||
|
|
||||||
|
path.nodes = new Collection<LearningPathNode>(nodes);
|
||||||
|
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service providing access to data about learning paths from the appropriate data source (database or Dwengo-api)
|
* Service providing access to data about learning paths from the appropriate data source (database or Dwengo-api)
|
||||||
*/
|
*/
|
||||||
|
@ -54,6 +120,17 @@ const learningPathService = {
|
||||||
);
|
);
|
||||||
return providerResponses.flat();
|
return providerResponses.flat();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a new learning path to the database.
|
||||||
|
* @param dto Learning path DTO from which the learning path will be created.
|
||||||
|
* @param admins Teachers who should become an admin of the learning path.
|
||||||
|
*/
|
||||||
|
async createNewLearningPath(dto: LearningPath, admins: TeacherDTO[]): Promise<void> {
|
||||||
|
const repo = getLearningPathRepository();
|
||||||
|
const path = mapToLearningPath(dto, admins);
|
||||||
|
await repo.save(path, {preventOverwrite: true})
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export default learningPathService;
|
export default learningPathService;
|
||||||
|
|
12
backend/src/util/base64-buffer-conversion.ts
Normal file
12
backend/src/util/base64-buffer-conversion.ts
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
/**
|
||||||
|
* Convert a Base64-encoded string into a buffer with the same data.
|
||||||
|
* @param base64 The Base64 encoded string.
|
||||||
|
*/
|
||||||
|
export function base64ToArrayBuffer(base64: string) {
|
||||||
|
var binaryString = atob(base64);
|
||||||
|
var bytes = new Uint8Array(binaryString.length);
|
||||||
|
for (var i = 0; i < binaryString.length; i++) {
|
||||||
|
bytes[i] = binaryString.charCodeAt(i);
|
||||||
|
}
|
||||||
|
return bytes.buffer;
|
||||||
|
}
|
|
@ -2,48 +2,36 @@ import { beforeAll, describe, it, expect } from 'vitest';
|
||||||
import { LearningObjectRepository } from '../../../src/data/content/learning-object-repository.js';
|
import { LearningObjectRepository } from '../../../src/data/content/learning-object-repository.js';
|
||||||
import { setupTestApp } from '../../setup-tests.js';
|
import { setupTestApp } from '../../setup-tests.js';
|
||||||
import { getLearningObjectRepository } from '../../../src/data/repositories.js';
|
import { getLearningObjectRepository } from '../../../src/data/repositories.js';
|
||||||
import example from '../../test-assets/learning-objects/pn-werkingnotebooks/pn-werkingnotebooks-example.js';
|
|
||||||
import { LearningObject } from '../../../src/entities/content/learning-object.entity.js';
|
import { LearningObject } from '../../../src/entities/content/learning-object.entity.js';
|
||||||
import { expectToBeCorrectEntity } from '../../test-utils/expectations.js';
|
import { expectToBeCorrectEntity } from '../../test-utils/expectations.js';
|
||||||
|
import {
|
||||||
|
testLearningObject01,
|
||||||
|
testLearningObject02,
|
||||||
|
testLearningObject03
|
||||||
|
} from "../../test_assets/content/learning-objects.testdata";
|
||||||
|
|
||||||
describe('LearningObjectRepository', () => {
|
describe('LearningObjectRepository', () => {
|
||||||
let learningObjectRepository: LearningObjectRepository;
|
let learningObjectRepository: LearningObjectRepository;
|
||||||
|
|
||||||
let exampleLearningObject: LearningObject;
|
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
await setupTestApp();
|
await setupTestApp();
|
||||||
learningObjectRepository = getLearningObjectRepository();
|
learningObjectRepository = getLearningObjectRepository();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be able to add a learning object to it without an error', async () => {
|
it('should return a learning object when queried by id', async () => {
|
||||||
exampleLearningObject = example.createLearningObject();
|
|
||||||
await learningObjectRepository.insert(exampleLearningObject);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return the learning object when queried by id', async () => {
|
|
||||||
const result = await learningObjectRepository.findByIdentifier({
|
const result = await learningObjectRepository.findByIdentifier({
|
||||||
hruid: exampleLearningObject.hruid,
|
hruid: testLearningObject01.hruid,
|
||||||
language: exampleLearningObject.language,
|
language: testLearningObject02.language,
|
||||||
version: exampleLearningObject.version,
|
version: testLearningObject03.version,
|
||||||
});
|
});
|
||||||
expect(result).toBeInstanceOf(LearningObject);
|
expect(result).toBeInstanceOf(LearningObject);
|
||||||
expectToBeCorrectEntity(
|
expectToBeCorrectEntity(result!, testLearningObject01);
|
||||||
{
|
|
||||||
name: 'actual',
|
|
||||||
entity: result!,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'expected',
|
|
||||||
entity: exampleLearningObject,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return null when non-existing version is queried', async () => {
|
it('should return null when non-existing version is queried', async () => {
|
||||||
const result = await learningObjectRepository.findByIdentifier({
|
const result = await learningObjectRepository.findByIdentifier({
|
||||||
hruid: exampleLearningObject.hruid,
|
hruid: testLearningObject01.hruid,
|
||||||
language: exampleLearningObject.language,
|
language: testLearningObject01.language,
|
||||||
version: 100,
|
version: 100,
|
||||||
});
|
});
|
||||||
expect(result).toBe(null);
|
expect(result).toBe(null);
|
||||||
|
@ -52,21 +40,27 @@ describe('LearningObjectRepository', () => {
|
||||||
let newerExample: LearningObject;
|
let newerExample: LearningObject;
|
||||||
|
|
||||||
it('should allow a learning object with the same id except a different version to be added', async () => {
|
it('should allow a learning object with the same id except a different version to be added', async () => {
|
||||||
newerExample = example.createLearningObject();
|
let testLearningObject01Newer = structuredClone(testLearningObject01);
|
||||||
newerExample.version = 10;
|
testLearningObject01Newer.version = 10;
|
||||||
newerExample.title += ' (nieuw)';
|
testLearningObject01Newer.title += " (nieuw)";
|
||||||
|
testLearningObject01Newer.content = Buffer.from("This is the new content.");
|
||||||
|
newerExample = learningObjectRepository.create(testLearningObject01Newer);
|
||||||
await learningObjectRepository.save(newerExample);
|
await learningObjectRepository.save(newerExample);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return the newest version of the learning object when queried by only hruid and language', async () => {
|
it('should return the newest version of the learning object when queried by only hruid and language', async () => {
|
||||||
const result = await learningObjectRepository.findLatestByHruidAndLanguage(newerExample.hruid, newerExample.language);
|
const result = await learningObjectRepository.findLatestByHruidAndLanguage(
|
||||||
|
newerExample.hruid, newerExample.language
|
||||||
|
);
|
||||||
expect(result).toBeInstanceOf(LearningObject);
|
expect(result).toBeInstanceOf(LearningObject);
|
||||||
expect(result?.version).toBe(10);
|
expect(result?.version).toBe(10);
|
||||||
expect(result?.title).toContain('(nieuw)');
|
expect(result?.title).toContain('(nieuw)');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return null when queried by non-existing hruid or language', async () => {
|
it('should return null when queried by non-existing hruid or language', async () => {
|
||||||
const result = await learningObjectRepository.findLatestByHruidAndLanguage('something_that_does_not_exist', exampleLearningObject.language);
|
const result = await learningObjectRepository.findLatestByHruidAndLanguage(
|
||||||
|
'something_that_does_not_exist', testLearningObject01.language
|
||||||
|
);
|
||||||
expect(result).toBe(null);
|
expect(result).toBe(null);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
import { LearningObjectExample } from './learning-object-example';
|
|
||||||
import { LearningObject } from '../../../src/entities/content/learning-object.entity';
|
|
||||||
|
|
||||||
export function createExampleLearningObjectWithAttachments(example: LearningObjectExample): LearningObject {
|
|
||||||
const learningObject = example.createLearningObject();
|
|
||||||
for (const creationFn of Object.values(example.createAttachment)) {
|
|
||||||
learningObject.attachments.push(creationFn(learningObject));
|
|
||||||
}
|
|
||||||
return learningObject;
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
import { LearningObject } from '../../../src/entities/content/learning-object.entity';
|
|
||||||
import { Attachment } from '../../../src/entities/content/attachment.entity';
|
|
||||||
|
|
||||||
interface LearningObjectExample {
|
|
||||||
createLearningObject: () => LearningObject;
|
|
||||||
createAttachment: Record<string, (owner: LearningObject) => Attachment>;
|
|
||||||
getHTMLRendering: () => string;
|
|
||||||
}
|
|
|
@ -1,2 +0,0 @@
|
||||||
::MC basic::
|
|
||||||
How are you? {}
|
|
|
@ -1,3 +0,0 @@
|
||||||
interface LearningPathExample {
|
|
||||||
createLearningPath: () => LearningPath;
|
|
||||||
}
|
|
|
@ -1,36 +0,0 @@
|
||||||
import { Language } from '@dwengo-1/common/util/language';
|
|
||||||
import { LearningPathTransition } from '../../../src/entities/content/learning-path-transition.entity';
|
|
||||||
import { LearningPathNode } from '../../../src/entities/content/learning-path-node.entity';
|
|
||||||
import { LearningPath } from '../../../src/entities/content/learning-path.entity';
|
|
||||||
|
|
||||||
export function createLearningPathTransition(
|
|
||||||
node: LearningPathNode,
|
|
||||||
transitionNumber: number,
|
|
||||||
condition: string | null,
|
|
||||||
to: LearningPathNode
|
|
||||||
): LearningPathTransition {
|
|
||||||
const trans = new LearningPathTransition();
|
|
||||||
trans.node = node;
|
|
||||||
trans.transitionNumber = transitionNumber;
|
|
||||||
trans.condition = condition || 'true';
|
|
||||||
trans.next = to;
|
|
||||||
return trans;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function createLearningPathNode(
|
|
||||||
learningPath: LearningPath,
|
|
||||||
nodeNumber: number,
|
|
||||||
learningObjectHruid: string,
|
|
||||||
version: number,
|
|
||||||
language: Language,
|
|
||||||
startNode: boolean
|
|
||||||
): LearningPathNode {
|
|
||||||
const node = new LearningPathNode();
|
|
||||||
node.learningPath = learningPath;
|
|
||||||
node.nodeNumber = nodeNumber;
|
|
||||||
node.learningObjectHruid = learningObjectHruid;
|
|
||||||
node.version = version;
|
|
||||||
node.language = language;
|
|
||||||
node.startNode = startNode;
|
|
||||||
return node;
|
|
||||||
}
|
|
|
@ -1,30 +0,0 @@
|
||||||
import { LearningPath } from '../../../src/entities/content/learning-path.entity';
|
|
||||||
import { Language } from '@dwengo-1/common/util/language';
|
|
||||||
import { envVars, getEnvVar } from '../../../src/util/envVars';
|
|
||||||
import { createLearningPathNode, createLearningPathTransition } from './learning-path-utils';
|
|
||||||
import { LearningPathNode } from '../../../src/entities/content/learning-path-node.entity';
|
|
||||||
|
|
||||||
function createNodes(learningPath: LearningPath): LearningPathNode[] {
|
|
||||||
const nodes = [
|
|
||||||
createLearningPathNode(learningPath, 0, 'u_pn_werkingnotebooks', 3, Language.Dutch, true),
|
|
||||||
createLearningPathNode(learningPath, 1, 'pn_werkingnotebooks2', 3, Language.Dutch, false),
|
|
||||||
createLearningPathNode(learningPath, 2, 'pn_werkingnotebooks3', 3, Language.Dutch, false),
|
|
||||||
];
|
|
||||||
nodes[0].transitions.push(createLearningPathTransition(nodes[0], 0, 'true', nodes[1]));
|
|
||||||
nodes[1].transitions.push(createLearningPathTransition(nodes[1], 0, 'true', nodes[2]));
|
|
||||||
return nodes;
|
|
||||||
}
|
|
||||||
|
|
||||||
const example: LearningPathExample = {
|
|
||||||
createLearningPath: () => {
|
|
||||||
const path = new LearningPath();
|
|
||||||
path.language = Language.Dutch;
|
|
||||||
path.hruid = `${getEnvVar(envVars.UserContentPrefix)}pn_werking`;
|
|
||||||
path.title = 'Werken met notebooks';
|
|
||||||
path.description = 'Een korte inleiding tot Python notebooks. Hoe ga je gemakkelijk en efficiënt met de notebooks aan de slag?';
|
|
||||||
path.nodes = createNodes(path);
|
|
||||||
return path;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default example;
|
|
|
@ -1,80 +0,0 @@
|
||||||
import { LearningPath } from '../../../src/entities/content/learning-path.entity';
|
|
||||||
import { Language } from '@dwengo-1/common/util/language';
|
|
||||||
import testMultipleChoiceExample from '../learning-objects/test-multiple-choice/test-multiple-choice-example';
|
|
||||||
import { dummyLearningObject } from '../learning-objects/dummy/dummy-learning-object-example';
|
|
||||||
import { createLearningPathNode, createLearningPathTransition } from './learning-path-utils';
|
|
||||||
import { LearningObject } from '../../../src/entities/content/learning-object.entity';
|
|
||||||
import { envVars, getEnvVar } from '../../../src/util/envVars';
|
|
||||||
|
|
||||||
export interface ConditionTestLearningPathAndLearningObjects {
|
|
||||||
branchingObject: LearningObject;
|
|
||||||
extraExerciseObject: LearningObject;
|
|
||||||
finalObject: LearningObject;
|
|
||||||
learningPath: LearningPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function createConditionTestLearningPathAndLearningObjects(): ConditionTestLearningPathAndLearningObjects {
|
|
||||||
const learningPath = new LearningPath();
|
|
||||||
learningPath.hruid = `${getEnvVar(envVars.UserContentPrefix)}test_conditions`;
|
|
||||||
learningPath.language = Language.English;
|
|
||||||
learningPath.title = 'Example learning path with conditional transitions';
|
|
||||||
learningPath.description = 'This learning path was made for the purpose of testing conditional transitions';
|
|
||||||
|
|
||||||
const branchingLearningObject = testMultipleChoiceExample.createLearningObject();
|
|
||||||
const extraExerciseLearningObject = dummyLearningObject(
|
|
||||||
'test_extra_exercise',
|
|
||||||
Language.English,
|
|
||||||
'Extra exercise (for students with difficulties)'
|
|
||||||
).createLearningObject();
|
|
||||||
const finalLearningObject = dummyLearningObject(
|
|
||||||
'test_final_learning_object',
|
|
||||||
Language.English,
|
|
||||||
'Final exercise (for everyone)'
|
|
||||||
).createLearningObject();
|
|
||||||
|
|
||||||
const branchingNode = createLearningPathNode(
|
|
||||||
learningPath,
|
|
||||||
0,
|
|
||||||
branchingLearningObject.hruid,
|
|
||||||
branchingLearningObject.version,
|
|
||||||
branchingLearningObject.language,
|
|
||||||
true
|
|
||||||
);
|
|
||||||
const extraExerciseNode = createLearningPathNode(
|
|
||||||
learningPath,
|
|
||||||
1,
|
|
||||||
extraExerciseLearningObject.hruid,
|
|
||||||
extraExerciseLearningObject.version,
|
|
||||||
extraExerciseLearningObject.language,
|
|
||||||
false
|
|
||||||
);
|
|
||||||
const finalNode = createLearningPathNode(
|
|
||||||
learningPath,
|
|
||||||
2,
|
|
||||||
finalLearningObject.hruid,
|
|
||||||
finalLearningObject.version,
|
|
||||||
finalLearningObject.language,
|
|
||||||
false
|
|
||||||
);
|
|
||||||
|
|
||||||
const transitionToExtraExercise = createLearningPathTransition(
|
|
||||||
branchingNode,
|
|
||||||
0,
|
|
||||||
'$[?(@[0] == 0)]', // The answer to the first question was the first one, which says that it is difficult for the student to follow along.
|
|
||||||
extraExerciseNode
|
|
||||||
);
|
|
||||||
const directTransitionToFinal = createLearningPathTransition(branchingNode, 1, '$[?(@[0] == 1)]', finalNode);
|
|
||||||
const transitionExtraExerciseToFinal = createLearningPathTransition(extraExerciseNode, 0, 'true', finalNode);
|
|
||||||
|
|
||||||
branchingNode.transitions = [transitionToExtraExercise, directTransitionToFinal];
|
|
||||||
extraExerciseNode.transitions = [transitionExtraExerciseToFinal];
|
|
||||||
|
|
||||||
learningPath.nodes = [branchingNode, extraExerciseNode, finalNode];
|
|
||||||
|
|
||||||
return {
|
|
||||||
branchingObject: branchingLearningObject,
|
|
||||||
finalObject: finalLearningObject,
|
|
||||||
extraExerciseObject: extraExerciseLearningObject,
|
|
||||||
learningPath: learningPath,
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -11,52 +11,45 @@ const IGNORE_PROPERTIES = ['parent'];
|
||||||
* Checks if the actual entity from the database conforms to the entity that was added previously.
|
* Checks if the actual entity from the database conforms to the entity that was added previously.
|
||||||
* @param actual The actual entity retrieved from the database
|
* @param actual The actual entity retrieved from the database
|
||||||
* @param expected The (previously added) entity we would expect to retrieve
|
* @param expected The (previously added) entity we would expect to retrieve
|
||||||
|
* @param propertyPrefix Prefix to append to property in error messages.
|
||||||
*/
|
*/
|
||||||
export function expectToBeCorrectEntity<T extends object>(actual: { entity: T; name?: string }, expected: { entity: T; name?: string }): void {
|
export function expectToBeCorrectEntity<T extends object>(
|
||||||
if (!actual.name) {
|
actual: T,
|
||||||
actual.name = 'actual';
|
expected: T,
|
||||||
}
|
propertyPrefix: string = ""
|
||||||
if (!expected.name) {
|
): void {
|
||||||
expected.name = 'expected';
|
for (const property in expected) {
|
||||||
}
|
const prefixedProperty = propertyPrefix + property;
|
||||||
for (const property in expected.entity) {
|
|
||||||
if (
|
if (
|
||||||
property in IGNORE_PROPERTIES &&
|
property in IGNORE_PROPERTIES &&
|
||||||
expected.entity[property] !== undefined && // If we don't expect a certain value for a property, we assume it can be filled in by the database however it wants.
|
expected[property] !== undefined && // If we don't expect a certain value for a property, we assume it can be filled in by the database however it wants.
|
||||||
typeof expected.entity[property] !== 'function' // Functions obviously are not persisted via the database
|
typeof expected[property] !== 'function' // Functions obviously are not persisted via the database
|
||||||
) {
|
) {
|
||||||
if (!Object.prototype.hasOwnProperty.call(actual.entity, property)) {
|
if (!Object.prototype.hasOwnProperty.call(actual, property)) {
|
||||||
throw new AssertionError({
|
throw new AssertionError({
|
||||||
message: `${expected.name} has defined property ${property}, but ${actual.name} is missing it.`,
|
message: `Expected property ${prefixedProperty}, but it is missing.`,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (typeof expected.entity[property] === 'boolean') {
|
if (typeof expected[property] === 'boolean') {
|
||||||
// Sometimes, booleans get represented by numbers 0 and 1 in the objects actual from the database.
|
// Sometimes, booleans get represented by numbers 0 and 1 in the objects actual from the database.
|
||||||
if (Boolean(expected.entity[property]) !== Boolean(actual.entity[property])) {
|
if (Boolean(expected[property]) !== Boolean(actual[property])) {
|
||||||
throw new AssertionError({
|
throw new AssertionError({
|
||||||
message: `${property} was ${expected.entity[property]} in ${expected.name},
|
message: `Expected ${prefixedProperty} to be ${expected[property]},
|
||||||
but ${actual.entity[property]} (${Boolean(expected.entity[property])}) in ${actual.name}`,
|
but was ${actual[property]} (${Boolean(expected[property])}).`,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else if (typeof expected.entity[property] !== typeof actual.entity[property]) {
|
} else if (typeof expected[property] !== typeof actual[property]) {
|
||||||
throw new AssertionError({
|
throw new AssertionError({
|
||||||
message: `${property} has type ${typeof expected.entity[property]} in ${expected.name}, but type ${typeof actual.entity[property]} in ${actual.name}.`,
|
message: `${prefixedProperty} was expected to have type ${typeof expected[property]},`
|
||||||
|
+ `but had type ${typeof actual[property]}.`,
|
||||||
});
|
});
|
||||||
} else if (typeof expected.entity[property] === 'object') {
|
} else if (typeof expected[property] === 'object') {
|
||||||
expectToBeCorrectEntity(
|
expectToBeCorrectEntity(actual[property] as object, expected[property] as object, property);
|
||||||
{
|
|
||||||
name: actual.name + '.' + property,
|
|
||||||
entity: actual.entity[property] as object,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: expected.name + '.' + property,
|
|
||||||
entity: expected.entity[property] as object,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
if (expected.entity[property] !== actual.entity[property]) {
|
if (expected[property] !== actual[property]) {
|
||||||
throw new AssertionError({
|
throw new AssertionError({
|
||||||
message: `${property} was ${expected.entity[property]} in ${expected.name}, but ${actual.entity[property]} in ${actual.name}`,
|
message: `${prefixedProperty} was expected to be ${expected[property]}, `
|
||||||
|
+ `but was ${actual[property]}.`,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,5 +6,5 @@ import path from 'node:path';
|
||||||
* @param relPath Path of the asset relative to the test-assets folder.
|
* @param relPath Path of the asset relative to the test-assets folder.
|
||||||
*/
|
*/
|
||||||
export function loadTestAsset(relPath: string): Buffer {
|
export function loadTestAsset(relPath: string): Buffer {
|
||||||
return fs.readFileSync(path.resolve(__dirname, `../test-assets/${relPath}`));
|
return fs.readFileSync(path.resolve(__dirname, `../test_assets/${relPath}`));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import { LearningObjectExample } from '../learning-object-example';
|
import { LearningObjectExample } from '../learning-object-example';
|
||||||
import { LearningObject } from '../../../../src/entities/content/learning-object.entity';
|
import { LearningObject } from '../../../../../src/entities/content/learning-object.entity';
|
||||||
import { Language } from '@dwengo-1/common/util/language';
|
import { Language } from '@dwengo-1/common/dist/util/language';
|
||||||
import { loadTestAsset } from '../../../test-utils/load-test-asset';
|
import { loadTestAsset } from '../../../../test-utils/load-test-asset';
|
||||||
import { DwengoContentType } from '../../../../src/services/learning-objects/processing/content-type';
|
import { DwengoContentType } from '../../../../../src/services/learning-objects/processing/content-type';
|
||||||
import { envVars, getEnvVar } from '../../../../src/util/envVars';
|
import { envVars, getEnvVar } from '../../../../../src/util/envVars';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a dummy learning object to be used in tests where multiple learning objects are needed (for example for use
|
* Create a dummy learning object to be used in tests where multiple learning objects are needed (for example for use
|
Before Width: | Height: | Size: 7.6 KiB After Width: | Height: | Size: 7.6 KiB |
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
|
@ -1,12 +1,12 @@
|
||||||
import { LearningObjectExample } from '../learning-object-example';
|
import { LearningObjectExample } from '../learning-object-example';
|
||||||
import { Language } from '@dwengo-1/common/util/language';
|
import { Language } from '@dwengo-1/common/dist/util/language';
|
||||||
import { DwengoContentType } from '../../../../src/services/learning-objects/processing/content-type';
|
import { DwengoContentType } from '../../../../../src/services/learning-objects/processing/content-type';
|
||||||
import { loadTestAsset } from '../../../test-utils/load-test-asset';
|
import { loadTestAsset } from '../../../../test-utils/load-test-asset';
|
||||||
import { LearningObject } from '../../../../src/entities/content/learning-object.entity';
|
import { LearningObject } from '../../../../../src/entities/content/learning-object.entity';
|
||||||
import { Attachment } from '../../../../src/entities/content/attachment.entity';
|
import { Attachment } from '../../../../../src/entities/content/attachment.entity';
|
||||||
import { envVars, getEnvVar } from '../../../../src/util/envVars';
|
import { envVars, getEnvVar } from '../../../../../src/util/envVars';
|
||||||
import { EducationalGoal } from '../../../../src/entities/content/educational-goal.entity';
|
import { EducationalGoal } from '../../../../../src/entities/content/educational-goal.entity';
|
||||||
import { ReturnValue } from '../../../../src/entities/content/return-value.entity';
|
import { ReturnValue } from '../../../../../src/entities/content/return-value.entity';
|
||||||
|
|
||||||
const ASSETS_PREFIX = 'learning-objects/pn-werkingnotebooks/';
|
const ASSETS_PREFIX = 'learning-objects/pn-werkingnotebooks/';
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
::MC basic::
|
||||||
|
Reflect on this learning path. What have you learned today? {}
|
|
@ -1,7 +1,7 @@
|
||||||
<div class="learning-object-gift">
|
<div class="learning-object-gift">
|
||||||
<div id="gift-q1" class="gift-question">
|
<div id="gift-q1" class="gift-question">
|
||||||
<h2 id="gift-q1-title" class="gift-title">MC basic</h2>
|
<h2 id="gift-q1-title" class="gift-title">MC basic</h2>
|
||||||
<p id="gift-q1-stem" class="gift-stem">How are you?</p>
|
<p id="gift-q1-stem" class="gift-stem">Reflect on this learning path. What have you learned today?</p>
|
||||||
<textarea id="gift-q1-answer" class="gift-essay-answer"></textarea>
|
<textarea id="gift-q1-answer" class="gift-essay-answer"></textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
|
@ -1,9 +1,9 @@
|
||||||
import { LearningObjectExample } from '../learning-object-example';
|
import { LearningObjectExample } from '../learning-object-example';
|
||||||
import { LearningObject } from '../../../../src/entities/content/learning-object.entity';
|
import { LearningObject } from '../../../../../src/entities/content/learning-object.entity';
|
||||||
import { loadTestAsset } from '../../../test-utils/load-test-asset';
|
import { loadTestAsset } from '../../../../test-utils/load-test-asset';
|
||||||
import { envVars, getEnvVar } from '../../../../src/util/envVars';
|
import { envVars, getEnvVar } from '../../../../../src/util/envVars';
|
||||||
import { Language } from '@dwengo-1/common/util/language';
|
import { Language } from '@dwengo-1/common/dist/util/language';
|
||||||
import { DwengoContentType } from '../../../../src/services/learning-objects/processing/content-type';
|
import { DwengoContentType } from '../../../../../src/services/learning-objects/processing/content-type';
|
||||||
|
|
||||||
const example: LearningObjectExample = {
|
const example: LearningObjectExample = {
|
||||||
createLearningObject: () => {
|
createLearningObject: () => {
|
|
@ -1,5 +1,5 @@
|
||||||
::MC basic::
|
::MC basic::
|
||||||
Are you following along well with the class? {
|
Are you following along well? {
|
||||||
~No, it's very difficult to follow along.
|
~No, it's very difficult to follow along.
|
||||||
=Yes, no problem!
|
=Yes, no problem!
|
||||||
}
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
<div class="learning-object-gift">
|
<div class="learning-object-gift">
|
||||||
<div id="gift-q1" class="gift-question">
|
<div id="gift-q1" class="gift-question">
|
||||||
<h2 id="gift-q1-title" class="gift-title">MC basic</h2>
|
<h2 id="gift-q1-title" class="gift-title">MC basic</h2>
|
||||||
<p id="gift-q1-stem" class="gift-stem">Are you following along well with the class?</p>
|
<p id="gift-q1-stem" class="gift-stem">Are you following along well?</p>
|
||||||
<div class="gift-choice-div">
|
<div class="gift-choice-div">
|
||||||
<input value="0" name="gift-q1-choices" id="gift-q1-choice-0" type="radio">
|
<input value="0" name="gift-q1-choices" id="gift-q1-choice-0" type="radio">
|
||||||
<label for="gift-q1-choice-0">[object Object]</label>
|
<label for="gift-q1-choice-0">[object Object]</label>
|
|
@ -1,9 +1,9 @@
|
||||||
import { LearningObjectExample } from '../learning-object-example';
|
import { LearningObjectExample } from '../learning-object-example';
|
||||||
import { LearningObject } from '../../../../src/entities/content/learning-object.entity';
|
import { LearningObject } from '../../../../../src/entities/content/learning-object.entity';
|
||||||
import { loadTestAsset } from '../../../test-utils/load-test-asset';
|
import { loadTestAsset } from '../../../../test-utils/load-test-asset';
|
||||||
import { envVars, getEnvVar } from '../../../../src/util/envVars';
|
import { envVars, getEnvVar } from '../../../../../src/util/envVars';
|
||||||
import { DwengoContentType } from '../../../../src/services/learning-objects/processing/content-type';
|
import { DwengoContentType } from '../../../../../src/services/learning-objects/processing/content-type';
|
||||||
import { Language } from '@dwengo-1/common/util/language';
|
import { Language } from '@dwengo-1/common/dist/util/language';
|
||||||
|
|
||||||
const example: LearningObjectExample = {
|
const example: LearningObjectExample = {
|
||||||
createLearningObject: () => {
|
createLearningObject: () => {
|
|
@ -1,15 +1,41 @@
|
||||||
import { EntityManager } from '@mikro-orm/core';
|
import {EntityManager, RequiredEntityData} from '@mikro-orm/core';
|
||||||
import {LearningObject} from '../../../src/entities/content/learning-object.entity';
|
import {LearningObject} from '../../../src/entities/content/learning-object.entity';
|
||||||
import {Language} from '@dwengo-1/common/util/language';
|
import {Language} from '@dwengo-1/common/util/language';
|
||||||
import {DwengoContentType} from '../../../src/services/learning-objects/processing/content-type';
|
import {DwengoContentType} from '../../../src/services/learning-objects/processing/content-type';
|
||||||
import {ReturnValue} from '../../../src/entities/content/return-value.entity';
|
import {ReturnValue} from '../../../src/entities/content/return-value.entity';
|
||||||
|
import {envVars, getEnvVar} from "../../../src/util/envVars";
|
||||||
|
import {loadTestAsset} from "../../test-utils/load-test-asset";
|
||||||
|
|
||||||
export function makeTestLearningObjects(em: EntityManager): LearningObject[] {
|
export function makeTestLearningObjects(em: EntityManager): LearningObject[] {
|
||||||
const returnValue: ReturnValue = new ReturnValue();
|
const returnValue: ReturnValue = new ReturnValue();
|
||||||
returnValue.callbackSchema = '';
|
returnValue.callbackSchema = '';
|
||||||
returnValue.callbackUrl = '';
|
returnValue.callbackUrl = '';
|
||||||
|
|
||||||
const learningObject01 = em.create(LearningObject, {
|
const learningObject01 = em.create(LearningObject, testLearningObject01);
|
||||||
|
const learningObject02 = em.create(LearningObject, testLearningObject02);
|
||||||
|
const learningObject03 = em.create(LearningObject, testLearningObject03);
|
||||||
|
const learningObject04 = em.create(LearningObject, testLearningObject04);
|
||||||
|
const learningObject05 = em.create(LearningObject, testLearningObject05);
|
||||||
|
|
||||||
|
const learningObjectMultipleChoice = em.create(LearningObject, testLearningObjectMultipleChoice);
|
||||||
|
const learningObjectEssayQuestion= em.create(LearningObject, testLearningObjectEssayQuestion);
|
||||||
|
|
||||||
|
const learningObjectPnNotebooks = em.create(LearningObject, testLearningObjectPnNotebooks);
|
||||||
|
|
||||||
|
return [
|
||||||
|
learningObject01, learningObject02, learningObject03, learningObject04, learningObject05,
|
||||||
|
learningObjectMultipleChoice, learningObjectEssayQuestion, learningObjectPnNotebooks
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createReturnValue(): ReturnValue {
|
||||||
|
const returnValue: ReturnValue = new ReturnValue();
|
||||||
|
returnValue.callbackSchema = '';
|
||||||
|
returnValue.callbackUrl = '';
|
||||||
|
return returnValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const testLearningObject01: RequiredEntityData<LearningObject> = {
|
||||||
hruid: 'id01',
|
hruid: 'id01',
|
||||||
language: Language.English,
|
language: Language.English,
|
||||||
version: 1,
|
version: 1,
|
||||||
|
@ -24,14 +50,14 @@ export function makeTestLearningObjects(em: EntityManager): LearningObject[] {
|
||||||
copyright: '',
|
copyright: '',
|
||||||
license: '',
|
license: '',
|
||||||
estimatedTime: 45,
|
estimatedTime: 45,
|
||||||
returnValue: returnValue,
|
returnValue: createReturnValue(),
|
||||||
available: true,
|
available: true,
|
||||||
contentLocation: '',
|
contentLocation: '',
|
||||||
attachments: [],
|
attachments: [],
|
||||||
content: Buffer.from("there's a shadow just behind me, shrouding every step i take, making every promise empty pointing every finger at me"),
|
content: Buffer.from("there's a shadow just behind me, shrouding every step i take, making every promise empty pointing every finger at me"),
|
||||||
});
|
};
|
||||||
|
|
||||||
const learningObject02 = em.create(LearningObject, {
|
export const testLearningObject02: RequiredEntityData<LearningObject> = {
|
||||||
hruid: 'id02',
|
hruid: 'id02',
|
||||||
language: Language.English,
|
language: Language.English,
|
||||||
version: 1,
|
version: 1,
|
||||||
|
@ -46,16 +72,16 @@ export function makeTestLearningObjects(em: EntityManager): LearningObject[] {
|
||||||
copyright: '',
|
copyright: '',
|
||||||
license: '',
|
license: '',
|
||||||
estimatedTime: 80,
|
estimatedTime: 80,
|
||||||
returnValue: returnValue,
|
returnValue: createReturnValue(),
|
||||||
available: true,
|
available: true,
|
||||||
contentLocation: '',
|
contentLocation: '',
|
||||||
attachments: [],
|
attachments: [],
|
||||||
content: Buffer.from(
|
content: Buffer.from(
|
||||||
"I've been crawling on my belly clearing out what could've been I've been wallowing in my own confused and insecure delusions"
|
"I've been crawling on my belly clearing out what could've been I've been wallowing in my own confused and insecure delusions"
|
||||||
),
|
),
|
||||||
});
|
};
|
||||||
|
|
||||||
const learningObject03 = em.create(LearningObject, {
|
export const testLearningObject03: RequiredEntityData<LearningObject> = {
|
||||||
hruid: 'id03',
|
hruid: 'id03',
|
||||||
language: Language.English,
|
language: Language.English,
|
||||||
version: 1,
|
version: 1,
|
||||||
|
@ -70,7 +96,7 @@ export function makeTestLearningObjects(em: EntityManager): LearningObject[] {
|
||||||
copyright: '',
|
copyright: '',
|
||||||
license: '',
|
license: '',
|
||||||
estimatedTime: 55,
|
estimatedTime: 55,
|
||||||
returnValue: returnValue,
|
returnValue: createReturnValue(),
|
||||||
available: true,
|
available: true,
|
||||||
contentLocation: '',
|
contentLocation: '',
|
||||||
attachments: [],
|
attachments: [],
|
||||||
|
@ -80,9 +106,9 @@ export function makeTestLearningObjects(em: EntityManager): LearningObject[] {
|
||||||
come back and see me later next patient please \
|
come back and see me later next patient please \
|
||||||
send in another victim of industrial disease'
|
send in another victim of industrial disease'
|
||||||
),
|
),
|
||||||
});
|
};
|
||||||
|
|
||||||
const learningObject04 = em.create(LearningObject, {
|
export const testLearningObject04: RequiredEntityData<LearningObject> = {
|
||||||
hruid: 'id04',
|
hruid: 'id04',
|
||||||
language: Language.English,
|
language: Language.English,
|
||||||
version: 1,
|
version: 1,
|
||||||
|
@ -97,7 +123,7 @@ export function makeTestLearningObjects(em: EntityManager): LearningObject[] {
|
||||||
copyright: '',
|
copyright: '',
|
||||||
license: '',
|
license: '',
|
||||||
estimatedTime: 55,
|
estimatedTime: 55,
|
||||||
returnValue: returnValue,
|
returnValue: createReturnValue(),
|
||||||
available: true,
|
available: true,
|
||||||
contentLocation: '',
|
contentLocation: '',
|
||||||
attachments: [],
|
attachments: [],
|
||||||
|
@ -107,9 +133,9 @@ export function makeTestLearningObjects(em: EntityManager): LearningObject[] {
|
||||||
I had the one-arm bandit fever \
|
I had the one-arm bandit fever \
|
||||||
There was an arrow through my heart and my soul'
|
There was an arrow through my heart and my soul'
|
||||||
),
|
),
|
||||||
});
|
};
|
||||||
|
|
||||||
const learningObject05 = em.create(LearningObject, {
|
export const testLearningObject05: RequiredEntityData<LearningObject> = {
|
||||||
hruid: 'id05',
|
hruid: 'id05',
|
||||||
language: Language.English,
|
language: Language.English,
|
||||||
version: 1,
|
version: 1,
|
||||||
|
@ -124,12 +150,103 @@ export function makeTestLearningObjects(em: EntityManager): LearningObject[] {
|
||||||
copyright: '',
|
copyright: '',
|
||||||
license: '',
|
license: '',
|
||||||
estimatedTime: 55,
|
estimatedTime: 55,
|
||||||
returnValue: returnValue,
|
returnValue: createReturnValue(),
|
||||||
available: true,
|
available: true,
|
||||||
contentLocation: '',
|
contentLocation: '',
|
||||||
attachments: [],
|
attachments: [],
|
||||||
content: Buffer.from('calling Elvis, is anybody home, calling elvis, I am here all alone'),
|
content: Buffer.from('calling Elvis, is anybody home, calling elvis, I am here all alone'),
|
||||||
});
|
};
|
||||||
|
|
||||||
return [learningObject01, learningObject02, learningObject03, learningObject04, learningObject05];
|
export const testLearningObjectMultipleChoice: RequiredEntityData<LearningObject> = {
|
||||||
|
hruid: `${getEnvVar(envVars.UserContentPrefix)}test_multiple_choice`,
|
||||||
|
language: Language.English,
|
||||||
|
version: 1,
|
||||||
|
title: "Self-evaluation",
|
||||||
|
description: "Time to evaluate how well you understand what you've learned so far.",
|
||||||
|
keywords: ["test"],
|
||||||
|
teacherExclusive: false,
|
||||||
|
skosConcepts: [],
|
||||||
|
educationalGoals: [],
|
||||||
|
copyright: "Groep 1 SEL-2 2025",
|
||||||
|
license: "CC0",
|
||||||
|
difficulty: 1,
|
||||||
|
estimatedTime: 1,
|
||||||
|
attachments: [],
|
||||||
|
available: true,
|
||||||
|
targetAges: [10, 11, 12, 13, 14, 15, 16, 17, 18],
|
||||||
|
admins: [],
|
||||||
|
contentType: DwengoContentType.GIFT,
|
||||||
|
content: loadTestAsset('content/learning-object-resources/test-multiple-choice/content.txt'),
|
||||||
|
returnValue: {
|
||||||
|
callbackUrl: `%SUBMISSION%`,
|
||||||
|
callbackSchema: '["antwoord vraag 1"]',
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const testLearningObjectEssayQuestion: RequiredEntityData<LearningObject> = {
|
||||||
|
hruid: `${getEnvVar(envVars.UserContentPrefix)}test_essay_question`,
|
||||||
|
language: Language.English,
|
||||||
|
version: 1,
|
||||||
|
title: "Reflection",
|
||||||
|
description: "Reflect on your learning progress.",
|
||||||
|
keywords: ["test"],
|
||||||
|
teacherExclusive: false,
|
||||||
|
skosConcepts: [],
|
||||||
|
educationalGoals: [],
|
||||||
|
copyright: "Groep 1 SEL-2 2025",
|
||||||
|
license: "CC0",
|
||||||
|
difficulty: 1,
|
||||||
|
estimatedTime: 1,
|
||||||
|
attachments: [],
|
||||||
|
available: true,
|
||||||
|
targetAges: [10, 11, 12, 13, 14, 15, 16, 17, 18],
|
||||||
|
admins: [],
|
||||||
|
contentType: DwengoContentType.GIFT,
|
||||||
|
content: loadTestAsset('content/learning-object-resources/test-essay/content.txt'),
|
||||||
|
returnValue: {
|
||||||
|
callbackUrl: `%SUBMISSION%`,
|
||||||
|
callbackSchema: '["antwoord vraag 1"]',
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const testLearningObjectPnNotebooks: RequiredEntityData<LearningObject> = {
|
||||||
|
hruid: `${getEnvVar(envVars.UserContentPrefix)}pn_werkingnotebooks`,
|
||||||
|
version: 3,
|
||||||
|
language: Language.Dutch,
|
||||||
|
title: "Werken met notebooks",
|
||||||
|
description: "Leren werken met notebooks",
|
||||||
|
keywords: ["Python", "KIKS", "Wiskunde", "STEM", "AI"],
|
||||||
|
targetAges: [14, 15, 16, 17, 18],
|
||||||
|
admins: [],
|
||||||
|
copyright: "dwengo",
|
||||||
|
educationalGoals: [],
|
||||||
|
license: "dwengo",
|
||||||
|
contentType: DwengoContentType.TEXT_MARKDOWN,
|
||||||
|
difficulty: 3,
|
||||||
|
estimatedTime: 10,
|
||||||
|
uuid: "2adf9929-b424-4650-bf60-186f730d38ab",
|
||||||
|
teacherExclusive: false,
|
||||||
|
skosConcepts: [
|
||||||
|
"http://ilearn.ilabt.imec.be/vocab/curr1/s-vaktaal",
|
||||||
|
"http://ilearn.ilabt.imec.be/vocab/curr1/s-digitale-media-en-toepassingen",
|
||||||
|
"http://ilearn.ilabt.imec.be/vocab/curr1/s-computers-en-systemen",
|
||||||
|
],
|
||||||
|
attachments: [
|
||||||
|
{
|
||||||
|
name: "dwengo.png",
|
||||||
|
mimeType: "image/png",
|
||||||
|
content: loadTestAsset("/content/learning-object-resources/pn-werkingnotebooks/dwengo.png")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Knop.png",
|
||||||
|
mimeType: "image/png",
|
||||||
|
content: loadTestAsset("/content/learning-object-resources/pn-werkingnotebooks/Knop.png")
|
||||||
|
}
|
||||||
|
],
|
||||||
|
available: false,
|
||||||
|
content: loadTestAsset("/content/learning-object-resources/pn-werkingnotebooks/content.md"),
|
||||||
|
returnValue: {
|
||||||
|
callbackUrl: "%SUBMISSION%",
|
||||||
|
callbackSchema: "[]"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,100 +1,237 @@
|
||||||
import {EntityManager} from '@mikro-orm/core';
|
import {EntityManager} from '@mikro-orm/core';
|
||||||
import {LearningPath} from '../../../src/entities/content/learning-path.entity';
|
import {LearningPath} from '../../../src/entities/content/learning-path.entity';
|
||||||
import {Language} from '@dwengo-1/common/util/language';
|
import {Language} from '@dwengo-1/common/util/language';
|
||||||
import { LearningPathTransition } from '../../../src/entities/content/learning-path-transition.entity';
|
import {mapToLearningPath} from "../../../src/services/learning-paths/learning-path-service";
|
||||||
import { LearningPathNode } from '../../../src/entities/content/learning-path-node.entity';
|
import {envVars, getEnvVar} from "../../../src/util/envVars";
|
||||||
|
import {LearningPath as LearningPathDTO} from "@dwengo-1/common/interfaces/learning-content";
|
||||||
|
import {
|
||||||
|
testLearningObject01, testLearningObject02, testLearningObject03, testLearningObject04, testLearningObject05,
|
||||||
|
testLearningObjectEssayQuestion,
|
||||||
|
testLearningObjectMultipleChoice, testLearningObjectPnNotebooks
|
||||||
|
} from "./learning-objects.testdata";
|
||||||
|
|
||||||
export function makeTestLearningPaths(em: EntityManager): LearningPath[] {
|
export function makeTestLearningPaths(_em: EntityManager): LearningPath[] {
|
||||||
const learningPathNode01: LearningPathNode = new LearningPathNode();
|
const learningPath01 = mapToLearningPath(testLearningPath01, []);
|
||||||
const learningPathNode02: LearningPathNode = new LearningPathNode();
|
const learningPath02 = mapToLearningPath(testLearningPath02, []);
|
||||||
const learningPathNode03: LearningPathNode = new LearningPathNode();
|
|
||||||
const learningPathNode04: LearningPathNode = new LearningPathNode();
|
|
||||||
const learningPathNode05: LearningPathNode = new LearningPathNode();
|
|
||||||
|
|
||||||
const transitions01: LearningPathTransition = new LearningPathTransition();
|
const partiallyDatabasePartiallyDwengoApiLearningPath
|
||||||
const transitions02: LearningPathTransition = new LearningPathTransition();
|
= mapToLearningPath(testPartiallyDatabaseAndPartiallyDwengoApiLearningPath, [])
|
||||||
const transitions03: LearningPathTransition = new LearningPathTransition();
|
const learningPathWithConditions = mapToLearningPath(testLearningPathWithConditions, [])
|
||||||
const transitions04: LearningPathTransition = new LearningPathTransition();
|
|
||||||
const transitions05: LearningPathTransition = new LearningPathTransition();
|
|
||||||
|
|
||||||
transitions01.condition = 'true';
|
return [
|
||||||
transitions01.next = learningPathNode02;
|
learningPath01,
|
||||||
|
learningPath02,
|
||||||
transitions02.condition = 'true';
|
partiallyDatabasePartiallyDwengoApiLearningPath,
|
||||||
transitions02.next = learningPathNode02;
|
learningPathWithConditions
|
||||||
|
|
||||||
transitions03.condition = 'true';
|
|
||||||
transitions03.next = learningPathNode04;
|
|
||||||
|
|
||||||
transitions04.condition = 'true';
|
|
||||||
transitions04.next = learningPathNode05;
|
|
||||||
|
|
||||||
transitions05.condition = 'true';
|
|
||||||
transitions05.next = learningPathNode05;
|
|
||||||
|
|
||||||
learningPathNode01.instruction = '';
|
|
||||||
learningPathNode01.language = Language.English;
|
|
||||||
learningPathNode01.learningObjectHruid = 'id01';
|
|
||||||
learningPathNode01.startNode = true;
|
|
||||||
learningPathNode01.transitions = [transitions01];
|
|
||||||
learningPathNode01.version = 1;
|
|
||||||
|
|
||||||
learningPathNode02.instruction = '';
|
|
||||||
learningPathNode02.language = Language.English;
|
|
||||||
learningPathNode02.learningObjectHruid = 'id02';
|
|
||||||
learningPathNode02.startNode = false;
|
|
||||||
learningPathNode02.transitions = [transitions02];
|
|
||||||
learningPathNode02.version = 1;
|
|
||||||
|
|
||||||
learningPathNode03.instruction = '';
|
|
||||||
learningPathNode03.language = Language.English;
|
|
||||||
learningPathNode03.learningObjectHruid = 'id03';
|
|
||||||
learningPathNode03.startNode = true;
|
|
||||||
learningPathNode03.transitions = [transitions03];
|
|
||||||
learningPathNode03.version = 1;
|
|
||||||
|
|
||||||
learningPathNode04.instruction = '';
|
|
||||||
learningPathNode04.language = Language.English;
|
|
||||||
learningPathNode04.learningObjectHruid = 'id04';
|
|
||||||
learningPathNode04.startNode = false;
|
|
||||||
learningPathNode04.transitions = [transitions04];
|
|
||||||
learningPathNode04.version = 1;
|
|
||||||
|
|
||||||
learningPathNode05.instruction = '';
|
|
||||||
learningPathNode05.language = Language.English;
|
|
||||||
learningPathNode05.learningObjectHruid = 'id05';
|
|
||||||
learningPathNode05.startNode = false;
|
|
||||||
learningPathNode05.transitions = [transitions05];
|
|
||||||
learningPathNode05.version = 1;
|
|
||||||
|
|
||||||
const nodes01: LearningPathNode[] = [
|
|
||||||
// LearningPathNode01,
|
|
||||||
// LearningPathNode02,
|
|
||||||
];
|
];
|
||||||
const learningPath01 = em.create(LearningPath, {
|
}
|
||||||
hruid: 'id01',
|
|
||||||
language: Language.English,
|
const nowString = new Date().toString();
|
||||||
admins: [],
|
|
||||||
title: 'repertoire Tool',
|
export const testLearningPath01: LearningPathDTO = {
|
||||||
description: 'all about Tool',
|
keywords: "test",
|
||||||
image: null,
|
target_ages: [16, 17, 18],
|
||||||
nodes: nodes01,
|
hruid: "id01",
|
||||||
});
|
language: Language.English,
|
||||||
|
title: "repertoire Tool",
|
||||||
const nodes02: LearningPathNode[] = [
|
description: "all about Tool",
|
||||||
// LearningPathNode03,
|
nodes: [
|
||||||
// LearningPathNode04,
|
{
|
||||||
// LearningPathNode05,
|
learningobject_hruid: testLearningObject01.hruid,
|
||||||
];
|
language: testLearningObject01.language,
|
||||||
const learningPath02 = em.create(LearningPath, {
|
version: testLearningObject01.version,
|
||||||
hruid: 'id02',
|
start_node: true,
|
||||||
language: Language.English,
|
created_at: nowString,
|
||||||
admins: [],
|
updatedAt: nowString,
|
||||||
title: 'repertoire Dire Straits',
|
transitions: [
|
||||||
description: 'all about Dire Straits',
|
{
|
||||||
image: null,
|
next: {
|
||||||
nodes: nodes02,
|
hruid: testLearningObject02.hruid,
|
||||||
});
|
language: testLearningObject02.language,
|
||||||
|
version: testLearningObject02.version
|
||||||
return [learningPath01, learningPath02];
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
learningobject_hruid: testLearningObject02.hruid,
|
||||||
|
language: testLearningObject02.language,
|
||||||
|
version: testLearningObject02.version,
|
||||||
|
created_at: nowString,
|
||||||
|
updatedAt: nowString,
|
||||||
|
transitions: []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
export const testLearningPath02: LearningPathDTO = {
|
||||||
|
keywords: "test",
|
||||||
|
target_ages: [16, 17, 18],
|
||||||
|
hruid: "id02",
|
||||||
|
language: Language.English,
|
||||||
|
title: "repertoire Dire Straits",
|
||||||
|
description: "all about Dire Straits",
|
||||||
|
nodes: [
|
||||||
|
{
|
||||||
|
learningobject_hruid: testLearningObject03.hruid,
|
||||||
|
language: testLearningObject03.language,
|
||||||
|
version: testLearningObject03.version,
|
||||||
|
start_node: true,
|
||||||
|
created_at: nowString,
|
||||||
|
updatedAt: nowString,
|
||||||
|
transitions: [
|
||||||
|
{
|
||||||
|
next: {
|
||||||
|
hruid: testLearningObject04.hruid,
|
||||||
|
language: testLearningObject04.language,
|
||||||
|
version: testLearningObject04.version
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
learningobject_hruid: testLearningObject04.hruid,
|
||||||
|
language: testLearningObject04.language,
|
||||||
|
version: testLearningObject04.version,
|
||||||
|
created_at: nowString,
|
||||||
|
updatedAt: nowString,
|
||||||
|
transitions: [
|
||||||
|
{
|
||||||
|
next: {
|
||||||
|
hruid: testLearningObject05.hruid,
|
||||||
|
language: testLearningObject05.language,
|
||||||
|
version: testLearningObject05.version
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
learningobject_hruid: testLearningObject05.hruid,
|
||||||
|
language: testLearningObject05.language,
|
||||||
|
version: testLearningObject05.version,
|
||||||
|
created_at: nowString,
|
||||||
|
updatedAt: nowString,
|
||||||
|
transitions: []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
export const testPartiallyDatabaseAndPartiallyDwengoApiLearningPath: LearningPathDTO = {
|
||||||
|
hruid: `${getEnvVar(envVars.UserContentPrefix)}pn_werking`,
|
||||||
|
title: "Werken met notebooks",
|
||||||
|
language: Language.Dutch,
|
||||||
|
description: 'Een korte inleiding tot Python notebooks. Hoe ga je gemakkelijk en efficiënt met de notebooks aan de slag?',
|
||||||
|
keywords: "Python KIKS Wiskunde STEM AI",
|
||||||
|
target_ages: [14, 15, 16, 17, 18],
|
||||||
|
nodes: [
|
||||||
|
{
|
||||||
|
learningobject_hruid: testLearningObjectPnNotebooks.hruid,
|
||||||
|
language: testLearningObjectPnNotebooks.language,
|
||||||
|
version: testLearningObjectPnNotebooks.version,
|
||||||
|
start_node: true,
|
||||||
|
created_at: nowString,
|
||||||
|
updatedAt: nowString,
|
||||||
|
transitions: [
|
||||||
|
{
|
||||||
|
default: true,
|
||||||
|
next: {
|
||||||
|
hruid: "pn_werkingnotebooks2",
|
||||||
|
language: Language.Dutch,
|
||||||
|
version: 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
learningobject_hruid: "pn_werkingnotebooks2",
|
||||||
|
language: Language.Dutch,
|
||||||
|
version: 3,
|
||||||
|
created_at: nowString,
|
||||||
|
updatedAt: nowString,
|
||||||
|
transitions: [
|
||||||
|
{
|
||||||
|
default: true,
|
||||||
|
next: {
|
||||||
|
hruid: "pn_werkingnotebooks3",
|
||||||
|
language: Language.Dutch,
|
||||||
|
version: 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
learningobject_hruid: "pn_werkingnotebooks3",
|
||||||
|
language: Language.Dutch,
|
||||||
|
version: 3,
|
||||||
|
created_at: nowString,
|
||||||
|
updatedAt: nowString,
|
||||||
|
transitions: []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
export const testLearningPathWithConditions: LearningPathDTO = {
|
||||||
|
hruid: `${getEnvVar(envVars.UserContentPrefix)}test_conditions`,
|
||||||
|
language: Language.English,
|
||||||
|
title: 'Example learning path with conditional transitions',
|
||||||
|
description: 'This learning path was made for the purpose of testing conditional transitions',
|
||||||
|
keywords: "test",
|
||||||
|
target_ages: [18, 19, 20, 21],
|
||||||
|
nodes: [
|
||||||
|
{
|
||||||
|
learningobject_hruid: testLearningObjectMultipleChoice.hruid,
|
||||||
|
language: testLearningObjectMultipleChoice.language,
|
||||||
|
version: testLearningObjectMultipleChoice.version,
|
||||||
|
start_node: true,
|
||||||
|
created_at: nowString,
|
||||||
|
updatedAt: nowString,
|
||||||
|
transitions: [
|
||||||
|
{
|
||||||
|
// If the answer to the first question was the first one (It's difficult to follow along):
|
||||||
|
condition: '$[?(@[0] == 0)]',
|
||||||
|
next: {
|
||||||
|
//... we let the student do an extra exercise.
|
||||||
|
hruid: testLearningObject01.hruid,
|
||||||
|
language: testLearningObject01.language,
|
||||||
|
version: testLearningObject01.version
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// If the answer to the first question was the second one (I can follow along):
|
||||||
|
condition: '$[?(@[0] == 1)]',
|
||||||
|
next: {
|
||||||
|
//... we let the student right through to the final question.
|
||||||
|
hruid: testLearningObjectEssayQuestion.hruid,
|
||||||
|
language: testLearningObjectEssayQuestion.language,
|
||||||
|
version: testLearningObjectEssayQuestion.version
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
learningobject_hruid: testLearningObject01.hruid,
|
||||||
|
language: testLearningObject01.language,
|
||||||
|
version: testLearningObject01.version,
|
||||||
|
created_at: nowString,
|
||||||
|
updatedAt: nowString,
|
||||||
|
transitions: [
|
||||||
|
{
|
||||||
|
default: true,
|
||||||
|
next: {
|
||||||
|
hruid: testLearningObjectEssayQuestion.hruid,
|
||||||
|
language: testLearningObjectEssayQuestion.language,
|
||||||
|
version: testLearningObjectEssayQuestion.version
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
learningobject_hruid: testLearningObjectEssayQuestion.hruid,
|
||||||
|
language: testLearningObjectEssayQuestion.language,
|
||||||
|
version: testLearningObjectEssayQuestion.version,
|
||||||
|
created_at: nowString,
|
||||||
|
updatedAt: nowString,
|
||||||
|
transitions: []
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ export interface Transition {
|
||||||
version: number;
|
version: number;
|
||||||
language: string;
|
language: string;
|
||||||
};
|
};
|
||||||
|
condition?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LearningObjectIdentifierDTO {
|
export interface LearningObjectIdentifierDTO {
|
||||||
|
@ -18,7 +19,7 @@ export interface LearningObjectIdentifierDTO {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LearningObjectNode {
|
export interface LearningObjectNode {
|
||||||
_id: string;
|
_id?: string;
|
||||||
learningobject_hruid: string;
|
learningobject_hruid: string;
|
||||||
version: number;
|
version: number;
|
||||||
language: Language;
|
language: Language;
|
||||||
|
@ -30,20 +31,20 @@ export interface LearningObjectNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LearningPath {
|
export interface LearningPath {
|
||||||
_id: string;
|
_id?: string;
|
||||||
language: string;
|
language: string;
|
||||||
hruid: string;
|
hruid: string;
|
||||||
title: string;
|
title: string;
|
||||||
description: string;
|
description: string;
|
||||||
image?: string; // Image might be missing, so it's optional
|
image?: string; // Image might be missing, so it's optional
|
||||||
num_nodes: number;
|
num_nodes?: number;
|
||||||
num_nodes_left: number;
|
num_nodes_left?: number;
|
||||||
nodes: LearningObjectNode[];
|
nodes: LearningObjectNode[];
|
||||||
keywords: string;
|
keywords: string;
|
||||||
target_ages: number[];
|
target_ages: number[];
|
||||||
min_age: number;
|
min_age?: number;
|
||||||
max_age: number;
|
max_age?: number;
|
||||||
__order: number;
|
__order?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LearningPathIdentifier {
|
export interface LearningPathIdentifier {
|
||||||
|
@ -62,8 +63,8 @@ export interface ReturnValue {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LearningObjectMetadata {
|
export interface LearningObjectMetadata {
|
||||||
_id: string;
|
_id?: string;
|
||||||
uuid: string;
|
uuid?: string;
|
||||||
hruid: string;
|
hruid: string;
|
||||||
version: number;
|
version: number;
|
||||||
language: Language;
|
language: Language;
|
||||||
|
@ -84,7 +85,7 @@ export interface LearningObjectMetadata {
|
||||||
|
|
||||||
export interface FilteredLearningObject {
|
export interface FilteredLearningObject {
|
||||||
key: string;
|
key: string;
|
||||||
_id: string;
|
_id?: string;
|
||||||
uuid: string;
|
uuid: string;
|
||||||
version: number;
|
version: number;
|
||||||
title: string;
|
title: string;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue