diff --git a/extensions/directus-extension-skrift-api/dist/index.js b/extensions/directus-extension-skrift-api/dist/index.js index 916fbd9..6cbecf4 100644 --- a/extensions/directus-extension-skrift-api/dist/index.js +++ b/extensions/directus-extension-skrift-api/dist/index.js @@ -328,6 +328,53 @@ const handler = (router, { services, getSchema, logger }) => { const envFormat = envMode === 'none' ? null : (fmtKey === 'a4' ? 'dinlang' : 'c6'); const hatDateien = files.length > 0; + // ── Zeichen prüfen (WARNEN, nicht ablehnen) ────────────────────────────── + // Nicht erlaubte Zeichen werden wie bisher entfernt; der Aufrufer bekommt + // zusätzlich eine Warnung, welche Zeichen entfernt wurden. + const unerlaubt = new Set(); + const pruefeZeichen = (s) => { + for (const ch of new Set(String(s || ''))) if (clean(ch) === '') unerlaubt.add(ch); + }; + if (!istDatei && !istKuvertOnly) pruefeZeichen(letter.text); + for (const e of recipients) { + for (const k of ['salutation', 'first_name', 'last_name', 'street', 'house_no', 'zip', 'city', 'country', 'free_text']) { + pruefeZeichen(e && e[k]); + } + } + const warnings = []; + if (unerlaubt.size) { + warnings.push({ code: 'unsupported_characters', characters: [...unerlaubt], + message: 'Some characters are not supported and were removed. See the allowed character set in the documentation.' }); + } + + // ── Textlänge prüfen (ABLEHNEN) – NUR einseitige Formate (A6) ──────────── + // A4 fließt automatisch über mehrere Seiten und kann nicht „zu lang" sein; + // A6-Karten sind einseitig → passt der Text nicht auf eine Seite, wird der + // Auftrag abgelehnt (die reine Umbruch-Zählung des Backends, kein Scriptalizer). + if (!istDatei && !istKuvertOnly && (fmtKey === 'a6_hoch' || fmtKey === 'a6_quer')) { + const layoutKey = fmtKey === 'a6_hoch' ? 'a6p' : 'a6l'; + try { + const r = await fetch(`${BACKEND_URL}/api/order/pagecount`, { + method: 'POST', + headers: { 'Content-Type': 'application/json', 'X-API-Token': BACKEND_TOKEN }, + body: JSON.stringify({ text: clean(String(letter.text || '')), format: layoutKey }), + signal: AbortSignal.timeout(8000), + }); + if (r.ok) { + const d = await r.json(); + const pages = Math.max(1, ...((d.counts || []).map((c) => Number(c.pages) || 1))); + if (pages > 1) { + return fehler(res, 422, `letter.text is too long for a single ${String(body.document_format)} card (needs ${pages} pages). Please shorten it.`); + } + } else { + logger.warn(`[skrift-api] Längenprüfung: pagecount HTTP ${r.status}`); + } + } catch (e) { + // Backend nicht erreichbar → Auftrag NICHT blockieren (fail-open). + logger.warn(`[skrift-api] Längenprüfung übersprungen: ${e.message}`); + } + } + const font = ['tilda', 'alva', 'ellie'].includes(body.font) ? body.font : 'tilda'; // Versandart nur Englisch: "single" (direkt an Empfänger) / "bulk" (Sammelversand an dich). const shippingType = String(body.shipping_type || '').toLowerCase() === 'single' ? 'einzeln' : 'sammel'; @@ -409,7 +456,7 @@ const handler = (router, { services, getSchema, logger }) => { body: JSON.stringify({ orderId }), }).catch((e) => logger.warn(`[skrift-api] Generierung nicht gestartet: ${e.message}`)); - return res.status(201).json({ order_number: orderNumber, status: 'pending' }); + return res.status(201).json({ order_number: orderNumber, status: 'pending', ...(warnings.length ? { warnings } : {}) }); } catch (err) { logger.error(`[skrift-api] orders: ${err.stack || err.message}`); return fehler(res, 500, 'Order could not be created.');