pdf-quiz-generator/backend/app/models/article.py
Daniel 325f7f400f feat: linked topic articles and card associations
Draft/published article library with stable section IDs, breadcrumbs, link remediation, question and card associations, manual card creation and side-by-side/mobile-drawer reading. Migration e8d4f1a27c93. Verified 42 deployed-image backend tests, 72 frontend tests/build and PostgreSQL migration round-trip.
2026-09-07 15:16:48 +02:00

45 lines
2.2 KiB
Python

from datetime import datetime
from sqlalchemy import Column, Integer, String, Text, JSON, DateTime, ForeignKey, UniqueConstraint
from sqlalchemy.orm import relationship
from app.database import Base
class Article(Base):
"""Educator-authored topic reading with stable section IDs for linking."""
__tablename__ = "articles"
id = Column(Integer, primary_key=True, index=True)
slug = Column(String(120), unique=True, nullable=False, index=True)
title = Column(String(300), nullable=False)
summary = Column(Text, nullable=True)
content = Column(Text, nullable=True) # Whole-article introduction (markdown).
# Stable subsections: [{"id": uuid-hex, "slug": "...", "title": "...", "content": "markdown"}].
sections = Column(JSON, nullable=False, default=list)
category_id = Column(Integer, ForeignKey("question_categories.id", ondelete="SET NULL"), nullable=True)
section_id = Column(Integer, ForeignKey("sections.id", ondelete="SET NULL"), nullable=True) # Optional PDF source range.
user_id = Column(Integer, ForeignKey("users.id", ondelete="SET NULL"), nullable=True)
status = Column(String, default="draft") # draft | published
created_at = Column(DateTime, default=datetime.utcnow)
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
category = relationship("QuestionCategory")
links = relationship("QuestionArticleLink", back_populates="article", cascade="all, delete-orphan")
class QuestionArticleLink(Base):
"""Question -> whole article or one stable section."""
__tablename__ = "question_article_links"
__table_args__ = (UniqueConstraint("question_id", "article_id", "section_id", name="uq_question_article_section"),)
id = Column(Integer, primary_key=True, index=True)
question_id = Column(Integer, ForeignKey("questions.id", ondelete="CASCADE"), nullable=False)
article_id = Column(Integer, ForeignKey("articles.id", ondelete="CASCADE"), nullable=False)
section_id = Column(String(64), nullable=True) # Article.sections[].id; None = whole article.
user_id = Column(Integer, ForeignKey("users.id", ondelete="SET NULL"), nullable=True)
created_at = Column(DateTime, default=datetime.utcnow)
article = relationship("Article", back_populates="links")