Imago/app/models/client.py
Bruno Charest cc99fea20a
Some checks failed
CI / Lint & Format (push) Has been cancelled
CI / Tests (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / Docker Build (push) Has been cancelled
Add comprehensive test suite for image processing and related services
- Implement tests for database generator to ensure proper session handling.
- Create tests for EXIF extraction and conversion functions.
- Add tests for image-related endpoints, ensuring proper data retrieval and isolation between clients.
- Develop tests for OCR functionality, including language detection and text extraction.
- Introduce tests for the image processing pipeline, covering success and failure scenarios.
- Validate rate limiting functionality and ensure independent counters for different clients.
- Implement scraper tests to verify HTML content fetching and error handling.
- Add unit tests for various services, including storage and filename generation.
- Establish worker entry point for ARQ to handle background image processing tasks.
2026-02-24 11:22:10 -05:00

71 lines
2.6 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, 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"<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 [])