From 058905715c0d2dbca6195c925b3192e03ff42575 Mon Sep 17 00:00:00 2001
From: Nicolas ROCHE <nroche@entrouvert.com>
Date: Tue, 28 Sep 2021 19:53:08 +0200
Subject: [PATCH] api: add PATCH action on event endpoint (#57305)

---
 chrono/api/urls.py      | 10 ++++----
 chrono/api/views.py     | 57 +++++++++++++++++++++++------------------
 tests/api/test_event.py |  6 ++---
 3 files changed, 40 insertions(+), 33 deletions(-)

diff --git a/chrono/api/urls.py b/chrono/api/urls.py
index 4179e66..18a90b5 100644
--- a/chrono/api/urls.py
+++ b/chrono/api/urls.py
@@ -44,36 +44,36 @@ urlpatterns = [
         views.recurring_events_list,
         name='api-agenda-recurring-events',
     ),
     url(
         r'^agenda/(?P<agenda_identifier>[\w-]+)/recurring-events/fillslots/$',
         views.recurring_fillslots,
         name='api-recurring-fillslots',
     ),
+    url(
+        r'^agenda/(?P<agenda_identifier>[\w-]+)/status/$',
+        views.event_status,
+        name='api-event-status',
+    ),
     url(
         r'^agenda/(?P<agenda_identifier>[\w-]+)/status/(?P<event_identifier>[\w:-]+)/$',
         views.event_status,
         name='api-event-status',
     ),
     url(
         r'^agenda/(?P<agenda_identifier>[\w-]+)/bookings/(?P<event_identifier>[\w:-]+)/$',
         views.event_bookings,
         name='api-event-bookings',
     ),
     url(
         r'^agenda/(?P<agenda_identifier>[\w-]+)/check/(?P<event_identifier>[\w:-]+)/$',
         views.event_check,
         name='api-event-check',
     ),
-    url(
-        r'^agenda/(?P<agenda_identifier>[\w-]+)/add-event/$',
-        views.agenda_add_event,
-        name='api-agenda-add-event',
-    ),
     url(
         r'^agenda/meetings/(?P<meeting_identifier>[\w-]+)/datetimes/$',
         views.meeting_datetimes,
         name='api-agenda-meeting-datetimes-legacy',
     ),
     url(r'^agenda/(?P<agenda_identifier>[\w-]+)/meetings/$', views.meeting_list, name='api-agenda-meetings'),
     url(
         r'^agenda/(?P<agenda_identifier>[\w-]+)/meetings/(?P<meeting_identifier>[\w-]+)/$',
diff --git a/chrono/api/views.py b/chrono/api/views.py
index 064b65c..4f3abdc 100644
--- a/chrono/api/views.py
+++ b/chrono/api/views.py
@@ -2161,16 +2161,17 @@ class ResizeBooking(APIView):
         return Response(response)
 
 
 resize_booking = ResizeBooking.as_view()
 
 
 class EventStatus(APIView):
     permission_classes = (permissions.IsAuthenticated,)
+    serializer_class = serializers.EventSerializer
 
     def get_object(self, agenda_identifier, event_identifier):
         try:
             agenda = Agenda.objects.get(slug=agenda_identifier, kind='events')
         except Agenda.DoesNotExist:
             try:
                 # legacy access by agenda id
                 agenda = Agenda.objects.get(pk=agenda_identifier, kind='events')
@@ -2190,16 +2191,47 @@ class EventStatus(APIView):
     def get(self, request, agenda_identifier=None, event_identifier=None, format=None):
         event = self.get_object(agenda_identifier, event_identifier)
         response = {
             'err': 0,
         }
         response.update(get_event_detail(request, event))
         return Response(response)
 
+    def post(self, request, agenda_identifier=None, format=None):
+        agenda = get_object_or_404(Agenda, slug=agenda_identifier, kind='events')
+
+        serializer = self.serializer_class(data=request.data)
+        if not serializer.is_valid():
+            raise APIError(
+                _('invalid payload'),
+                err_class='invalid payload',
+                errors=serializer.errors,
+                http_status=status.HTTP_400_BAD_REQUEST,
+            )
+        payload = serializer.validated_data
+        event = Event.objects.create(agenda=agenda, **payload)
+        if event.recurrence_days and event.recurrence_end_date:
+            event.create_all_recurrences()
+        return Response({'err': 0, 'data': get_event_detail(request, event)})
+
+    def patch(self, request, agenda_identifier=None, event_identifier=None, format=None):
+        event = self.get_object(agenda_identifier, event_identifier)
+        serializer = self.serializer_class(event, data=request.data, partial=True)
+        if not serializer.is_valid():
+            raise APIError(
+                _('invalid payload'),
+                err_class='invalid payload',
+                errors=serializer.errors,
+                http_status=status.HTTP_400_BAD_REQUEST,
+            )
+        event = serializer.save()
+        # TODO: manage recurrencies
+        return Response({'err': 0, 'data': get_event_detail(request, event)})
+
 
 event_status = EventStatus.as_view()
 
 
 class EventCheck(APIView):
     permission_classes = (permissions.IsAuthenticated,)
 
     def get_object(self, agenda_identifier, event_identifier):
@@ -2416,33 +2448,8 @@ class BookingsStatistics(APIView):
                     'series': series,
                 },
                 'err': 0,
             }
         )
 
 
 bookings_statistics = BookingsStatistics.as_view()
-
-
-class AgendaAddEventView(APIView):
-    permission_classes = (permissions.IsAuthenticated,)
-    serializer_class = serializers.EventSerializer
-
-    def post(self, request, agenda_identifier):
-        agenda = get_object_or_404(Agenda, slug=agenda_identifier, kind='events')
-
-        serializer = self.serializer_class(data=request.data)
-        if not serializer.is_valid():
-            raise APIError(
-                _('invalid payload'),
-                err_class='invalid payload',
-                errors=serializer.errors,
-                http_status=status.HTTP_400_BAD_REQUEST,
-            )
-        payload = serializer.validated_data
-        event = Event.objects.create(agenda=agenda, **payload)
-        if event.recurrence_days and event.recurrence_end_date:
-            event.create_all_recurrences()
-        return Response({'err': 0, 'data': get_event_detail(request, event)})
-
-
-agenda_add_event = AgendaAddEventView.as_view()
diff --git a/tests/api/test_event.py b/tests/api/test_event.py
index 9ddf81a..657776f 100644
--- a/tests/api/test_event.py
+++ b/tests/api/test_event.py
@@ -156,17 +156,17 @@ def test_event_checked(app, user):
     agenda.save()
     app.post('/api/agenda/%s/check/%s/' % (agenda.slug, event.slug), status=404)
     agenda.kind = 'virtual'
     agenda.save()
     app.post('/api/agenda/%s/check/%s/' % (agenda.slug, event.slug), status=404)
 
 
 def test_add_event(app, user):
-    api_url = '/api/agenda/%s/add-event/' % ('999')
+    api_url = '/api/agenda/%s/status/' % ('999')
 
     # no authentication
     resp = app.post(api_url, status=401)
     assert resp.json['detail'] == 'Authentication credentials were not provided.'
 
     # wrong password
     app.authorization = ('Basic', ('john.doe', 'wrong'))
     resp = app.post(api_url, status=401)
@@ -176,24 +176,24 @@ def test_add_event(app, user):
 
     # missing agenda
     resp = app.post(api_url, status=404)
     assert resp.json['detail'] == 'Not found.'
 
     # using meeting agenda
     meeting_agenda = Agenda(label='Foo bar Meeting', kind='meetings')
     meeting_agenda.save()
-    api_url = '/api/agenda/%s/add-event/' % (meeting_agenda.slug)
+    api_url = '/api/agenda/%s/status/' % (meeting_agenda.slug)
     resp = app.post(api_url, status=404)
     assert resp.json['detail'] == 'Not found.'
 
     agenda = Agenda(label='Foo bar')
     agenda.maximal_booking_delay = 0
     agenda.save()
-    api_url = '/api/agenda/%s/add-event/' % (agenda.slug)
+    api_url = '/api/agenda/%s/status/' % (agenda.slug)
 
     # missing fields
     resp = app.post(api_url, status=400)
     assert resp.json['err']
     assert resp.json['errors'] == {
         'start_datetime': ['This field is required.'],
         'places': ['This field is required.'],
     }
-- 
2.30.2

