109 lines
3.1 KiB
Python
109 lines
3.1 KiB
Python
"""
|
|
Pydantic schemas for Session API endpoints.
|
|
"""
|
|
|
|
from datetime import datetime
|
|
from typing import List, Literal, Optional
|
|
|
|
from pydantic import BaseModel, Field
|
|
|
|
|
|
class UserAnswerInput(BaseModel):
|
|
"""Input schema for a single user answer."""
|
|
|
|
item_id: int = Field(..., description="Item/question ID")
|
|
response: str = Field(..., min_length=1, max_length=10, description="User's answer (A, B, C, D)")
|
|
time_spent: int = Field(default=0, ge=0, description="Time spent on this question (seconds)")
|
|
|
|
|
|
class SessionCompleteRequest(BaseModel):
|
|
"""Request schema for completing a session."""
|
|
|
|
end_time: datetime = Field(..., description="Session end timestamp")
|
|
user_answers: List[UserAnswerInput] = Field(..., description="List of user answers")
|
|
|
|
|
|
class UserAnswerOutput(BaseModel):
|
|
"""Output schema for a single user answer."""
|
|
|
|
id: int
|
|
item_id: int
|
|
response: str
|
|
is_correct: bool
|
|
time_spent: int
|
|
bobot_earned: float
|
|
scoring_mode_used: str
|
|
|
|
model_config = {"from_attributes": True}
|
|
|
|
|
|
class SessionCompleteResponse(BaseModel):
|
|
"""Response schema for completed session with CTT scores."""
|
|
|
|
id: int
|
|
session_id: str
|
|
wp_user_id: str
|
|
website_id: int
|
|
tryout_id: str
|
|
start_time: datetime
|
|
end_time: Optional[datetime]
|
|
is_completed: bool
|
|
scoring_mode_used: str
|
|
|
|
# CTT scores
|
|
total_benar: int = Field(description="Total correct answers")
|
|
total_bobot_earned: float = Field(description="Total weight earned")
|
|
NM: Optional[int] = Field(description="Nilai Mentah (raw score) [0, 1000]")
|
|
NN: Optional[int] = Field(description="Nilai Nasional (normalized score) [0, 1000]")
|
|
|
|
# Normalization metadata
|
|
rataan_used: Optional[float] = Field(description="Mean value used for normalization")
|
|
sb_used: Optional[float] = Field(description="Standard deviation used for normalization")
|
|
|
|
# User answers
|
|
user_answers: List[UserAnswerOutput]
|
|
|
|
model_config = {"from_attributes": True}
|
|
|
|
|
|
class SessionCreateRequest(BaseModel):
|
|
"""Request schema for creating a new session."""
|
|
|
|
session_id: str = Field(..., description="Unique session identifier")
|
|
wp_user_id: str = Field(..., description="WordPress user ID")
|
|
website_id: int = Field(..., description="Website identifier")
|
|
tryout_id: str = Field(..., description="Tryout identifier")
|
|
scoring_mode: Literal["ctt", "irt", "hybrid"] = Field(
|
|
default="ctt", description="Scoring mode for this session"
|
|
)
|
|
|
|
|
|
class SessionResponse(BaseModel):
|
|
"""Response schema for session data."""
|
|
|
|
id: int
|
|
session_id: str
|
|
wp_user_id: str
|
|
website_id: int
|
|
tryout_id: str
|
|
start_time: datetime
|
|
end_time: Optional[datetime]
|
|
is_completed: bool
|
|
scoring_mode_used: str
|
|
|
|
# CTT scores (populated after completion)
|
|
total_benar: int
|
|
total_bobot_earned: float
|
|
NM: Optional[int]
|
|
NN: Optional[int]
|
|
|
|
# IRT scores (populated after completion)
|
|
theta: Optional[float]
|
|
theta_se: Optional[float]
|
|
|
|
# Normalization metadata
|
|
rataan_used: Optional[float]
|
|
sb_used: Optional[float]
|
|
|
|
model_config = {"from_attributes": True}
|