""" Classroom API - Pydantic Models. Alle Request/Response Models fuer die Classroom API. """ from typing import Dict, List, Optional, Any from pydantic import BaseModel, Field # === Request Models === class CreateSessionRequest(BaseModel): """Request zum Erstellen einer neuen Session.""" teacher_id: str = Field(..., description="ID des Lehrers") class_id: str = Field(..., description="ID der Klasse") subject: str = Field(..., description="Unterrichtsfach") topic: Optional[str] = Field(None, description="Thema der Stunde") phase_durations: Optional[Dict[str, int]] = Field( None, description="Optionale individuelle Phasendauern in Minuten" ) class NotesRequest(BaseModel): """Request zum Aktualisieren von Notizen.""" notes: str = Field("", description="Stundennotizen") homework: str = Field("", description="Hausaufgaben") class ExtendTimeRequest(BaseModel): """Request zum Verlaengern der aktuellen Phase (Feature f28).""" minutes: int = Field(5, ge=1, le=30, description="Zusaetzliche Minuten (1-30)") # === Response Models === class PhaseInfo(BaseModel): """Informationen zu einer Phase.""" phase: str display_name: str icon: str duration_minutes: int is_completed: bool is_current: bool is_future: bool class TimerStatus(BaseModel): """Timer-Status einer Phase.""" remaining_seconds: int remaining_formatted: str total_seconds: int total_formatted: str elapsed_seconds: int elapsed_formatted: str percentage_remaining: int percentage_elapsed: int percentage: int = Field(description="Alias fuer percentage_remaining (Visual Timer)") warning: bool overtime: bool overtime_seconds: int overtime_formatted: Optional[str] is_paused: bool = Field(False, description="Ist der Timer pausiert?") class SuggestionItem(BaseModel): """Ein Aktivitaets-Vorschlag.""" id: str title: str description: str activity_type: str estimated_minutes: int icon: str content_url: Optional[str] class SessionResponse(BaseModel): """Vollstaendige Session-Response.""" session_id: str teacher_id: str class_id: str subject: str topic: Optional[str] current_phase: str phase_display_name: str phase_started_at: Optional[str] lesson_started_at: Optional[str] lesson_ended_at: Optional[str] timer: TimerStatus phases: List[PhaseInfo] phase_history: List[Dict[str, Any]] notes: str homework: str is_active: bool is_ended: bool is_paused: bool = Field(False, description="Ist die Stunde pausiert?") class SuggestionsResponse(BaseModel): """Response fuer Vorschlaege.""" suggestions: List[SuggestionItem] current_phase: str phase_display_name: str total_available: int class PhasesListResponse(BaseModel): """Liste aller verfuegbaren Phasen.""" phases: List[Dict[str, Any]] class ActiveSessionsResponse(BaseModel): """Liste aktiver Sessions.""" sessions: List[Dict[str, Any]] count: int # === Session History Models (Feature f17) === class SessionHistoryItem(BaseModel): """Ein Eintrag in der Session-Historie.""" session_id: str teacher_id: str class_id: str subject: str topic: Optional[str] lesson_started_at: Optional[str] lesson_ended_at: Optional[str] total_duration_minutes: int phases_completed: int notes: str homework: str class SessionHistoryResponse(BaseModel): """Response fuer Session-Historie.""" sessions: List[SessionHistoryItem] total_count: int page: int page_size: int # === Template Models === class TemplatePhaseConfig(BaseModel): """Konfiguration einer Phase im Template.""" phase: str duration_minutes: int activities: List[str] = Field(default_factory=list) notes: str = "" class CreateTemplateRequest(BaseModel): """Request zum Erstellen eines Templates.""" name: str = Field(..., min_length=1, max_length=100) description: str = Field("", max_length=500) subject: str = Field(..., min_length=1) grade_level: Optional[str] = None phase_configs: Optional[List[TemplatePhaseConfig]] = None tags: List[str] = Field(default_factory=list) is_public: bool = False class UpdateTemplateRequest(BaseModel): """Request zum Aktualisieren eines Templates.""" name: Optional[str] = Field(None, min_length=1, max_length=100) description: Optional[str] = Field(None, max_length=500) subject: Optional[str] = None grade_level: Optional[str] = None phase_configs: Optional[List[TemplatePhaseConfig]] = None tags: Optional[List[str]] = None is_public: Optional[bool] = None class TemplateResponse(BaseModel): """Response fuer ein einzelnes Template.""" template_id: str name: str description: str subject: str grade_level: Optional[str] phase_configs: List[TemplatePhaseConfig] tags: List[str] is_public: bool is_system: bool created_by: str created_at: str updated_at: Optional[str] usage_count: int class TemplateListResponse(BaseModel): """Response fuer Template-Liste.""" templates: List[TemplateResponse] total_count: int class CreateFromTemplateRequest(BaseModel): """Request zum Erstellen einer Session aus Template.""" template_id: str class_id: str topic: Optional[str] = None phase_duration_overrides: Optional[Dict[str, int]] = None # === Homework Models === class CreateHomeworkRequest(BaseModel): """Request zum Erstellen einer Hausaufgabe.""" session_id: Optional[str] = None teacher_id: str class_id: str subject: str title: str = Field(..., min_length=1, max_length=200) description: str = Field("", max_length=2000) due_date: Optional[str] = None estimated_minutes: Optional[int] = Field(None, ge=5, le=180) materials: List[str] = Field(default_factory=list) tags: List[str] = Field(default_factory=list) class UpdateHomeworkRequest(BaseModel): """Request zum Aktualisieren einer Hausaufgabe.""" title: Optional[str] = Field(None, min_length=1, max_length=200) description: Optional[str] = Field(None, max_length=2000) due_date: Optional[str] = None estimated_minutes: Optional[int] = Field(None, ge=5, le=180) status: Optional[str] = None materials: Optional[List[str]] = None tags: Optional[List[str]] = None class HomeworkResponse(BaseModel): """Response fuer eine Hausaufgabe.""" homework_id: str session_id: Optional[str] teacher_id: str class_id: str subject: str title: str description: str due_date: Optional[str] estimated_minutes: Optional[int] status: str materials: List[str] tags: List[str] created_at: str updated_at: Optional[str] class HomeworkListResponse(BaseModel): """Response fuer Hausaufgaben-Liste.""" homework: List[HomeworkResponse] total_count: int # === Material Models === class CreateMaterialRequest(BaseModel): """Request zum Erstellen eines Materials.""" teacher_id: str title: str = Field(..., min_length=1, max_length=200) description: str = Field("", max_length=1000) material_type: str = Field(..., description="Type: link, document, video, interactive, image") content_url: Optional[str] = None content_data: Optional[Dict[str, Any]] = None phase: Optional[str] = None subject: Optional[str] = None tags: List[str] = Field(default_factory=list) is_public: bool = False class UpdateMaterialRequest(BaseModel): """Request zum Aktualisieren eines Materials.""" title: Optional[str] = Field(None, min_length=1, max_length=200) description: Optional[str] = Field(None, max_length=1000) material_type: Optional[str] = None content_url: Optional[str] = None content_data: Optional[Dict[str, Any]] = None phase: Optional[str] = None subject: Optional[str] = None tags: Optional[List[str]] = None is_public: Optional[bool] = None class MaterialResponse(BaseModel): """Response fuer ein Material.""" material_id: str teacher_id: str title: str description: str material_type: str content_url: Optional[str] content_data: Optional[Dict[str, Any]] phase: Optional[str] subject: Optional[str] tags: List[str] is_public: bool usage_count: int created_at: str updated_at: Optional[str] class MaterialListResponse(BaseModel): """Response fuer Material-Liste.""" materials: List[MaterialResponse] total_count: int # === Feedback Models === class CreateFeedbackRequest(BaseModel): """Request zum Erstellen von Feedback.""" teacher_id: str session_id: Optional[str] = None category: str = Field(..., description="bug, feature, usability, content, other") title: str = Field(..., min_length=1, max_length=200) description: str = Field(..., min_length=10, max_length=5000) priority: str = Field("medium", description="low, medium, high, critical") context_data: Optional[Dict[str, Any]] = None class FeedbackResponse(BaseModel): """Response fuer ein Feedback.""" feedback_id: str teacher_id: str session_id: Optional[str] category: str title: str description: str priority: str status: str context_data: Optional[Dict[str, Any]] admin_notes: Optional[str] created_at: str updated_at: Optional[str] class FeedbackListResponse(BaseModel): """Response fuer Feedback-Liste.""" feedback: List[FeedbackResponse] total_count: int class FeedbackStatsResponse(BaseModel): """Response fuer Feedback-Statistiken.""" total: int by_category: Dict[str, int] by_status: Dict[str, int] by_priority: Dict[str, int] # === Settings Models === class PhaseDurationsUpdate(BaseModel): """Update fuer Phasendauern.""" einstieg: Optional[int] = Field(None, ge=1, le=30) erarbeitung: Optional[int] = Field(None, ge=5, le=45) sicherung: Optional[int] = Field(None, ge=3, le=20) transfer: Optional[int] = Field(None, ge=3, le=20) reflexion: Optional[int] = Field(None, ge=2, le=15) class PreferencesUpdate(BaseModel): """Update fuer Lehrer-Praeferenzen.""" auto_advance: Optional[bool] = None sound_enabled: Optional[bool] = None notification_enabled: Optional[bool] = None theme: Optional[str] = None language: Optional[str] = None class TeacherSettingsResponse(BaseModel): """Response fuer Lehrer-Einstellungen.""" teacher_id: str phase_durations: Dict[str, int] preferences: Dict[str, Any] created_at: str updated_at: Optional[str] # === Analytics Models === class ReflectionRequest(BaseModel): """Request zum Erstellen/Aktualisieren einer Reflexion.""" session_id: str teacher_id: str overall_rating: int = Field(..., ge=1, le=5) time_management_rating: int = Field(..., ge=1, le=5) student_engagement_rating: int = Field(..., ge=1, le=5) goals_achieved_rating: int = Field(..., ge=1, le=5) what_worked_well: str = Field("", max_length=2000) what_to_improve: str = Field("", max_length=2000) notes_for_next_time: str = Field("", max_length=2000) tags: List[str] = Field(default_factory=list) class ReflectionResponse(BaseModel): """Response fuer eine Reflexion.""" reflection_id: str session_id: str teacher_id: str overall_rating: int time_management_rating: int student_engagement_rating: int goals_achieved_rating: int what_worked_well: str what_to_improve: str notes_for_next_time: str tags: List[str] created_at: str updated_at: Optional[str] # === Teacher Context Models (v1 API) === class TeacherContextResponse(BaseModel): """Response fuer Teacher Context.""" teacher_id: str federal_state: Optional[str] school_type: Optional[str] subjects: List[str] class_levels: List[str] current_macro_phase: Optional[str] onboarding_completed: bool preferences: Dict[str, Any] created_at: str updated_at: Optional[str] class UpdateTeacherContextRequest(BaseModel): """Request zum Aktualisieren des Teacher Context.""" federal_state: Optional[str] = None school_type: Optional[str] = None subjects: Optional[List[str]] = None class_levels: Optional[List[str]] = None current_macro_phase: Optional[str] = None preferences: Optional[Dict[str, Any]] = None class EventResponse(BaseModel): """Response fuer ein Schuljahres-Event.""" event_id: str teacher_id: str title: str event_type: str start_date: str end_date: Optional[str] description: Optional[str] status: str metadata: Optional[Dict[str, Any]] created_at: str class CreateEventRequest(BaseModel): """Request zum Erstellen eines Events.""" title: str = Field(..., min_length=1, max_length=200) event_type: str start_date: str end_date: Optional[str] = None description: Optional[str] = Field(None, max_length=1000) metadata: Optional[Dict[str, Any]] = None class RoutineResponse(BaseModel): """Response fuer eine wiederkehrende Routine.""" routine_id: str teacher_id: str title: str routine_type: str recurrence_pattern: str day_of_week: Optional[int] time_of_day: Optional[str] description: Optional[str] is_active: bool metadata: Optional[Dict[str, Any]] created_at: str class CreateRoutineRequest(BaseModel): """Request zum Erstellen einer Routine.""" title: str = Field(..., min_length=1, max_length=200) routine_type: str recurrence_pattern: str day_of_week: Optional[int] = Field(None, ge=0, le=6) time_of_day: Optional[str] = None description: Optional[str] = Field(None, max_length=500) metadata: Optional[Dict[str, Any]] = None