Services: Admin-Lehrer, Backend-Lehrer, Studio v2, Website, Klausur-Service, School-Service, Voice-Service, Geo-Service, BreakPilot Drive, Agent-Core Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
132 lines
3.8 KiB
Python
132 lines
3.8 KiB
Python
"""
|
|
Klausur-Service Student Routes
|
|
|
|
Endpoints for student work management.
|
|
"""
|
|
|
|
import os
|
|
import uuid
|
|
from datetime import datetime, timezone
|
|
|
|
from fastapi import APIRouter, HTTPException, Request, UploadFile, File, Form
|
|
from fastapi.responses import FileResponse
|
|
|
|
from models.exam import StudentKlausur
|
|
from models.enums import StudentKlausurStatus
|
|
from services.auth_service import get_current_user
|
|
from config import UPLOAD_DIR
|
|
import storage
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
@router.post("/api/v1/klausuren/{klausur_id}/students")
|
|
async def upload_student_work(
|
|
klausur_id: str,
|
|
student_name: str = Form(...),
|
|
file: UploadFile = File(...),
|
|
request: Request = None
|
|
):
|
|
"""Upload a student's work."""
|
|
user = get_current_user(request)
|
|
|
|
if klausur_id not in storage.klausuren_db:
|
|
raise HTTPException(status_code=404, detail="Klausur not found")
|
|
|
|
klausur = storage.klausuren_db[klausur_id]
|
|
|
|
# Save file
|
|
upload_dir = f"{UPLOAD_DIR}/{klausur_id}"
|
|
os.makedirs(upload_dir, exist_ok=True)
|
|
|
|
file_ext = os.path.splitext(file.filename)[1]
|
|
file_id = str(uuid.uuid4())
|
|
file_path = f"{upload_dir}/{file_id}{file_ext}"
|
|
|
|
with open(file_path, "wb") as f:
|
|
content = await file.read()
|
|
f.write(content)
|
|
|
|
# Create student record
|
|
student = StudentKlausur(
|
|
id=file_id,
|
|
klausur_id=klausur_id,
|
|
student_name=student_name,
|
|
student_id=None,
|
|
file_path=file_path,
|
|
ocr_text=None,
|
|
status=StudentKlausurStatus.UPLOADED,
|
|
criteria_scores={},
|
|
gutachten=None,
|
|
raw_points=0,
|
|
grade_points=0,
|
|
created_at=datetime.now(timezone.utc)
|
|
)
|
|
|
|
storage.students_db[student.id] = student
|
|
klausur.students.append(student)
|
|
|
|
return student.to_dict()
|
|
|
|
|
|
@router.get("/api/v1/klausuren/{klausur_id}/students")
|
|
async def list_students(klausur_id: str, request: Request):
|
|
"""List all students for a Klausur."""
|
|
user = get_current_user(request)
|
|
|
|
if klausur_id not in storage.klausuren_db:
|
|
raise HTTPException(status_code=404, detail="Klausur not found")
|
|
|
|
klausur = storage.klausuren_db[klausur_id]
|
|
return [s.to_dict() for s in klausur.students]
|
|
|
|
|
|
@router.get("/api/v1/students/{student_id}/file")
|
|
async def get_student_file(student_id: str, request: Request):
|
|
"""Get the uploaded file for a student."""
|
|
user = get_current_user(request)
|
|
|
|
if student_id not in storage.students_db:
|
|
raise HTTPException(status_code=404, detail="Student work not found")
|
|
|
|
student = storage.students_db[student_id]
|
|
|
|
if not student.file_path or not os.path.exists(student.file_path):
|
|
raise HTTPException(status_code=404, detail="File not found")
|
|
|
|
# Determine media type from file extension
|
|
ext = os.path.splitext(student.file_path)[1].lower()
|
|
media_types = {
|
|
'.pdf': 'application/pdf',
|
|
'.png': 'image/png',
|
|
'.jpg': 'image/jpeg',
|
|
'.jpeg': 'image/jpeg',
|
|
'.gif': 'image/gif',
|
|
}
|
|
media_type = media_types.get(ext, 'application/octet-stream')
|
|
|
|
return FileResponse(student.file_path, media_type=media_type)
|
|
|
|
|
|
@router.delete("/api/v1/students/{student_id}")
|
|
async def delete_student_work(student_id: str, request: Request):
|
|
"""Delete a student's work."""
|
|
user = get_current_user(request)
|
|
|
|
if student_id not in storage.students_db:
|
|
raise HTTPException(status_code=404, detail="Student work not found")
|
|
|
|
student = storage.students_db[student_id]
|
|
|
|
# Remove from klausur
|
|
if student.klausur_id in storage.klausuren_db:
|
|
klausur = storage.klausuren_db[student.klausur_id]
|
|
klausur.students = [s for s in klausur.students if s.id != student_id]
|
|
|
|
# Delete file
|
|
if student.file_path and os.path.exists(student.file_path):
|
|
os.remove(student.file_path)
|
|
|
|
del storage.students_db[student_id]
|
|
return {"success": True}
|