diff --git a/backend/igny8_core/api/authentication.py b/backend/igny8_core/api/authentication.py index d010ef01..8ccb864e 100644 --- a/backend/igny8_core/api/authentication.py +++ b/backend/igny8_core/api/authentication.py @@ -119,10 +119,18 @@ class APIKeyAuthentication(BaseAuthentication): if not site: return None # API key not found or site inactive - # Get account and user + # Get account and user (prefer owner but gracefully fall back) account = site.account - user = account.owner # Use account owner as the authenticated user + user = account.owner + if not user or not getattr(user, 'is_active', False): + # Fall back to any active developer/owner/admin in the account + user = account.users.filter( + is_active=True, + role__in=['developer', 'owner', 'admin'] + ).order_by('role').first() or account.users.filter(is_active=True).first() + if not user: + raise AuthenticationFailed('No active user available for this account.') if not user.is_active: raise AuthenticationFailed('User account is disabled.') diff --git a/backend/igny8_core/auth/migrations/0005_account_owner_nullable.py b/backend/igny8_core/auth/migrations/0005_account_owner_nullable.py new file mode 100644 index 00000000..f5e166b1 --- /dev/null +++ b/backend/igny8_core/auth/migrations/0005_account_owner_nullable.py @@ -0,0 +1,23 @@ +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + dependencies = [ + ('igny8_core_auth', '0004_add_invoice_payment_models'), + ] + + operations = [ + migrations.AlterField( + model_name='account', + name='owner', + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name='owned_accounts', + to='igny8_core_auth.user', + ), + ), + ] + diff --git a/backend/igny8_core/auth/models.py b/backend/igny8_core/auth/models.py index 34a6fab7..af7be4e0 100644 --- a/backend/igny8_core/auth/models.py +++ b/backend/igny8_core/auth/models.py @@ -65,7 +65,13 @@ class Account(models.Model): name = models.CharField(max_length=255) slug = models.SlugField(unique=True, max_length=255) - owner = models.ForeignKey('igny8_core_auth.User', on_delete=models.PROTECT, related_name='owned_accounts') + owner = models.ForeignKey( + 'igny8_core_auth.User', + on_delete=models.SET_NULL, + null=True, + blank=True, + related_name='owned_accounts', + ) stripe_customer_id = models.CharField(max_length=255, blank=True, null=True) plan = models.ForeignKey('igny8_core_auth.Plan', on_delete=models.PROTECT, related_name='accounts') credits = models.IntegerField(default=0, validators=[MinValueValidator(0)]) diff --git a/backend/igny8_core/business/automation/migrations/0001_initial.py b/backend/igny8_core/business/automation/migrations/0001_initial.py index 2e0e7dee..2ed1dde6 100644 --- a/backend/igny8_core/business/automation/migrations/0001_initial.py +++ b/backend/igny8_core/business/automation/migrations/0001_initial.py @@ -10,7 +10,7 @@ class Migration(migrations.Migration): initial = True dependencies = [ - ('igny8_core_auth', '__latest__'), + ('igny8_core_auth', '0004_add_invoice_payment_models'), ] operations = [