Imago/app/models/client.py

71 lines
2.7 KiB
Python

"""
Modèle SQLAlchemy — APIClient : clients authentifiés du hub
"""
import enum
import uuid as uuid_lib
from datetime import datetime, timezone
from sqlalchemy import (
Column, String, JSON, Boolean, DateTime, Enum as SAEnum,
BigInteger, Integer,
)
from sqlalchemy.orm import relationship
from app.database import Base
class ClientPlan(str, enum.Enum):
FREE = "free"
STANDARD = "standard"
PREMIUM = "premium"
class APIClient(Base):
__tablename__ = "api_clients"
# ── Identité ──────────────────────────────────────────────
id = Column(
String(36),
primary_key=True,
default=lambda: str(uuid_lib.uuid4()),
index=True,
)
name = Column(String(256), nullable=False)
# ── Authentification ──────────────────────────────────────
api_key_hash = Column(String(64), nullable=False, unique=True, index=True)
# ── Permissions ───────────────────────────────────────────
scopes = Column(JSON, nullable=False, default=list)
plan = Column(
SAEnum(ClientPlan),
default=ClientPlan.FREE,
nullable=False,
)
is_active = Column(Boolean, default=True, nullable=False)
# ── Quota tracking ─────────────────────────────────────────
storage_used_bytes = Column(BigInteger, default=0, nullable=False)
quota_storage_mb = Column(Integer, default=500, nullable=False)
quota_images = Column(Integer, default=1000, nullable=False)
# ── Timestamps ────────────────────────────────────────────
created_at = Column(DateTime(timezone=True), default=lambda: datetime.now(timezone.utc))
updated_at = Column(
DateTime(timezone=True),
default=lambda: datetime.now(timezone.utc),
onupdate=lambda: datetime.now(timezone.utc),
)
# ── Relations (ajoutée par Livrable 1.2) ──────────────────
images = relationship(
"Image",
back_populates="client",
cascade="all, delete-orphan",
)
def __repr__(self) -> str:
return f"<APIClient id={self.id} name={self.name} plan={self.plan}>"
def has_scope(self, scope: str) -> bool:
"""Vérifie si le client possède le scope demandé."""
return scope in (self.scopes or [])