From 8413df8d64dc815ed51411761a0819af6a166480 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Laur=C3=A9line=20Gu=C3=A9rin?= <zebuline@entrouvert.com>
Date: Tue, 12 May 2020 10:26:43 +0200
Subject: [PATCH 2/2] api: list bookings of user_external_id for an event
 (#40719)

---
 chrono/api/urls.py  |  5 ++++
 chrono/api/views.py | 35 ++++++++++++++++++++++++++
 tests/test_api.py   | 61 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 101 insertions(+)

diff --git a/chrono/api/urls.py b/chrono/api/urls.py
index 8cbd115..9f63a6b 100644
--- a/chrono/api/urls.py
+++ b/chrono/api/urls.py
@@ -33,6 +33,11 @@ urlpatterns = [
         views.slot_status,
         name='api-event-status',
     ),
+    url(
+        r'^agenda/(?P<agenda_identifier>[\w-]+)/bookings/(?P<event_identifier>[\w-]+)/$',
+        views.slot_bookings,
+        name='api-event-bookings',
+    ),
     url(
         r'^agenda/meetings/(?P<meeting_identifier>[\w-]+)/datetimes/$',
         views.meeting_datetimes,
diff --git a/chrono/api/views.py b/chrono/api/views.py
index f16a054..2d98f7e 100644
--- a/chrono/api/views.py
+++ b/chrono/api/views.py
@@ -1088,6 +1088,41 @@ class SlotStatus(APIView):
 slot_status = SlotStatus.as_view()
 
 
+class SlotBookings(APIView):
+    permission_classes = (permissions.IsAuthenticated,)
+
+    def get_object(self, agenda_identifier, event_identifier):
+        try:
+            return Event.objects.get(slug=event_identifier, agenda__slug=agenda_identifier)
+        except Event.DoesNotExist:
+            try:
+                # legacy access by event id
+                return Event.objects.get(pk=int(event_identifier), agenda__slug=agenda_identifier)
+            except (ValueError, Event.DoesNotExist):
+                raise Http404()
+
+    def get(self, request, agenda_identifier=None, event_identifier=None, format=None):
+        if not request.GET.get('user_external_id'):
+            response = {
+                'err': 1,
+                'err_class': 'missing param user_external_id',
+                'err_desc': _('missing param user_external_id'),
+            }
+            return Response(response)
+        event = self.get_object(agenda_identifier, event_identifier)
+        booking_queryset = event.booking_set.filter(
+            user_external_id=request.GET['user_external_id'], primary_booking__isnull=True
+        )
+        response = {
+            'err': 0,
+            'data': [{'booking_id': b.pk, 'in_waiting_list': b.in_waiting_list} for b in booking_queryset],
+        }
+        return Response(response)
+
+
+slot_bookings = SlotBookings.as_view()
+
+
 class BookingICS(APIView):
     permission_classes = (permissions.IsAuthenticated,)
 
diff --git a/tests/test_api.py b/tests/test_api.py
index f9527bc..f235dca 100644
--- a/tests/test_api.py
+++ b/tests/test_api.py
@@ -1290,6 +1290,67 @@ def test_status(app, some_data, user):
     resp = app.get('/api/agenda/%s/status/%s/' % (agenda_id, 'unknown'), status=404)
 
 
+def test_bookings(app, some_data, user):
+    agenda = Agenda.objects.filter(label=u'Foo bar')[0]
+    event = Event.objects.filter(agenda=agenda).exclude(start_datetime__lt=now())[0]
+    event.slug = 'event-slug'
+    event.places = 5
+    event.waiting_list_places = 5
+    event.save()
+
+    # create a booking not on the waiting list
+    primary1 = Booking.objects.create(event=event, in_waiting_list=False, user_external_id='42')
+    Booking.objects.create(
+        event=event, in_waiting_list=False, primary_booking=primary1, user_external_id='42'
+    )
+    primary2 = Booking.objects.create(event=event, in_waiting_list=False, user_external_id='foobar')
+    Booking.objects.create(event=event, in_waiting_list=False, user_external_id='')
+    primary4 = Booking.objects.create(event=event, in_waiting_list=True, user_external_id='42')
+
+    app.authorization = ('Basic', ('john.doe', 'password'))
+
+    # unknown agenda
+    resp = app.get(
+        '/api/agenda/foobar/bookings/%s/' % (event.pk), params={'user_external_id': '42'}, status=404
+    )
+    # unknown event
+    resp = app.get(
+        '/api/agenda/%s/bookings/0/' % (agenda.slug), params={'user_external_id': '42'}, status=404
+    )
+    resp = app.get(
+        '/api/agenda/%s/bookings/foobar/' % (agenda.slug), params={'user_external_id': '42'}, status=404
+    )
+
+    # get event by pk
+    resp = app.get('/api/agenda/%s/bookings/%s/' % (agenda.slug, event.pk), params={'user_external_id': '42'})
+    assert resp.json['err'] == 0
+    assert resp.json['data'] == [
+        {'booking_id': primary1.pk, 'in_waiting_list': False},
+        {'booking_id': primary4.pk, 'in_waiting_list': True},
+    ]
+    # get event by slug
+    resp = app.get(
+        '/api/agenda/%s/bookings/%s/' % (agenda.slug, event.slug), params={'user_external_id': 'foobar'}
+    )
+    assert resp.json['err'] == 0
+    assert resp.json['data'] == [
+        {'booking_id': primary2.pk, 'in_waiting_list': False},
+    ]
+    resp = app.get(
+        '/api/agenda/%s/bookings/%s/' % (agenda.slug, event.slug), params={'user_external_id': '35'}
+    )
+    assert resp.json['err'] == 0
+    assert resp.json['data'] == []
+    # no user_external_id in params
+    resp = app.get('/api/agenda/%s/bookings/%s/' % (agenda.slug, event.slug), params={'user_external_id': ''})
+    assert resp.json['err'] == 1
+    assert resp.json['reason'] == 'missing param user_external_id'  # legacy
+    assert resp.json['err_class'] == 'missing param user_external_id'
+    assert resp.json['err_desc'] == 'missing param user_external_id'
+    resp = app.get('/api/agenda/%s/bookings/%s/' % (agenda.slug, event.slug))
+    assert resp.json['err'] == 1
+
+
 def test_waiting_list_datetimes(app, some_data, user):
     agenda_id = Agenda.objects.filter(label=u'Foo bar')[0].id
     event = Event.objects.filter(agenda_id=agenda_id).exclude(start_datetime__lt=now())[0]
-- 
2.20.1

