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:
Executable
+159
@@ -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 <hr...> 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
|
||||
Reference in New Issue
Block a user