fix: Restore all files lost during destructive rebase
A previous `git pull --rebase origin main` dropped 177 local commits,
losing 3400+ files across admin-v2, backend, studio-v2, website,
klausur-service, and many other services. The partial restore attempt
(660295e2) only recovered some files.
This commit restores all missing files from pre-rebase ref 98933f5e
while preserving post-rebase additions (night-scheduler, night-mode UI,
NightModeWidget dashboard integration).
Restored features include:
- AI Module Sidebar (FAB), OCR Labeling, OCR Compare
- GPU Dashboard, RAG Pipeline, Magic Help
- Klausur-Korrektur (8 files), Abitur-Archiv (5+ files)
- Companion, Zeugnisse-Crawler, Screen Flow
- Full backend, studio-v2, website, klausur-service
- All compliance SDKs, agent-core, voice-service
- CI/CD configs, documentation, scripts
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
135
backend/klausur_service_proxy.py
Normal file
135
backend/klausur_service_proxy.py
Normal file
@@ -0,0 +1,135 @@
|
||||
"""
|
||||
Klausur-Service API Proxy
|
||||
Routes API requests from /api/klausur/* to the klausur-service microservice
|
||||
"""
|
||||
|
||||
import os
|
||||
import jwt
|
||||
import datetime
|
||||
import httpx
|
||||
from fastapi import APIRouter, Request, HTTPException, Response
|
||||
|
||||
# Klausur Service URL
|
||||
KLAUSUR_SERVICE_URL = os.getenv("KLAUSUR_SERVICE_URL", "http://klausur-service:8086")
|
||||
JWT_SECRET = os.getenv("JWT_SECRET", "your-super-secret-jwt-key-change-in-production")
|
||||
ENVIRONMENT = os.getenv("ENVIRONMENT", "development")
|
||||
|
||||
# Demo teacher UUID for development mode
|
||||
DEMO_TEACHER_ID = "e9484ad9-32ee-4f2b-a4e1-d182e02ccf20"
|
||||
|
||||
router = APIRouter(prefix="/klausur", tags=["klausur"])
|
||||
|
||||
|
||||
def get_demo_token() -> str:
|
||||
"""Generate a demo JWT token for development mode"""
|
||||
payload = {
|
||||
"user_id": DEMO_TEACHER_ID,
|
||||
"email": "demo@breakpilot.app",
|
||||
"role": "admin",
|
||||
"exp": datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(hours=24),
|
||||
"iat": datetime.datetime.now(datetime.timezone.utc)
|
||||
}
|
||||
return jwt.encode(payload, JWT_SECRET, algorithm="HS256")
|
||||
|
||||
|
||||
async def proxy_request(request: Request, path: str) -> Response:
|
||||
"""Forward a request to the klausur service"""
|
||||
url = f"{KLAUSUR_SERVICE_URL}/api/v1{path}"
|
||||
|
||||
# Forward headers, especially Authorization
|
||||
headers = {}
|
||||
if "authorization" in request.headers:
|
||||
headers["Authorization"] = request.headers["authorization"]
|
||||
elif ENVIRONMENT == "development":
|
||||
# In development mode, use demo token if no auth provided
|
||||
demo_token = get_demo_token()
|
||||
headers["Authorization"] = f"Bearer {demo_token}"
|
||||
if "content-type" in request.headers:
|
||||
headers["Content-Type"] = request.headers["content-type"]
|
||||
|
||||
# Get request body for POST/PUT/PATCH/DELETE
|
||||
body = None
|
||||
if request.method in ("POST", "PUT", "PATCH", "DELETE"):
|
||||
body = await request.body()
|
||||
|
||||
async with httpx.AsyncClient(timeout=60.0) as client:
|
||||
try:
|
||||
response = await client.request(
|
||||
method=request.method,
|
||||
url=url,
|
||||
headers=headers,
|
||||
content=body,
|
||||
params=request.query_params
|
||||
)
|
||||
return Response(
|
||||
content=response.content,
|
||||
status_code=response.status_code,
|
||||
headers=dict(response.headers),
|
||||
media_type=response.headers.get("content-type", "application/json")
|
||||
)
|
||||
except httpx.ConnectError:
|
||||
raise HTTPException(
|
||||
status_code=503,
|
||||
detail="Klausur service unavailable"
|
||||
)
|
||||
except httpx.TimeoutException:
|
||||
raise HTTPException(
|
||||
status_code=504,
|
||||
detail="Klausur service timeout"
|
||||
)
|
||||
|
||||
|
||||
# Health check
|
||||
@router.get("/health")
|
||||
async def health():
|
||||
"""Health check for klausur service connection"""
|
||||
async with httpx.AsyncClient(timeout=5.0) as client:
|
||||
try:
|
||||
response = await client.get(f"{KLAUSUR_SERVICE_URL}/health")
|
||||
return {"klausur_service": "healthy", "connected": response.status_code == 200}
|
||||
except Exception:
|
||||
return {"klausur_service": "unhealthy", "connected": False}
|
||||
|
||||
|
||||
# Klausuren
|
||||
@router.api_route("/klausuren", methods=["GET", "POST"])
|
||||
async def klausuren(request: Request):
|
||||
return await proxy_request(request, "/klausuren")
|
||||
|
||||
|
||||
@router.api_route("/klausuren/{klausur_id}", methods=["GET", "PUT", "DELETE"])
|
||||
async def klausur_by_id(klausur_id: str, request: Request):
|
||||
return await proxy_request(request, f"/klausuren/{klausur_id}")
|
||||
|
||||
|
||||
# Students
|
||||
@router.api_route("/klausuren/{klausur_id}/students", methods=["GET", "POST"])
|
||||
async def klausur_students(klausur_id: str, request: Request):
|
||||
return await proxy_request(request, f"/klausuren/{klausur_id}/students")
|
||||
|
||||
|
||||
@router.api_route("/students/{student_id}", methods=["GET", "DELETE"])
|
||||
async def student_by_id(student_id: str, request: Request):
|
||||
return await proxy_request(request, f"/students/{student_id}")
|
||||
|
||||
|
||||
# Grading
|
||||
@router.api_route("/students/{student_id}/criteria", methods=["PUT"])
|
||||
async def update_criteria(student_id: str, request: Request):
|
||||
return await proxy_request(request, f"/students/{student_id}/criteria")
|
||||
|
||||
|
||||
@router.api_route("/students/{student_id}/gutachten", methods=["PUT"])
|
||||
async def update_gutachten(student_id: str, request: Request):
|
||||
return await proxy_request(request, f"/students/{student_id}/gutachten")
|
||||
|
||||
|
||||
@router.api_route("/students/{student_id}/finalize", methods=["POST"])
|
||||
async def finalize_student(student_id: str, request: Request):
|
||||
return await proxy_request(request, f"/students/{student_id}/finalize")
|
||||
|
||||
|
||||
# Grade info
|
||||
@router.get("/grade-info")
|
||||
async def grade_info(request: Request):
|
||||
return await proxy_request(request, "/grade-info")
|
||||
Reference in New Issue
Block a user