# scripts/seed_saudi_accounts.py import os import django # Set up Django environment os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'hospital_management.settings') django.setup() import random import uuid import secrets from datetime import timedelta from django.contrib.auth.hashers import make_password from django.utils import timezone as django_timezone from django.db import transaction from accounts.models import User, TwoFactorDevice, SocialAccount, UserSession, PasswordHistory from core.models import Tenant from hr.models import Employee, Department # ------------------------------- # Saudi-specific data constants # ------------------------------- SAUDI_FIRST_NAMES_MALE = [ 'Mohammed', 'Abdullah', 'Ahmed', 'Omar', 'Ali', 'Hassan', 'Khalid', 'Faisal', 'Saad', 'Fahd', 'Bandar', 'Turki', 'Nasser', 'Saud', 'Abdulrahman', 'Abdulaziz', 'Salman', 'Waleed', 'Majid', 'Rayan', 'Yazeed', 'Mansour', 'Osama', 'Tariq', 'Adel', 'Nawaf', 'Sultan', 'Mishaal', 'Badr', 'Ziad' ] SAUDI_FIRST_NAMES_FEMALE = [ 'Fatima', 'Aisha', 'Maryam', 'Khadija', 'Sarah', 'Noura', 'Hala', 'Reem', 'Lina', 'Dana', 'Rana', 'Nada', 'Layla', 'Amira', 'Zahra', 'Yasmin', 'Dina', 'Noor', 'Rahma', 'Salma', 'Lama', 'Ghada', 'Rania', 'Maha', 'Wedad', 'Najla', 'Shahd', 'Jood', 'Rand', 'Malak' ] SAUDI_FAMILY_NAMES = [ 'Al-Rashid', 'Al-Harbi', 'Al-Qahtani', 'Al-Dosari', 'Al-Otaibi', 'Al-Mutairi', 'Al-Shammari', 'Al-Zahrani', 'Al-Ghamdi', 'Al-Maliki', 'Al-Subai', 'Al-Jubayr', 'Al-Faisal', 'Al-Saud', 'Al-Shaalan', 'Al-Rajhi', 'Al-Sudairy', 'Al-Ajmi', 'Al-Anzi', 'Al-Dawsari', 'Al-Shamrani', 'Al-Balawi', 'Al-Juhani', 'Al-Sulami' ] SAUDI_CITIES = [ 'Riyadh', 'Jeddah', 'Mecca', 'Medina', 'Dammam', 'Khobar', 'Dhahran', 'Taif', 'Tabuk', 'Buraidah', 'Khamis Mushait', 'Hofuf', 'Mubarraz', 'Jubail', 'Yanbu', 'Abha', 'Najran', 'Jazan', 'Hail', 'Arar' ] SAUDI_PROVINCES = [ 'Riyadh Province', 'Makkah Province', 'Eastern Province', 'Asir Province', 'Jazan Province', 'Medina Province', 'Qassim Province', 'Tabuk Province', 'Hail Province', 'Northern Borders Province', 'Najran Province', 'Al Bahah Province' ] SAUDI_DEPARTMENTS = [ 'Internal Medicine', 'Cardiology', 'Orthopedics', 'Neurology', 'Oncology', 'Pediatrics', 'Emergency Medicine', 'Radiology', 'Laboratory Medicine', 'Pharmacy', 'Surgery', 'Obstetrics and Gynecology', 'Dermatology', 'Ophthalmology', 'ENT', 'Anesthesiology', 'Pathology', 'Psychiatry' ] SAUDI_JOB_TITLES = { 'PHYSICIAN': ['Consultant Physician', 'Senior Physician', 'Staff Physician', 'Resident Physician', 'Chief Medical Officer'], 'NURSE': ['Head Nurse', 'Senior Nurse', 'Staff Nurse', 'Charge Nurse', 'Clinical Nurse Specialist'], 'PHARMACIST': ['Clinical Pharmacist', 'Staff Pharmacist', 'Pharmacy Manager', 'Pharmaceutical Consultant'], 'ADMIN': ['Medical Director', 'Hospital Administrator', 'Department Manager', 'Operations Manager'], 'LAB_TECH': ['Senior Lab Technician', 'Medical Laboratory Scientist', 'Lab Supervisor'], 'RAD_TECH': ['Senior Radiologic Technologist', 'CT Technologist', 'MRI Technologist'], 'RADIOLOGIST': ['Consultant Radiologist', 'Senior Radiologist', 'Interventional Radiologist'], 'MEDICAL_ASSISTANT': ['Medical Assistant'], 'CLERICAL': ['Clerical Staff'], } SAUDI_LICENSE_PREFIXES = ['MOH', 'SCFHS', 'SMLE', 'SFH'] ROLE_DISTRIBUTION = { 'PHYSICIAN': 0.15, 'NURSE': 0.25, 'PHARMACIST': 0.08, 'LAB_TECH': 0.10, 'RAD_TECH': 0.08, 'RADIOLOGIST': 0.05, 'ADMIN': 0.07, 'MEDICAL_ASSISTANT': 0.12, 'CLERICAL': 0.10 } # ------------------------------- # Helpers # ------------------------------- def ensure_departments(tenant): """ Ensure Department objects exist for this tenant; return a list of them. Adjust if your Department is global (then drop tenant filtering). """ existing = list(Department.objects.filter(tenant=tenant)) if 'tenant' in [f.name for f in Department._meta.fields] else list(Department.objects.all()) if existing: return existing # create seed departments bulk = [] for name in SAUDI_DEPARTMENTS: if 'tenant' in [f.name for f in Department._meta.fields]: bulk.append(Department(name=name, tenant=tenant)) else: bulk.append(Department(name=name)) Department.objects.bulk_create(bulk, ignore_conflicts=True) return list(Department.objects.filter(tenant=tenant)) if 'tenant' in [f.name for f in Department._meta.fields] else list(Department.objects.all()) def generate_saudi_mobile_e164(): """Generate Saudi E.164 mobile: +9665XXXXXXXX""" return f"+9665{random.randint(10000000, 99999999)}" def generate_saudi_license(): """Generate Saudi medical license number (fictional format)""" prefix = random.choice(SAUDI_LICENSE_PREFIXES) return f"{prefix}-{random.randint(100000, 999999)}" def tenant_scoped_unique_username(tenant, base_username: str) -> str: """ Make username unique within a tenant (your User has tenant-scoped unique constraint). """ username = base_username i = 1 while User.objects.filter(tenant=tenant, username=username).exists(): i += 1 username = f"{base_username}{i}" return username def pick_job_title(role: str) -> str: titles = SAUDI_JOB_TITLES.get(role) if titles: return random.choice(titles) # fallback return role.replace('_', ' ').title() # ------------------------------- # Generators # ------------------------------- def create_saudi_users(tenants, users_per_tenant=50): """ Create Users (auth + security), then populate Employee profile. Relies on the post_save signal to create Employee automatically. """ all_users = [] for tenant in tenants: departments = ensure_departments(tenant) tenant_users = [] for role, pct in ROLE_DISTRIBUTION.items(): count = max(1, int(users_per_tenant * pct)) for _ in range(count): is_male = random.choice([True, False]) first_name = random.choice(SAUDI_FIRST_NAMES_MALE if is_male else SAUDI_FIRST_NAMES_FEMALE) father_name = random.choice(SAUDI_FIRST_NAMES_MALE) grandfather_name = random.choice(SAUDI_FIRST_NAMES_MALE) last_name = random.choice(SAUDI_FAMILY_NAMES) # base username like "mohammed.alrashid" base_username = f"{first_name.lower()}.{last_name.lower().replace('-', '').replace('al', '')}" username = tenant_scoped_unique_username(tenant, base_username) email = f"{username}@{tenant.name.lower().replace(' ', '').replace('-', '')}.sa" is_admin = role in ['ADMIN', 'SUPER_ADMIN'] is_superuser = role == 'SUPER_ADMIN' # Auth-level fields only user = User.objects.create( tenant=tenant, username=username, email=email, first_name=first_name, last_name=last_name, is_active=True, is_staff=is_admin, is_superuser=is_superuser, # security/session (these live on User by design) force_password_change=random.choice([True, False]), password_expires_at=django_timezone.now() + timedelta(days=random.randint(90, 365)), failed_login_attempts=random.randint(0, 2), two_factor_enabled=random.choice([True, False]) if role in ['PHYSICIAN', 'ADMIN', 'PHARMACIST'] else False, max_concurrent_sessions=random.choice([1, 2, 3, 5]), session_timeout_minutes=random.choice([30, 60, 120, 240]), last_password_change=django_timezone.now() - timedelta(days=random.randint(1, 90)), date_joined=django_timezone.now() - timedelta(days=random.randint(1, 365)), ) user.set_password('Hospital@123') user.save() # Signal should have created Employee; now populate Employee fields emp: Employee = user.employee_profile # created by signal emp.tenant = tenant # ensure alignment emp.first_name = first_name emp.father_name = father_name emp.grandfather_name = grandfather_name emp.last_name = last_name # Contact (E.164 KSA) mobile = generate_saudi_mobile_e164() emp.phone = mobile emp.mobile_phone = mobile emp.email = email # Role/Org emp.role = role emp.department = random.choice(departments) if departments else None emp.job_title = pick_job_title(role) # License (only some roles) if role in ['PHYSICIAN', 'NURSE', 'PHARMACIST', 'RADIOLOGIST']: emp.license_number = generate_saudi_license() emp.license_state = random.choice(SAUDI_PROVINCES) emp.license_expiry_date = django_timezone.now().date() + timedelta(days=random.randint(365, 1095)) if role == 'PHYSICIAN': # fictitious local analogue to NPI emp.npi_number = f"SA{random.randint(1000000, 9999999)}" # Preferences emp.user_timezone = 'Asia/Riyadh' emp.language = random.choice(['ar', 'en', 'ar_SA']) emp.theme = random.choice([Employee.Theme.LIGHT, Employee.Theme.DARK, Employee.Theme.AUTO]) # Status / approval (approved later per-tenant) emp.is_verified = True emp.is_approved = True emp.approval_date = django_timezone.now() - timedelta(days=random.randint(1, 180)) emp.save() tenant_users.append(user) all_users.append(user) # Approval relationships: choose an approver among admins in this tenant admin_users = [u for u in tenant_users if u.is_staff or u.is_superuser] if admin_users: approver = random.choice(admin_users) for u in tenant_users: if u != approver: emp = u.employee_profile emp.approved_by = approver emp.save(update_fields=['approved_by']) print(f"Created {len(tenant_users)} users for {tenant.name}") return all_users def create_saudi_two_factor_devices(users): """Create two-factor authentication devices for Saudi users""" devices = [] device_types = ['TOTP', 'SMS', 'EMAIL'] device_names = { 'TOTP': ['Google Authenticator', 'Microsoft Authenticator', 'Authy', 'LastPass Authenticator'], 'SMS': ['Primary Mobile', 'Work Mobile', 'Emergency Contact'], 'EMAIL': ['Work Email', 'Personal Email', 'Backup Email'] } for user in users: if user.two_factor_enabled: device_count = random.randint(1, 3) emp = getattr(user, 'employee_profile', None) for _ in range(device_count): device_type = random.choice(device_types) device_data = { 'user': user, 'device_id': uuid.uuid4(), 'name': random.choice(device_names[device_type]), 'device_type': device_type, 'is_active': True, 'is_verified': True, 'verified_at': django_timezone.now() - timedelta(days=random.randint(1, 30)), 'last_used_at': django_timezone.now() - timedelta(hours=random.randint(1, 168)), 'usage_count': random.randint(5, 100), 'created_at': django_timezone.now() - timedelta(days=random.randint(1, 60)) } if device_type == 'TOTP': device_data['secret_key'] = secrets.token_urlsafe(32) elif device_type == 'SMS': device_data['phone_number'] = emp.mobile_phone if emp else None elif device_type == 'EMAIL': device_data['email_address'] = emp.email if emp and emp.email else user.email device = TwoFactorDevice.objects.create(**device_data) devices.append(device) print(f"Created {len(devices)} two-factor devices") return devices def create_saudi_social_accounts(users): """Create social authentication accounts for Saudi users""" social_accounts = [] providers = ['GOOGLE', 'MICROSOFT', 'APPLE', 'LINKEDIN'] for user in users: if random.choice([True, False, False, False]): # ~25% chance provider = random.choice(providers) display_name = user.get_full_name() or (user.employee_profile.get_display_name() if hasattr(user, 'employee_profile') else user.username) social_account = SocialAccount.objects.create( user=user, provider=provider, provider_id=f"{provider.lower()}_{random.randint(100000000, 999999999)}", provider_email=user.email, display_name=display_name, profile_url=f"https://{provider.lower()}.com/profile/{user.username}", avatar_url=f"https://{provider.lower()}.com/avatar/{user.username}.jpg", access_token=secrets.token_urlsafe(64), refresh_token=secrets.token_urlsafe(64), token_expires_at=django_timezone.now() + timedelta(hours=1), is_active=True, created_at=django_timezone.now() - timedelta(days=random.randint(1, 180)), last_login_at=django_timezone.now() - timedelta(hours=random.randint(1, 48)) ) social_accounts.append(social_account) print(f"Created {len(social_accounts)} social accounts") return social_accounts def create_saudi_user_sessions(users): """Create user sessions for Saudi healthcare users""" sessions = [] saudi_ips = [ '37.99.', '37.200.', '31.9.', '31.173.', '188.161.', '185.84.', '188.245.', '217.9.', '82.205.', '5.63.' ] browsers = [ 'Chrome 120.0.0.0', 'Safari 17.1.2', 'Firefox 121.0.0', 'Edge 120.0.0.0', 'Chrome Mobile 120.0.0.0', 'Safari Mobile 17.1.2' ] operating_systems = [ 'Windows 11', 'Windows 10', 'macOS 14.0', 'iOS 17.1.2', 'Android 14', 'Ubuntu 22.04' ] device_types = ['DESKTOP', 'MOBILE', 'TABLET'] login_methods = ['PASSWORD', 'TWO_FACTOR', 'SOCIAL', 'SSO'] for user in users: session_count = random.randint(1, 5) timeout_minutes = user.session_timeout_minutes or 30 for i in range(session_count): ip_prefix = random.choice(saudi_ips) ip_address = f"{ip_prefix}{random.randint(1, 255)}.{random.randint(1, 255)}" session_start = django_timezone.now() - timedelta(hours=random.randint(1, 720)) is_active = (i == 0) and random.choice([True, True, False]) # recent likely active session = UserSession.objects.create( user=user, session_key=f"session_{secrets.token_urlsafe(20)}", session_id=uuid.uuid4(), ip_address=ip_address, user_agent=f"Mozilla/5.0 (compatible; HospitalSystem/1.0; {random.choice(browsers)})", device_type=random.choice(device_types), browser=random.choice(browsers), operating_system=random.choice(operating_systems), country='Saudi Arabia', region=random.choice(SAUDI_PROVINCES), city=random.choice(SAUDI_CITIES), is_active=is_active, login_method=random.choice(login_methods), created_at=session_start, last_activity_at=session_start + timedelta(minutes=random.randint(1, 480)), expires_at=session_start + timedelta(minutes=timeout_minutes), ended_at=None if is_active else session_start + timedelta(hours=random.randint(1, 8)) ) sessions.append(session) print(f"Created {len(sessions)} user sessions") return sessions def create_saudi_password_history(users): """Create password history for Saudi users""" password_history = [] passwords = ['Hospital@123', 'Medical@456', 'Health@789', 'Saudi@2024', 'Secure@Pass'] for user in users: history_count = random.randint(1, 5) for i in range(history_count): password = random.choice(passwords) history_entry = PasswordHistory.objects.create( user=user, password_hash=make_password(password), created_at=django_timezone.now() - timedelta(days=random.randint(30 * i, 30 * (i + 1))) ) password_history.append(history_entry) print(f"Created {len(password_history)} password history entries") return password_history # ------------------------------- # Main # ------------------------------- def main(): print("Starting Saudi Healthcare Accounts Data Generation...") tenants = list(Tenant.objects.all()) if not tenants: print("āŒ No tenants found. Please seed core tenants first.") return print("\n1. Creating Saudi Healthcare Users (with Employee profiles)...") users = create_saudi_users(tenants, users_per_tenant=40) print("\n2. Creating Two-Factor Authentication Devices...") devices = create_saudi_two_factor_devices(users) print("\n3. Creating Social Authentication Accounts...") social_accounts = create_saudi_social_accounts(users) print("\n4. Creating User Sessions...") sessions = create_saudi_user_sessions(users) print("\n5. Creating Password History...") password_history = create_saudi_password_history(users) print(f"\nāœ… Saudi Healthcare Accounts Data Generation Complete!") print(f"šŸ“Š Summary:") print(f" - Users: {len(users)}") print(f" - Two-Factor Devices: {len(devices)}") print(f" - Social Accounts: {len(social_accounts)}") print(f" - User Sessions: {len(sessions)}") print(f" - Password History Entries: {len(password_history)}") role_counts = {} for u in users: role = u.employee_profile.role if hasattr(u, 'employee_profile') else 'UNKNOWN' role_counts[role] = role_counts.get(role, 0) + 1 print(f"\nšŸ‘„ User Role Distribution:") for role, count in sorted(role_counts.items()): print(f" - {role.replace('_', ' ').title()}: {count}") return { 'users': users, 'devices': devices, 'social_accounts': social_accounts, 'sessions': sessions, 'password_history': password_history, } if __name__ == "__main__": main()