asdasd
This commit is contained in:
@@ -31,6 +31,14 @@ class AccountContextMiddleware(MiddlewareMixin):
|
||||
# First, try to get user from Django session (cookie-based auth)
|
||||
# This handles cases where frontend uses credentials: 'include' with session cookies
|
||||
if hasattr(request, 'user') and request.user and request.user.is_authenticated:
|
||||
# Block superuser access via session on non-admin routes (JWT required)
|
||||
auth_header = request.META.get('HTTP_AUTHORIZATION', '')
|
||||
if request.user.is_superuser and not auth_header.startswith('Bearer '):
|
||||
logout(request)
|
||||
return JsonResponse(
|
||||
{'success': False, 'error': 'Session authentication not allowed for API. Use JWT.'},
|
||||
status=status.HTTP_403_FORBIDDEN,
|
||||
)
|
||||
# User is authenticated via session - refresh from DB to get latest account/plan data
|
||||
# This ensures changes to account/plan are reflected immediately without re-login
|
||||
try:
|
||||
|
||||
@@ -288,14 +288,27 @@ class RegisterSerializer(serializers.Serializer):
|
||||
from igny8_core.business.billing.models import CreditTransaction
|
||||
|
||||
with transaction.atomic():
|
||||
# ALWAYS assign the existing free plan for simple signup
|
||||
# No fallbacks: if free plan is misconfigured, surface error immediately
|
||||
try:
|
||||
plan = Plan.objects.get(slug='free', is_active=True)
|
||||
except Plan.DoesNotExist:
|
||||
raise serializers.ValidationError({
|
||||
"plan": "Free plan not configured. Please contact support."
|
||||
})
|
||||
plan_slug = validated_data.get('plan_slug')
|
||||
paid_plans = ['starter', 'growth', 'scale']
|
||||
|
||||
if plan_slug and plan_slug in paid_plans:
|
||||
try:
|
||||
plan = Plan.objects.get(slug=plan_slug, is_active=True)
|
||||
except Plan.DoesNotExist:
|
||||
raise serializers.ValidationError({
|
||||
"plan": f"Plan '{plan_slug}' not available. Please contact support."
|
||||
})
|
||||
account_status = 'pending_payment'
|
||||
initial_credits = 0
|
||||
else:
|
||||
try:
|
||||
plan = Plan.objects.get(slug='free', is_active=True)
|
||||
except Plan.DoesNotExist:
|
||||
raise serializers.ValidationError({
|
||||
"plan": "Free plan not configured. Please contact support."
|
||||
})
|
||||
account_status = 'trial'
|
||||
initial_credits = plan.get_effective_credits_per_month()
|
||||
|
||||
# Generate account name if not provided
|
||||
account_name = validated_data.get('account_name')
|
||||
@@ -338,32 +351,31 @@ class RegisterSerializer(serializers.Serializer):
|
||||
slug = f"{base_slug}-{counter}"
|
||||
counter += 1
|
||||
|
||||
# Get trial credits from plan
|
||||
trial_credits = plan.get_effective_credits_per_month()
|
||||
|
||||
# Create account with trial status and credits seeded
|
||||
# Create account with status and credits seeded (0 for paid pending)
|
||||
account = Account.objects.create(
|
||||
name=account_name,
|
||||
slug=slug,
|
||||
owner=user,
|
||||
plan=plan,
|
||||
credits=trial_credits, # CRITICAL: Seed initial credits
|
||||
status='trial' # CRITICAL: Set as trial account
|
||||
credits=initial_credits,
|
||||
status=account_status,
|
||||
payment_method=validated_data.get('payment_method') or 'bank_transfer',
|
||||
)
|
||||
|
||||
# Log initial credit transaction for transparency
|
||||
CreditTransaction.objects.create(
|
||||
account=account,
|
||||
transaction_type='subscription',
|
||||
amount=trial_credits,
|
||||
balance_after=trial_credits,
|
||||
description=f'Free plan credits from {plan.name}',
|
||||
metadata={
|
||||
'plan_slug': plan.slug,
|
||||
'registration': True,
|
||||
'trial': True
|
||||
}
|
||||
)
|
||||
# Log initial credit transaction only for free/trial accounts with credits
|
||||
if initial_credits > 0:
|
||||
CreditTransaction.objects.create(
|
||||
account=account,
|
||||
transaction_type='subscription',
|
||||
amount=initial_credits,
|
||||
balance_after=initial_credits,
|
||||
description=f'Free plan credits from {plan.name}',
|
||||
metadata={
|
||||
'plan_slug': plan.slug,
|
||||
'registration': True,
|
||||
'trial': True
|
||||
}
|
||||
)
|
||||
|
||||
# Update user to reference the new account
|
||||
user.account = account
|
||||
|
||||
@@ -476,7 +476,7 @@ class SiteViewSet(AccountModelViewSet):
|
||||
"""ViewSet for managing Sites."""
|
||||
serializer_class = SiteSerializer
|
||||
permission_classes = [IsAuthenticatedAndActive, HasTenantAccess, IsEditorOrAbove]
|
||||
authentication_classes = [JWTAuthentication, CSRFExemptSessionAuthentication]
|
||||
authentication_classes = [JWTAuthentication]
|
||||
|
||||
def get_permissions(self):
|
||||
"""Allow normal users (viewer) to create sites, but require editor+ for other operations."""
|
||||
@@ -721,7 +721,7 @@ class SectorViewSet(AccountModelViewSet):
|
||||
"""ViewSet for managing Sectors."""
|
||||
serializer_class = SectorSerializer
|
||||
permission_classes = [IsAuthenticatedAndActive, HasTenantAccess, IsEditorOrAbove]
|
||||
authentication_classes = [JWTAuthentication, CSRFExemptSessionAuthentication]
|
||||
authentication_classes = [JWTAuthentication]
|
||||
|
||||
def get_queryset(self):
|
||||
"""Return sectors from sites accessible to the current user."""
|
||||
|
||||
@@ -34,7 +34,7 @@ class CreditBalanceViewSet(viewsets.ViewSet):
|
||||
Unified API Standard v1.0 compliant
|
||||
"""
|
||||
permission_classes = [IsAuthenticatedAndActive, HasTenantAccess]
|
||||
authentication_classes = [JWTAuthentication, CSRFExemptSessionAuthentication]
|
||||
authentication_classes = [JWTAuthentication]
|
||||
throttle_scope = 'billing'
|
||||
throttle_classes = [DebugScopedRateThrottle]
|
||||
|
||||
@@ -98,7 +98,7 @@ class CreditUsageViewSet(AccountModelViewSet):
|
||||
queryset = CreditUsageLog.objects.all()
|
||||
serializer_class = CreditUsageLogSerializer
|
||||
permission_classes = [IsAuthenticatedAndActive, HasTenantAccess]
|
||||
authentication_classes = [JWTAuthentication, CSRFExemptSessionAuthentication]
|
||||
authentication_classes = [JWTAuthentication]
|
||||
pagination_class = CustomPageNumberPagination
|
||||
throttle_scope = 'billing'
|
||||
throttle_classes = [DebugScopedRateThrottle]
|
||||
@@ -389,7 +389,7 @@ class CreditTransactionViewSet(AccountModelViewSet):
|
||||
queryset = CreditTransaction.objects.all()
|
||||
serializer_class = CreditTransactionSerializer
|
||||
permission_classes = [IsAuthenticatedAndActive, HasTenantAccess, IsAdminOrOwner]
|
||||
authentication_classes = [JWTAuthentication, CSRFExemptSessionAuthentication]
|
||||
authentication_classes = [JWTAuthentication]
|
||||
pagination_class = CustomPageNumberPagination
|
||||
throttle_scope = 'billing'
|
||||
throttle_classes = [DebugScopedRateThrottle]
|
||||
@@ -409,7 +409,7 @@ class CreditTransactionViewSet(AccountModelViewSet):
|
||||
class BillingOverviewViewSet(viewsets.ViewSet):
|
||||
"""User-facing billing overview API"""
|
||||
permission_classes = [IsAuthenticatedAndActive]
|
||||
authentication_classes = [JWTAuthentication, CSRFExemptSessionAuthentication]
|
||||
authentication_classes = [JWTAuthentication]
|
||||
|
||||
def account_balance(self, request):
|
||||
"""Get account balance with subscription info"""
|
||||
@@ -445,7 +445,7 @@ class BillingOverviewViewSet(viewsets.ViewSet):
|
||||
class AdminBillingViewSet(viewsets.ViewSet):
|
||||
"""Admin-only billing management API"""
|
||||
permission_classes = [IsAuthenticatedAndActive, permissions.IsAdminUser]
|
||||
authentication_classes = [JWTAuthentication, CSRFExemptSessionAuthentication]
|
||||
authentication_classes = [JWTAuthentication]
|
||||
|
||||
def stats(self, request):
|
||||
"""Get system-wide billing statistics"""
|
||||
|
||||
@@ -36,7 +36,7 @@ class SystemSettingsViewSet(AccountModelViewSet):
|
||||
queryset = SystemSettings.objects.all()
|
||||
serializer_class = SystemSettingsSerializer
|
||||
permission_classes = [IsAuthenticatedAndActive, HasTenantAccess]
|
||||
authentication_classes = [JWTAuthentication, CSRFExemptSessionAuthentication]
|
||||
authentication_classes = [JWTAuthentication]
|
||||
pagination_class = CustomPageNumberPagination
|
||||
throttle_scope = 'system'
|
||||
throttle_classes = [DebugScopedRateThrottle]
|
||||
@@ -87,7 +87,7 @@ class AccountSettingsViewSet(AccountModelViewSet):
|
||||
queryset = AccountSettings.objects.all()
|
||||
serializer_class = AccountSettingsSerializer
|
||||
permission_classes = [IsAuthenticatedAndActive, HasTenantAccess]
|
||||
authentication_classes = [JWTAuthentication, CSRFExemptSessionAuthentication]
|
||||
authentication_classes = [JWTAuthentication]
|
||||
pagination_class = CustomPageNumberPagination
|
||||
throttle_scope = 'system'
|
||||
throttle_classes = [DebugScopedRateThrottle]
|
||||
@@ -147,7 +147,7 @@ class UserSettingsViewSet(AccountModelViewSet):
|
||||
queryset = UserSettings.objects.all()
|
||||
serializer_class = UserSettingsSerializer
|
||||
permission_classes = [IsAuthenticatedAndActive, HasTenantAccess]
|
||||
authentication_classes = [JWTAuthentication, CSRFExemptSessionAuthentication]
|
||||
authentication_classes = [JWTAuthentication]
|
||||
pagination_class = CustomPageNumberPagination
|
||||
throttle_scope = 'system'
|
||||
throttle_classes = [DebugScopedRateThrottle]
|
||||
@@ -213,7 +213,7 @@ class ModuleSettingsViewSet(AccountModelViewSet):
|
||||
queryset = ModuleSettings.objects.all()
|
||||
serializer_class = ModuleSettingsSerializer
|
||||
permission_classes = [IsAuthenticatedAndActive, HasTenantAccess]
|
||||
authentication_classes = [JWTAuthentication, CSRFExemptSessionAuthentication]
|
||||
authentication_classes = [JWTAuthentication]
|
||||
pagination_class = CustomPageNumberPagination
|
||||
throttle_scope = 'system'
|
||||
throttle_classes = [DebugScopedRateThrottle]
|
||||
@@ -301,7 +301,7 @@ class ModuleEnableSettingsViewSet(AccountModelViewSet):
|
||||
"""
|
||||
queryset = ModuleEnableSettings.objects.all()
|
||||
serializer_class = ModuleEnableSettingsSerializer
|
||||
authentication_classes = [JWTAuthentication, CSRFExemptSessionAuthentication]
|
||||
authentication_classes = [JWTAuthentication]
|
||||
throttle_scope = 'system'
|
||||
throttle_classes = [DebugScopedRateThrottle]
|
||||
|
||||
@@ -466,7 +466,7 @@ class AISettingsViewSet(AccountModelViewSet):
|
||||
queryset = AISettings.objects.all()
|
||||
serializer_class = AISettingsSerializer
|
||||
permission_classes = [IsAuthenticatedAndActive, HasTenantAccess]
|
||||
authentication_classes = [JWTAuthentication, CSRFExemptSessionAuthentication]
|
||||
authentication_classes = [JWTAuthentication]
|
||||
pagination_class = CustomPageNumberPagination
|
||||
throttle_scope = 'system'
|
||||
throttle_classes = [DebugScopedRateThrottle]
|
||||
|
||||
Reference in New Issue
Block a user