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>
185 lines
6.4 KiB
Python
185 lines
6.4 KiB
Python
"""
|
|
Classroom API - Settings Routes
|
|
|
|
Teacher settings endpoints (Feature f16).
|
|
"""
|
|
|
|
import logging
|
|
|
|
from fastapi import APIRouter, HTTPException, Depends
|
|
|
|
from classroom_engine import get_default_durations
|
|
|
|
from ..models import (
|
|
TeacherSettingsResponse,
|
|
UpdatePhaseDurationsRequest,
|
|
UpdatePreferencesRequest,
|
|
)
|
|
from ..services.persistence import (
|
|
init_db_if_needed,
|
|
DB_ENABLED,
|
|
SessionLocal,
|
|
)
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
router = APIRouter(tags=["Settings"])
|
|
|
|
|
|
def get_db():
|
|
"""Database session dependency."""
|
|
if DB_ENABLED and SessionLocal:
|
|
db = SessionLocal()
|
|
try:
|
|
yield db
|
|
finally:
|
|
db.close()
|
|
else:
|
|
yield None
|
|
|
|
|
|
@router.get("/settings/{teacher_id}", response_model=TeacherSettingsResponse)
|
|
async def get_teacher_settings(
|
|
teacher_id: str,
|
|
db=Depends(get_db)
|
|
):
|
|
"""
|
|
Holt die Einstellungen eines Lehrers.
|
|
|
|
Gibt die personalisierten Phasen-Dauern und UI-Praeferenzen zurueck.
|
|
Falls keine Einstellungen existieren, werden Defaults erstellt.
|
|
|
|
Args:
|
|
teacher_id: ID des Lehrers
|
|
|
|
Returns:
|
|
TeacherSettingsResponse mit allen Einstellungen
|
|
"""
|
|
if DB_ENABLED and db:
|
|
try:
|
|
from classroom_engine.repository import TeacherSettingsRepository
|
|
repo = TeacherSettingsRepository(db)
|
|
settings = repo.get_or_create(teacher_id)
|
|
return TeacherSettingsResponse(
|
|
teacher_id=settings.teacher_id,
|
|
default_phase_durations=settings.default_phase_durations or get_default_durations(),
|
|
audio_enabled=settings.audio_enabled if settings.audio_enabled is not None else True,
|
|
high_contrast=settings.high_contrast if settings.high_contrast is not None else False,
|
|
show_statistics=settings.show_statistics if settings.show_statistics is not None else True,
|
|
)
|
|
except Exception as e:
|
|
logger.error(f"Failed to get teacher settings: {e}")
|
|
raise HTTPException(status_code=500, detail=f"Fehler beim Laden der Einstellungen: {e}")
|
|
|
|
# Fallback: Defaults
|
|
return TeacherSettingsResponse(
|
|
teacher_id=teacher_id,
|
|
default_phase_durations=get_default_durations(),
|
|
audio_enabled=True,
|
|
high_contrast=False,
|
|
show_statistics=True,
|
|
)
|
|
|
|
|
|
@router.put("/settings/{teacher_id}/durations", response_model=TeacherSettingsResponse)
|
|
async def update_phase_durations(
|
|
teacher_id: str,
|
|
request: UpdatePhaseDurationsRequest,
|
|
db=Depends(get_db)
|
|
):
|
|
"""
|
|
Aktualisiert die Standard-Phasendauern eines Lehrers.
|
|
|
|
Ermoeglicht Lehrern, ihre bevorzugten Phasen-Dauern zu speichern.
|
|
Diese werden dann bei neuen Sessions als Default verwendet.
|
|
|
|
Args:
|
|
teacher_id: ID des Lehrers
|
|
request: Neue Phasen-Dauern in Minuten
|
|
|
|
Returns:
|
|
Aktualisierte TeacherSettingsResponse
|
|
"""
|
|
# Validierung: Nur gueltige Phasen erlauben
|
|
valid_phases = {"einstieg", "erarbeitung", "sicherung", "transfer", "reflexion"}
|
|
for phase in request.durations:
|
|
if phase not in valid_phases:
|
|
raise HTTPException(
|
|
status_code=400,
|
|
detail=f"Ungueltige Phase: {phase}. Erlaubt: {valid_phases}"
|
|
)
|
|
if request.durations[phase] < 1 or request.durations[phase] > 120:
|
|
raise HTTPException(
|
|
status_code=400,
|
|
detail=f"Phasen-Dauer muss zwischen 1 und 120 Minuten liegen"
|
|
)
|
|
|
|
if DB_ENABLED and db:
|
|
try:
|
|
from classroom_engine.repository import TeacherSettingsRepository
|
|
repo = TeacherSettingsRepository(db)
|
|
settings = repo.update_phase_durations(teacher_id, request.durations)
|
|
return TeacherSettingsResponse(
|
|
teacher_id=settings.teacher_id,
|
|
default_phase_durations=settings.default_phase_durations,
|
|
audio_enabled=settings.audio_enabled if settings.audio_enabled is not None else True,
|
|
high_contrast=settings.high_contrast if settings.high_contrast is not None else False,
|
|
show_statistics=settings.show_statistics if settings.show_statistics is not None else True,
|
|
)
|
|
except Exception as e:
|
|
logger.error(f"Failed to update phase durations: {e}")
|
|
raise HTTPException(status_code=500, detail=f"Fehler beim Speichern: {e}")
|
|
|
|
raise HTTPException(
|
|
status_code=503,
|
|
detail="Datenbank nicht verfuegbar - Einstellungen koennen nicht gespeichert werden"
|
|
)
|
|
|
|
|
|
@router.put("/settings/{teacher_id}/preferences", response_model=TeacherSettingsResponse)
|
|
async def update_preferences(
|
|
teacher_id: str,
|
|
request: UpdatePreferencesRequest,
|
|
db=Depends(get_db)
|
|
):
|
|
"""
|
|
Aktualisiert die UI-Praeferenzen eines Lehrers.
|
|
|
|
Ermoeglicht das Speichern von:
|
|
- audio_enabled: Audio-Hinweise aktiviert
|
|
- high_contrast: Hoher Kontrast fuer Beamer
|
|
- show_statistics: Statistiken nach Stundenende anzeigen
|
|
|
|
Args:
|
|
teacher_id: ID des Lehrers
|
|
request: Zu aktualisierende Praeferenzen
|
|
|
|
Returns:
|
|
Aktualisierte TeacherSettingsResponse
|
|
"""
|
|
if DB_ENABLED and db:
|
|
try:
|
|
from classroom_engine.repository import TeacherSettingsRepository
|
|
repo = TeacherSettingsRepository(db)
|
|
settings = repo.update_preferences(
|
|
teacher_id=teacher_id,
|
|
audio_enabled=request.audio_enabled,
|
|
high_contrast=request.high_contrast,
|
|
show_statistics=request.show_statistics
|
|
)
|
|
return TeacherSettingsResponse(
|
|
teacher_id=settings.teacher_id,
|
|
default_phase_durations=settings.default_phase_durations or get_default_durations(),
|
|
audio_enabled=settings.audio_enabled if settings.audio_enabled is not None else True,
|
|
high_contrast=settings.high_contrast if settings.high_contrast is not None else False,
|
|
show_statistics=settings.show_statistics if settings.show_statistics is not None else True,
|
|
)
|
|
except Exception as e:
|
|
logger.error(f"Failed to update preferences: {e}")
|
|
raise HTTPException(status_code=500, detail=f"Fehler beim Speichern: {e}")
|
|
|
|
raise HTTPException(
|
|
status_code=503,
|
|
detail="Datenbank nicht verfuegbar - Einstellungen koennen nicht gespeichert werden"
|
|
)
|