From 64a8a4b7f14cc7862e66f8b4b1b3cc3425da0d8b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Laur=C3=A9line=20Gu=C3=A9rin?= <zebuline@entrouvert.com>
Date: Tue, 23 Feb 2021 09:00:23 +0100
Subject: [PATCH] api: patch booking extra_data (#51340)

---
 chrono/api/views.py |  9 ++++++-
 tests/test_api.py   | 58 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 66 insertions(+), 1 deletion(-)

diff --git a/chrono/api/views.py b/chrono/api/views.py
index 9a35085..bc5e82e 100644
--- a/chrono/api/views.py
+++ b/chrono/api/views.py
@@ -1243,7 +1243,7 @@ class BookingSerializer(serializers.ModelSerializer):
 
     class Meta:
         model = Booking
-        fields = ['user_was_present', 'user_absence_reason']
+        fields = ['user_was_present', 'user_absence_reason', 'extra_data']
 
     def validate_user_absence_reason(self, value):
         if value is None:
@@ -1308,11 +1308,18 @@ class BookingAPI(APIView):
                 status=status.HTTP_400_BAD_REQUEST,
             )
 
+        if 'extra_data' in serializer.validated_data:
+            extra_data = self.booking.extra_data or {}
+            extra_data.update(serializer.validated_data['extra_data'] or {})
+            serializer.validated_data['extra_data'] = extra_data
+
         serializer.save()
         if 'user_was_present' in request.data:
             self.booking.secondary_booking_set.update(user_was_present=self.booking.user_was_present)
         if 'user_absence_reason' in request.data:
             self.booking.secondary_booking_set.update(user_absence_reason=self.booking.user_absence_reason)
+        if 'extra_data' in request.data:
+            self.booking.secondary_booking_set.update(extra_data=self.booking.extra_data)
 
         response = {'err': 0, 'booking_id': self.booking.pk}
         return Response(response)
diff --git a/tests/test_api.py b/tests/test_api.py
index 3c31d07..32f3664 100644
--- a/tests/test_api.py
+++ b/tests/test_api.py
@@ -2093,6 +2093,64 @@ def test_booking_patch_api_absence_reason(app, user):
     assert other_booking.user_absence_reason == ''  # not changed
 
 
+def test_booking_patch_api_extra_data(app, user):
+    agenda = Agenda.objects.create(kind='events')
+    event = Event.objects.create(agenda=agenda, start_datetime=now(), places=10)
+    booking = Booking.objects.create(event=event, user_was_present=True)
+
+    app.authorization = ('Basic', ('john.doe', 'password'))
+
+    app.patch_json('/api/booking/%s/' % booking.pk, params={'extra_data': {'foo': 'bar'}})
+    booking.refresh_from_db()
+    assert booking.user_was_present is True  # not changed
+    assert booking.extra_data == {'foo': 'bar'}
+
+    app.patch_json('/api/booking/%s/' % booking.pk, params={'extra_data': {'foo': 'baz'}})
+    booking.refresh_from_db()
+    assert booking.user_was_present is True  # not changed
+    assert booking.extra_data == {'foo': 'baz'}
+
+    app.patch_json('/api/booking/%s/' % booking.pk, params={'extra_data': {'foooo': 'bar'}})
+    booking.refresh_from_db()
+    assert booking.user_was_present is True  # not changed
+    assert booking.extra_data == {'foo': 'baz', 'foooo': 'bar'}
+
+    app.patch_json('/api/booking/%s/' % booking.pk, params={'extra_data': {'foooo': 'baz', 'foo': None}})
+    booking.refresh_from_db()
+    assert booking.user_was_present is True  # not changed
+    assert booking.extra_data == {'foo': None, 'foooo': 'baz'}
+
+    # make secondary bookings
+    Booking.objects.create(event=event, primary_booking=booking, user_was_present=False)
+    Booking.objects.create(event=event, primary_booking=booking, user_was_present=False)
+    # and other booking
+    other_booking = Booking.objects.create(event=event)
+
+    app.patch_json('/api/booking/%s/' % booking.pk, params={'extra_data': {'foooo': 'baz', 'foo': None}})
+    assert booking.user_was_present is True  # not changed
+    assert booking.extra_data == {'foo': None, 'foooo': 'baz'}
+    # all secondary bookings are upadted
+    assert list(booking.secondary_booking_set.values_list('extra_data', flat=True)) == [
+        {'foo': None, 'foooo': 'baz'},
+        {'foo': None, 'foooo': 'baz'},
+    ]
+    assert list(booking.secondary_booking_set.values_list('user_was_present', flat=True)) == [
+        False,
+        False,
+    ]  # not changed
+    other_booking.refresh_from_db()
+    assert other_booking.extra_data is None  # not changed
+
+    app.patch_json('/api/booking/%s/' % booking.pk, params={'extra_data': None})
+    booking.refresh_from_db()
+    assert booking.user_was_present is True  # not changed
+    assert booking.extra_data == {'foo': None, 'foooo': 'baz'}  # not changed
+    app.patch_json('/api/booking/%s/' % booking.pk, params={'extra_data': {}})
+    booking.refresh_from_db()
+    assert booking.user_was_present is True  # not changed
+    assert booking.extra_data == {'foo': None, 'foooo': 'baz'}  # not changed
+
+
 def test_booking_cancellation_api(app, some_data, user):
     agenda = Agenda.objects.filter(label=u'Foo bar')[0]
     event = [x for x in Event.objects.filter(agenda=agenda) if x.in_bookable_period()][0]
-- 
2.29.2

