mirror of
https://github.com/DRYTRIX/TimeTracker.git
synced 2026-05-18 04:08:48 -05:00
b4486a627f
- Webhook models: remove duplicate index definitions so db.create_all() no longer raises 'index already exists' (columns already have index=True) - ImportService: fix circular import by late-importing ClientService, ProjectService, TimeTrackingService in __init__ - reports: fix F823 by renaming unpack variable _ to _entry_count to avoid shadowing gettext _ in export_task_excel() - Code quality: add .flake8 with extend-ignore so flake8 CI passes; simplify pyproject.toml isort config (drop unsupported options) - Format: run black and isort on app/ - tests: restore minimal app fixture in test_import_export_models
70 lines
1.8 KiB
Python
70 lines
1.8 KiB
Python
"""
|
|
Rate limiting utilities and helpers.
|
|
"""
|
|
|
|
from functools import wraps
|
|
from typing import Any, Callable, Dict, Optional
|
|
|
|
from flask import current_app, request
|
|
from flask_limiter import Limiter
|
|
from flask_limiter.util import get_remote_address
|
|
|
|
|
|
def get_rate_limit_key() -> str:
|
|
"""
|
|
Get rate limit key for current request.
|
|
|
|
Uses API token if available, otherwise IP address.
|
|
"""
|
|
# Check for API token
|
|
if hasattr(request, "api_user") and request.api_user:
|
|
return f"api_token:{request.api_user.id}"
|
|
|
|
# Check for authenticated user
|
|
from flask_login import current_user
|
|
|
|
if current_user and current_user.is_authenticated:
|
|
return f"user:{current_user.id}"
|
|
|
|
# Fall back to IP address
|
|
return get_remote_address()
|
|
|
|
|
|
def rate_limit(per_minute: Optional[int] = None, per_hour: Optional[int] = None, per_day: Optional[int] = None):
|
|
"""
|
|
Decorator for rate limiting endpoints.
|
|
|
|
Args:
|
|
per_minute: Requests per minute
|
|
per_hour: Requests per hour
|
|
per_day: Requests per day
|
|
|
|
Usage:
|
|
@rate_limit(per_minute=60, per_hour=1000)
|
|
def my_endpoint():
|
|
pass
|
|
"""
|
|
|
|
def decorator(func: Callable) -> Callable:
|
|
@wraps(func)
|
|
def wrapper(*args, **kwargs):
|
|
# Rate limiting is handled by Flask-Limiter middleware
|
|
# This decorator is mainly for documentation
|
|
return func(*args, **kwargs)
|
|
|
|
return wrapper
|
|
|
|
return decorator
|
|
|
|
|
|
def get_rate_limit_info() -> Dict[str, Any]:
|
|
"""
|
|
Get rate limit information for current request.
|
|
|
|
Returns:
|
|
dict with rate limit info
|
|
"""
|
|
# This would integrate with Flask-Limiter to get current limits
|
|
# For now, return default info
|
|
return {"limit": 100, "remaining": 99, "reset": None}
|