"""Migration script to add multi-property support to existing database.""" import sys import os # Add backend to path sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) from sqlalchemy import inspect, text from app.db.session import Base, SessionLocal, engine from app.models import ( Organization, OrganizationMember, Property, PropertyAccess, PropertyManager, PropertySettings, User, Space, ) def migrate(): """Run migration to add multi-property tables and data.""" db = SessionLocal() inspector = inspect(engine) existing_tables = inspector.get_table_names() print("Starting multi-property migration...") # Step 1: Create all new tables print("1. Creating new tables...") Base.metadata.create_all(bind=engine) print(" Tables created successfully.") # Step 2: Add property_id column to spaces if not exists space_columns = [col["name"] for col in inspector.get_columns("spaces")] if "property_id" not in space_columns: print("2. Adding property_id column to spaces...") with engine.connect() as conn: conn.execute(text("ALTER TABLE spaces ADD COLUMN property_id INTEGER REFERENCES properties(id)")) conn.commit() print(" Column added.") else: print("2. property_id column already exists in spaces.") # Step 3: Add guest columns to bookings if not exists booking_columns = [col["name"] for col in inspector.get_columns("bookings")] with engine.connect() as conn: if "guest_name" not in booking_columns: print("3. Adding guest columns to bookings...") conn.execute(text("ALTER TABLE bookings ADD COLUMN guest_name VARCHAR")) conn.execute(text("ALTER TABLE bookings ADD COLUMN guest_email VARCHAR")) conn.execute(text("ALTER TABLE bookings ADD COLUMN guest_organization VARCHAR")) conn.execute(text("ALTER TABLE bookings ADD COLUMN is_anonymous BOOLEAN DEFAULT 0 NOT NULL")) conn.commit() print(" Guest columns added.") else: print("3. Guest columns already exist in bookings.") # Step 4: Create "Default Property" print("4. Creating Default Property...") existing_default = db.query(Property).filter(Property.name == "Default Property").first() if not existing_default: default_prop = Property( name="Default Property", description="Default property for migrated spaces", is_public=True, is_active=True, ) db.add(default_prop) db.flush() # Step 5: Migrate existing spaces to Default Property print("5. Migrating existing spaces to Default Property...") spaces_without_property = db.query(Space).filter(Space.property_id == None).all() # noqa: E711 for space in spaces_without_property: space.property_id = default_prop.id db.flush() print(f" Migrated {len(spaces_without_property)} spaces.") # Step 6: Rename admin users to superadmin print("6. Updating admin roles to superadmin...") admin_users = db.query(User).filter(User.role == "admin").all() for u in admin_users: u.role = "superadmin" db.flush() print(f" Updated {len(admin_users)} users.") # Step 7: Create PropertyManager entries for superadmins print("7. Creating PropertyManager entries for superadmins...") superadmins = db.query(User).filter(User.role == "superadmin").all() for sa in superadmins: existing_pm = db.query(PropertyManager).filter( PropertyManager.property_id == default_prop.id, PropertyManager.user_id == sa.id, ).first() if not existing_pm: db.add(PropertyManager(property_id=default_prop.id, user_id=sa.id)) db.flush() print(f" Created entries for {len(superadmins)} superadmins.") db.commit() print("\nMigration completed successfully!") else: print(" Default Property already exists. Skipping data migration.") print("\nMigration already applied.") db.close() if __name__ == "__main__": migrate()