Preisregel im Brief, Preispruefung in Workflow 2

This commit is contained in:
2026-09-20 12:46:07 +02:00
parent 45d28afe9b
commit a96cfe9ee2

View File

@@ -57,7 +57,7 @@ node("Webhook Start", "n8n-nodes-base.webhook", 2.1, [-460, 280],
KONF = node("Konfiguration", "n8n-nodes-base.set", 3.4, [-240, 190], {
"mode": "manual", "assignments": {"assignments": [
{"id": nid(), "name": "nw_base", "value": "https://app.neuronwriter.com/neuron-api/0.5/writer", "type": "string"},
{"id": nid(), "name": "gitea_base", "value": "https://gitea.lucas-orth.de", "type": "string"},
{"id": nid(), "name": "gitea_base", "value": "http://gitea:3000", "type": "string"},
{"id": nid(), "name": "gitea_owner", "value": "lucas.orth", "type": "string"},
{"id": nid(), "name": "gitea_repo", "value": "Skrift-Auto-Article", "type": "string"},
{"id": nid(), "name": "branch", "value": "main", "type": "string"},
@@ -66,7 +66,7 @@ KONF = node("Konfiguration", "n8n-nodes-base.set", 3.4, [-240, 190], {
{"id": nid(), "name": "nachbessern_ordner","value": "nachbessern", "type": "string"},
{"id": nid(), "name": "status_pfad", "value": "status-importe.json", "type": "string"},
{"id": nid(), "name": "wp_base", "value": "https://skrift.de", "type": "string"},
{"id": nid(), "name": "score_ziel", "value": 72, "type": "number"},
{"id": nid(), "name": "score_ziel", "value": "={{ $json.body && $json.body.score_ziel ? Number($json.body.score_ziel) : 72 }}", "type": "number"},
{"id": nid(), "name": "pause_zwischen_artikeln", "value": 5, "type": "number"},
{"id": nid(), "name": "benachrichtigung_an", "value": "privat@lucas-orth.de", "type": "string"},
]}, "options": {}})
@@ -81,14 +81,17 @@ link(KONF, LISTE)
FILTER = code("Artikeldateien filtern", [200, 190], """
const antwort = $input.first().json;
// n8n liefert den Koerper bei fullResponse je nach Version als body oder data.
const K = (r) => (r && r.body !== undefined) ? r.body : ((r || {}).data);
const ka = K(antwort);
if (antwort.statusCode === 404) {
return [{ json: { leer: true, grund: 'Ordner "artikel" existiert noch nicht im Repo.' } }];
}
if (antwort.statusCode !== 200) {
throw new Error('Artikelordner konnte nicht gelesen werden (HTTP ' + antwort.statusCode
+ '). Antwort: ' + JSON.stringify(antwort.body).slice(0, 400));
+ '). Antwort: ' + JSON.stringify(ka).slice(0, 400));
}
const dateien = (antwort.body || []).filter(e =>
const dateien = (ka || []).filter(e =>
e.type === 'file' && /^artikel-.+\\.json$/.test(e.name));
if (!dateien.length) {
@@ -134,6 +137,9 @@ PRUEFEN = code("Artikel pruefen", [1340, 420], r"""
const meta = $('Artikel nacheinander').first().json;
const artRoh = $('Artikeldatei laden').first().json;
const briefAntwort = $input.first().json;
// n8n liefert den Koerper bei fullResponse je nach Version als body oder data.
const K = (r) => (r && r.body !== undefined) ? r.body : ((r || {}).data);
const kb = K(briefAntwort);
let artikel;
try { artikel = JSON.parse(Buffer.from(artRoh.content, 'base64').toString('utf8')); }
@@ -150,12 +156,26 @@ if (artikel.slug !== meta.slug) {
}
let brief = null;
if (briefAntwort.statusCode === 200 && briefAntwort.body && briefAntwort.body.content) {
try { brief = JSON.parse(Buffer.from(briefAntwort.body.content, 'base64').toString('utf8')); }
if (briefAntwort.statusCode === 200 && kb && kb.content) {
try { brief = JSON.parse(Buffer.from(kb.content, 'base64').toString('utf8')); }
catch (e) { brief = null; }
}
return [{ json: { slug: meta.slug, artikel, brief, brief_vorhanden: !!brief } }];
// Preise muessen als Shortcode stehen, nie ausgeschrieben.
const preisTreffer = [];
const re = /(\d{1,3}(?:[.,]\d{1,2})?)\s*(?:€|EUR|Euro)/gi;
let m;
while ((m = re.exec(String(artikel.content_html || ''))) !== null) {
preisTreffer.push(m[0].trim());
}
const shortcodes = (String(artikel.content_html || '').match(/\[skrift_preis[^\]]*\]/g) || []);
return [{ json: { slug: meta.slug, artikel, brief, brief_vorhanden: !!brief,
preis_warnung: preisTreffer.length
? `${preisTreffer.length} ausgeschriebene(r) Preis(e) im Text: ${[...new Set(preisTreffer)].slice(0,5).join(', ')}. `
+ 'Bitte durch [skrift_preis key="..."] ersetzen.'
: null,
preis_shortcodes: shortcodes.length } }];
""")
link(BRIEF, PRUEFEN)
@@ -271,12 +291,15 @@ link(NACH, NACH_PRUEF)
NACH_VOR = code("Nachbesserung vorbereiten", [2660, 640], """
const n = $('Fehlende Begriffe ermitteln').first().json;
const p = $input.first().json;
const da = p.statusCode === 200 && p.body && p.body.sha;
// n8n liefert den Koerper bei fullResponse je nach Version als body oder data.
const K = (r) => (r && r.body !== undefined) ? r.body : ((r || {}).data);
const kp = K(p);
const da = p.statusCode === 200 && kp && kp.sha;
const konf = $('Konfiguration').first().json;
return [{ json: { ...n, methode: da ? 'PUT' : 'POST', commit_body: JSON.stringify({
content: Buffer.from(JSON.stringify(n.bericht, null, 2), 'utf8').toString('base64'),
message: `Nachbesserung ${n.slug}: Score ${n.score} unter Ziel`,
branch: konf.branch, ...(da ? { sha: p.body.sha } : {}),
branch: konf.branch, ...(da ? { sha: kp.sha } : {}),
})}}];
""")
link(NACH_PRUEF, NACH_VOR)
@@ -296,7 +319,9 @@ link(NACH_COMMIT, NACH_FEHLER, out=1)
NACH_OK = code("Nachbesserung gemerkt", [3100, 640], """
const n = $('Fehlende Begriffe ermitteln').first().json;
const p = $('Artikel pruefen').first().json;
return [{ json: { slug: n.slug, ergebnis: 'nachbessern', score: n.score,
preis_warnung: p.preis_warnung || null,
score_ziel: n.bericht.score_ziel, pfad: n.pfad,
anzahl_pflicht: n.anzahl_pflicht, anzahl_erweitert: n.anzahl_erweitert,
wortzahl: n.bericht.wortzahl,
@@ -335,8 +360,11 @@ KAT_PRUEF = code("Kategorie pruefen", [2880, 240], """
const s = $('Score auswerten').first().json;
const gesucht = String(s.artikel.kategorie).trim();
const antwort = $input.first().json;
const treffer = (antwort.statusCode === 200 && Array.isArray(antwort.body))
? antwort.body.find(c => c.name.toLowerCase() === gesucht.toLowerCase()) : null;
// n8n liefert den Koerper bei fullResponse je nach Version als body oder data.
const K = (r) => (r && r.body !== undefined) ? r.body : ((r || {}).data);
const ka = K(antwort);
const treffer = (antwort.statusCode === 200 && Array.isArray(ka))
? ka.find(c => c.name.toLowerCase() === gesucht.toLowerCase()) : null;
return [{ json: { ...s, kategorie_id: treffer ? treffer.id : null,
kategorie_name: gesucht, kategorie_fehlt: !treffer } }];
""")
@@ -374,8 +402,11 @@ const dup = $('Beitrag vorhanden?').first().json;
const a = s.artikel;
// Duplikatspruefung: exakter Slug-Treffer entscheidet ueber anlegen oder aktualisieren.
const treffer = (dup.statusCode === 200 && Array.isArray(dup.body))
? dup.body.find(p => p.slug === s.slug) : null;
// n8n liefert den Koerper bei fullResponse je nach Version als body oder data.
const K = (r) => (r && r.body !== undefined) ? r.body : ((r || {}).data);
const kd = K(dup);
const treffer = (dup.statusCode === 200 && Array.isArray(kd))
? kd.find(p => p.slug === s.slug) : null;
const heute = new Date().toISOString().slice(0, 10);
@@ -453,6 +484,8 @@ return [{ json: {
: null,
faq_eintraege: faq_ok,
seo_titel: (p.meta || {})._seopress_titles_title || null,
preis_warnung: v.preis_warnung || null,
preis_shortcodes: v.preis_shortcodes || 0,
}}];
""")
link(WP_SCHREIB, WP_PRUEF)
@@ -516,9 +549,12 @@ const konf = $('Konfiguration').first().json;
let bestand = [];
let sha = null;
if (p.statusCode === 200 && p.body && p.body.content) {
sha = p.body.sha;
try { bestand = JSON.parse(Buffer.from(p.body.content, 'base64').toString('utf8')); }
// n8n liefert den Koerper bei fullResponse je nach Version als body oder data.
const K = (r) => (r && r.body !== undefined) ? r.body : ((r || {}).data);
const kp = K(p);
if (p.statusCode === 200 && kp && kp.content) {
sha = kp.sha;
try { bestand = JSON.parse(Buffer.from(kp.content, 'base64').toString('utf8')); }
catch (e) { bestand = []; }
if (!Array.isArray(bestand)) bestand = [];
}
@@ -565,6 +601,7 @@ if (s.importiert.length) {
z.push(` Vorschau: ${r.vorschau_url}`);
z.push(` Bearbeiten: ${r.bearbeiten_url}`);
if (r.meta_warnung) z.push(` ACHTUNG: ${r.meta_warnung}`);
if (r.preis_warnung) z.push(` PREISE: ${r.preis_warnung}`);
if (r.cache_hinweis) z.push(` Hinweis: ${r.cache_hinweis}`);
});
z.push('');
@@ -578,6 +615,7 @@ if (s.nachbessern.length) {
z.push(` Wortzahl ${r.wortzahl.ist} von ${r.wortzahl.ziel} (${r.wortzahl.differenz > 0 ? '+' : ''}${r.wortzahl.differenz})`);
}
z.push(` Datei: ${r.pfad}`);
if (r.preis_warnung) z.push(` PREISE: ${r.preis_warnung}`);
});
z.push('');
}