from datetime import datetime from enum import Enum from typing import List, Optional from pydantic import BaseModel, Field, validator from app.schemas.question import Question from app.schemas.user import User class QuizQuestionBase(BaseModel): question_id: int position: int = 0 class QuizQuestionCreate(QuizQuestionBase): pass class QuizQuestionUpdate(QuizQuestionBase): question_id: Optional[int] = None position: Optional[int] = None class QuizQuestionInDBBase(QuizQuestionBase): id: int quiz_id: int class Config: orm_mode = True class QuizQuestion(QuizQuestionInDBBase): question: Optional[Question] = None class QuizBase(BaseModel): title: str description: Optional[str] = None is_public: bool = False time_limit_minutes: int = 10 pass_percentage: float = 70.0 class QuizCreate(QuizBase): questions: List[QuizQuestionCreate] = Field(..., min_items=1) @validator("questions") def validate_unique_questions(cls, v): question_ids = [q.question_id for q in v] if len(question_ids) != len(set(question_ids)): raise ValueError("Quiz cannot contain duplicate questions") return v class QuizUpdate(QuizBase): title: Optional[str] = None description: Optional[str] = None is_public: Optional[bool] = None time_limit_minutes: Optional[int] = None pass_percentage: Optional[float] = None questions: Optional[List[QuizQuestionCreate]] = None @validator("questions") def validate_unique_questions(cls, v): if v is not None: question_ids = [q.question_id for q in v] if len(question_ids) != len(set(question_ids)): raise ValueError("Quiz cannot contain duplicate questions") return v class QuizInDBBase(QuizBase): id: int user_id: int created_at: datetime updated_at: datetime class Config: orm_mode = True class Quiz(QuizInDBBase): user: Optional[User] = None questions: List[QuizQuestion] = [] class QuizWithoutDetails(QuizInDBBase): user: Optional[User] = None question_count: int class AttemptStatus(str, Enum): started = "started" completed = "completed" abandoned = "abandoned" class QuizAnswerBase(BaseModel): quiz_question_id: int selected_option_id: Optional[int] = None class QuizAnswerCreate(QuizAnswerBase): pass class QuizAnswerUpdate(QuizAnswerBase): selected_option_id: Optional[int] = None class QuizAnswerInDBBase(QuizAnswerBase): id: int quiz_attempt_id: int is_correct: Optional[bool] = None answered_at: datetime class Config: orm_mode = True class QuizAnswer(QuizAnswerInDBBase): pass class QuizAttemptBase(BaseModel): quiz_id: int status: AttemptStatus = AttemptStatus.started score: Optional[float] = None started_at: datetime = Field(default_factory=datetime.utcnow) completed_at: Optional[datetime] = None class QuizAttemptCreate(QuizAttemptBase): pass class QuizAttemptUpdate(QuizAttemptBase): status: Optional[AttemptStatus] = None score: Optional[float] = None completed_at: Optional[datetime] = None class QuizAttemptInDBBase(QuizAttemptBase): id: int user_id: int class Config: orm_mode = True class QuizAttempt(QuizAttemptInDBBase): quiz: Optional[Quiz] = None answers: List[QuizAnswer] = [] class QuizSubmitAnswer(BaseModel): selected_option_id: int