shinkan-jinkendo/backend/routers/import_wiki_admin.py
Lars 97a7fe7cba
Some checks failed
Deploy Development / deploy (push) Successful in 54s
Test Suite / lint-backend (push) Successful in 0s
Test Suite / build-frontend (push) Successful in 5s
Test Suite / playwright-tests (push) Failing after 1m55s
fix: reimport dict-cursor bug + add admin cleanup endpoint
Problem 1: Reimport fails completely (all exercises fail)
Root cause: Line 465 existing[0] instead of existing['id']
Fix: Changed to existing['id'] for dict-cursor compatibility

Problem 2: 221 exercises skipped, only 2 in database
Root cause: Orphaned wiki_import_references from failed imports
Fix: New admin endpoint to manually cleanup orphaned references

New endpoints:
- DELETE /api/import/mediawiki/admin/cleanup-orphaned-references
  Deletes all references where local_id doesn't exist in target table
  Returns count of deleted references per type

- GET /api/import/mediawiki/admin/stats
  Shows references vs. actual count + orphaned count
  Helps diagnose import state issues

Usage:
1. Call cleanup endpoint to remove orphaned references
2. Run normal import (reimport=false)
3. Should import all previously failed exercises
2026-04-27 08:52:05 +02:00

96 lines
3.1 KiB
Python

"""
Admin-Hilfsfunktionen für MediaWiki-Import
"""
from fastapi import APIRouter, Depends, HTTPException
from db import get_db, get_cursor
from routers.import_wiki import require_admin
router = APIRouter(prefix="/api/import/mediawiki/admin", tags=["import-admin"])
@router.delete("/cleanup-orphaned-references")
def cleanup_orphaned_references(session: dict = Depends(require_admin)):
"""
Löscht verwaiste Import-Referenzen (Referenz existiert, aber Übung fehlt).
Nützlich nach fehlgeschlagenen Imports.
"""
deleted = {"exercises": 0, "skills": 0, "methods": 0}
with get_db() as conn:
cur = get_cursor(conn)
# Exercises
cur.execute("""
DELETE FROM wiki_import_references
WHERE content_type = 'exercise'
AND local_id NOT IN (SELECT id FROM exercises)
""")
deleted["exercises"] = cur.rowcount
# Skills
cur.execute("""
DELETE FROM wiki_import_references
WHERE content_type = 'skill'
AND local_id NOT IN (SELECT id FROM skills)
""")
deleted["skills"] = cur.rowcount
# Methods
cur.execute("""
DELETE FROM wiki_import_references
WHERE content_type = 'method'
AND local_id NOT IN (SELECT id FROM training_methods)
""")
deleted["methods"] = cur.rowcount
conn.commit()
return {
"ok": True,
"deleted": deleted,
"message": f"Deleted {sum(deleted.values())} orphaned references"
}
@router.get("/stats")
def get_import_stats(session: dict = Depends(require_admin)):
"""Statistik über Import-Referenzen vs. tatsächliche Einträge."""
with get_db() as conn:
cur = get_cursor(conn)
# Exercises
cur.execute("SELECT COUNT(*) as count FROM wiki_import_references WHERE content_type = 'exercise'")
refs_exercises = cur.fetchone()['count']
cur.execute("SELECT COUNT(*) as count FROM exercises WHERE import_source = 'mediawiki'")
actual_exercises = cur.fetchone()['count']
# Skills
cur.execute("SELECT COUNT(*) as count FROM wiki_import_references WHERE content_type = 'skill'")
refs_skills = cur.fetchone()['count']
cur.execute("SELECT COUNT(*) as count FROM skills")
actual_skills = cur.fetchone()['count']
# Methods
cur.execute("SELECT COUNT(*) as count FROM wiki_import_references WHERE content_type = 'method'")
refs_methods = cur.fetchone()['count']
cur.execute("SELECT COUNT(*) as count FROM training_methods")
actual_methods = cur.fetchone()['count']
return {
"exercises": {
"references": refs_exercises,
"actual": actual_exercises,
"orphaned": refs_exercises - actual_exercises
},
"skills": {
"references": refs_skills,
"actual": actual_skills,
"orphaned": refs_skills - actual_skills
},
"methods": {
"references": refs_methods,
"actual": actual_methods,
"orphaned": refs_methods - actual_methods
}
}