test(backend): Testen voor DatabaseLearningObjectProvider.getLearningObjectHTML toegevoegd.
Hierbij optredende problemen ook opgelost.
This commit is contained in:
parent
a3b995393b
commit
91e3b5ad91
15 changed files with 103 additions and 60 deletions
|
@ -1,12 +1,13 @@
|
|||
/**
|
||||
* Based on https://github.com/dwengovzw/Learning-Object-Repository/blob/main/app/processors/audio/audio_processor.js
|
||||
*/
|
||||
import Processor from "../processor.js";
|
||||
|
||||
import DOMPurify from 'isomorphic-dompurify';
|
||||
import {type} from "node:os";
|
||||
import {DwengoContentType} from "../content-type";
|
||||
import {StringProcessor} from "../string-processor";
|
||||
|
||||
class AudioProcessor extends Processor<string> {
|
||||
class AudioProcessor extends StringProcessor {
|
||||
|
||||
constructor() {
|
||||
super(DwengoContentType.AUDIO_MPEG);
|
||||
|
|
|
@ -2,13 +2,13 @@
|
|||
* Based on https://github.com/dwengovzw/Learning-Object-Repository/blob/main/app/processors/extern/extern_processor.js
|
||||
*/
|
||||
|
||||
import Processor from "../processor.js";
|
||||
import DOMPurify from 'isomorphic-dompurify';
|
||||
import {ProcessingError} from "../processing-error";
|
||||
import {isValidHttpUrl} from "../../../../util/links";
|
||||
import {DwengoContentType} from "../content-type";
|
||||
import {StringProcessor} from "../string-processor";
|
||||
|
||||
class ExternProcessor extends Processor<string> {
|
||||
class ExternProcessor extends StringProcessor {
|
||||
constructor() {
|
||||
super(DwengoContentType.EXTERN);
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
* Based on https://github.com/dwengovzw/Learning-Object-Repository/blob/main/app/processors/gift/gift_processor.js
|
||||
*/
|
||||
|
||||
import Processor from "../processor.js";
|
||||
import DOMPurify from 'isomorphic-dompurify';
|
||||
import {GIFTQuestion, parse} from "gift-pegjs"
|
||||
import {DwengoContentType} from "../content-type";
|
||||
|
@ -15,8 +14,9 @@ import {MatchingQuestionRenderer} from "./question-renderers/matching-question-r
|
|||
import {NumericalQuestionRenderer} from "./question-renderers/numerical-question-renderer";
|
||||
import {ShortQuestionRenderer} from "./question-renderers/short-question-renderer";
|
||||
import {TrueFalseQuestionRenderer} from "./question-renderers/true-false-question-renderer";
|
||||
import {StringProcessor} from "../string-processor";
|
||||
|
||||
class GiftProcessor extends Processor<string> {
|
||||
class GiftProcessor extends StringProcessor {
|
||||
|
||||
private renderers: RendererMap = {
|
||||
Category: new CategoryQuestionRenderer(),
|
||||
|
|
|
@ -2,13 +2,13 @@
|
|||
* Based on https://github.com/dwengovzw/Learning-Object-Repository/blob/main/app/processors/image/inline_image_processor.js
|
||||
*/
|
||||
|
||||
import Processor from "../processor.js";
|
||||
import DOMPurify from 'isomorphic-dompurify';
|
||||
import {DwengoContentType} from "../content-type.js";
|
||||
import {ProcessingError} from "../processing-error.js";
|
||||
import {isValidHttpUrl} from "../../../../util/links";
|
||||
import {StringProcessor} from "../string-processor";
|
||||
|
||||
class InlineImageProcessor extends Processor<string> {
|
||||
class InlineImageProcessor extends StringProcessor {
|
||||
constructor(contentType: DwengoContentType = DwengoContentType.IMAGE_INLINE) {
|
||||
super(contentType);
|
||||
}
|
||||
|
|
|
@ -42,45 +42,43 @@ function extractLearningObjectIdFromHref(href: string): LearningObjectIdentifier
|
|||
* - embeddings of other learning objects.
|
||||
*/
|
||||
const dwengoMarkedRenderer: RendererObject = {
|
||||
heading(heading: Heading) {
|
||||
heading(heading: Heading): string {
|
||||
const text = heading.text;
|
||||
const level = heading.depth;
|
||||
const escapedText = text.toLowerCase().replace(/[^\w]+/g, '-');
|
||||
|
||||
return `
|
||||
<h${level}>
|
||||
<a name="${escapedText}" class="anchor" href="#${escapedText}">
|
||||
<span class="header-link"></span>
|
||||
</a>
|
||||
${text}
|
||||
</h${level}>`;
|
||||
return `<h${level}>\n` +
|
||||
` <a name="${escapedText}" class="anchor" href="#${escapedText}">\n` +
|
||||
` <span class="header-link"></span>\n` +
|
||||
` </a>\n` +
|
||||
` ${text}\n` +
|
||||
`</h${level}>\n`
|
||||
},
|
||||
|
||||
// When the syntax for a link is used => [text](href "title")
|
||||
// render a custom link when the prefix for a learning object is used.
|
||||
link(link: Link) {
|
||||
link(link: Link): string {
|
||||
const href = link.href;
|
||||
const title = link.title || "";
|
||||
const text = link.text;
|
||||
const text = marked.parseInline(link.text); // There could for example be an image in the link.
|
||||
|
||||
if (href.startsWith(prefixes.learningObject)) {
|
||||
// link to learning-object
|
||||
const learningObjectId = extractLearningObjectIdFromHref(href);
|
||||
return `
|
||||
<a href="${getUrlStringForLearningObjectHTML(learningObjectId)}]" target="_blank" title="${title}">${text}</a>
|
||||
`;
|
||||
return `<a href="${getUrlStringForLearningObjectHTML(learningObjectId)}" target="_blank" title="${title}">${text}</a>`;
|
||||
} else {
|
||||
// any other link
|
||||
if (!isValidHttpUrl(href)) {
|
||||
throw new ProcessingError("Link is not a valid HTTP URL!");
|
||||
}
|
||||
//<a href="https://kiks.ilabt.imec.be/hub/tmplogin?id=0101" title="Notebooks Werking"><img src="Knop.png" alt="" title="Knop"></a>
|
||||
return `<a href="${href}" target="_blank" title="${title}">${text}</a>`;
|
||||
}
|
||||
},
|
||||
|
||||
// When the syntax for an image is used => 
|
||||
// render a learning object, pdf, audio or video if a prefix is used.
|
||||
image(img: Image) {
|
||||
image(img: Image): string {
|
||||
const href = img.href;
|
||||
if (href.startsWith(prefixes.learningObject)) {
|
||||
// embedded learning-object
|
||||
|
|
|
@ -2,14 +2,14 @@
|
|||
* Based on https://github.com/dwengovzw/Learning-Object-Repository/blob/main/app/processors/markdown/markdown_processor.js
|
||||
*/
|
||||
|
||||
import {marked} from 'marked'
|
||||
import Processor from '../processor.js';
|
||||
import {marked} from 'marked';
|
||||
import InlineImageProcessor from '../image/inline-image-processor.js';
|
||||
import {DwengoContentType} from "../content-type";
|
||||
import {ProcessingError} from "../processing-error";
|
||||
import dwengoMarkedRenderer from "./dwengo-marked-renderer";
|
||||
import {StringProcessor} from "../string-processor";
|
||||
import {ProcessingError} from "../processing-error";
|
||||
|
||||
class MarkdownProcessor extends Processor<string> {
|
||||
class MarkdownProcessor extends StringProcessor {
|
||||
constructor() {
|
||||
super(DwengoContentType.TEXT_MARKDOWN);
|
||||
}
|
||||
|
@ -17,9 +17,9 @@ class MarkdownProcessor extends Processor<string> {
|
|||
override renderFn(mdText: string) {
|
||||
let html = "";
|
||||
try {
|
||||
mdText = this.replaceLinks(mdText); // Replace html image links with path based on metadata
|
||||
marked.use({renderer: dwengoMarkedRenderer});
|
||||
html = marked(mdText, {async: false});
|
||||
html = this.replaceLinks(html); // Replace html image links path
|
||||
} catch (e: any) {
|
||||
throw new ProcessingError(e.message);
|
||||
}
|
||||
|
|
|
@ -2,13 +2,13 @@
|
|||
* Based on https://github.com/dwengovzw/Learning-Object-Repository/blob/main/app/processors/pdf/pdf_processor.js
|
||||
*/
|
||||
|
||||
import Processor from "../processor.js";
|
||||
import DOMPurify from 'isomorphic-dompurify';
|
||||
import {DwengoContentType} from "../content-type.js";
|
||||
import {isValidHttpUrl} from "../../../../util/links.js";
|
||||
import {ProcessingError} from "../processing-error.js";
|
||||
import {StringProcessor} from "../string-processor";
|
||||
|
||||
class PdfProcessor extends Processor<string> {
|
||||
class PdfProcessor extends StringProcessor {
|
||||
constructor() {
|
||||
super(DwengoContentType.APPLICATION_PDF);
|
||||
}
|
||||
|
|
|
@ -48,7 +48,6 @@ abstract class Processor<T> {
|
|||
|
||||
/**
|
||||
* Function which actually executes the rendering of a learning object.
|
||||
* By default, this just means rendering the content in the content property of the learning object.
|
||||
*
|
||||
* When implementing this function, we may assume that we are responsible for the content type of the learning
|
||||
* object.
|
||||
|
@ -56,9 +55,7 @@ abstract class Processor<T> {
|
|||
* @param toRender Learning object to render
|
||||
* @protected
|
||||
*/
|
||||
protected renderLearningObjectFn(toRender: LearningObject): string {
|
||||
return this.render(toRender.content as T);
|
||||
}
|
||||
protected abstract renderLearningObjectFn(toRender: LearningObject): string;
|
||||
}
|
||||
|
||||
export default Processor;
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
import Processor from "./processor";
|
||||
import {LearningObject} from "../../../entities/content/learning-object.entity";
|
||||
|
||||
export abstract class StringProcessor extends Processor<string> {
|
||||
/**
|
||||
* Function which actually executes the rendering of a learning object.
|
||||
* By default, this just means rendering the content in the content property of the learning object (interpreted
|
||||
* as string)
|
||||
*
|
||||
* When implementing this function, we may assume that we are responsible for the content type of the learning
|
||||
* object.
|
||||
*
|
||||
* @param toRender Learning object to render
|
||||
* @protected
|
||||
*/
|
||||
protected renderLearningObjectFn(toRender: LearningObject): string {
|
||||
return this.render(toRender.content.toString("ascii"));
|
||||
}
|
||||
}
|
|
@ -2,11 +2,11 @@
|
|||
* Based on https://github.com/dwengovzw/Learning-Object-Repository/blob/main/app/processors/text/text_processor.js
|
||||
*/
|
||||
|
||||
import DOMPurify from 'isomorphic-dompurify'
|
||||
import Processor from "../processor.js"
|
||||
import DOMPurify from 'isomorphic-dompurify';
|
||||
import {DwengoContentType} from "../content-type.js";
|
||||
import {StringProcessor} from "../string-processor";
|
||||
|
||||
class TextProcessor extends Processor<string> {
|
||||
class TextProcessor extends StringProcessor {
|
||||
constructor() {
|
||||
super(DwengoContentType.TEXT_PLAIN);
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ import {LearningObjectIdentifier} from "../interfaces/learning-content";
|
|||
|
||||
export function isValidHttpUrl(url: string): boolean {
|
||||
try {
|
||||
const parsedUrl = new URL(url);
|
||||
const parsedUrl = new URL(url, "http://test.be");
|
||||
return parsedUrl.protocol === "http:" || parsedUrl.protocol === "https:";
|
||||
} catch (e) {
|
||||
return false;
|
||||
|
|
|
@ -25,28 +25,34 @@ describe("DatabaseLearningObjectProvider", () => {
|
|||
await setupTestApp();
|
||||
exampleLearningObject = await initExampleData();
|
||||
});
|
||||
|
||||
it("should return the learning object when it is queried by its id", async () => {
|
||||
const result: FilteredLearningObject | null = await databaseLearningObjectProvider.getLearningObjectById(exampleLearningObject);
|
||||
expect(result).toBeTruthy();
|
||||
expectToBeCorrectFilteredLearningObject(result!, exampleLearningObject);
|
||||
});
|
||||
|
||||
it("should return the learning object when it is queried by only hruid and language (but not version)", async () => {
|
||||
const result: FilteredLearningObject | null = await databaseLearningObjectProvider.getLearningObjectById({
|
||||
hruid: exampleLearningObject.hruid,
|
||||
language: exampleLearningObject.language
|
||||
describe("getLearningObjectById", () => {
|
||||
it("should return the learning object when it is queried by its id", async () => {
|
||||
const result: FilteredLearningObject | null = await databaseLearningObjectProvider.getLearningObjectById(exampleLearningObject);
|
||||
expect(result).toBeTruthy();
|
||||
expectToBeCorrectFilteredLearningObject(result!, exampleLearningObject);
|
||||
});
|
||||
expect(result).toBeTruthy();
|
||||
expectToBeCorrectFilteredLearningObject(result!, exampleLearningObject);
|
||||
});
|
||||
|
||||
it("should return null when queried with an id that does not exist", async () => {
|
||||
const result: FilteredLearningObject | null = await databaseLearningObjectProvider.getLearningObjectById({
|
||||
hruid: "non_existing_hruid",
|
||||
language: Language.Dutch
|
||||
it("should return the learning object when it is queried by only hruid and language (but not version)", async () => {
|
||||
const result: FilteredLearningObject | null = await databaseLearningObjectProvider.getLearningObjectById({
|
||||
hruid: exampleLearningObject.hruid,
|
||||
language: exampleLearningObject.language
|
||||
});
|
||||
expect(result).toBeTruthy();
|
||||
expectToBeCorrectFilteredLearningObject(result!, exampleLearningObject);
|
||||
});
|
||||
expect(result).toBeNull();
|
||||
});
|
||||
|
||||
it("should return null when queried with an id that does not exist", async () => {
|
||||
const result: FilteredLearningObject | null = await databaseLearningObjectProvider.getLearningObjectById({
|
||||
hruid: "non_existing_hruid",
|
||||
language: Language.Dutch
|
||||
});
|
||||
expect(result).toBeNull();
|
||||
});
|
||||
});
|
||||
describe("getLearningObjectHTML", () => {
|
||||
it("should return the correct rendering of the learning object", async () => {
|
||||
const result = await databaseLearningObjectProvider.getLearningObjectHTML(exampleLearningObject);
|
||||
expect(result).toEqual(example.getHTMLRendering());
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -3,5 +3,6 @@ import {Attachment} from "../../../src/entities/content/attachment.entity";
|
|||
|
||||
type LearningObjectExample = {
|
||||
createLearningObject: () => LearningObject,
|
||||
createAttachment: {[key: string]: (owner: LearningObject) => Attachment}
|
||||
createAttachment: {[key: string]: (owner: LearningObject) => Attachment},
|
||||
getHTMLRendering: () => string
|
||||
};
|
||||
|
|
|
@ -45,7 +45,7 @@ const example: LearningObjectExample = {
|
|||
|
||||
learningObject.returnValue = returnValue;
|
||||
learningObject.available = true;
|
||||
learningObject.content = loadTestAsset(`${ASSETS_PREFIX}/dwengo.png`);
|
||||
learningObject.content = loadTestAsset(`${ASSETS_PREFIX}/content.md`);
|
||||
|
||||
return learningObject
|
||||
},
|
||||
|
@ -66,6 +66,7 @@ const example: LearningObjectExample = {
|
|||
att.content = loadTestAsset(`${ASSETS_PREFIX}/Knop.png`)
|
||||
return att;
|
||||
}
|
||||
}
|
||||
},
|
||||
getHTMLRendering: () => loadTestAsset(`${ASSETS_PREFIX}/rendering.html`).toString()
|
||||
}
|
||||
export default example;
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
<h1>
|
||||
<a name="werken-met-notebooks" class="anchor" href="#werken-met-notebooks">
|
||||
<span class="header-link"></span>
|
||||
</a>
|
||||
Werken met notebooks
|
||||
</h1>
|
||||
<p>Het lesmateriaal van 'Python in wiskunde en STEM' wordt aangeboden in de vorm van interactieve <strong><em>notebooks</em></strong>. Notebooks zijn <em>digitale documenten</em> die zowel uitvoerbare code bevatten als tekst, afbeeldingen, video, hyperlinks ...</p>
|
||||
<p><em>Nieuwe begrippen</em> worden aangebracht via tekstuele uitleg, video en afbeeldingen.</p>
|
||||
<p>Er zijn uitgewerkte <em>voorbeelden</em> met daarnaast ook kleine en grote <em>opdrachten</em>. In deze opdrachten zal je aangereikte code kunnen uitvoeren, maar ook zelf code opstellen.</p>
|
||||
<p>De code die in de notebooks gebruikt wordt, is Python versie 3. We kozen voor Python omdat dit een heel toegankelijke programmeertaal is, die vaak ook intuC/tief is.
|
||||
Python is bovendien bezig aan een opmars en wordt gebruikt door bedrijven, zoals Google, NASA, Netflix, Uber, AstraZeneca, Barco, Instagram en YouTube.</p>
|
||||
<p>We kozen voor notebooks omdat daar enkele belangrijke voordelen aan verbonden zijn: leerkrachten moeten geen geavanceerde installaties doen om de notebooks te gebruiken, leerkrachten kunnen verschillende soorten van lesinhouden aanbieden via C)C)n platform, de notebooks zijn interactief, leerlingen bouwen de oplossing van een probleem stap voor stap op in de notebook waardoor dat proces zichtbaar is voor de leerkracht (<a href="https://libstore.ugent.be/fulltxt/RUG01/003/151/437/RUG01-003151437_2023_0001_AC.pdf" target="_blank" title="">Jeroen Van der Hooft, 2023</a>).</p>
|
||||
<hr>
|
||||
<p>Klik je op onderstaande knop 'Open notebooks', dan word je doorgestuurd naar een andere website waar jouw persoonlijke notebooks ingeladen worden. (Dit kan even duren.)</p>
|
||||
<p>Links op het scherm vind je er twee bestanden met extensie <em>.ipynb</em>.
|
||||
Dit zijn de twee notebooks waarin je resp. een overzicht krijgt van de opbouw en mogelijkheden en hoe je er mee aan de slag kan. Dubbelklik op de bestandsnaam om een notebook te openen.</p>
|
||||
<p>Je ziet er ook een map <em>images</em> met de afbeeldingen die in de notebooks getoond worden.</p>
|
||||
<p>In deze eerste twee notebooks leer je hoe de notebooks zijn opgevat en hoe je ermee aan de slag kan.
|
||||
Na het doorlopen van beide notebooks heb je een goed idee van hoe onze Python notebooks zijn opgevat.</p>
|
||||
<p><a href="https://kiks.ilabt.imec.be/hub/tmplogin?id=0101" target="_blank" title="Notebooks Werking"><img alt="" src="Knop.png"></a></p>
|
Loading…
Add table
Add a link
Reference in a new issue