diff --git a/commcare_connect/events/tests.py b/commcare_connect/events/tests.py index 0fa873ed..15cb8e14 100644 --- a/commcare_connect/events/tests.py +++ b/commcare_connect/events/tests.py @@ -1,3 +1,5 @@ +from datetime import datetime + from rest_framework.test import APIClient from commcare_connect.opportunity.models import Opportunity @@ -8,34 +10,44 @@ def test_post_events(mobile_user_with_connect_link: User, api_client: APIClient, opportunity: Opportunity): api_client.force_authenticate(mobile_user_with_connect_link) + assert Event.objects.count() == 0 response = api_client.post( "/api/events/", data=[ { - "event_type": "invalid_event_name", + "event_type": Event.Type.INVITE_SENT, + "user": mobile_user_with_connect_link.pk, + "opportunity": opportunity.pk, + "date_created": datetime.utcnow(), + }, + { + "event_type": Event.Type.RECORDS_APPROVED, "user": mobile_user_with_connect_link.pk, "opportunity": opportunity.pk, - } + "date_created": datetime.utcnow(), + }, ], format="json", ) - assert response.status_code == 400 - assert Event.objects.count() == 0 + assert response.status_code == 201 + assert Event.objects.count() == 2 response = api_client.post( "/api/events/", data=[ { "event_type": Event.Type.INVITE_SENT, - "user": mobile_user_with_connect_link.pk, + "user": -1, "opportunity": opportunity.pk, + "date_created": datetime.utcnow(), }, { "event_type": Event.Type.RECORDS_APPROVED, "user": mobile_user_with_connect_link.pk, "opportunity": opportunity.pk, + "date_created": datetime.utcnow(), }, ], format="json", ) - assert response.status_code == 201 + assert response.status_code == 400 assert Event.objects.count() == 2 diff --git a/commcare_connect/events/views.py b/commcare_connect/events/views.py index eaa752f3..5d285c28 100644 --- a/commcare_connect/events/views.py +++ b/commcare_connect/events/views.py @@ -1,5 +1,6 @@ import django_tables2 as tables from dal.autocomplete import ModelSelect2 +from django.db import transaction from django.utils.decorators import method_decorator from django.views.decorators.csrf import csrf_exempt from django_filters import ChoiceFilter, FilterSet, ModelChoiceFilter @@ -34,9 +35,24 @@ def create(self, request, *args, **kwargs): serializer = self.get_serializer(data=request.data, many=True) serializer.is_valid(raise_exception=True) - - event_objects = [Event(**item) for item in serializer.validated_data] - Event.objects.bulk_create(event_objects) + try: + event_objects = [Event(**item) for item in serializer.validated_data] + Event.objects.bulk_create(event_objects) + except Exception as e: + # Bulk create failed, try saving each item individually + failed_items = [] + + for item in serializer.validated_data: + try: + with transaction.atomic(): + Event.objects.save(**item) + except Exception: + failed_items.append((item, e)) + + if failed_items: + partial_error_response = {"error": "Some items could not be saved", "failed_items": failed_items} + headers = self.get_success_headers(serializer.data) + return Response(partial_error_response, status=status.HTTP_206_PARTIAL_CONTENT, headers=headers) headers = self.get_success_headers(serializer.data) return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)