Funktionen: Vertragsunterlagen als K15-Anhang, Belehrung vor dem Bestellknopf
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
03bdeb4461
commit
2c059cb3d6
11 files changed
+574
-39
No files matched your search
@@ -2,13 +2,19 @@
|
||||
// Saetze 'analyse' (AVV, Leistungsbeschreibung der Website-Analyse) und 'termine' (Leistungsbeschreibung, AVV und
|
||||
// Widerrufsbelehrung mit Muster-Widerrufsformular des Terminplaners). analyseLegal.js ist ein duenner Wrapper darum.
|
||||
// Die Fassung ist der Berliner Kalendertag der Texte (JJJJ-MM-TT); eine ausgelieferte Fassung wird nie ueberschrieben.
|
||||
import { access, readFile } from 'node:fs/promises'
|
||||
import { access, open, readFile, stat } from 'node:fs/promises'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { join } from 'node:path'
|
||||
import { Router } from 'express'
|
||||
import { config } from '../config.js'
|
||||
|
||||
const publicDir = fileURLToPath(new URL('../../public/', import.meta.url))
|
||||
/** Wurzel der ausgelieferten Dateien (Standard: public/); nur Tests tauschen sie gegen ein Verzeichnis mit Kopien aus. */
|
||||
let basisDir = publicDir
|
||||
/** Nur fuer Tests: Verzeichnis, in dem legalPdfFiles und featureLegalReady die Dateien suchen (null = public/). */
|
||||
export function setLegalDirForTests(dir) {
|
||||
basisDir = dir ?? publicDir
|
||||
}
|
||||
const VERSION_RE = /^\d{4}-\d{2}-\d{2}$/
|
||||
|
||||
/**
|
||||
@@ -56,7 +62,7 @@ export function legalPdfFiles(satz, version) {
|
||||
const dokumente = satzDokumente(satz)
|
||||
const v = pruefeFassung(version)
|
||||
return Object.fromEntries(
|
||||
Object.entries(dokumente).map(([doc, d]) => [doc, { filename: `${d.pdf}-${v}.pdf`, path: join(publicDir, 'rechtliches', `${d.slug}-${v}.pdf`) }])
|
||||
Object.entries(dokumente).map(([doc, d]) => [doc, { filename: `${d.pdf}-${v}.pdf`, path: join(basisDir, 'rechtliches', `${d.slug}-${v}.pdf`) }])
|
||||
)
|
||||
}
|
||||
|
||||
@@ -90,18 +96,36 @@ export async function featureLegalAttachments(featureKey, opts) {
|
||||
return satz ? legalPdfAttachments(satz, aktuelleFassung(satz), opts) : []
|
||||
}
|
||||
|
||||
/**
|
||||
* Ist die Datei ein lesbares PDF? Grösse > 0 (stat) und die ersten fünf Bytes "%PDF-"; nur diese fünf Bytes werden gelesen, nie die
|
||||
* ganze Datei (featureLegalReady läuft bei jeder Bestellung, vor jeder Stripe-Sitzung). Wirft bei jedem Lesefehler.
|
||||
*/
|
||||
async function istLesbaresPdf(pfad) {
|
||||
const info = await stat(pfad)
|
||||
if (!info.isFile() || info.size <= 0) return false
|
||||
const datei = await open(pfad, 'r')
|
||||
try {
|
||||
const kopf = Buffer.alloc(5)
|
||||
const { bytesRead } = await datei.read(kopf, 0, 5, 0)
|
||||
return bytesRead === 5 && kopf.toString('latin1') === '%PDF-'
|
||||
} finally {
|
||||
await datei.close()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* true, wenn alle Rechtsdokumente der Funktion in der aktuellen Fassung vorliegen: HTML-Seiten (die die Bestellseite
|
||||
* verlinkt) und PDFs (die Mail anhaengt). Unbekannte Funktion und jeder Lesefehler: false (fail-closed).
|
||||
* verlinkt) und PDFs (die Mail anhaengt; je PDF stat und die ersten fuenf Bytes, nicht der ganze Inhalt). Unbekannte
|
||||
* Funktion und jeder Lesefehler: false (fail-closed), nie ein Wurf.
|
||||
*/
|
||||
export async function featureLegalReady(featureKey) {
|
||||
try {
|
||||
const satz = funktionSatz(featureKey)
|
||||
if (!satz) return true
|
||||
const v = aktuelleFassung(satz)
|
||||
await Promise.all(Object.values(legalPaths(satz, v)).map((adresse) => access(join(publicDir, adresse))))
|
||||
await legalPdfAttachments(satz, v)
|
||||
return true
|
||||
await Promise.all(Object.values(legalPaths(satz, v)).map((adresse) => access(join(basisDir, adresse))))
|
||||
const lesbar = await Promise.all(Object.values(legalPdfFiles(satz, v)).map((f) => istLesbaresPdf(f.path)))
|
||||
return lesbar.every(Boolean)
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user