""" User and Role Seeder Creates default roles and an admin user """ import sys from pathlib import Path from datetime import datetime, timezone import bcrypt # Add parent directory to path to import modules sys.path.insert(0, str(Path(__file__).resolve().parents[1])) from sqlalchemy.orm import Session from src.shared.config.database import SessionLocal # Import all models to ensure relationships are properly initialized from src.models import * from src.auth.models.role import Role from src.auth.models.user import User from src.shared.config.logging_config import get_logger logger = get_logger(__name__) def get_roles_data(): """Generate default roles data""" return [ { 'name': 'admin', 'description': 'Full system access with all administrative privileges' }, { 'name': 'staff', 'description': 'Hotel staff with operational access' }, { 'name': 'customer', 'description': 'Regular customer/guest user' }, { 'name': 'accountant', 'description': 'Financial management and accounting access' }, { 'name': 'housekeeping', 'description': 'Housekeeping and room management access' } ] def seed_roles(db: Session): """Seed roles into the database""" try: roles_data = get_roles_data() created_count = 0 updated_count = 0 role_map = {} for role_data in roles_data: existing = db.query(Role).filter(Role.name == role_data['name']).first() if existing: logger.info(f'Role already exists: {role_data["name"]}') role_map[role_data['name']] = existing else: logger.info(f'Creating role: {role_data["name"]}') role = Role(**role_data) db.add(role) db.flush() # Flush to get the ID role_map[role_data['name']] = role created_count += 1 db.commit() logger.info(f'Role seeding completed! Created: {created_count}, Existing: {len(roles_data) - created_count}') return role_map except Exception as e: logger.error(f'Error seeding roles: {str(e)}', exc_info=True) db.rollback() raise def seed_admin_user(db: Session, admin_role: Role, email: str = 'admin@hotel.com', password: str = 'admin123', full_name: str = 'Admin User'): """Seed admin user into the database""" try: # Check if admin user already exists existing = db.query(User).filter(User.email == email).first() if existing: logger.info(f'Admin user already exists: {email}') # Update role if needed if existing.role_id != admin_role.id: existing.role_id = admin_role.id existing.updated_at = datetime.now(timezone.utc) db.commit() logger.info(f'Updated admin user role: {email}') return existing # Create new admin user logger.info(f'Creating admin user: {email}') password_bytes = password.encode('utf-8') salt = bcrypt.gensalt() hashed_password = bcrypt.hashpw(password_bytes, salt).decode('utf-8') admin_user = User( email=email, password=hashed_password, full_name=full_name, role_id=admin_role.id, is_active=True, phone=None, address=None ) db.add(admin_user) db.commit() db.refresh(admin_user) logger.info(f'Admin user created successfully: {email}') return admin_user except Exception as e: logger.error(f'Error seeding admin user: {str(e)}', exc_info=True) db.rollback() raise def seed_users_and_roles(db: Session, admin_email: str = 'admin@hotel.com', admin_password: str = 'admin123', admin_name: str = 'Admin User'): """Seed roles and admin user""" try: # First, seed roles role_map = seed_roles(db) # Get admin role admin_role = role_map.get('admin') if not admin_role: raise ValueError('Admin role not found after seeding') # Seed admin user admin_user = seed_admin_user(db, admin_role, admin_email, admin_password, admin_name) return role_map, admin_user except Exception as e: logger.error(f'Error seeding users and roles: {str(e)}', exc_info=True) raise def main(): """Main function to run the seeder""" import argparse parser = argparse.ArgumentParser(description='Seed roles and admin user') parser.add_argument( '--email', default='admin@hotel.com', help='Admin user email (default: admin@hotel.com)' ) parser.add_argument( '--password', default='admin123', help='Admin user password (default: admin123)' ) parser.add_argument( '--name', default='Admin User', help='Admin user full name (default: Admin User)' ) args = parser.parse_args() logger.info('Starting user and role seeder...') db = SessionLocal() try: role_map, admin_user = seed_users_and_roles( db, admin_email=args.email, admin_password=args.password, admin_name=args.name ) logger.info(f'User and role seeder completed successfully!') logger.info(f'Admin user: {admin_user.email} (ID: {admin_user.id})') logger.info(f'Roles created: {len(role_map)}') print(f'\n✓ Admin user created successfully!') print(f' Email: {admin_user.email}') print(f' Password: {args.password}') print(f' Role: admin') print(f'\n⚠️ IMPORTANT: Change the default password after first login!') except Exception as e: logger.error(f'Failed to seed users and roles: {str(e)}', exc_info=True) sys.exit(1) finally: db.close() if __name__ == '__main__': main()