Files
Christian Krakau-Louis 03b982e7c2 Initial clean commit
2025-05-13 08:59:02 +00:00

158 lines
7.1 KiB
Python

"""
Migration script to add Google and Authentik OAuth fields to the User table
"""
from datetime import datetime
import logging
from sqlalchemy import text, inspect
logger = logging.getLogger(__name__)
def run_migration():
"""
Add new columns to the User table for Google and Authentik OAuth integration
Returns:
- True: if changes were made successfully
- None: if no changes were needed (already up to date)
- False: if errors occurred
"""
from musicround import db
# Track changes made
changes_made = False
try:
# Connect to the database
inspector = inspect(db.engine)
existing_columns = [column['name'] for column in inspector.get_columns('user')]
# Use connection for executing SQL statements
with db.engine.connect() as conn:
# Add auth_provider column if it doesn't exist
if 'auth_provider' not in existing_columns:
logger.info("Adding auth_provider column")
try:
conn.execute(text('ALTER TABLE user ADD COLUMN auth_provider VARCHAR(20)'))
# Set default value for existing rows
conn.execute(text("UPDATE user SET auth_provider = 'local' WHERE auth_provider IS NULL"))
conn.commit()
changes_made = True
logger.info("Added auth_provider column")
except Exception as e:
logger.error(f"Error adding auth_provider column: {str(e)}")
# Add Google OAuth columns
if 'google_id' not in existing_columns:
logger.info("Adding google_id column")
try:
conn.execute(text('ALTER TABLE user ADD COLUMN google_id VARCHAR(100)'))
conn.commit()
changes_made = True
logger.info("Added google_id column")
except Exception as e:
logger.error(f"Error adding google_id column: {str(e)}")
if 'google_token' not in existing_columns:
logger.info("Adding google_token column")
try:
conn.execute(text('ALTER TABLE user ADD COLUMN google_token TEXT'))
conn.commit()
changes_made = True
logger.info("Added google_token column")
except Exception as e:
logger.error(f"Error adding google_token column: {str(e)}")
if 'google_refresh_token' not in existing_columns:
logger.info("Adding google_refresh_token column")
try:
conn.execute(text('ALTER TABLE user ADD COLUMN google_refresh_token TEXT'))
conn.commit()
changes_made = True
logger.info("Added google_refresh_token column")
except Exception as e:
logger.error(f"Error adding google_refresh_token column: {str(e)}")
# Add Authentik OAuth columns
if 'authentik_id' not in existing_columns:
logger.info("Adding authentik_id column")
try:
conn.execute(text('ALTER TABLE user ADD COLUMN authentik_id VARCHAR(100)'))
conn.commit()
changes_made = True
logger.info("Added authentik_id column")
except Exception as e:
logger.error(f"Error adding authentik_id column: {str(e)}")
if 'authentik_token' not in existing_columns:
logger.info("Adding authentik_token column")
try:
conn.execute(text('ALTER TABLE user ADD COLUMN authentik_token TEXT'))
conn.commit()
changes_made = True
logger.info("Added authentik_token column")
except Exception as e:
logger.error(f"Error adding authentik_token column: {str(e)}")
if 'authentik_refresh_token' not in existing_columns:
logger.info("Adding authentik_refresh_token column")
try:
conn.execute(text('ALTER TABLE user ADD COLUMN authentik_refresh_token TEXT'))
conn.commit()
changes_made = True
logger.info("Added authentik_refresh_token column")
except Exception as e:
logger.error(f"Error adding authentik_refresh_token column: {str(e)}")
# Make password_hash nullable for OAuth-only users
try:
# Due to SQLite limitations, we need to recreate the table to change column nullability
# Check if it's already nullable
is_nullable = False
result = conn.execute(text("PRAGMA table_info('user')"))
columns_info = result.fetchall()
for col in columns_info:
if col[1] == 'password_hash' and col[3] == 0: # 0 means nullable
is_nullable = True
break
if not is_nullable:
logger.info("Modifying password_hash to be nullable")
# Get all column definitions
columns = []
for col_info in columns_info:
name = col_info[1]
type_name = col_info[2]
not_null = "NOT NULL" if col_info[3] == 1 and name != "password_hash" else ""
pk = "PRIMARY KEY" if col_info[5] == 1 else ""
columns.append(f"{name} {type_name} {pk} {not_null}".strip())
# Create a temporary table with the new schema
column_defs = ", ".join(columns)
conn.execute(text(f'CREATE TABLE user_temp ({column_defs})'))
# Copy data from the old table
conn.execute(text('INSERT INTO user_temp SELECT * FROM user'))
# Replace the old table
conn.execute(text('DROP TABLE user'))
conn.execute(text('ALTER TABLE user_temp RENAME TO user'))
conn.commit()
changes_made = True
logger.info("Made password_hash column nullable for OAuth-only users")
else:
logger.info("password_hash is already nullable")
except Exception as e:
logger.error(f"Error modifying password_hash column: {str(e)}")
except Exception as e:
logger.error(f"Error in migration: {str(e)}")
return False # Return False for errors
# Report results
if changes_made:
logger.info("Migration completed successfully")
return True # Changes were made successfully
else:
logger.info("No changes were needed")
return None # No changes were needed (database is already up to date)