getHTMLContent takes type argument now, communications texts successfully migrated

This commit is contained in:
Paul Veltheim
2025-10-30 20:50:40 +02:00
parent 9a739e59cb
commit 22fcf9f5ba
8 changed files with 126 additions and 409 deletions
+9
View File
@@ -119,6 +119,15 @@ ALTER TABLE public.click_to_exercises
ADD CONSTRAINT click_to_exercises_exercise_id_fkey
FOREIGN KEY (exercise_id) REFERENCES exercises(id);
CREATE SEQUENCE public.communications_pages_html_id_seq;
CREATE TABLE public.communications_pages_html (
id integer PRIMARY KEY NOT NULL DEFAULT nextval('communications_pages_html_id_seq'::regclass),
content text NOT NULL
);
ALTER SEQUENCE public.communications_pages_html_id_seq OWNED BY public.communications_pages_html.id;
CREATE TABLE public.dnd_categories (
id bigint PRIMARY KEY NOT NULL GENERATED BY DEFAULT AS IDENTITY,
created_at timestamp with time zone NOT NULL DEFAULT now(),
+16 -3
View File
@@ -4,7 +4,7 @@ import { JSDOM } from "jsdom";
import DOMPurify from "dompurify";
/*
This route fetches html content from db according to id
This route fetches html content from db according to id and page type
*/
export async function GET(req) {
// create URL-object from request
@@ -13,11 +13,24 @@ export async function GET(req) {
// split path to segments
const pathSegments = url.pathname.split("/");
// get page type from url parameters
const type = url.searchParams.get("type");
// get last segment, which is the correct id of the page
const id = pathSegments[pathSegments.length - 1];
// get content from db based on id
const content = await getHTMLContent(id);
// returns correct db table based on url. Prevents malicious code
const getTableType = (type) => {
if (type == "resources") {
return "learning_pages_html";
} else if (type == "communications") {
return "communications_pages_html";
} else {
return "";
}
};
const content = await getHTMLContent(id, getTableType(type));
// returns the fetched html as json
return new Response(JSON.stringify({ content }), {
@@ -1,393 +0,0 @@
import Link from "next/link";
import Image from "next/image";
import { Container, Column } from "@/components/ui/layout/container";
import { GlossaryParagraph } from "@/components/ui/glossary/GlossaryText";
import "../../themes/lessons.css";
export const chapters = [
{
id: "1",
title: "1. Über Vergangenes sprechen",
content: Chapter1,
link: "/grammar/communications/1",
},
{
id: "2",
title: "2. Anleitungen formulieren",
content: Chapter2,
link: "/grammar/communications/2",
},
{
id: "3",
title: "3. Offizielle Mitteilungen (Nachrichten usw.) formulieren",
content: Chapter3,
link: "/grammar/communications/3",
},
{
id: "4",
title:
"4. Höflich mit anderen Menschen umgehen (Sich vorstellen, Gäste empfangen und betreuen, Small Talk)",
content: Chapter4,
link: "/grammar/communications/4",
},
{
id: "5",
title: "5. Menschen beschreiben / Ich und meine Familie",
content: Chapter5,
link: "/grammar/communications/5",
},
{
id: "6",
title: "6. Über Hobbys und Freizeit sprechen",
content: Chapter6,
link: "/grammar/communications/6",
},
{
id: "7",
title: "7. Über Beruf und Arbeitsplatz sprechen",
content: Chapter7,
link: "/grammar/communications/7",
},
{
id: "8",
title: "8. Firmen und Produkte beschreiben",
content: Chapter8,
link: "/grammar/communications/8",
},
{
id: "9",
title: "9. Werbung machen",
content: Chapter9,
link: "/grammar/communications/9",
},
{
id: "10",
title: "10. Einkaufen privat und geschäftlich",
content: Chapter10,
link: "/grammar/communications/10",
},
{
id: "11",
title: "11. Räume beschreiben",
content: Chapter11,
link: "/grammar/communications/11",
},
{
id: "12",
title: "12. Über historische Ereignisse sprechen",
content: Chapter12,
link: "/grammar/communications/12",
},
{
id: "13",
title: "13. Pläne machen",
content: Chapter13,
link: "/grammar/communications/13",
},
{
id: "14",
title:
"14. an Versammlungen und Geschäftstreffen teilnehmen und sie leiten",
content: Chapter14,
link: "/grammar/communications/14",
},
{
id: "15",
title: "15. Jemandem gratulieren",
content: Chapter15,
link: "/grammar/communications/15",
},
{
id: "16",
title: "16. Sich beschweren / etw. reklamieren",
content: Chapter16,
link: "/grammar/communications/16",
},
];
function Chapter1() {
return (
<Container className="chapter-content">
<ul>
<li>
<Link href="/grammar/themes/perfekt">Perfekt</Link>
</li>
<li>Präteritum</li>
<li>Plusquamperfekt</li>
<li>Saltzklammer</li>
</ul>
<h2>
Hier lernst du, wie du auf Deutsch über Ereignisse sprichst, die in der
Vergangenheit liegen.
</h2>
<h3>Wie geht das?</h3>
<GlossaryParagraph>
Sieh dir die drei Textbeispiele an, die über das letzte Wochenende
erzählen. Schau dir besonders die <strong>Verbformen</strong> an.
</GlossaryParagraph>
<p>1.</p>
<GlossaryParagraph>
Letztes Wochenende <strong>habe</strong>ich viel{" "}
<strong>unternommen</strong>. Am Samstagmorgen <strong>bin</strong> ich
früh <strong>aufgestanden</strong> und <strong>habe</strong> zuerst
ausgiebig <strong>gefrühstückt</strong>. Danach <strong>habe</strong>{" "}
ich meine Freunde <strong>getroffen</strong> und wir{" "}
<strong>haben</strong> zusammen einen Ausflug in den Park{" "}
<strong>gemacht</strong>. Dort <strong>haben</strong> wir Fußball{" "}
<strong>gespielt</strong> und anschließend ein Picknick{" "}
<strong>gemacht</strong>. Am Nachmittag <strong>bin</strong> ich nach
Hause <strong>gegangen</strong> und <strong>habe</strong> einen Film{" "}
<strong>geschaut</strong>. Abends <strong>habe</strong> ich mit meiner
Familie <strong>gekocht</strong> und wir <strong>haben</strong>{" "}
gemeinsam <strong>gegessen</strong>.
</GlossaryParagraph>
<GlossaryParagraph>
Sonntag <strong>habe</strong> ich lange <strong>geschlafen</strong> und{" "}
<strong>bin</strong> erst gegen Mittag <strong>aufgestanden</strong>.
Ich <strong>habe</strong> ein paar Besorgungen <strong>gemacht</strong>{" "}
und dann meine Wohnung <strong>aufgeräumt</strong>. Am Abend{" "}
<strong>sind</strong> wir in einen Klub <strong>gefahren</strong> und{" "}
<strong>haben getanzt</strong>. Insgesamt <strong>war</strong> es ein
schönes und erholsames Wochenende.
</GlossaryParagraph>
<p>2.</p>
<GlossaryParagraph>
Letztes Wochenende <strong>war</strong> abwechslungsreich und
entspannend. Am Samstag
<strong>wachte</strong> ich früh <strong>auf</strong> und{" "}
<strong>frühstückte</strong> in Ruhe. Danach <strong>erledigte</strong>{" "}
ich einige Einkäufe und <strong>traf</strong> mich mit Freunden im Café.
Wir <strong>plauderten</strong> lange und <strong>genossen</strong> den
sonnigen Tag.
</GlossaryParagraph>
<GlossaryParagraph>
Am Abend <strong>schaute</strong> ich einen Film und{" "}
<strong>ließ</strong> den Tag gemütlich ausklingen. Am Sonntag{" "}
<strong>schlief</strong> ich <strong>aus</strong> und{" "}
<strong>machte</strong> einen langen Spaziergang im Park. Die frische
Luft <strong>tat</strong> gut. Nachmittags <strong>backte</strong> ich
einen Kuchen und <strong>las</strong> ein Buch.
</GlossaryParagraph>
<GlossaryParagraph>
Am Abend <strong>bereitete</strong> ich mich auf die neue Woche{" "}
<strong>vor</strong> und <strong>entspannte</strong> mich mit Musik. Es{" "}
<strong>war</strong> ein gelungenes Wochenende.
</GlossaryParagraph>
<p>3.</p>
<GlossaryParagraph>
Letztes Wochenende <strong>war</strong> erholsam und schön. Am Samstag{" "}
<strong>wachte</strong> ich früh <strong>auf</strong>, weil ich am Abend
zuvor früh schlafen <strong>gegangen war</strong>. Nach dem Frühstück{" "}
<strong>ging</strong> ich einkaufen, denn ich <strong>hatte</strong> am
Freitag <strong>vergessen</strong>, einige Dinge zu besorgen. Am
Nachmittag <strong>traf</strong> ich mich mit Freunden im Park. Wir{" "}
<strong>redeten</strong> über vieles und <strong>lachten</strong> viel.
</GlossaryParagraph>
<GlossaryParagraph>
Am Sonntag <strong>schlief</strong> ich lange, weil ich die ganze Woche
viel <strong>gearbeitet hatte</strong>. Nach dem Mittagessen{" "}
<strong>machte</strong> ich einen Spaziergang. Die Sonne{" "}
<strong>schien</strong>, und die Luft <strong>war</strong> frisch. Am
Abend <strong>las</strong> ich ein Buch, das ich schon lange{" "}
<strong>angefangen hatte</strong>. Es <strong>war</strong> ein
wunderbares Wochenende.
</GlossaryParagraph>
<Container bg="var(--red)">Übung 1 medium</Container>
<h3>Was muss ich wissen und können?</h3>
<p></p>
<Image
src="/das_perfekt_2.png"
alt="Das Perfekt und das Plusquamperfekt"
width={872}
height={387}
/>
</Container>
);
}
function Chapter2() {
return (
<Column className="chapter-content">
<ul>
<li>Passiv</li>
<li>Infinitivkonstruktionen</li>
<li>Finalsätze u. a.</li>
</ul>
</Column>
);
}
function Chapter3() {
return (
<Column className="chapter-content">
<ul>
<li>Konjunktiv I bei indirekten Zitaten</li>
<li>indirekte Frage- und Aussagesätze</li>
<li>subjektive Modalität</li>
<li>Futur II u. a. Vermutungen</li>
</ul>
</Column>
);
}
function Chapter4() {
return (
<Column className="chapter-content">
<ul>
<li>Konjunktiv II als Höflichkeitsform</li>
<li>Das Pronomen es (z. B. bei Witterungsverben)</li>
<li>Dativ-Verben (geben, schenken usw.)</li>
</ul>
</Column>
);
}
function Chapter5() {
return (
<Column className="chapter-content">
<ul>
<li>Vergleiche (wie und als)</li>
<li>Adjektivdeklination</li>
</ul>
</Column>
);
}
function Chapter6() {
return (
<Column className="chapter-content">
<ul>
<li>Adjektivdeklination</li>
<li>Temporalangaben, -adverbien, -sätze</li>
</ul>
</Column>
);
}
function Chapter7() {
return (
<Column className="chapter-content">
<ul>
<li>Hilfsverben</li>
<li>Artikelverwendung</li>
</ul>
</Column>
);
}
function Chapter8() {
return (
<Column className="chapter-content">
<ul>
<li>Adjektivdeklination</li>
<li>Lokalangaben, -adverbien, -sätze</li>
<li>Passiv</li>
<li>
Adverbien zur Darstellung von Chronologie in Prozessbeschreibungen
</li>
</ul>
</Column>
);
}
function Chapter9() {
return (
<Column className="chapter-content">
<ul>
<li>Adjektivdeklination</li>
<li>Vergleiche</li>
<li>Präpositionen bei der Beschreibung von Leistungen und Produkten</li>
</ul>
</Column>
);
}
function Chapter10() {
return (
<Column className="chapter-content">
<ul>
<li>Genuszuordnung</li>
<li>Formen der Artikel</li>
<li>Gebrauch der Artikel</li>
<li>andere Artikelwörter</li>
<li>Akkusativ Bildung und Verwendung</li>
</ul>
</Column>
);
}
function Chapter11() {
return (
<Column className="chapter-content">
<ul>
<li>
Lokalpräpositionen (Wechsel- und ausgewählte lokale
Akk/Dat-Präpositionen)
</li>
<li>Lokaladverbien (insb. Verwendung im Satz)</li>
</ul>
</Column>
);
}
function Chapter12() {
return (
<Column className="chapter-content">
<ul>
<li>Vergangenheitstempora, auch (hyster.) Präsens</li>
<li>Temporaladverbien</li>
</ul>
</Column>
);
}
function Chapter13() {
return (
<Column className="chapter-content">
<ul>
<li>Präsens + Temporaladverbien</li>
<li>Temporalangaben und -sätze</li>
<li>Konditionalsätze (real/irreal mit Konjunktiv II und würde)</li>
<li>Futur I</li>
</ul>
</Column>
);
}
function Chapter14() {
return (
<Column className="chapter-content">
<ul>
<li>Temporaladverbien</li>
<li>Versch. Konjunktionalsätze</li>
<li>Uneingeleitete Nebensätze</li>
</ul>
</Column>
);
}
function Chapter15() {
return (
<Column className="chapter-content">
<ul>
<li>Komparation der Adjektive</li>
<li>Anrede (du/Sie)</li>
<li>
<Link href="/grammar/themes/perfekt">Perfekt</Link> / Präteritum
</li>
</ul>
</Column>
);
}
function Chapter16() {
return (
<Column className="chapter-content">
<ul>
<li>Konjunktiv</li>
<li>Imperativ</li>
<li>Rektion der Verben</li>
</ul>
</Column>
);
}
@@ -5,7 +5,7 @@ import "../../../resources/[chapter]/chapters.css";
import layout from "@/shared/styles/layout.module.css";
import { useParams, useRouter } from "next/navigation";
import { LinkButton } from "@/components/ui/linkbutton";
import { chapters } from "./chapters";
import RenderHTML, { PageType } from "@/app/html-renderer";
export default function Chapters() {
const { chapter } = useParams();
@@ -33,7 +33,7 @@ export default function Chapters() {
erklärt.
</p>
<p>Folgende Grammatik-Themen sind damit verbunden: </p>
<Chapter.content />
<RenderHTML contentId={Chapter.id} type="communications" />
</>
)}
<Row justify="space-between" pb="xl">
@@ -51,3 +51,88 @@ export default function Chapters() {
</Column>
);
}
export const chapters = [
{
id: "1",
title: "1. Über Vergangenes sprechen",
link: "/grammar/communications/1",
},
{
id: "2",
title: "2. Anleitungen formulieren",
link: "/grammar/communications/2",
},
{
id: "3",
title: "3. Offizielle Mitteilungen (Nachrichten usw.) formulieren",
link: "/grammar/communications/3",
},
{
id: "4",
title:
"4. Höflich mit anderen Menschen umgehen (Sich vorstellen, Gäste empfangen und betreuen, Small Talk)",
link: "/grammar/communications/4",
},
{
id: "5",
title: "5. Menschen beschreiben / Ich und meine Familie",
link: "/grammar/communications/5",
},
{
id: "6",
title: "6. Über Hobbys und Freizeit sprechen",
link: "/grammar/communications/6",
},
{
id: "7",
title: "7. Über Beruf und Arbeitsplatz sprechen",
link: "/grammar/communications/7",
},
{
id: "8",
title: "8. Firmen und Produkte beschreiben",
link: "/grammar/communications/8",
},
{
id: "9",
title: "9. Werbung machen",
link: "/grammar/communications/9",
},
{
id: "10",
title: "10. Einkaufen privat und geschäftlich",
link: "/grammar/communications/10",
},
{
id: "11",
title: "11. Räume beschreiben",
link: "/grammar/communications/11",
},
{
id: "12",
title: "12. Über historische Ereignisse sprechen",
link: "/grammar/communications/12",
},
{
id: "13",
title: "13. Pläne machen",
link: "/grammar/communications/13",
},
{
id: "14",
title:
"14. an Versammlungen und Geschäftstreffen teilnehmen und sie leiten",
link: "/grammar/communications/14",
},
{
id: "15",
title: "15. Jemandem gratulieren",
link: "/grammar/communications/15",
},
{
id: "16",
title: "16. Sich beschweren / etw. reklamieren",
link: "/grammar/communications/16",
},
];
@@ -1,6 +1,6 @@
"use client";
import { chapters } from "./[chapter]/chapters";
import { chapters } from "./[chapter]/page";
import Link from "next/link";
import "@/app/grammar/themes/lessons.css";
+5 -6
View File
@@ -6,15 +6,14 @@ The returned content can be used by js functions that are used to render individ
parameter contentId: id of the HTML content in db
NOTE: Currently this function fetches content corresponding to id. This is ok when rendering
lesson pages, since they are named 1-n. This function could be used to render any page content,
if the fetching function was changed in backend to find content based on some other identifier.
This function probably doens't need any changes, but at this moment it is only used to render chapter pages.
parameter type: page type
NOTE: This function could be enhanced by providing HTML sanitizing before returning content.
One option for this would be using dompurify sanitizer
*/
export default function RenderHTML({ contentId }) {
export default function RenderHTML({ contentId, type }) {
// create state for HTML content
const [html, setHtml] = useState("");
@@ -23,7 +22,7 @@ export default function RenderHTML({ contentId }) {
// function to fetch HTML content using html-services, and set it to state html
async function fetchHTML() {
// fetch response through next.js route using getHTMLContent function
const res = await fetch(`/api/html-content/${contentId}`);
const res = await fetch(`/api/html-content/${contentId}?type=${type}`);
// chnages the response to proper json
const data = await res.json();
+3 -2
View File
@@ -8,8 +8,9 @@ import { useParams, useRouter } from "next/navigation";
import { LinkButton } from "@/components/ui/linkbutton";
import { Button } from "@/components/ui/button";
import Editor from "@/components/ui/editor";
import RenderHTML from "@/app/html-renderer";
import RenderHTML, { PageType } from "@/app/html-renderer";
import { checkUseIsAdmin } from "@/context/user.context";
import { PAGE_TYPES } from "next/dist/lib/page-types";
export default function Chapters() {
const { chapter } = useParams();
@@ -91,7 +92,7 @@ export default function Chapters() {
{checkUseIsAdmin() == true && (
<Button onClick={() => setEditorActive(true)}>Open editor</Button>
)}
<RenderHTML contentId={Chapter.id} />
<RenderHTML contentId={Chapter.id} type="resources" />
{/*<Chapter.content />*/}
</>
)}
+5 -2
View File
@@ -5,6 +5,8 @@ This function fetches html content from database
parameter id: id of the content in table learning_pages_html
parameter type: PageType enum denoting the sql table name
NOTE: This function could be used to fetch html content to all pages, not just
for chapter pages, e.g. gradesa/resources/*. In that case, the database table
should be updated to include some kind of identifier other than id number
@@ -13,11 +15,12 @@ NOTE: This function could be used to fetch html content to all pages, not just
other identifier as parameter for this function.
*/
export async function getHTMLContent(id) {
export async function getHTMLContent(id, type) {
try {
console.log("Table type: ", type);
// get content from db using parameterized query
const result = await DB.pool(
"SELECT content FROM learning_pages_html WHERE id = $1",
"SELECT content FROM " + type + " WHERE id = $1",
[id]
);