from datetime import datetime from sqlalchemy import Column, DateTime, ForeignKey, Integer, String, Text from app.database import Base class QuestionFeedback(Base): """A learner telling an educator something is wrong with a question. It replaces the comment thread that used to sit under every question. A discussion is public and needs moderating; this is a private report that someone is expected to act on, which is what people were using comments for anyway. It carries the question id because that is what an educator needs to find the thing being reported. """ __tablename__ = "question_feedback" id = Column(Integer, primary_key=True, index=True) question_id = Column(Integer, ForeignKey("questions.id", ondelete="CASCADE"), nullable=False, index=True) user_id = Column(Integer, ForeignKey("users.id", ondelete="SET NULL"), nullable=True, index=True) message = Column(Text, nullable=False) #: open | resolved. Kept rather than deleted on resolve, so a question with #: a history of the same complaint is visibly that. status = Column(String(20), nullable=False, default="open", index=True) reply = Column(Text, nullable=True) replied_by = Column(Integer, ForeignKey("users.id", ondelete="SET NULL"), nullable=True) replied_at = Column(DateTime, nullable=True) created_at = Column(DateTime, default=datetime.utcnow, index=True) class ArticleFeedback(Base): """A reader telling whoever maintains an article that something is wrong. The same shape as a question report, and deliberately so: an educator works through one queue, not two that behave differently. `section_id` is a key inside `articles.sections`, not a foreign key — the sections live in a JSON column and are only projected into `article_section_index` while the article is published. A foreign key onto that projection would delete every outstanding report the moment somebody unpublished an article to fix it, which is precisely when the reports matter. Null means the report is about the article as a whole. """ __tablename__ = "article_feedback" id = Column(Integer, primary_key=True, index=True) article_id = Column(Integer, ForeignKey("articles.id", ondelete="CASCADE"), nullable=False, index=True) section_id = Column(String(64), nullable=True, index=True) #: What the section was called when the report was written. A section can be #: renamed or deleted between the report and the reply, and "the report is #: about a section that no longer exists" is unactionable on its own. section_title = Column(String(300), nullable=True) user_id = Column(Integer, ForeignKey("users.id", ondelete="SET NULL"), nullable=True, index=True) message = Column(Text, nullable=False) #: open | resolved, as for a question report. status = Column(String(20), nullable=False, default="open", index=True) reply = Column(Text, nullable=True) replied_by = Column(Integer, ForeignKey("users.id", ondelete="SET NULL"), nullable=True) replied_at = Column(DateTime, nullable=True) created_at = Column(DateTime, default=datetime.utcnow, index=True)