""" Classroom API - Events & Routines Routes School year events, recurring routines endpoints (Phase 8). """ from typing import Optional from datetime import datetime import logging from fastapi import APIRouter, HTTPException, Query, Depends from ..models import ( CreateEventRequest, EventResponse, CreateRoutineRequest, RoutineResponse, ) from ..services.persistence import ( DB_ENABLED, SessionLocal, ) logger = logging.getLogger(__name__) router = APIRouter(tags=["Context"]) def get_db(): """Database session dependency.""" if DB_ENABLED and SessionLocal: db = SessionLocal() try: yield db finally: db.close() else: yield None # === Events Endpoints === @router.get("/v1/events") async def get_events( teacher_id: str = Query(...), status: Optional[str] = None, event_type: Optional[str] = None, limit: int = 50, db=Depends(get_db) ): """Holt Events eines Lehrers.""" if not DB_ENABLED or not db: return {"events": [], "count": 0} try: from classroom_engine.repository import SchoolyearEventRepository repo = SchoolyearEventRepository(db) events = repo.get_by_teacher(teacher_id, status=status, event_type=event_type, limit=limit) return { "events": [repo.to_dict(e) for e in events], "count": len(events), } except Exception as e: logger.error(f"Failed to get events: {e}") raise HTTPException(status_code=500, detail=f"Fehler: {e}") @router.get("/v1/events/upcoming") async def get_upcoming_events( teacher_id: str = Query(...), days: int = 30, limit: int = 10, db=Depends(get_db) ): """Holt anstehende Events der naechsten X Tage.""" if not DB_ENABLED or not db: return {"events": [], "count": 0} try: from classroom_engine.repository import SchoolyearEventRepository repo = SchoolyearEventRepository(db) events = repo.get_upcoming(teacher_id, days=days, limit=limit) return { "events": [repo.to_dict(e) for e in events], "count": len(events), } except Exception as e: logger.error(f"Failed to get upcoming events: {e}") raise HTTPException(status_code=500, detail=f"Fehler: {e}") @router.post("/v1/events", response_model=EventResponse) async def create_event( teacher_id: str, request: CreateEventRequest, db=Depends(get_db) ): """Erstellt ein neues Schuljahr-Event.""" if not DB_ENABLED or not db: raise HTTPException(status_code=503, detail="Datenbank nicht verfuegbar") try: from classroom_engine.repository import SchoolyearEventRepository repo = SchoolyearEventRepository(db) start_date = datetime.fromisoformat(request.start_date.replace('Z', '+00:00')) end_date = None if request.end_date: end_date = datetime.fromisoformat(request.end_date.replace('Z', '+00:00')) event = repo.create( teacher_id=teacher_id, title=request.title, event_type=request.event_type, start_date=start_date, end_date=end_date, class_id=request.class_id, subject=request.subject, description=request.description, needs_preparation=request.needs_preparation, reminder_days_before=request.reminder_days_before, ) return EventResponse( id=event.id, teacher_id=event.teacher_id, event_type=event.event_type.value, title=event.title, description=event.description, start_date=event.start_date.isoformat(), end_date=event.end_date.isoformat() if event.end_date else None, class_id=event.class_id, subject=event.subject, status=event.status.value, needs_preparation=event.needs_preparation, preparation_done=event.preparation_done, reminder_days_before=event.reminder_days_before, ) except Exception as e: logger.error(f"Failed to create event: {e}") raise HTTPException(status_code=500, detail=f"Fehler: {e}") @router.delete("/v1/events/{event_id}") async def delete_event(event_id: str, db=Depends(get_db)): """Loescht ein Event.""" if not DB_ENABLED or not db: raise HTTPException(status_code=503, detail="Datenbank nicht verfuegbar") try: from classroom_engine.repository import SchoolyearEventRepository repo = SchoolyearEventRepository(db) if repo.delete(event_id): return {"success": True, "deleted_id": event_id} raise HTTPException(status_code=404, detail="Event nicht gefunden") except HTTPException: raise except Exception as e: logger.error(f"Failed to delete event: {e}") raise HTTPException(status_code=500, detail=f"Fehler: {e}") # === Routines Endpoints === @router.get("/v1/routines") async def get_routines( teacher_id: str = Query(...), is_active: bool = True, routine_type: Optional[str] = None, db=Depends(get_db) ): """Holt Routinen eines Lehrers.""" if not DB_ENABLED or not db: return {"routines": [], "count": 0} try: from classroom_engine.repository import RecurringRoutineRepository repo = RecurringRoutineRepository(db) routines = repo.get_by_teacher(teacher_id, is_active=is_active, routine_type=routine_type) return { "routines": [repo.to_dict(r) for r in routines], "count": len(routines), } except Exception as e: logger.error(f"Failed to get routines: {e}") raise HTTPException(status_code=500, detail=f"Fehler: {e}") @router.get("/v1/routines/today") async def get_today_routines(teacher_id: str = Query(...), db=Depends(get_db)): """Holt Routinen die heute stattfinden.""" if not DB_ENABLED or not db: return {"routines": [], "count": 0} try: from classroom_engine.repository import RecurringRoutineRepository repo = RecurringRoutineRepository(db) routines = repo.get_today(teacher_id) return { "routines": [repo.to_dict(r) for r in routines], "count": len(routines), } except Exception as e: logger.error(f"Failed to get today's routines: {e}") raise HTTPException(status_code=500, detail=f"Fehler: {e}") @router.post("/v1/routines", response_model=RoutineResponse) async def create_routine( teacher_id: str, request: CreateRoutineRequest, db=Depends(get_db) ): """Erstellt eine neue wiederkehrende Routine.""" if not DB_ENABLED or not db: raise HTTPException(status_code=503, detail="Datenbank nicht verfuegbar") try: from classroom_engine.repository import RecurringRoutineRepository repo = RecurringRoutineRepository(db) routine = repo.create( teacher_id=teacher_id, title=request.title, routine_type=request.routine_type, recurrence_pattern=request.recurrence_pattern, day_of_week=request.day_of_week, day_of_month=request.day_of_month, time_of_day=request.time_of_day, duration_minutes=request.duration_minutes, description=request.description, ) return RoutineResponse( id=routine.id, teacher_id=routine.teacher_id, routine_type=routine.routine_type.value, title=routine.title, description=routine.description, recurrence_pattern=routine.recurrence_pattern.value, day_of_week=routine.day_of_week, day_of_month=routine.day_of_month, time_of_day=routine.time_of_day.isoformat() if routine.time_of_day else None, duration_minutes=routine.duration_minutes, is_active=routine.is_active, ) except Exception as e: logger.error(f"Failed to create routine: {e}") raise HTTPException(status_code=500, detail=f"Fehler: {e}") @router.delete("/v1/routines/{routine_id}") async def delete_routine(routine_id: str, db=Depends(get_db)): """Loescht eine Routine.""" if not DB_ENABLED or not db: raise HTTPException(status_code=503, detail="Datenbank nicht verfuegbar") try: from classroom_engine.repository import RecurringRoutineRepository repo = RecurringRoutineRepository(db) if repo.delete(routine_id): return {"success": True, "deleted_id": routine_id} raise HTTPException(status_code=404, detail="Routine nicht gefunden") except HTTPException: raise except Exception as e: logger.error(f"Failed to delete routine: {e}") raise HTTPException(status_code=500, detail=f"Fehler: {e}")