QC: fix Survivalist article + add checks 12-13 (XML-API refs, unlinked sources)

- Fix artikel_survivalist: 'BGG-Daten via XML API v2' -> klickbare Links
- verify_article.sh: CHECK 12 (keine XML-API-Referenzen)
- verify_article.sh: CHECK 13 (Quellen müssen verlinkt sein)
This commit is contained in:
Hermes Agent
2026-06-23 12:37:59 +02:00
parent 26f8ac477d
commit 42069f9aa7
2 changed files with 303 additions and 0 deletions
+159
View File
@@ -0,0 +1,159 @@
#!/bin/bash
# verify_article.sh — Prüft Artikel-HTML auf Einhaltung aller redaktionellen Standards
# Usage: ./verify_article.sh <artikel_datei.html>
# Exit 0 = alle Checks bestanden, Exit 1 = Fehler gefunden
#
# Aufruf aus Cronjobs: bash /home/hermes/workspace/verify_article.sh /home/hermes/workspace/artikel_*.html
set -euo pipefail
FILE="${1:-}"
ERRORS=0
WARNINGS=0
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
NC='\033[0m' # No Color
ok() { echo -e "${GREEN}$1${NC}"; }
fail() { echo -e "${RED}$1${NC}"; ERRORS=$((ERRORS+1)); }
warn() { echo -e "${YELLOW}⚠️ $1${NC}"; WARNINGS=$((WARNINGS+1)); }
if [ -z "$FILE" ] || [ ! -f "$FILE" ]; then
echo "Usage: $0 <artikel_datei.html>"
exit 1
fi
echo "=== Verifiziere: $FILE ==="
echo ""
# ── CHECK 1: Exactly one read-more ──────────────────────────────────
# Nur echte HTML-Tags zählen, nicht &lt;hr...&gt; Referenzen in QC-Zeilen
READMORE_COUNT=$(grep -c '<hr id="system-readmore"' "$FILE" || true)
if [ "$READMORE_COUNT" = "1" ]; then
ok "Read-More: genau 1"
elif [ "$READMORE_COUNT" = "0" ]; then
fail "Read-More: KEIN <hr id=\"system-readmore\" /> gefunden"
else
fail "Read-More: $READMORE_COUNT Stück (muss genau 1 sein)"
fi
# ── CHECK 2: No <br> immediately after read-more ────────────────────
if grep -A1 'system-readmore' "$FILE" | grep -q '<br'; then
fail "<br> direkt nach Read-More (erzeugt doppelte Linie)"
else
ok "Kein <br> nach Read-More"
fi
# ── CHECK 3: p.meta not div.meta ────────────────────────────────────
if grep -q '<div class="meta">' "$FILE"; then
fail "<div class=\"meta\"> statt <p class=\"meta\"> (article_server regex schlägt fehl)"
else
ok "<p class=\"meta\"> korrekt"
fi
# ── CHECK 4: No emojis in article body (QC line excluded) ──────────
# Extract body between <article> and </article>, strip everything from QC line onward
BODY=$(sed -n '/<article>/,/<\/article>/p' "$FILE" | sed '/<p class="qc">/,$d')
if echo "$BODY" | python3 -c "import sys,re; t=sys.stdin.read(); sys.exit(0 if re.search(r'[\U0001F300-\U0001F9FF\U00002600-\U000027BF\U0001F600-\U0001F64F]',t) else 1)"; then
fail "Emojis im Artikel-Body gefunden"
else
ok "Keine Emojis"
fi
# ── CHECK 5: File ends with </html> ─────────────────────────────────
LAST_LINE=$(tail -1 "$FILE")
if echo "$LAST_LINE" | grep -q '</html>'; then
ok "Datei endet mit </html>"
else
fail "Letzte Zeile ist nicht </html> (Fremd-Content nach Artikel-Ende?)"
fi
# ── CHECK 6: No meta-line in body (title, date, reading time) ───────
if echo "$BODY" | grep -qP '<p[^>]*>.*\d{1,2}\.\s+\w+\s+\d{4}.*·.*Lesezeit'; then
warn "Meta-Zeile möglicherweise im Body (Datum · Rubrik · Lesezeit)"
fi
# ── CHECK 7: Sources heading uses span-strong, not h2 ───────────────
if echo "$BODY" | grep -q '<h2>Quellen</h2>'; then
fail "<h2>Quellen</h2> statt <span><strong>Quellen</strong></span>"
else
ok "Quellen-Überschrift korrekt (kein <h2>)"
fi
# ── CHECK 8: All links have target="_blank" ─────────────────────────
LINKS_TOTAL=$(echo "$BODY" | grep -o '<a ' | wc -l)
LINKS_BLANK=$(echo "$BODY" | grep -o 'target="_blank"' | wc -l)
if [ "$LINKS_TOTAL" -gt 0 ] && [ "$LINKS_TOTAL" != "$LINKS_BLANK" ]; then
MISSING=$((LINKS_TOTAL - LINKS_BLANK))
fail "$MISSING von $LINKS_TOTAL Links ohne target=\"_blank\""
else
ok "Alle $LINKS_TOTAL Links mit target=\"_blank\""
fi
# ── CHECK 9: Meta description present ───────────────────────────────
if grep -q '<meta name="description" content="[^"]*[a-zA-Z]' "$FILE"; then
ok "Meta-Description vorhanden"
else
fail "Meta-Description fehlt oder leer"
fi
# ── CHECK 10: No QC line outside <p class="qc"> ────────────────────
QC_COUNT=$(echo "$BODY" | grep -c 'class="qc"' || true)
QC_RAW=$(echo "$BODY" | grep -cP 'QC:\s*[✓✔]' || true)
if [ "$QC_RAW" -gt "$QC_COUNT" ]; then
fail "QC-Hinweis nicht in <p class=\"qc\"> (wird nicht gestrippt)"
else
ok "QC-Zeile korrekt in <p class=\"qc\">"
fi
# ── CHECK 11: Autoren gegen BGG verifizieren ─────────────────────────
echo ""
echo "--- BGG Autoren-Faktencheck ---"
AUTHOR_CHECK=$(python3 /home/hermes/workspace/check_authors.py "$FILE" 2>&1)
AUTHOR_EXIT=$?
echo "$AUTHOR_CHECK"
if [ $AUTHOR_EXIT -eq 1 ]; then
ERRORS=$((ERRORS + 1))
elif [ $AUTHOR_EXIT -eq 2 ]; then
WARNINGS=$((WARNINGS + 1))
fi
# ── CHECK 12: Keine XML-API-Referenzen im Artikel ──────────────────
if echo "$BODY" | grep -qiP 'xml\s*api|XMLAPI|xmlapi|betriebsgeheimnis'; then
fail "XML-API-Referenz oder 'Betriebsgeheimnis' im Artikel (nicht leser-tauglich)"
else
ok "Keine XML-API-Referenzen"
fi
# ── CHECK 13: Quellen-Block muss klickbare Links enthalten ──────────
# Sucht Quellen-Überschrift (h2, span, strong) und prüft ob danach Links kommen
SOURCES_SECTION=$(echo "$BODY" | sed -n '/<h2>Quellen<\/h2>/,$p; /<span.*>.*Quellen.*<\/span>/,$p' || echo "")
if [ -n "$SOURCES_SECTION" ]; then
SOURCE_LINKS=$(echo "$SOURCES_SECTION" | grep -c '<a href=' || true)
if [ "$SOURCE_LINKS" -eq 0 ]; then
fail "Quellen-Block ohne klickbare Links (nur Fließtext)"
else
ok "Quellen-Block mit $SOURCE_LINKS klickbaren Links"
fi
else
fail "Kein Quellen-Block gefunden (h2/span>Quellen fehlt)"
fi
# ── SUMMARY ─────────────────────────────────────────────────────────
echo ""
echo "═══════════════════════════════════════"
if [ $ERRORS -eq 0 ] && [ $WARNINGS -eq 0 ]; then
echo -e "${GREEN}✅ ALLE CHECKS BESTANDEN${NC}"
echo "═══════════════════════════════════════"
exit 0
elif [ $ERRORS -eq 0 ]; then
echo -e "${YELLOW}⚠️ $WARNINGS Warnung(en) — KEINE Fehler${NC}"
echo "═══════════════════════════════════════"
exit 0
else
echo -e "${RED}$ERRORS Fehler, $WARNINGS Warnungen${NC}"
echo "═══════════════════════════════════════"
exit 1
fi