from datetime import datetime from typing import Optional from pydantic import BaseModel # ── Начало попытки ────────────────────────────────────────── class AttemptStart(BaseModel): test_id: int class AnswerForTest(BaseModel): """Вариант ответа без поля is_correct — не раскрываем правильные ответы.""" id: int text: str model_config = {"from_attributes": True} class QuestionForTest(BaseModel): id: int text: str is_multiple: bool # True = несколько правильных ответов → показываем чекбоксы answers: list[AnswerForTest] # перемешаны случайно model_config = {"from_attributes": True} class AttemptStarted(BaseModel): """Возвращается после старта попытки.""" id: int test_id: int test_title: str test_description: Optional[str] started_at: datetime time_limit: Optional[int] # минуты, из теста allow_navigation_back: bool # из теста questions: list[QuestionForTest] # перемешаны случайно model_config = {"from_attributes": True} # ── Сдача попытки ──────────────────────────────────────────── class QuestionAnswer(BaseModel): """Ответы сотрудника на один вопрос.""" question_id: int answer_ids: list[int] # выбранные варианты (может быть пустым) class AttemptSubmitDto(BaseModel): answers: list[QuestionAnswer] # ── Результат ──────────────────────────────────────────────── class AnswerResult(BaseModel): id: int text: str is_correct: bool # правильный ли ответ вообще is_selected: bool # выбрал ли его сотрудник model_config = {"from_attributes": True} class QuestionResult(BaseModel): id: int text: str is_answered_correctly: bool # вся комбинация ответов верна answers: list[AnswerResult] model_config = {"from_attributes": True} class AttemptResult(BaseModel): id: int test_id: int test_title: str started_at: datetime finished_at: datetime score: float # процент правильных ответов passed: bool # преодолён ли порог зачёта passing_score: int # порог из теста correct_count: int total_count: int questions: list[QuestionResult] model_config = {"from_attributes": True} # ── Трекер результатов ──────────────────────────────────────── class AttemptListItem(BaseModel): id: int test_id: int test_title: str test_version: int user_id: int user_name: str started_at: datetime finished_at: Optional[datetime] score: Optional[float] correct_count: Optional[int] total_count: Optional[int] passed: Optional[bool] model_config = {"from_attributes": True} class AttemptListResponse(BaseModel): items: list[AttemptListItem] total: int page: int page_size: int