syncova-policies/app/api/site-pages/route.ts
Weapie 5aa8880190 Gebaerdensprach-Video ermoeglichen und Erklaerung anpassen
Ein DGS-Video liess sich bisher gar nicht einbinden: Der Markdown-
Prozessor laeuft mit Sanitizing, und remark reicht rohes HTML dann von
vornherein nicht durch - <video> kam als leeres <p> heraus. Eine
erweiterte Freigabeliste allein half deshalb nicht.

Statt rohes HTML fuer alle Textfelder zu oeffnen - auch fuer die 121
Erklaerungen - bekommt die Gebaerdensprach-Seite zwei eigene Felder fuer
Video- und Untertiteladresse. Ausgegeben wird ein natives <video
controls> mit <track kind="captions"> und Bildunterschrift.

Adressen werden zweimal geprueft, beim Speichern und vor der Ausgabe:
zugelassen sind nur der eigene Server und https. javascript:, data:,
protokollrelative und einfache http-Adressen werden abgewiesen. iframe
bleibt bewusst gesperrt - eine YouTube-Einbindung wuerde Besucherdaten
an Dritte uebertragen.

Erklaerung zur Barrierefreiheit entsprechend gekuerzt: Die beiden
Luecken nach § 4 BITV 2.0 entfallen, es bleibt die ungepruefte
Druckansicht.

Geprueft: Video wird mit Untertitelspur ausgeliefert und ist per Tastatur
erreichbar, axe-core meldet auf beiden neuen Seiten in hell und dunkel
keine Verstoesse, Adresspruefung weist alle acht Testfaelle korrekt zu.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 16:18:09 +02:00

71 lines
2.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { NextRequest, NextResponse } from 'next/server'
import { PrismaClient } from '@prisma/client'
import { requireAdmin } from '@/lib/require-admin'
import { SITE_MEDIA, SITE_PAGES, isSafeMediaUrl } from '@/lib/site-pages'
import { readSitePages } from '@/lib/site-pages.server'
// Prisma client instance
const prisma = new PrismaClient()
// GET /api/site-pages - liefert die Inhalte der rechtlichen Seiten
export async function GET() {
try {
return NextResponse.json(await readSitePages())
} catch (error) {
console.error('Error fetching site pages:', error)
return NextResponse.json(
{ error: 'Fehler beim Abrufen der Seiteninhalte' },
{ status: 500 }
)
}
}
// PUT /api/site-pages - speichert die Inhalte der rechtlichen Seiten (Admin)
export async function PUT(request: NextRequest) {
try {
const denied = await requireAdmin()
if (denied) return denied
const data = await request.json()
// Nur die bekannten Seiten übernehmen, jeweils getrimmt. Ein leerer Text
// ist zulässig und bedeutet: Seite nicht veröffentlichen.
const values = Object.fromEntries(
[...SITE_PAGES, ...SITE_MEDIA].map((key) => [
key,
String(data[key] ?? '').trim(),
])
)
// Medienadressen landen in einem src-Attribut. Nur eigener Server oder
// https – alles andere wird abgewiesen, statt still gespeichert zu werden.
const ungueltig = SITE_MEDIA.filter((key) => !isSafeMediaUrl(values[key]))
if (ungueltig.length > 0) {
return NextResponse.json(
{
error: 'Ungültige Adresse',
details: ungueltig.map(
(key) =>
`${key}: nur eine Adresse auf diesem Server (beginnt mit /) oder https ist zulässig`
),
},
{ status: 400 }
)
}
const saved = await prisma.sitePages.upsert({
where: { id: 1 },
update: values,
create: { id: 1, ...values },
})
return NextResponse.json(saved)
} catch (error) {
console.error('Error updating site pages:', error)
return NextResponse.json(
{ error: 'Fehler beim Speichern der Seiteninhalte' },
{ status: 500 }
)
}
}