from datetime import datetime from sqlalchemy import Column, DateTime, ForeignKey, Integer from app.database import Base class CategoryGrant(Base): """Scoped editorial access for a non-moderator. A grant names any combination of exam, discipline tag and category, and covers the questions matching *all* the dimensions it sets — so "Step 1" plus "Cardiology" grants exactly Step 1 cardiology questions. An unset dimension means "any". It is access, not a role: the holder can create, edit and delete the questions it covers, and nothing else. A folder is the fourth dimension and the odd one out: the other three describe questions, so a grant over them keeps covering whatever is filed there later, while a folder is a list somebody wrote by hand. It is here rather than in a table of its own because a grant is a grant — one place to read what a person holds, and one predicate that answers what they reach. """ __tablename__ = "category_grants" id = Column(Integer, primary_key=True, index=True) # Each dimension is optional and means "any". A grant must name at least one, # or it would silently mean "everything". category_id = Column(Integer, ForeignKey("question_categories.id", ondelete="CASCADE"), nullable=True, index=True) exam_id = Column(Integer, ForeignKey("exams.id", ondelete="CASCADE"), nullable=True, index=True) tag_id = Column(Integer, nullable=True, index=True) # question_tags is raw DDL folder_id = Column(Integer, ForeignKey("question_folders.id", ondelete="CASCADE"), nullable=True, index=True) user_id = Column(Integer, ForeignKey("users.id", ondelete="CASCADE"), nullable=False, index=True) granted_by = Column(Integer, ForeignKey("users.id", ondelete="SET NULL"), nullable=True) created_at = Column(DateTime, default=datetime.utcnow)