| """ |
| Simple SQLite Fallback Database Setup |
| |
| This script initializes the SQLite fallback database with all required tables. |
| """ |
|
|
| import asyncio |
| import logging |
| import sys |
| from pathlib import Path |
|
|
| |
| backend_dir = Path(__file__).parent |
| sys.path.insert(0, str(backend_dir)) |
|
|
| from sqlalchemy.ext.asyncio import create_async_engine, async_sessionmaker, AsyncSession |
| from sqlalchemy import text |
|
|
| |
| logging.basicConfig( |
| level=logging.INFO, |
| format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' |
| ) |
| logger = logging.getLogger(__name__) |
|
|
|
|
| async def setup_sqlite_fallback(): |
| """Setup SQLite fallback database.""" |
| print("🚀 Setting up SQLite Fallback Database") |
| print("=" * 50) |
| |
| try: |
| |
| from core.config import settings |
| |
| print(f"SQLite Fallback Enabled: {settings.ENABLE_SQLITE_FALLBACK}") |
| print(f"SQLite Database Path: {settings.SQLITE_DATABASE_PATH}") |
| |
| if not settings.ENABLE_SQLITE_FALLBACK: |
| print("❌ SQLite fallback is disabled in configuration") |
| return False |
| |
| |
| db_path = Path(settings.SQLITE_DATABASE_PATH) |
| db_path.parent.mkdir(parents=True, exist_ok=True) |
| |
| sqlite_url = f"sqlite+aiosqlite:///{settings.SQLITE_DATABASE_PATH}" |
| |
| engine = create_async_engine( |
| sqlite_url, |
| echo=True, |
| connect_args={ |
| "check_same_thread": False, |
| } |
| ) |
| |
| print(f"✅ SQLite engine created: {sqlite_url}") |
| |
| |
| SessionLocal = async_sessionmaker( |
| engine, |
| class_=AsyncSession, |
| expire_on_commit=False |
| ) |
| |
| |
| async with SessionLocal() as session: |
| await session.execute(text("SELECT 1")) |
| print("✅ SQLite connection test passed") |
| |
| |
| print("\n📝 Creating tables...") |
| |
| async with SessionLocal() as session: |
| |
| await session.execute(text(""" |
| CREATE TABLE IF NOT EXISTS users ( |
| id INTEGER PRIMARY KEY, |
| email VARCHAR(255) UNIQUE NOT NULL, |
| password_hash VARCHAR(255) NOT NULL, |
| full_name VARCHAR(255), |
| company VARCHAR(255), |
| is_active BOOLEAN DEFAULT TRUE NOT NULL, |
| is_verified BOOLEAN DEFAULT FALSE NOT NULL, |
| is_superuser BOOLEAN DEFAULT FALSE NOT NULL, |
| verified_at TIMESTAMP, |
| created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, |
| updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, |
| last_login_at TIMESTAMP |
| ) |
| """)) |
| print(" ✅ Users table created") |
| |
| |
| await session.execute(text(""" |
| CREATE TABLE IF NOT EXISTS roles ( |
| id INTEGER PRIMARY KEY, |
| name VARCHAR(255) UNIQUE NOT NULL, |
| slug VARCHAR(255) UNIQUE NOT NULL, |
| description TEXT, |
| level INTEGER DEFAULT 0 NOT NULL, |
| is_active BOOLEAN DEFAULT TRUE NOT NULL, |
| is_system BOOLEAN DEFAULT FALSE NOT NULL, |
| created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, |
| updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL |
| ) |
| """)) |
| print(" ✅ Roles table created") |
| |
| |
| await session.execute(text(""" |
| CREATE TABLE IF NOT EXISTS permissions ( |
| id INTEGER PRIMARY KEY, |
| name VARCHAR(255) UNIQUE NOT NULL, |
| slug VARCHAR(255) UNIQUE NOT NULL, |
| description TEXT, |
| resource VARCHAR(255) NOT NULL, |
| action VARCHAR(255) NOT NULL, |
| is_active BOOLEAN DEFAULT TRUE NOT NULL, |
| created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, |
| updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL |
| ) |
| """)) |
| print(" ✅ Permissions table created") |
| |
| |
| await session.execute(text(""" |
| CREATE TABLE IF NOT EXISTS user_roles ( |
| user_id INTEGER NOT NULL, |
| role_id INTEGER NOT NULL, |
| PRIMARY KEY (user_id, role_id), |
| FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE, |
| FOREIGN KEY (role_id) REFERENCES roles(id) ON DELETE CASCADE |
| ) |
| """)) |
| print(" ✅ User roles junction table created") |
| |
| |
| await session.execute(text(""" |
| CREATE TABLE IF NOT EXISTS api_keys ( |
| id INTEGER PRIMARY KEY, |
| key_name VARCHAR(255) NOT NULL, |
| key_prefix VARCHAR(255) NOT NULL, |
| user_id INTEGER NOT NULL, |
| is_active BOOLEAN DEFAULT TRUE NOT NULL, |
| expires_at TIMESTAMP, |
| last_used_at TIMESTAMP, |
| usage_count INTEGER DEFAULT 0 NOT NULL, |
| rate_limit_per_minute INTEGER DEFAULT 60 NOT NULL, |
| permissions TEXT, |
| scope VARCHAR(255) DEFAULT 'read' NOT NULL, |
| created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, |
| updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, |
| FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE |
| ) |
| """)) |
| print(" ✅ API Keys table created") |
| |
| |
| await session.execute(text(""" |
| CREATE TABLE IF NOT EXISTS evaluations ( |
| id INTEGER PRIMARY KEY, |
| user_id INTEGER NOT NULL, |
| job_id VARCHAR(255) UNIQUE NOT NULL, |
| status VARCHAR(50) DEFAULT 'pending' NOT NULL, |
| model_config TEXT NOT NULL, |
| pipeline_config TEXT NOT NULL, |
| result_json TEXT, |
| error_message TEXT, |
| experiment_run_id VARCHAR(255), |
| total_attacks INTEGER DEFAULT 0 NOT NULL, |
| successful_attacks INTEGER DEFAULT 0 NOT NULL, |
| success_rate VARCHAR(50) DEFAULT '0%' NOT NULL, |
| execution_time_ms INTEGER, |
| progress TEXT, |
| created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, |
| updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, |
| started_at TIMESTAMP, |
| completed_at TIMESTAMP, |
| FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE |
| ) |
| """)) |
| print(" ✅ Evaluations table created") |
| |
| |
| await session.execute(text("CREATE INDEX IF NOT EXISTS idx_users_email ON users(email)")) |
| await session.execute(text("CREATE INDEX IF NOT EXISTS idx_evaluations_user_id ON evaluations(user_id)")) |
| await session.execute(text("CREATE INDEX IF NOT EXISTS idx_evaluations_job_id ON evaluations(job_id)")) |
| await session.execute(text("CREATE INDEX IF NOT EXISTS idx_evaluations_status ON evaluations(status)")) |
| await session.execute(text("CREATE INDEX IF NOT EXISTS idx_api_keys_user_id ON api_keys(user_id)")) |
| await session.execute(text("CREATE INDEX IF NOT EXISTS idx_api_keys_key_prefix ON api_keys(key_prefix)")) |
| |
| print(" ✅ Indexes created") |
| |
| |
| await session.execute(text("PRAGMA foreign_keys = ON")) |
| await session.execute(text("PRAGMA journal_mode = WAL")) |
| await session.execute(text("PRAGMA synchronous = NORMAL")) |
| await session.execute(text("PRAGMA cache_size = 10000")) |
| await session.execute(text("PRAGMA temp_store = memory")) |
| |
| await session.commit() |
| print(" ✅ SQLite optimizations enabled") |
| |
| |
| async with SessionLocal() as session: |
| result = await session.execute(text(""" |
| SELECT name FROM sqlite_master |
| WHERE type='table' |
| AND name NOT LIKE 'sqlite_%' |
| ORDER BY name |
| """)) |
| |
| tables = result.fetchall() |
| table_names = [table[0] for table in tables] |
| |
| print(f"\n📋 Created {len(table_names)} tables:") |
| for table_name in table_names: |
| print(f" - {table_name}") |
| |
| |
| await engine.dispose() |
| |
| print(f"\n🎉 SQLite fallback database setup completed successfully!") |
| print(f" Database file: {db_path.absolute()}") |
| print(f" File size: {db_path.stat().st_size} bytes" if db_path.exists() else "") |
| |
| return True |
| |
| except Exception as e: |
| print(f"❌ Setup failed: {e}") |
| logger.error(f"Setup failed: {e}") |
| return False |
|
|
|
|
| if __name__ == "__main__": |
| success = asyncio.run(setup_sqlite_fallback()) |
| exit(0 if success else 1) |
|
|