""" 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, default=lambda: datetime.now(timezone.utc)) updated_at = Column( DateTime, 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"" def has_scope(self, scope: str) -> bool: """Vérifie si le client possède le scope demandé.""" return scope in (self.scopes or [])