Spaces:
Sleeping
Sleeping
| """SQLAlchemy models for the dynamic RBAC system: roles, modules, per-role | |
| module permissions, and the DB-backed nav menu.""" | |
| from datetime import datetime, timezone | |
| from sqlalchemy import Boolean, Column, DateTime, ForeignKey, Integer, String, Text, UniqueConstraint | |
| from sqlalchemy.orm import relationship | |
| from ...database import Base | |
| def _utcnow(): | |
| return datetime.now(timezone.utc) | |
| class Role(Base): | |
| __tablename__ = "dda_roles" | |
| id = Column(Integer, primary_key=True, index=True) | |
| name = Column(String(64), nullable=False, unique=True, index=True) | |
| description = Column(String(255), default="") | |
| rank = Column(Integer, default=0) | |
| # Seeded roles (viewer/uploader/analyst/admin) — protected from deletion | |
| # so the built-in permission gates in dda_auth.py always have a role to | |
| # resolve against. | |
| is_system = Column(Boolean, default=False) | |
| # Roles are never deleted (see rbac/routes.py) — deactivate instead. | |
| # Informational only today, same as Module.status — not yet enforced in | |
| # dda_auth.py/permissions.py. | |
| is_active = Column(Boolean, default=True) | |
| created_at = Column(DateTime, default=_utcnow) | |
| class Module(Base): | |
| __tablename__ = "dda_modules" | |
| id = Column(Integer, primary_key=True, index=True) | |
| key = Column(String(64), nullable=False, unique=True, index=True) | |
| name = Column(String(128), nullable=False) | |
| description = Column(String(255), default="") | |
| status = Column(String(20), default="in_use") # in_use | deprecated | |
| created_at = Column(DateTime, default=_utcnow) | |
| class RolePermission(Base): | |
| __tablename__ = "dda_role_permissions" | |
| __table_args__ = (UniqueConstraint("role_id", "module_id", name="uq_role_module"),) | |
| id = Column(Integer, primary_key=True, index=True) | |
| role_id = Column(Integer, ForeignKey("dda_roles.id"), nullable=False, index=True) | |
| module_id = Column(Integer, ForeignKey("dda_modules.id"), nullable=False, index=True) | |
| can_view = Column(Boolean, default=False) | |
| can_create = Column(Boolean, default=False) | |
| can_edit = Column(Boolean, default=False) | |
| can_delete = Column(Boolean, default=False) | |
| role = relationship("Role") | |
| module = relationship("Module") | |
| class MenuItem(Base): | |
| __tablename__ = "dda_menu_items" | |
| id = Column(Integer, primary_key=True, index=True) | |
| label = Column(String(128), nullable=False) | |
| url = Column(String(255), nullable=False) | |
| module_id = Column(Integer, ForeignKey("dda_modules.id"), nullable=True, index=True) | |
| # Self-referential parent for one level of nesting — unused today (this | |
| # app's nav is flat) but keeps the model ready without a later migration. | |
| parent_id = Column(Integer, ForeignKey("dda_menu_items.id"), nullable=True) | |
| sort_order = Column(Integer, default=0) | |
| icon = Column(String(64), default="") | |
| is_active = Column(Boolean, default=True) | |
| created_at = Column(DateTime, default=_utcnow) | |
| module = relationship("Module") | |
| parent = relationship("MenuItem", remote_side=[id], backref="children") | |