# models.py # -*- coding: utf-8 -*- from datetime import datetime, date, time from sqlalchemy import ( Column, Integer, String, Text, Date, Time, DateTime, Float, ForeignKey, Index ) from sqlalchemy.orm import declarative_base, relationship Base = declarative_base() class Course(Base): __tablename__ = "courses" id = Column(Integer, primary_key=True, autoincrement=True) title = Column(String(255), nullable=False, index=True) description = Column(Text, nullable=True) created_at = Column(DateTime, default=datetime.utcnow, nullable=False) lessons = relationship("Lesson", back_populates="course", cascade="all, delete-orphan") materials = relationship("Material", back_populates="course", cascade="all, delete-orphan") schedule_items = relationship("Schedule", back_populates="course", cascade="all, delete-orphan") enrollments = relationship("Enrollment", back_populates="course", cascade="all, delete-orphan") grades = relationship("Grade", back_populates="course", cascade="all, delete-orphan") certificates = relationship("Certificate", back_populates="course", cascade="all, delete-orphan") makeups = relationship("MakeupRequest", back_populates="course", cascade="all, delete-orphan") class Lesson(Base): __tablename__ = "lessons" id = Column(Integer, primary_key=True, autoincrement=True) course_id = Column(Integer, ForeignKey("courses.id", ondelete="CASCADE"), nullable=False, index=True) title = Column(String(255), nullable=False) description = Column(Text, nullable=True) video_path = Column(Text, nullable=True) # pode ser URL (YouTube) ou caminho local created_at = Column(DateTime, default=datetime.utcnow, nullable=False) course = relationship("Course", back_populates="lessons") class Material(Base): __tablename__ = "materials" id = Column(Integer, primary_key=True, autoincrement=True) course_id = Column(Integer, ForeignKey("courses.id", ondelete="CASCADE"), nullable=False, index=True) title = Column(String(255), nullable=False) description = Column(Text, nullable=True) pdf_path = Column(Text, nullable=True) created_at = Column(DateTime, default=datetime.utcnow, nullable=False) course = relationship("Course", back_populates="materials") class Schedule(Base): __tablename__ = "schedule" id = Column(Integer, primary_key=True, autoincrement=True) course_id = Column(Integer, ForeignKey("courses.id", ondelete="CASCADE"), nullable=False, index=True) class_date = Column(Date, nullable=True) start_time = Column(Time, nullable=True) end_time = Column(Time, nullable=True) # Campo 'topic' guarda JSON/texto com metadados (topic/module_id/assigned_emails/…) topic = Column(Text, nullable=True) created_at = Column(DateTime, default=datetime.utcnow, nullable=False) course = relationship("Course", back_populates="schedule_items") # Acelera buscas por data/hora por curso Index("ix_schedule_course_date", Schedule.course_id, Schedule.class_date, Schedule.start_time) class Enrollment(Base): __tablename__ = "enrollments" id = Column(Integer, primary_key=True, autoincrement=True) course_id = Column(Integer, ForeignKey("courses.id", ondelete="CASCADE"), nullable=False, index=True) student_name = Column(String(255), nullable=True) student_email = Column(String(255), nullable=False, index=True) # armazenar em minúsculas created_at = Column(DateTime, default=datetime.utcnow, nullable=False) course = relationship("Course", back_populates="enrollments") # Evita duplicidade de matrícula do mesmo email no mesmo curso (lógica no app faz dedupe também) Index("ix_enrollment_course_email", Enrollment.course_id, Enrollment.student_email) class Grade(Base): __tablename__ = "grades" id = Column(Integer, primary_key=True, autoincrement=True) course_id = Column(Integer, ForeignKey("courses.id", ondelete="CASCADE"), nullable=False, index=True) student_name = Column(String(255), nullable=True) student_email = Column(String(255), nullable=False, index=True) grade = Column(Float, nullable=True) note = Column(Text, nullable=True) created_at = Column(DateTime, default=datetime.utcnow, nullable=False) course = relationship("Course", back_populates="grades") class MakeupRequest(Base): __tablename__ = "makeup_requests" id = Column(Integer, primary_key=True, autoincrement=True) course_id = Column(Integer, ForeignKey("courses.id", ondelete="CASCADE"), nullable=False, index=True) student_name = Column(String(255), nullable=False) student_email = Column(String(255), nullable=False, index=True) requested_date = Column(Date, nullable=True) note = Column(Text, nullable=True) status = Column(String(32), default="pending", nullable=False) # pending/approved/denied created_at = Column(DateTime, default=datetime.utcnow, nullable=False) course = relationship("Course", back_populates="makeups") class Certificate(Base): __tablename__ = "certificates" id = Column(Integer, primary_key=True, autoincrement=True) course_id = Column(Integer, ForeignKey("courses.id", ondelete="CASCADE"), nullable=False, index=True) student_name = Column(String(255), nullable=False) student_email = Column(String(255), nullable=False, index=True) pdf_path = Column(Text, nullable=True) issued_at = Column(DateTime, nullable=True, index=True) course = relationship("Course", back_populates="certificates")