This repository has been archived on 2026-02-15. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
BreakPilot Dev 19855efacc
Some checks failed
Tests / Go Tests (push) Has been cancelled
Tests / Python Tests (push) Has been cancelled
Tests / Integration Tests (push) Has been cancelled
Tests / Go Lint (push) Has been cancelled
Tests / Python Lint (push) Has been cancelled
Tests / Security Scan (push) Has been cancelled
Tests / All Checks Passed (push) Has been cancelled
Security Scanning / Secret Scanning (push) Has been cancelled
Security Scanning / Dependency Vulnerability Scan (push) Has been cancelled
Security Scanning / Go Security Scan (push) Has been cancelled
Security Scanning / Python Security Scan (push) Has been cancelled
Security Scanning / Node.js Security Scan (push) Has been cancelled
Security Scanning / Docker Image Security (push) Has been cancelled
Security Scanning / Security Summary (push) Has been cancelled
CI/CD Pipeline / Go Tests (push) Has been cancelled
CI/CD Pipeline / Python Tests (push) Has been cancelled
CI/CD Pipeline / Website Tests (push) Has been cancelled
CI/CD Pipeline / Linting (push) Has been cancelled
CI/CD Pipeline / Security Scan (push) Has been cancelled
CI/CD Pipeline / Docker Build & Push (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Deploy to Staging (push) Has been cancelled
CI/CD Pipeline / Deploy to Production (push) Has been cancelled
CI/CD Pipeline / CI Summary (push) Has been cancelled
ci/woodpecker/manual/build-ci-image Pipeline was successful
ci/woodpecker/manual/main Pipeline failed
feat: BreakPilot PWA - Full codebase (clean push without large binaries)
All services: admin-v2, studio-v2, website, ai-compliance-sdk,
consent-service, klausur-service, voice-service, and infrastructure.
Large PDFs and compiled binaries excluded via .gitignore.
2026-02-11 13:25:58 +01:00

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}