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:
184
backend/classroom/routes/settings.py
Normal file
184
backend/classroom/routes/settings.py
Normal file
@@ -0,0 +1,184 @@
|
||||
"""
|
||||
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"
|
||||
)
|
||||
Reference in New Issue
Block a user