from __future__ import annotations from datetime import datetime from sqlalchemy import DateTime, Index, SmallInteger, String, Text, func, text from sqlalchemy.dialects.postgresql import JSONB from sqlalchemy.orm import Mapped, mapped_column from app.models.db import Base STATUS_ACTIVE = 1 STATUS_BANNED = 2 BINDING_MODE_SINGLE = "single" BINDING_MODE_MULTIPLE = "multiple" BINDING_MODE_ALL = "all" class TokenBinding(Base): __tablename__ = "token_bindings" __table_args__ = ( Index("idx_token_bindings_hash", "token_hash"), Index("idx_token_bindings_ip", "bound_ip"), ) id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True) token_hash: Mapped[str] = mapped_column(String(64), unique=True, nullable=False) token_display: Mapped[str] = mapped_column(String(20), nullable=False) bound_ip: Mapped[str] = mapped_column(Text, nullable=False) binding_mode: Mapped[str] = mapped_column( String(16), nullable=False, default=BINDING_MODE_SINGLE, server_default=text("'single'"), ) allowed_ips: Mapped[list[str]] = mapped_column( JSONB, nullable=False, default=list, server_default=text("'[]'::jsonb"), ) status: Mapped[int] = mapped_column( SmallInteger, nullable=False, default=STATUS_ACTIVE, server_default=text("1"), ) first_used_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), nullable=False, server_default=func.now(), ) last_used_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), nullable=False, server_default=func.now(), ) created_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), nullable=False, server_default=func.now(), )