Files
pragativeer-v2/backend/models.py

171 lines
5.8 KiB
Python

from datetime import datetime, date
from enum import Enum
from typing import List, Optional, Dict, Any
from uuid import UUID, uuid4
from sqlmodel import Field, SQLModel, Relationship, JSON
# --- ENUMS ---
class ClassEnum(str, Enum):
ELEVENTH = "11"
TWELFTH = "12"
DROPPER = "Dropper"
class ExamEnum(str, Enum):
JEE_MAIN = "JEE_Main"
JEE_ADVANCED = "JEE_Advanced"
NEET = "NEET"
class MediumEnum(str, Enum):
ENGLISH = "English"
HINDI = "Hindi"
BILINGUAL = "Bilingual"
class TierEnum(str, Enum):
FREE = "Free"
PRO = "Pro"
AI_COACH = "Al_Coach"
class QuestionTypeEnum(str, Enum):
MCQ_SINGLE = "MCQ_Single"
MCQ_MULTIPLE = "MCQ_Multiple"
NUMERICAL = "Numerical"
class SourceTypeEnum(str, Enum):
DPS = "DPS"
TEST = "Test"
MICROTEST = "MicroTest"
class ErrorTypeEnum(str, Enum):
CONCEPTUAL = "Conceptual"
CALCULATION = "Calculation"
READING = "Reading"
TIME_PRESSURE = "Time_Pressure"
# --- CORE DB MODELS ---
class User(SQLModel, table=True):
id: UUID = Field(default_factory=uuid4, primary_key=True)
email: Optional[str] = Field(default=None, unique=True)
phone: Optional[str] = Field(default=None, unique=True)
password_hash: str
name: str
student_class: ClassEnum = Field(alias="class")
target_exam: ExamEnum
medium: MediumEnum
school: Optional[str] = None
city: str
state: str
tier: TierEnum = Field(default=TierEnum.FREE)
trial_end: Optional[datetime] = None
subscription_end: Optional[datetime] = None
streak_count: int = Field(default=0)
longest_streak: int = Field(default=0)
created_at: datetime = Field(default_factory=datetime.utcnow)
last_active: datetime = Field(default_factory=datetime.utcnow)
active_session_token: Optional[str] = None
class Parent(SQLModel, table=True):
id: UUID = Field(default_factory=uuid4, primary_key=True)
email: str
phone: str
password_hash: str
name: str
language: str = Field(default="English") # e.g., Hindi, English
linked_students: List[str] = Field(default=[], sa_type=JSON)
created_at: datetime = Field(default_factory=datetime.utcnow)
class Question(SQLModel, table=True):
id: UUID = Field(default_factory=uuid4, primary_key=True)
subject: str # Physics, Chemistry, Maths, Biology
topic: str
subtopic: str
difficulty: str # Easy, Medium, Hard
type: QuestionTypeEnum
question_text: str
question_text_hi: Optional[str] = None
options: Optional[Dict[str, Any]] = Field(default=None, sa_type=JSON)
options_hi: Optional[Dict[str, Any]] = Field(default=None, sa_type=JSON)
correct_answer: Dict[str, Any] = Field(sa_type=JSON)
solution_text: str
solution_text_hi: Optional[str] = None
language: MediumEnum
year: Optional[int] = None
exam: Optional[ExamEnum] = None
tags: Optional[str] = None
is_active: bool = Field(default=True)
created_by: UUID
verified_by: Optional[UUID] = None
class DPS(SQLModel, table=True):
id: UUID = Field(default_factory=uuid4, primary_key=True)
date: date
title: str
questions: List[str] = Field(default=[], sa_type=JSON) # Array of question UUID strings
difficulty: str
time_limit: int
is_active: bool = Field(default=True)
created_by: UUID
class Test(SQLModel, table=True):
id: UUID = Field(default_factory=uuid4, primary_key=True)
title: str
type: str # Weekly, Mock, PYQ
exam_pattern: ExamEnum
sections: Dict[str, Any] = Field(sa_type=JSON) # Array of {name, questions[], time_limit}
total_time: int
difficulty: str
scheduled_date: Optional[datetime] = None
end_date: Optional[datetime] = None
is_active: bool = Field(default=True)
created_by: UUID
class Attempt(SQLModel, table=True):
id: UUID = Field(default_factory=uuid4, primary_key=True)
user_id: UUID = Field(foreign_key="user.id")
source_type: SourceTypeEnum
source_id: UUID
started_at: datetime
submitted_at: Optional[datetime] = None
time_taken: Optional[int] = None # in seconds
answers: Optional[Dict[str, Any]] = Field(default=None, sa_type=JSON) # Array of {question_id, selected_answer, is_correct, time_spent}
score: int = Field(default=0)
total_questions: int
accuracy: float = Field(default=0.0)
status: str = Field(default="In_Progress") # In_Progress, Submitted, Timed_Out
class Mistake(SQLModel, table=True):
id: UUID = Field(default_factory=uuid4, primary_key=True)
user_id: UUID = Field(foreign_key="user.id")
question_id: UUID = Field(foreign_key="question.id")
attempt_id: UUID = Field(foreign_key="attempt.id")
error_type: ErrorTypeEnum
topic: str
subtopic: str
next_review: datetime
review_count: int = Field(default=0)
consecutive_correct: int = Field(default=0)
is_mastered: bool = Field(default=False)
created_at: datetime = Field(default_factory=datetime.utcnow)
class StudyPlan(SQLModel, table=True):
id: UUID = Field(default_factory=uuid4, primary_key=True)
user_id: UUID = Field(foreign_key="user.id")
date: date
tasks: Dict[str, Any] = Field(sa_type=JSON) # Array of {type, description, duration_minutes, status}
is_completed: bool = Field(default=False)
generated_at: datetime = Field(default_factory=datetime.utcnow)
feedback: Optional[str] = None
class Subscription(SQLModel, table=True):
id: UUID = Field(default_factory=uuid4, primary_key=True)
user_id: UUID = Field(foreign_key="user.id")
tier: TierEnum
billing_cycle: str # Monthly, Quarterly, Annual
start_date: datetime
end_date: datetime
amount: int # Stored in Paise (INR)
payment_id: str # Razorpay order ID / payment ID
status: str # Active, Expired, Cancelled, Paused
auto_renew: bool = Field(default=True)
coupon_code: Optional[str] = None