feat: production deployment - full update with providers, admin, glossaries, pricing, tests
Major changes across backend, frontend, infrastructure: - Provider system with model selection (Google, DeepL, OpenAI, Ollama, Google Cloud) - Admin panel: user management, pricing, settings - Glossary system with CSV import/export - Subscription and tier quota management - Security hardening (rate limiting, API key auth, path traversal fixes) - Docker compose for dev, prod, and IONOS deployment - Alembic migrations for new tables - Frontend: dashboard, pricing page, landing page, i18n (en/fr) - Test suite and verification scripts Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -28,7 +28,7 @@ try:
|
||||
except ImportError:
|
||||
PASSLIB_AVAILABLE = False
|
||||
|
||||
from database.connection import get_db_session
|
||||
from database.connection import get_sync_session
|
||||
from database.repositories import UserRepository
|
||||
from database.models import User, PlanType, SubscriptionStatus
|
||||
from models.subscription import PLANS
|
||||
@@ -113,9 +113,38 @@ def verify_token(token: str) -> Optional[Dict[str, Any]]:
|
||||
return None
|
||||
|
||||
|
||||
def get_or_create_google_user(
|
||||
email: str, name: str, avatar_url: Optional[str] = None
|
||||
) -> User:
|
||||
"""Find existing user by email or create one for Google OAuth."""
|
||||
with get_sync_session() as db:
|
||||
repo = UserRepository(db)
|
||||
user = repo.get_by_email(email)
|
||||
|
||||
if user:
|
||||
updates: Dict[str, Any] = {"last_login_at": datetime.now(timezone.utc)}
|
||||
if avatar_url and not user.avatar_url:
|
||||
updates["avatar_url"] = avatar_url
|
||||
if not user.email_verified:
|
||||
updates["email_verified"] = True
|
||||
updated = repo.update(user.id, **updates)
|
||||
return updated if updated else user
|
||||
|
||||
random_password = secrets.token_urlsafe(32)
|
||||
hashed = hash_password(random_password)
|
||||
user = repo.create(
|
||||
email=email,
|
||||
name=name,
|
||||
hashed_password=hashed,
|
||||
tier="free",
|
||||
)
|
||||
updated = repo.update(user.id, email_verified=True, avatar_url=avatar_url)
|
||||
return updated if updated else user
|
||||
|
||||
|
||||
def create_user(email: str, name: str, password: str) -> User:
|
||||
"""Create a new user in the database"""
|
||||
with get_db_session() as db:
|
||||
with get_sync_session() as db:
|
||||
repo = UserRepository(db)
|
||||
|
||||
# Check if email already exists
|
||||
@@ -135,7 +164,7 @@ def create_user(email: str, name: str, password: str) -> User:
|
||||
|
||||
def authenticate_user(email: str, password: str) -> Optional[User]:
|
||||
"""Authenticate user and return user object if valid"""
|
||||
with get_db_session() as db:
|
||||
with get_sync_session() as db:
|
||||
repo = UserRepository(db)
|
||||
user = repo.get_by_email(email)
|
||||
|
||||
@@ -152,28 +181,28 @@ def authenticate_user(email: str, password: str) -> Optional[User]:
|
||||
|
||||
def get_user_by_id(user_id: str) -> Optional[User]:
|
||||
"""Get user by ID from database"""
|
||||
with get_db_session() as db:
|
||||
with get_sync_session() as db:
|
||||
repo = UserRepository(db)
|
||||
return repo.get_by_id(user_id)
|
||||
|
||||
|
||||
def get_user_by_email(email: str) -> Optional[User]:
|
||||
"""Get user by email from database"""
|
||||
with get_db_session() as db:
|
||||
with get_sync_session() as db:
|
||||
repo = UserRepository(db)
|
||||
return repo.get_by_email(email)
|
||||
|
||||
|
||||
def update_user(user_id: str, updates: Dict[str, Any]) -> Optional[User]:
|
||||
"""Update user fields in database"""
|
||||
with get_db_session() as db:
|
||||
with get_sync_session() as db:
|
||||
repo = UserRepository(db)
|
||||
return repo.update(user_id, **updates)
|
||||
|
||||
|
||||
def add_credits(user_id: str, credits: int) -> bool:
|
||||
"""Add credits to user account"""
|
||||
with get_db_session() as db:
|
||||
with get_sync_session() as db:
|
||||
repo = UserRepository(db)
|
||||
result = repo.add_credits(user_id, credits)
|
||||
return result is not None
|
||||
@@ -181,7 +210,7 @@ def add_credits(user_id: str, credits: int) -> bool:
|
||||
|
||||
def use_credits(user_id: str, credits: int) -> bool:
|
||||
"""Use credits from user account"""
|
||||
with get_db_session() as db:
|
||||
with get_sync_session() as db:
|
||||
repo = UserRepository(db)
|
||||
return repo.use_credits(user_id, credits)
|
||||
|
||||
@@ -190,7 +219,7 @@ def increment_usage(
|
||||
user_id: str, docs: int = 0, pages: int = 0, api_calls: int = 0
|
||||
) -> bool:
|
||||
"""Increment user usage counters"""
|
||||
with get_db_session() as db:
|
||||
with get_sync_session() as db:
|
||||
repo = UserRepository(db)
|
||||
result = repo.increment_usage(
|
||||
user_id, docs=docs, pages=pages, api_calls=api_calls
|
||||
@@ -200,7 +229,7 @@ def increment_usage(
|
||||
|
||||
def check_usage_limits(user_id: str) -> Dict[str, Any]:
|
||||
"""Check if user is within their plan limits"""
|
||||
with get_db_session() as db:
|
||||
with get_sync_session() as db:
|
||||
repo = UserRepository(db)
|
||||
user = repo.get_by_id(user_id)
|
||||
|
||||
@@ -232,7 +261,7 @@ def check_usage_limits(user_id: str) -> Dict[str, Any]:
|
||||
|
||||
def get_user_usage_stats(user_id: str) -> Dict[str, Any]:
|
||||
"""Get detailed usage statistics for a user"""
|
||||
with get_db_session() as db:
|
||||
with get_sync_session() as db:
|
||||
repo = UserRepository(db)
|
||||
user = repo.get_by_id(user_id)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user