""" Role Permissions Migration Script (Phase 3) This script migrates role_permissions from the legacy role enum to the new dynamic role system. For each role_permission, it maps the current role enum value to the corresponding role_id. Usage: python migrate_role_permissions_to_dynamic_roles.py Environment Variables: DATABASE_URL - PostgreSQL connection string """ import os import sys from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker from database import Base from models import RolePermission, Role, UserRole from dotenv import load_dotenv # Load environment variables load_dotenv() # Database connection DATABASE_URL = os.getenv("DATABASE_URL") if not DATABASE_URL: print("Error: DATABASE_URL environment variable not set") sys.exit(1) engine = create_engine(DATABASE_URL) SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) def migrate_role_permissions(): """Migrate role_permissions from enum role to role_id""" db = SessionLocal() try: print("šŸš€ Starting role_permissions migration (Phase 3)...") print("="*60) # Step 1: Load all roles into a map print("\nšŸ“‹ Loading roles from database...") roles = db.query(Role).all() role_map = {role.code: role for role in roles} print(f"āœ“ Loaded {len(roles)} roles:") for role in roles: print(f" • {role.name} ({role.code}) - ID: {role.id}") # Step 2: Get all role_permissions print("\nšŸ” Loading role_permissions...") role_permissions = db.query(RolePermission).all() print(f"āœ“ Found {len(role_permissions)} role_permission records to migrate") if not role_permissions: print("\nāœ… No role_permissions to migrate!") return # Step 3: Check if any role_permissions already have role_id set perms_with_role_id = [rp for rp in role_permissions if rp.role_id is not None] if perms_with_role_id: print(f"\nāš ļø Warning: {len(perms_with_role_id)} role_permissions already have role_id set") response = input("Do you want to re-migrate these records? (yes/no): ") if response.lower() != 'yes': print("Skipping role_permissions that already have role_id set...") role_permissions = [rp for rp in role_permissions if rp.role_id is None] print(f"Will migrate {len(role_permissions)} role_permissions without role_id") if not role_permissions: print("\nāœ… No role_permissions to migrate!") return # Step 4: Migrate role_permissions print(f"\nšŸ”„ Migrating {len(role_permissions)} role_permission records...") migration_stats = { UserRole.guest: 0, UserRole.member: 0, UserRole.admin: 0, UserRole.superadmin: 0 } for rp in role_permissions: # Get the enum role code (e.g., "guest", "member", "admin", "superadmin") role_code = rp.role.value # Find the matching role in the roles table if role_code not in role_map: print(f" āš ļø Warning: No matching role found for '{role_code}' (permission_id: {rp.permission_id})") continue # Set the role_id rp.role_id = role_map[role_code].id migration_stats[rp.role] = migration_stats.get(rp.role, 0) + 1 # Commit all changes db.commit() print(f"āœ“ Migrated {len(role_permissions)} role_permission records") # Step 5: Display migration summary print("\n" + "="*60) print("šŸ“Š Migration Summary:") print("="*60) print("\nRole permissions migrated by role:") for role_enum, count in migration_stats.items(): if count > 0: print(f" • {role_enum.value}: {count} permissions") # Step 6: Verify migration print("\nšŸ” Verifying migration...") perms_without_role_id = db.query(RolePermission).filter(RolePermission.role_id == None).count() perms_with_role_id = db.query(RolePermission).filter(RolePermission.role_id != None).count() print(f" • Role permissions with role_id: {perms_with_role_id}") print(f" • Role permissions without role_id: {perms_without_role_id}") if perms_without_role_id > 0: print(f"\nāš ļø Warning: {perms_without_role_id} role_permissions still don't have role_id set!") else: print("\nāœ… All role_permissions successfully migrated!") print("\n" + "="*60) print("āœ… Role permissions migration completed successfully!") print("="*60) print("\nšŸ“ Next Steps:") print(" 1. Update auth.py to use dynamic roles") print(" 2. Update server.py role checks") print(" 3. Verify system still works with new roles") print(" 4. In Phase 4, remove legacy enum columns") except Exception as e: db.rollback() print(f"\nāŒ Error migrating role_permissions: {str(e)}") import traceback traceback.print_exc() raise finally: db.close() if __name__ == "__main__": migrate_role_permissions()