"""Модели пользователей, ролей и доступа.""" from datetime import date, datetime from sqlalchemy import ( Boolean, Date, DateTime, ForeignKey, String, UniqueConstraint, func, ) from sqlalchemy.orm import Mapped, mapped_column, relationship from app.db.session import Base from app.models.enums import LoginTokenStatus, MemberType, MessengerType, RoleCode, UserStatus from app.models.types import enum_col class User(Base): __tablename__ = "users" id: Mapped[int] = mapped_column(primary_key=True) full_name: Mapped[str | None] = mapped_column(String(200)) messenger_type: Mapped[MessengerType] = mapped_column(enum_col(MessengerType)) messenger_id: Mapped[str] = mapped_column(String(64)) phone: Mapped[str | None] = mapped_column(String(32)) status: Mapped[UserStatus] = mapped_column( enum_col(UserStatus), default=UserStatus.ACTIVE ) member_type: Mapped[MemberType | None] = mapped_column(enum_col(MemberType)) joined_at: Mapped[date | None] = mapped_column(Date) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now()) updated_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), server_default=func.now(), onupdate=func.now() ) __table_args__ = (UniqueConstraint("messenger_type", "messenger_id", name="uq_user_messenger"),) regions: Mapped[list["UserRegion"]] = relationship(back_populates="user") roles: Mapped[list["UserRole"]] = relationship( back_populates="user", foreign_keys="UserRole.user_id" ) class UserRegion(Base): __tablename__ = "user_regions" id: Mapped[int] = mapped_column(primary_key=True) user_id: Mapped[int] = mapped_column(ForeignKey("users.id", ondelete="CASCADE")) region_id: Mapped[int] = mapped_column(ForeignKey("regions.id", ondelete="CASCADE")) is_primary: Mapped[bool] = mapped_column(Boolean, default=False) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now()) __table_args__ = (UniqueConstraint("user_id", "region_id", name="uq_user_region"),) user: Mapped[User] = relationship(back_populates="regions") class Role(Base): __tablename__ = "roles" id: Mapped[int] = mapped_column(primary_key=True) code: Mapped[RoleCode] = mapped_column(enum_col(RoleCode), unique=True) name: Mapped[str] = mapped_column(String(100)) class UserRole(Base): __tablename__ = "user_roles" id: Mapped[int] = mapped_column(primary_key=True) user_id: Mapped[int] = mapped_column(ForeignKey("users.id", ondelete="CASCADE")) role_id: Mapped[int] = mapped_column(ForeignKey("roles.id")) region_id: Mapped[int | None] = mapped_column(ForeignKey("regions.id")) granted_by: Mapped[int | None] = mapped_column(ForeignKey("users.id")) granted_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now()) __table_args__ = (UniqueConstraint("user_id", "role_id", "region_id", name="uq_user_role"),) user: Mapped[User] = relationship(back_populates="roles", foreign_keys=[user_id]) class LoginToken(Base): __tablename__ = "login_tokens" id: Mapped[str] = mapped_column(String(36), primary_key=True) token: Mapped[str] = mapped_column(String(128), unique=True) user_id: Mapped[int | None] = mapped_column(ForeignKey("users.id")) region_id: Mapped[int | None] = mapped_column(ForeignKey("regions.id")) issued_by: Mapped[int | None] = mapped_column(ForeignKey("users.id")) status: Mapped[LoginTokenStatus] = mapped_column( enum_col(LoginTokenStatus), default=LoginTokenStatus.ACTIVE ) expires_at: Mapped[datetime] = mapped_column(DateTime(timezone=True)) used_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True)) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now()) class Session(Base): __tablename__ = "sessions" id: Mapped[str] = mapped_column(String(36), primary_key=True) user_id: Mapped[int] = mapped_column(ForeignKey("users.id", ondelete="CASCADE")) token_hash: Mapped[str] = mapped_column(String(128), unique=True) messenger_type: Mapped[MessengerType] = mapped_column(enum_col(MessengerType)) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now()) expires_at: Mapped[datetime] = mapped_column(DateTime(timezone=True)) revoked_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))