from __future__ import annotations import enum from datetime import datetime from sqlalchemy import Boolean, Column, DateTime, Enum, Float, ForeignKey, Integer from sqlalchemy.orm import relationship from app.db.base_class import Base class ProgressStatus(enum.Enum): NOT_STARTED = "not_started" IN_PROGRESS = "in_progress" COMPLETED = "completed" class UserProgress(Base): """ UserProgress model for tracking user progress through lessons. """ id = Column(Integer, primary_key=True, index=True) user_id = Column(Integer, ForeignKey("user.id"), nullable=False) lesson_id = Column(Integer, ForeignKey("lesson.id"), nullable=False) status = Column(Enum(ProgressStatus), default=ProgressStatus.NOT_STARTED) progress_percentage = Column(Float, default=0.0) completed_at = Column(DateTime, nullable=True) points_earned = Column(Integer, default=0) created_at = Column(DateTime, default=datetime.utcnow) updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) # Relationships user = relationship("User", back_populates="progress") lesson = relationship("Lesson", back_populates="progress") # This ensures that a user can only have one progress record per lesson __table_args__ = ( # UniqueConstraint('user_id', 'lesson_id', name='user_lesson_progress_uc'), ) class UserAnswer(Base): """ UserAnswer model for tracking user answers to quiz questions. """ id = Column(Integer, primary_key=True, index=True) user_id = Column(Integer, ForeignKey("user.id"), nullable=False) question_id = Column(Integer, ForeignKey("question.id"), nullable=False) answer_id = Column(Integer, ForeignKey("answer.id"), nullable=False) is_correct = Column(Boolean, default=False) points_earned = Column(Integer, default=0) attempt_number = Column(Integer, default=1) time_taken_seconds = Column(Integer, nullable=True) # Time taken to answer created_at = Column(DateTime, default=datetime.utcnow) # Relationships user = relationship("User", back_populates="answers") question = relationship("Question", back_populates="user_answers") answer = relationship("Answer", back_populates="user_answers") # This allows tracking of multiple attempts __table_args__ = ( # UniqueConstraint('user_id', 'question_id', 'attempt_number', name='user_question_attempt_uc'), )