- Add SQLAlchemy models for User, Translation, ApiKey, UsageLog, PaymentHistory - Add database connection management with PostgreSQL/SQLite support - Add repository layer for CRUD operations - Add Alembic migration setup with initial migration - Update auth_service to automatically use database when DATABASE_URL is set - Update docker-compose.yml with PostgreSQL service and Redis (non-optional) - Add database migration script (scripts/migrate_to_db.py) - Update .env.example with database configuration
161 lines
5.3 KiB
Python
161 lines
5.3 KiB
Python
"""
|
|
Migration script to move data from JSON files to database
|
|
Run this once to migrate existing users to the new database system
|
|
"""
|
|
import json
|
|
import os
|
|
import sys
|
|
from pathlib import Path
|
|
from datetime import datetime
|
|
|
|
# Add parent directory to path
|
|
sys.path.insert(0, str(Path(__file__).parent.parent))
|
|
|
|
from database.connection import init_db, get_db_session
|
|
from database.repositories import UserRepository
|
|
from database.models import PlanType, SubscriptionStatus
|
|
|
|
|
|
def migrate_users_from_json():
|
|
"""Migrate users from JSON file to database"""
|
|
json_path = Path("data/users.json")
|
|
|
|
if not json_path.exists():
|
|
print("No users.json found, nothing to migrate")
|
|
return 0
|
|
|
|
# Initialize database
|
|
print("Initializing database tables...")
|
|
init_db()
|
|
|
|
# Load JSON data
|
|
with open(json_path, 'r') as f:
|
|
users_data = json.load(f)
|
|
|
|
print(f"Found {len(users_data)} users to migrate")
|
|
|
|
migrated = 0
|
|
skipped = 0
|
|
errors = 0
|
|
|
|
with get_db_session() as db:
|
|
repo = UserRepository(db)
|
|
|
|
for user_id, user_data in users_data.items():
|
|
try:
|
|
# Check if user already exists
|
|
existing = repo.get_by_email(user_data.get('email', ''))
|
|
if existing:
|
|
print(f" Skipping {user_data.get('email')} - already exists")
|
|
skipped += 1
|
|
continue
|
|
|
|
# Map plan string to enum
|
|
plan_str = user_data.get('plan', 'free')
|
|
try:
|
|
plan = PlanType(plan_str)
|
|
except ValueError:
|
|
plan = PlanType.FREE
|
|
|
|
# Map subscription status
|
|
status_str = user_data.get('subscription_status', 'active')
|
|
try:
|
|
status = SubscriptionStatus(status_str)
|
|
except ValueError:
|
|
status = SubscriptionStatus.ACTIVE
|
|
|
|
# Create user with original ID
|
|
from database.models import User
|
|
user = User(
|
|
id=user_id,
|
|
email=user_data.get('email', '').lower(),
|
|
name=user_data.get('name', ''),
|
|
password_hash=user_data.get('password_hash', ''),
|
|
email_verified=user_data.get('email_verified', False),
|
|
avatar_url=user_data.get('avatar_url'),
|
|
plan=plan,
|
|
subscription_status=status,
|
|
stripe_customer_id=user_data.get('stripe_customer_id'),
|
|
stripe_subscription_id=user_data.get('stripe_subscription_id'),
|
|
docs_translated_this_month=user_data.get('docs_translated_this_month', 0),
|
|
pages_translated_this_month=user_data.get('pages_translated_this_month', 0),
|
|
api_calls_this_month=user_data.get('api_calls_this_month', 0),
|
|
extra_credits=user_data.get('extra_credits', 0),
|
|
)
|
|
|
|
# Parse dates
|
|
if user_data.get('created_at'):
|
|
try:
|
|
user.created_at = datetime.fromisoformat(user_data['created_at'].replace('Z', '+00:00'))
|
|
except:
|
|
pass
|
|
|
|
if user_data.get('updated_at'):
|
|
try:
|
|
user.updated_at = datetime.fromisoformat(user_data['updated_at'].replace('Z', '+00:00'))
|
|
except:
|
|
pass
|
|
|
|
db.add(user)
|
|
db.commit()
|
|
|
|
print(f" Migrated: {user.email}")
|
|
migrated += 1
|
|
|
|
except Exception as e:
|
|
print(f" Error migrating {user_data.get('email', user_id)}: {e}")
|
|
errors += 1
|
|
db.rollback()
|
|
|
|
print(f"\nMigration complete:")
|
|
print(f" Migrated: {migrated}")
|
|
print(f" Skipped: {skipped}")
|
|
print(f" Errors: {errors}")
|
|
|
|
# Backup original file
|
|
if migrated > 0:
|
|
backup_path = json_path.with_suffix('.json.bak')
|
|
os.rename(json_path, backup_path)
|
|
print(f"\nOriginal file backed up to: {backup_path}")
|
|
|
|
return migrated
|
|
|
|
|
|
def verify_migration():
|
|
"""Verify the migration was successful"""
|
|
from database.connection import get_db_session
|
|
from database.repositories import UserRepository
|
|
|
|
with get_db_session() as db:
|
|
repo = UserRepository(db)
|
|
count = repo.count_users()
|
|
print(f"\nDatabase now contains {count} users")
|
|
|
|
# List first 5 users
|
|
users = repo.get_all_users(limit=5)
|
|
if users:
|
|
print("\nSample users:")
|
|
for user in users:
|
|
print(f" - {user.email} ({user.plan.value})")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
print("=" * 50)
|
|
print("JSON to Database Migration Script")
|
|
print("=" * 50)
|
|
|
|
# Check environment
|
|
db_url = os.getenv("DATABASE_URL", "")
|
|
if db_url:
|
|
print(f"Database: PostgreSQL")
|
|
else:
|
|
print(f"Database: SQLite (development)")
|
|
|
|
print()
|
|
|
|
# Run migration
|
|
migrate_users_from_json()
|
|
|
|
# Verify
|
|
verify_migration()
|