Projet

Général

Profil

0002-api-add-an-enpoint-to-patch-an-event-57305.patch

Nicolas Roche (absent jusqu'au 3 avril), 06 octobre 2021 14:56

Télécharger (12,1 ko)

Voir les différences:

Subject: [PATCH 2/2] api: add an enpoint to patch an event (#57305)

 chrono/api/urls.py      |   5 ++
 chrono/api/views.py     |  74 +++++++++++++++++
 tests/api/test_event.py | 180 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 259 insertions(+)
chrono/api/urls.py
44 44
        views.recurring_events_list,
45 45
        name='api-agenda-recurring-events',
46 46
    ),
47 47
    url(
48 48
        r'^agenda/(?P<agenda_identifier>[\w-]+)/recurring-events/fillslots/$',
49 49
        views.recurring_fillslots,
50 50
        name='api-recurring-fillslots',
51 51
    ),
52
    url(
53
        r'^agenda/(?P<agenda_identifier>[\w-]+)/event/(?P<event_identifier>[\w:-]+)/$',
54
        views.events,
55
        name='api-event',
56
    ),
52 57
    url(
53 58
        r'^agenda/(?P<agenda_identifier>[\w-]+)/status/(?P<event_identifier>[\w:-]+)/$',
54 59
        views.event_status,
55 60
        name='api-event-status',
56 61
    ),
57 62
    url(
58 63
        r'^agenda/(?P<agenda_identifier>[\w-]+)/bookings/(?P<event_identifier>[\w:-]+)/$',
59 64
        views.event_bookings,
chrono/api/views.py
2198 2198
    def success(self, booking):
2199 2199
        response = {'err': 0, 'booking_id': booking.pk}
2200 2200
        return Response(response)
2201 2201

  
2202 2202

  
2203 2203
resize_booking = ResizeBooking.as_view()
2204 2204

  
2205 2205

  
2206
class Events(APIView):
2207
    permission_classes = (permissions.IsAuthenticated,)
2208
    serializer_class = serializers.EventSerializer
2209

  
2210
    def get_object(self, agenda_identifier, event_identifier):
2211
        agenda = get_object_or_404(Agenda, slug=agenda_identifier, kind='events')
2212
        if ':' in event_identifier:
2213
            return get_event_recurrence(agenda, event_identifier)
2214
        try:
2215
            return agenda.event_set.get(slug=event_identifier)
2216
        except Event.DoesNotExist:
2217
            raise Http404()
2218

  
2219
    def patch(self, request, agenda_identifier=None, event_identifier=None, format=None):
2220
        event = self.get_object(agenda_identifier, event_identifier)
2221
        serializer = self.serializer_class(event, data=request.data, partial=True)
2222
        if not serializer.is_valid():
2223
            raise APIError(
2224
                _('invalid payload'),
2225
                err_class='invalid payload',
2226
                errors=serializer.errors,
2227
                http_status=status.HTTP_400_BAD_REQUEST,
2228
            )
2229

  
2230
        payload = serializer.validated_data
2231
        changed_data = []
2232
        for field in serializer.fields.keys():
2233
            if field in payload and payload[field] != getattr(event, field):
2234
                changed_data.append(field)
2235

  
2236
        if event.primary_event:
2237
            for field in changed_data:
2238
                if field in (
2239
                    'recurrence_end_date',
2240
                    'publication_date',
2241
                    'recurrence_days',
2242
                    'recurrence_week_interval',
2243
                ):
2244
                    raise APIError(
2245
                        _('%s cannot be modified on an event recurrence') % field,
2246
                        err_class='%s cannot be modified on an event recurrence' % field,
2247
                        http_status=status.HTTP_400_BAD_REQUEST,
2248
                    )
2249

  
2250
        protected_fields = ['start_datetime', 'recurrence_days', 'recurrence_week_interval']
2251
        if event.recurrence_days and event.has_recurrences_booked():
2252
            for field in changed_data:
2253
                if field in protected_fields:
2254
                    raise APIError(
2255
                        _('%s cannot be modified because some recurrences have bookings attached to them.')
2256
                        % field,
2257
                        err_class='%s cannot be modified because some recurrences have bookings attached to them.'
2258
                        % field,
2259
                        http_status=status.HTTP_400_BAD_REQUEST,
2260
                    )
2261
            if 'recurrence_end_date' in changed_data and event.has_recurrences_booked(
2262
                after=payload['recurrence_end_date']
2263
            ):
2264
                raise APIError(
2265
                    _('recurrence_end_date cannot be modified because bookings exist after this date.'),
2266
                    err_class='recurrence_end_date cannot be modified because bookings exist after this date.',
2267
                    http_status=status.HTTP_400_BAD_REQUEST,
2268
                )
2269

  
2270
        with event.update_recurrences(
2271
            changed_data, payload, protected_fields, protected_fields + ['recurrence_end_date']
2272
        ):
2273
            event = serializer.save()
2274
        return Response({'err': 0, 'data': get_event_detail(request, event)})
2275

  
2276

  
2277
events = Events.as_view()
2278

  
2279

  
2206 2280
class EventStatus(APIView):
2207 2281
    permission_classes = (permissions.IsAuthenticated,)
2208 2282

  
2209 2283
    def get_object(self, agenda_identifier, event_identifier):
2210 2284
        try:
2211 2285
            agenda = Agenda.objects.get(slug=agenda_identifier, kind='events')
2212 2286
        except Agenda.DoesNotExist:
2213 2287
            try:
tests/api/test_event.py
326 326
        '2021-11-20',
327 327
        '2021-11-29',
328 328
        '2021-12-02',
329 329
        '2021-12-04',
330 330
        '2021-12-13',
331 331
        '2021-12-16',
332 332
        '2021-12-18',
333 333
    ]
334

  
335

  
336
def test_update_event(app, user):
337
    api_url = '/api/agenda/%s/event/%s/' % ('nop', 'nop')
338

  
339
    # no authentication
340
    resp = app.patch(api_url, status=401)
341
    assert resp.json['detail'] == 'Authentication credentials were not provided.'
342

  
343
    # wrong password
344
    app.authorization = ('Basic', ('john.doe', 'wrong'))
345
    resp = app.patch(api_url, status=401)
346
    assert resp.json['detail'] == 'Invalid username/password.'
347

  
348
    app.authorization = ('Basic', ('john.doe', 'password'))
349

  
350
    # missing agenda
351
    resp = app.patch(api_url, status=404)
352
    assert resp.json['detail'] == 'Not found.'
353

  
354
    meeting_agenda = Agenda.objects.create(label='Foo bar Meeting', kind='meetings')
355

  
356
    # using meeting agenda
357
    api_url = '/api/agenda/%s/event/%s/' % (meeting_agenda.slug, 'nop')
358
    resp = app.patch(api_url, status=404)
359
    assert resp.json['detail'] == 'Not found.'
360

  
361
    agenda = Agenda.objects.create(label='Foo bar')
362

  
363
    # missing event
364
    api_url = '/api/agenda/%s/event/%s/' % (agenda.slug, 'nop')
365
    resp = app.patch(api_url, status=404)
366
    assert resp.json['detail'] == 'Not found.'
367

  
368
    # missing recurring event
369
    api_url = '/api/agenda/%s/event/%s/' % (agenda.slug, 'nop:2021-11-15-1538')
370
    resp = app.patch(api_url, status=400)
371
    assert resp.json['err']
372
    assert resp.json['err_desc'] == 'unknown recurring event slug: nop'
373

  
374
    event = Event.objects.create(agenda=agenda, start_datetime=now(), places=10, waiting_list_places=5)
375
    api_url = '/api/agenda/%s/event/%s/' % (agenda.slug, event.slug)
376

  
377
    # update with errors in datetime parts
378
    params = {
379
        'start_datetime': '2021-11-15 minuit',
380
        'recurrence_days': '7, 8',
381
    }
382
    resp = app.patch(api_url, params=params, status=400)
383
    assert resp.json['err']
384
    assert resp.json['err_desc'] == 'invalid payload'
385
    assert 'Datetime has wrong format' in resp.json['errors']['start_datetime'][0]
386
    assert resp.json['errors']['recurrence_days']['0'][0] == 'Ensure this value is less than or equal to 6.'
387

  
388
    # update with almost all optional managed fields
389
    params = {
390
        'start_datetime': '2021-11-15 15:38',
391
        'duration': 42,
392
        'publication_date': '2021-09-20',
393
        'places': 8,
394
        'waiting_list_places': 3,
395
        'label': 'FOO camp',
396
        'description': 'An event',
397
        'pricing': 'free',
398
        'url': 'http://example.org/foo/bar/?',
399
    }
400
    resp = app.patch(api_url, params=params)
401
    assert not resp.json['err']
402
    event = Event.objects.filter(agenda=agenda).get(slug=event.slug)
403
    assert event.duration == 42
404
    assert event.places == 8
405
    assert event.waiting_list_places == 3
406
    assert event.label == 'FOO camp'
407
    assert event.description == 'An event'
408
    assert event.pricing == 'free'
409
    assert event.url == 'http://example.org/foo/bar/?'
410

  
411
    # update event as a recurring event
412
    params = {
413
        'recurrence_days': '0,3,5',
414
        'recurrence_week_interval': 2,
415
        'recurrence_end_date': '2021-12-27',
416
    }
417
    resp = app.patch(api_url, params=params)
418
    assert not resp.json['err']
419
    event = Event.objects.filter(agenda=agenda).get(slug=event.slug)
420
    assert event.recurrences.count() == 9
421
    assert [x.places for x in event.recurrences.all()] == [8] * 9
422

  
423
    recurrence_slug = event.recurrences.first().slug
424
    assert recurrence_slug == 'foo-bar-event--2021-11-15-1538'
425
    recurrence_url = '/api/agenda/%s/event/%s/' % (agenda.slug, 'foo-bar-event:2021-11-15-1538')
426

  
427
    # update unprotected fields of one of the event recurrencies
428
    params = {
429
        'start_datetime': '2021-11-14 14:00',
430
        'duration': 43,
431
        'places': 9,
432
        'waiting_list_places': 4,
433
        'label': 'BAR camp',
434
        'description': 'An occurence of an event recurrence',
435
        'pricing': '5€',
436
        'url': 'http://example.org/bar/bar/',
437
    }
438
    resp = app.patch(recurrence_url, params=params)
439
    assert not resp.json['err']
440
    recurrence = Event.objects.filter(agenda=agenda).get(slug=recurrence_slug)
441
    assert recurrence.duration == 43
442
    assert recurrence.places == 9
443
    assert recurrence.waiting_list_places == 4
444
    assert recurrence.label == 'BAR camp'
445
    assert recurrence.description == 'An occurence of an event recurrence'
446
    assert recurrence.pricing == '5€'
447
    assert recurrence.url == 'http://example.org/bar/bar/'
448

  
449
    # try to update protected fields of one of the event recurrencies
450
    params = {
451
        'publication_date': '2021-11-15',
452
    }
453
    resp = app.patch(recurrence_url, params=params, status=400)
454
    assert resp.json['err']
455
    assert 'cannot be modified' in resp.json['err_desc']
456

  
457
    #  update protected fields of one of the event recurrencies providing same value
458
    assert 'cannot be modified' in resp.json['err_desc']
459
    params = {
460
        'recurrence_week_interval': 1,
461
    }
462
    resp = app.patch(recurrence_url, params=params)
463
    assert not resp.json['err']
464

  
465
    booking = Booking.objects.create(event=event.recurrences.all()[2])
466

  
467
    # update unprotected fields
468
    params = {
469
        'places': 7,
470
    }
471
    resp = app.patch(api_url, params=params)
472
    assert not resp.json['err']
473
    event = Event.objects.filter(agenda=agenda).get(slug=event.slug)
474
    assert [x.places for x in event.recurrences.all()] == [7] * 9
475

  
476
    # try to update recurring event protected fields
477
    params = {
478
        'recurrence_days': '1,2',
479
    }
480
    resp = app.patch(api_url, params=params, status=400)
481
    assert resp.json['err']
482
    assert 'cannot be modified' in resp.json['err_desc']
483

  
484
    assert booking.event.start_datetime.date() == datetime.date(2021, 11, 20)
485

  
486
    # try to reduce recurrence end date before booked event
487
    params = {
488
        'recurrence_end_date': '2021-11-20',
489
    }
490
    resp = app.patch(api_url, params=params, status=400)
491
    assert resp.json['err']
492
    assert 'bookings exist after this date.' in resp.json['err_desc']
493

  
494
    # reduce recurrence end date after booked event
495
    params = {
496
        'recurrence_end_date': '2021-11-21',
497
    }
498
    resp = app.patch(api_url, params=params)
499
    assert not resp.json['err']
500
    event = Event.objects.filter(agenda=agenda).get(slug=event.slug)
501
    assert event.recurrences.count() == 3
502

  
503
    booking.cancel()
504

  
505
    # update no more protected fields
506
    params = {
507
        'recurrence_days': '1,2,3,4,5',
508
        'recurrence_week_interval': 1,
509
    }
510
    resp = app.patch(api_url, params=params)
511
    assert not resp.json['err']
512
    event = Event.objects.filter(agenda=agenda).get(slug=event.slug)
513
    assert event.recurrences.count() == 5
334
-