import uuid from django.db import models class Course(models.Model): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) org_id = models.UUIDField(db_index=True) title = models.CharField(max_length=255) slug = models.SlugField(max_length=255, unique=True) description = models.TextField(blank=True) version = models.PositiveIntegerField(default=1) is_published = models.BooleanField(default=False) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) class Meta: ordering = ["title"] def __str__(self): return self.title class Module(models.Model): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) course = models.ForeignKey(Course, on_delete=models.CASCADE, related_name="modules") title = models.CharField(max_length=255) order = models.PositiveIntegerField(default=0) version = models.PositiveIntegerField(default=1) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) class Meta: ordering = ["order"] constraints = [ models.UniqueConstraint(fields=["course", "order"], name="unique_course_module_order") ] def __str__(self): return f"{self.course.title} / {self.title}" class Lesson(models.Model): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) module = models.ForeignKey(Module, on_delete=models.CASCADE, related_name="lessons") title = models.CharField(max_length=255) order = models.PositiveIntegerField(default=0) version = models.PositiveIntegerField(default=1) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) class Meta: ordering = ["order"] constraints = [ models.UniqueConstraint(fields=["module", "order"], name="unique_module_lesson_order") ] def __str__(self): return f"{self.module} / {self.title}" class Page(models.Model): CONTENT_TEXT = "text" CONTENT_VIDEO = "video" CONTENT_QUIZ = "quiz" CONTENT_EMBED = "embed" CONTENT_TYPE_CHOICES = [ (CONTENT_TEXT, "Text"), (CONTENT_VIDEO, "Video"), (CONTENT_QUIZ, "Quiz"), (CONTENT_EMBED, "Embed"), ] id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) lesson = models.ForeignKey(Lesson, on_delete=models.CASCADE, related_name="pages") title = models.CharField(max_length=255) order = models.PositiveIntegerField(default=0) content_type = models.CharField( max_length=20, choices=CONTENT_TYPE_CHOICES, default=CONTENT_TEXT ) content_body = models.TextField(blank=True) is_required = models.BooleanField(default=True) # Minimum active dwell time (seconds) a learner must accumulate before advancing. required_seconds = models.PositiveIntegerField(default=0) version = models.PositiveIntegerField(default=1) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) class Meta: ordering = ["order"] constraints = [ models.UniqueConstraint(fields=["lesson", "order"], name="unique_lesson_page_order") ] def __str__(self): return f"{self.lesson} / {self.title}"