"""RBAC 角色-权限模型。 Role ──╮ ├── RolePermission ── Permission User ──╯ └── UserRole ────╯ 前端通过 GET /auth/me 的 permissions 字段获取当前用户权限列表,本地不做角色-权限映射。 """ from datetime import datetime from sqlalchemy import Boolean, DateTime, ForeignKey, String, Text from sqlalchemy.orm import Mapped, mapped_column from app.core.ids import new_permission_id, new_role_id from app.core.time import utc_now from app.db.base import Base class Role(Base): __tablename__ = "roles" id: Mapped[str] = mapped_column(String(40), primary_key=True, default=new_role_id) name: Mapped[str] = mapped_column(String(80), unique=True, nullable=False, index=True) description: Mapped[str] = mapped_column(Text, nullable=False, default="") is_system: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utc_now) updated_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), default=utc_now, onupdate=utc_now ) class Permission(Base): __tablename__ = "permissions" id: Mapped[str] = mapped_column(String(40), primary_key=True, default=new_permission_id) resource: Mapped[str] = mapped_column(String(80), nullable=False, index=True) action: Mapped[str] = mapped_column(String(80), nullable=False) description: Mapped[str] = mapped_column(Text, nullable=False, default="") created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utc_now) @property def code(self) -> str: return f"{self.resource}:{self.action}" class UserRole(Base): __tablename__ = "user_roles" user_id: Mapped[str] = mapped_column( String(40), ForeignKey("users.id", ondelete="CASCADE"), primary_key=True, ) role_id: Mapped[str] = mapped_column( String(40), ForeignKey("roles.id", ondelete="CASCADE"), primary_key=True, ) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utc_now) class RolePermission(Base): __tablename__ = "role_permissions" role_id: Mapped[str] = mapped_column( String(40), ForeignKey("roles.id", ondelete="CASCADE"), primary_key=True, ) permission_id: Mapped[str] = mapped_column( String(40), ForeignKey("permissions.id", ondelete="CASCADE"), primary_key=True, ) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utc_now)