#!/usr/bin/env python3 """ Database migration: Project portal auth (Phase 1). Adds the per-project portal gate columns to `projects`: - portal_enabled (BOOLEAN, default 0) - portal_password_hash (TEXT, nullable) - portal_link_token (TEXT, nullable) [+ unique index] Idempotent. Run once per existing DB: docker exec terra-view-terra-view-1 python3 backend/migrate_add_project_portal_auth.py """ import sqlite3 from pathlib import Path _COLUMNS = { "portal_enabled": "BOOLEAN DEFAULT 0", "portal_password_hash": "TEXT", "portal_link_token": "TEXT", } def migrate(): possible_paths = [Path("data/seismo_fleet.db"), Path("data/sfm.db"), Path("data/seismo.db")] db_path = next((p for p in possible_paths if p.exists()), None) if db_path is None: print(f"Database not found in any of: {[str(p) for p in possible_paths]}") print("A fresh DB created via models.py will include these columns automatically.") return print(f"Using database: {db_path}") conn = sqlite3.connect(db_path) cursor = conn.cursor() cursor.execute("PRAGMA table_info(projects)") existing = {row[1] for row in cursor.fetchall()} for col, ddl in _COLUMNS.items(): if col in existing: print(f"○ Column already exists: projects.{col}") continue try: cursor.execute(f"ALTER TABLE projects ADD COLUMN {col} {ddl}") print(f"✓ Added column: projects.{col} ({ddl})") except sqlite3.OperationalError as e: print(f"✗ Failed to add projects.{col}: {e}") # Unique index on the link token (separate from ADD COLUMN; idempotent via IF NOT EXISTS). try: cursor.execute("CREATE UNIQUE INDEX IF NOT EXISTS ix_projects_portal_link_token " "ON projects (portal_link_token)") print("✓ Ensured unique index: ix_projects_portal_link_token") except sqlite3.OperationalError as e: print(f"✗ Failed to create index: {e}") conn.commit() conn.close() print("\n✓ Project portal-auth migration complete.") if __name__ == "__main__": migrate()