79 lines
2.8 KiB
Python
79 lines
2.8 KiB
Python
import enum
|
|
import uuid
|
|
from datetime import datetime
|
|
|
|
from sqlalchemy import ForeignKey, Index, Integer, String, Text, func
|
|
from sqlalchemy.dialects.postgresql import ENUM
|
|
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
|
|
|
from proxy_pool.db.base import Base, TimestampMixin, UUIDPrimaryKeyMixin
|
|
|
|
|
|
class CreditTxType(str, enum.StrEnum):
|
|
PURCHASE = "purchase"
|
|
ACQUIRE = "acquire"
|
|
REFUND = "refund"
|
|
ADMIN_ADJUST = "admin_adjust"
|
|
|
|
|
|
class User(UUIDPrimaryKeyMixin, TimestampMixin, Base):
|
|
__tablename__ = "users"
|
|
|
|
email: Mapped[str] = mapped_column(String(320), unique=True)
|
|
display_name: Mapped[str | None] = mapped_column(String(128))
|
|
is_active: Mapped[bool] = mapped_column(default=True)
|
|
|
|
api_keys: Mapped[list["ApiKey"]] = relationship(back_populates="user")
|
|
credit_entries: Mapped[list["CreditLedger"]] = relationship(back_populates="user")
|
|
|
|
|
|
class ApiKey(UUIDPrimaryKeyMixin, TimestampMixin, Base):
|
|
__tablename__ = "api_keys"
|
|
__table_args__ = (
|
|
Index("ix_api_keys_hash", "key_hash", unique=True),
|
|
Index("ix_api_keys_prefix", "prefix"),
|
|
)
|
|
|
|
user_id: Mapped[uuid.UUID] = mapped_column(
|
|
ForeignKey("users.id", ondelete="CASCADE"),
|
|
)
|
|
key_hash: Mapped[str] = mapped_column(String(128))
|
|
prefix: Mapped[str] = mapped_column(String(8))
|
|
label: Mapped[str | None] = mapped_column(String(128))
|
|
is_active: Mapped[bool] = mapped_column(default=True)
|
|
last_used_at: Mapped[datetime | None] = mapped_column()
|
|
expires_at: Mapped[datetime | None] = mapped_column()
|
|
|
|
user: Mapped["User"] = relationship(back_populates="api_keys")
|
|
|
|
|
|
class CreditLedger(UUIDPrimaryKeyMixin, TimestampMixin, Base):
|
|
__tablename__ = "credit_ledger"
|
|
__table_args__ = (Index("ix_ledger_user_created", "user_id", "created_at"),)
|
|
|
|
user_id: Mapped[uuid.UUID] = mapped_column(
|
|
ForeignKey("users.id", ondelete="CASCADE"),
|
|
)
|
|
amount: Mapped[int] = mapped_column(Integer)
|
|
tx_type: Mapped[CreditTxType] = mapped_column(
|
|
ENUM(CreditTxType, name="credit_tx_type"),
|
|
)
|
|
description: Mapped[str | None] = mapped_column(Text)
|
|
reference_id: Mapped[uuid.UUID | None] = mapped_column()
|
|
|
|
user: Mapped["User"] = relationship(back_populates="credit_entries")
|
|
|
|
|
|
class ProxyLease(UUIDPrimaryKeyMixin, Base):
|
|
__tablename__ = "proxy_leases"
|
|
__table_args__ = (
|
|
Index("ix_leases_user", "user_id"),
|
|
Index("ix_leases_proxy_active", "proxy_id", "is_released"),
|
|
)
|
|
|
|
user_id: Mapped[uuid.UUID] = mapped_column(ForeignKey("users.id"))
|
|
proxy_id: Mapped[uuid.UUID] = mapped_column(ForeignKey("proxies.id"))
|
|
acquired_at: Mapped[datetime] = mapped_column(server_default=func.now())
|
|
expires_at: Mapped[datetime] = mapped_column()
|
|
is_released: Mapped[bool] = mapped_column(default=False)
|