- Simplified HasTenantAccess permission logic to ensure every authenticated user has an account. - Added fallback to system account for OpenAI settings in AI configuration. - Allowed any authenticated user to check task progress in IntegrationSettingsViewSet. - Created a script to identify and fix orphaned users without accounts. - Updated error response handling in business endpoints for clarity.
148 lines
4.5 KiB
Python
148 lines
4.5 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Script to identify and fix orphaned users (users without accounts).
|
|
|
|
This script will:
|
|
1. Find all users with account = NULL
|
|
2. For each user, either:
|
|
- Assign them to an existing account if possible
|
|
- Create a new account for them
|
|
- Delete them if they're test/invalid users
|
|
3. Report the results
|
|
|
|
Run this from backend directory:
|
|
python3 fix_orphaned_users.py
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
import django
|
|
|
|
# Setup Django
|
|
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'igny8_core.settings')
|
|
django.setup()
|
|
|
|
from igny8_core.auth.models import User, Account, Plan
|
|
from django.db import transaction
|
|
|
|
def main():
|
|
print("=" * 80)
|
|
print("ORPHANED USERS FIX SCRIPT")
|
|
print("=" * 80)
|
|
|
|
# Find users without accounts
|
|
orphaned_users = User.objects.filter(account__isnull=True)
|
|
count = orphaned_users.count()
|
|
|
|
print(f"\nFound {count} user(s) without accounts:\n")
|
|
|
|
if count == 0:
|
|
print("✅ No orphaned users found. System is healthy!")
|
|
return
|
|
|
|
# List them
|
|
for i, user in enumerate(orphaned_users, 1):
|
|
print(f"{i}. ID: {user.id}")
|
|
print(f" Email: {user.email}")
|
|
print(f" Username: {user.username}")
|
|
print(f" Role: {user.role}")
|
|
print(f" Active: {user.is_active}")
|
|
print(f" Superuser: {user.is_superuser}")
|
|
print(f" Created: {user.created_at}")
|
|
print()
|
|
|
|
# Ask what to do
|
|
print("\nOptions:")
|
|
print("1. Auto-fix: Create accounts for all orphaned users")
|
|
print("2. Delete all orphaned users")
|
|
print("3. Exit without changes")
|
|
|
|
choice = input("\nEnter choice (1-3): ").strip()
|
|
|
|
if choice == '1':
|
|
auto_fix_users(orphaned_users)
|
|
elif choice == '2':
|
|
delete_users(orphaned_users)
|
|
else:
|
|
print("\n❌ No changes made. Exiting.")
|
|
|
|
def auto_fix_users(users):
|
|
"""Create accounts for orphaned users"""
|
|
print("\n" + "=" * 80)
|
|
print("AUTO-FIXING ORPHANED USERS")
|
|
print("=" * 80 + "\n")
|
|
|
|
# Get or create free plan
|
|
try:
|
|
free_plan = Plan.objects.get(slug='free', is_active=True)
|
|
except Plan.DoesNotExist:
|
|
print("❌ ERROR: Free plan not found. Cannot create accounts.")
|
|
print(" Please create a 'free' plan first or assign users manually.")
|
|
return
|
|
|
|
fixed_count = 0
|
|
|
|
with transaction.atomic():
|
|
for user in users:
|
|
try:
|
|
# Generate account name
|
|
if user.first_name or user.last_name:
|
|
account_name = f"{user.first_name} {user.last_name}".strip()
|
|
else:
|
|
account_name = user.email.split('@')[0]
|
|
|
|
# Generate unique slug
|
|
base_slug = account_name.lower().replace(' ', '-').replace('_', '-')[:50] or 'account'
|
|
slug = base_slug
|
|
counter = 1
|
|
while Account.objects.filter(slug=slug).exists():
|
|
slug = f"{base_slug}-{counter}"
|
|
counter += 1
|
|
|
|
# Create account
|
|
account = Account.objects.create(
|
|
name=account_name,
|
|
slug=slug,
|
|
owner=user,
|
|
plan=free_plan,
|
|
credits=free_plan.get_effective_credits_per_month(),
|
|
status='trial',
|
|
billing_email=user.email,
|
|
)
|
|
|
|
# Assign account to user
|
|
user.account = account
|
|
user.save()
|
|
|
|
print(f"✅ Fixed user: {user.email}")
|
|
print(f" Created account: {account.name} (ID: {account.id})")
|
|
print(f" Credits: {account.credits}")
|
|
print()
|
|
|
|
fixed_count += 1
|
|
|
|
except Exception as e:
|
|
print(f"❌ ERROR fixing user {user.email}: {e}")
|
|
print()
|
|
|
|
print("=" * 80)
|
|
print(f"✅ Successfully fixed {fixed_count} user(s)")
|
|
print("=" * 80)
|
|
|
|
def delete_users(users):
|
|
"""Delete orphaned users"""
|
|
print("\n⚠️ WARNING: This will permanently delete the selected users!")
|
|
confirm = input("Type 'DELETE' to confirm: ").strip()
|
|
|
|
if confirm != 'DELETE':
|
|
print("\n❌ Deletion cancelled.")
|
|
return
|
|
|
|
count = users.count()
|
|
users.delete()
|
|
|
|
print(f"\n✅ Deleted {count} user(s)")
|
|
|
|
if __name__ == '__main__':
|
|
main()
|