Imago/app/middleware/__init__.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

66 lines
2.0 KiB
Python

"""
Middleware de rate limiting — par client et par plan.
Utilise slowapi (basé sur limits) avec identification par client_id
plutôt que par IP, pour compter les requêtes par client API.
Limites par plan (par heure) :
- free : 20 uploads, 50 AI
- standard : 100 uploads, 200 AI
- premium : 500 uploads, 1000 AI
"""
import logging
from slowapi import Limiter
from slowapi.util import get_remote_address
from starlette.requests import Request
from app.config import settings
logger = logging.getLogger(__name__)
def _get_client_id_from_request(request: Request) -> str:
"""
Extrait le client_id depuis la state de la requête.
Fallback vers l'IP si le client n'est pas encore authentifié.
"""
# Le client_id est injecté par le middleware ou la dépendance auth
client_id = getattr(request.state, "client_id", None)
if client_id:
return str(client_id)
return get_remote_address(request)
# Instance globale du limiter
limiter = Limiter(key_func=_get_client_id_from_request)
def get_upload_rate_limit(plan: str) -> str:
"""Retourne la limite de rate pour les uploads selon le plan."""
limits = {
"free": f"{settings.RATE_LIMIT_FREE_UPLOAD}/hour",
"standard": f"{settings.RATE_LIMIT_STANDARD_UPLOAD}/hour",
"premium": f"{settings.RATE_LIMIT_PREMIUM_UPLOAD}/hour",
}
return limits.get(plan, limits["free"])
def get_ai_rate_limit(plan: str) -> str:
"""Retourne la limite de rate pour les endpoints AI selon le plan."""
limits = {
"free": f"{settings.RATE_LIMIT_FREE_AI}/hour",
"standard": f"{settings.RATE_LIMIT_STANDARD_AI}/hour",
"premium": f"{settings.RATE_LIMIT_PREMIUM_AI}/hour",
}
return limits.get(plan, limits["free"])
def upload_rate_limit_key(request: Request) -> str:
"""Clé dynamique pour le rate limiting des uploads."""
return _get_client_id_from_request(request)
def ai_rate_limit_key(request: Request) -> str:
"""Clé dynamique pour le rate limiting des endpoints AI."""
return _get_client_id_from_request(request)