diff --git a/backend/igny8_core/modules/system/integration_views.py b/backend/igny8_core/modules/system/integration_views.py index be3dad21..c6adb5ce 100644 --- a/backend/igny8_core/modules/system/integration_views.py +++ b/backend/igny8_core/modules/system/integration_views.py @@ -90,67 +90,48 @@ class IntegrationSettingsViewSet(viewsets.ViewSet): ) # Get API key and config from request or saved settings - # Handle empty request.data gracefully (for API monitor) - try: - request_data = request.data if hasattr(request, 'data') and request.data else {} - if not isinstance(request_data, dict): - request_data = {} - except Exception: - request_data = {} + config = request.data.get('config', {}) if isinstance(request.data.get('config'), dict) else {} + api_key = request.data.get('apiKey') or config.get('apiKey') - config = request_data.get('config', {}) if isinstance(request_data.get('config'), dict) else {} - api_key = request_data.get('apiKey') or config.get('apiKey') - - # Ensure config is a dict + # Merge request.data with config if config is a dict if not isinstance(config, dict): config = {} if not api_key: # Try to get from saved settings - account = None - try: - account = getattr(request, 'account', None) - if account: - logger.info(f"[test_connection] Account from request: {account.id}") - # Fallback to user's account - if not account: - user = getattr(request, 'user', None) - if user and hasattr(user, 'is_authenticated') and user.is_authenticated: - account = getattr(user, 'account', None) - if account: - logger.info(f"[test_connection] Account from user: {account.id}") - # Fallback to default account (only for API monitor/testing) - if not account: - from igny8_core.auth.models import Account - try: - account = Account.objects.first() - if account: - logger.info(f"[test_connection] Using fallback account: {account.id}") - except Exception as e: - logger.debug(f"[test_connection] Could not get fallback account: {e}") - account = None - - if account: - try: - from .models import IntegrationSettings - logger.info(f"[test_connection] Looking for saved settings for account {account.id}") - saved_settings = IntegrationSettings.objects.get( - integration_type=integration_type, - account=account - ) - api_key = saved_settings.config.get('apiKey') if saved_settings.config else None - logger.info(f"[test_connection] Found saved settings, has_apiKey={bool(api_key)}") - except IntegrationSettings.DoesNotExist: - logger.debug(f"[test_connection] No saved settings found for {integration_type} and account {account.id if account else 'None'}") - except Exception as e: - logger.debug(f"[test_connection] Error getting saved settings: {e}") - except Exception as e: - logger.debug(f"[test_connection] Error during account/settings lookup: {e}") + account = getattr(request, 'account', None) + logger.info(f"[test_connection] Account from request: {account.id if account else None}") + # Fallback to user's account + if not account: + user = getattr(request, 'user', None) + if user and hasattr(user, 'is_authenticated') and user.is_authenticated: + account = getattr(user, 'account', None) + # Fallback to default account + if not account: + from igny8_core.auth.models import Account + try: + account = Account.objects.first() + except Exception: + pass + + if account: + try: + from .models import IntegrationSettings + logger.info(f"[test_connection] Looking for saved settings for account {account.id}") + saved_settings = IntegrationSettings.objects.get( + integration_type=integration_type, + account=account + ) + api_key = saved_settings.config.get('apiKey') + logger.info(f"[test_connection] Found saved settings, has_apiKey={bool(api_key)}") + except IntegrationSettings.DoesNotExist: + logger.warning(f"[test_connection] No saved settings found for {integration_type} and account {account.id}") + pass if not api_key: - logger.info(f"[test_connection] No API key found in request or saved settings - returning 400 (expected for API monitor)") + logger.error(f"[test_connection] No API key found in request or saved settings") return error_response( - error='API key is required. Please provide an API key in the request or configure it in settings.', + error='API key is required', status_code=status.HTTP_400_BAD_REQUEST, request=request ) @@ -229,7 +210,7 @@ class IntegrationSettingsViewSet(viewsets.ViewSet): total_tokens = usage.get('total_tokens', 0) # Calculate cost using model rates (reference plugin: line 274-275) - from igny8_core.ai.constants import MODEL_RATES + from igny8_core.utils.ai_processor import MODEL_RATES rates = MODEL_RATES.get(model, {'input': 2.00, 'output': 8.00}) cost = (input_tokens * rates['input'] + output_tokens * rates['output']) / 1000000 @@ -254,9 +235,25 @@ class IntegrationSettingsViewSet(viewsets.ViewSet): ) else: body = response.text + # Map OpenAI API errors to appropriate HTTP status codes + # OpenAI 401 (invalid API key) should be 400 (Bad Request) in our API + # OpenAI 4xx errors are client errors (invalid request) -> 400 + # OpenAI 5xx errors are server errors -> 500 + if response.status_code == 401: + # Invalid API key - this is a validation error, not an auth error + status_code = status.HTTP_400_BAD_REQUEST + elif 400 <= response.status_code < 500: + # Other client errors from OpenAI (invalid request, rate limit, etc.) + status_code = status.HTTP_400_BAD_REQUEST + elif response.status_code >= 500: + # Server errors from OpenAI + status_code = status.HTTP_500_INTERNAL_SERVER_ERROR + else: + status_code = response.status_code + return error_response( error=f'HTTP {response.status_code} – {body[:200]}', - status_code=response.status_code, + status_code=status_code, request=request ) except requests.exceptions.RequestException as e: @@ -287,9 +284,25 @@ class IntegrationSettingsViewSet(viewsets.ViewSet): ) else: body = response.text + # Map OpenAI API errors to appropriate HTTP status codes + # OpenAI 401 (invalid API key) should be 400 (Bad Request) in our API + # OpenAI 4xx errors are client errors (invalid request) -> 400 + # OpenAI 5xx errors are server errors -> 500 + if response.status_code == 401: + # Invalid API key - this is a validation error, not an auth error + status_code = status.HTTP_400_BAD_REQUEST + elif 400 <= response.status_code < 500: + # Other client errors from OpenAI (invalid request, rate limit, etc.) + status_code = status.HTTP_400_BAD_REQUEST + elif response.status_code >= 500: + # Server errors from OpenAI + status_code = status.HTTP_500_INTERNAL_SERVER_ERROR + else: + status_code = response.status_code + return error_response( error=f'HTTP {response.status_code} – {body[:200]}', - status_code=response.status_code, + status_code=status_code, request=request ) except requests.exceptions.RequestException as e: