Files
membership-be/migrate_role_permissions_to_dynamic_roles.py
2025-12-16 20:03:50 +07:00

146 lines
5.2 KiB
Python

"""
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()