""" 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")