diff --git a/.github/workflows/containerbuild.yml b/.github/workflows/containerbuild.yml index d05cb80191..7b367f0eb0 100644 --- a/.github/workflows/containerbuild.yml +++ b/.github/workflows/containerbuild.yml @@ -6,7 +6,6 @@ on: - unstable - hotfixes - master - - search-recommendations tags: - 'v*' pull_request: diff --git a/contentcuration/contentcuration/tests/viewsets/test_recommendations.py b/contentcuration/contentcuration/tests/viewsets/test_recommendations.py index e23b4ad17a..ef615f69ff 100644 --- a/contentcuration/contentcuration/tests/viewsets/test_recommendations.py +++ b/contentcuration/contentcuration/tests/viewsets/test_recommendations.py @@ -67,26 +67,28 @@ def test_recommend_success(self, mock_load_recommendations): def test_recommend_invalid_data_empty_data(self): self.client.force_authenticate(user=self.admin_user) + error_message = "Invalid request data. Please check the required fields." invalid_data = {} response = self.client.post(reverse("recommendations"), data=invalid_data, format="json") self.assertEqual(response.status_code, 400) - self.assertIn("topics", response.json()['error']) + self.assertIn(error_message, response.json()['error']) def test_recommend_invalid_data_wrong_topic_data(self): self.client.force_authenticate(user=self.admin_user) + error_message = "Invalid request data. Please check the required fields." invalid_data = {'topics': [{'ramdon_field': "random_value"}]} response = self.client.post(reverse("recommendations"), data=invalid_data, format="json") self.assertEqual(response.status_code, 400) - self.assertIn("ramdon_field", response.json()['error']) + self.assertEqual(error_message, response.json()['error']) @patch("contentcuration.utils.automation_manager.AutomationManager.load_recommendations") def test_recommendation_invalid_data_formats(self, mock_load_recommendations): self.client.force_authenticate(user=self.admin_user) - error_message = "Invalid topic format" + error_message = "Invalid input provided." mock_load_recommendations.side_effect = ValueError(error_message) response = self.client.post(reverse("recommendations"), data=self.topics, @@ -100,27 +102,25 @@ def test_recommendation_invalid_data_formats(self, mock_load_recommendations): def test_recommendation_service_unavailable(self, mock_load_recommendations): self.client.force_authenticate(user=self.admin_user) - error_message = "Connection error" + error_message = "Recommendation service unavailable" mock_load_recommendations.side_effect = ConnectionError(error_message) response = self.client.post(reverse("recommendations"), data=self.topics, format="json") self.assertEqual(response.status_code, 503) - self.assertEqual(response.json(), - {"error": f"Recommendation service unavailable: {error_message}"}) + self.assertEqual(response.json(), {"error": error_message}) mock_load_recommendations.assert_called_once() @patch("contentcuration.utils.automation_manager.AutomationManager.load_recommendations") def test_recommendation_generic_error(self, mock_load_recommendations): self.client.force_authenticate(user=self.admin_user) - error_message = "Unexpected internal error" + error_message = "Unable to load recommendations" mock_load_recommendations.side_effect = RuntimeError(error_message) response = self.client.post(reverse("recommendations"), data=self.topics, format="json") self.assertEqual(response.status_code, 500) - self.assertEqual(response.content.decode(), - f"Unable to load recommendations: {error_message}") + self.assertEqual(response.content.decode(), error_message) mock_load_recommendations.assert_called_once() diff --git a/contentcuration/contentcuration/viewsets/recommendation.py b/contentcuration/contentcuration/viewsets/recommendation.py index eb2fef8a35..ac469350d7 100644 --- a/contentcuration/contentcuration/viewsets/recommendation.py +++ b/contentcuration/contentcuration/viewsets/recommendation.py @@ -1,3 +1,4 @@ +import logging from http import HTTPStatus import jsonschema @@ -10,6 +11,8 @@ from contentcuration.utils.automation_manager import AutomationManager from contentcuration.viewsets.user import IsAIFeatureEnabledForUser +logger = logging.getLogger(__name__) + class RecommendationView(APIView): @@ -27,15 +30,20 @@ def post(self, request): embed_topics_request.validate(request_data) except jsonschema.ValidationError as e: - return JsonResponse({"error": f"Required fields missing: {str(e)}"}, status=HTTPStatus.BAD_REQUEST) + logger.error("Schema validation error: %s", str(e)) + return JsonResponse({"error": "Invalid request data. Please check the required fields."}, status=HTTPStatus.BAD_REQUEST) try: recommendations = self.manager.load_recommendations(request_data, override_threshold) return JsonResponse(data=recommendations, safe=False) except (ValueError, TypeError) as e: - return JsonResponse({"error": str(e)}, status=HTTPStatus.BAD_REQUEST) + logger.error("Validation error occurred: %s", str(e), exc_info=True) + return JsonResponse({"error": "Invalid input provided."}, + status=HTTPStatus.BAD_REQUEST) except ConnectionError as e: - return JsonResponse({"error": f"Recommendation service unavailable: {str(e)}"}, + logger.error("Connection error occurred: %s", str(e), exc_info=True) + return JsonResponse({"error": "Recommendation service unavailable"}, status=HTTPStatus.SERVICE_UNAVAILABLE) except Exception as e: - return HttpResponseServerError(f"Unable to load recommendations: {str(e)}") + logger.error("Unexpected error occurred: %s", str(e), exc_info=True) + return HttpResponseServerError("Unable to load recommendations") diff --git a/requirements.in b/requirements.in index fad8647120..c03fe67455 100644 --- a/requirements.in +++ b/requirements.in @@ -33,4 +33,3 @@ python-dateutil>=2.8.1 jsonschema>=3.2.0 django-celery-results packaging>=21.0 -pgvector