Projet

Général

Profil

0003-api-add-endpoint-to-book-multiple-events-independent.patch

Valentin Deniaud, 02 août 2021 16:07

Télécharger (5,27 ko)

Voir les différences:

Subject: [PATCH 3/3] api: add endpoint to book multiple events independently
 (#55367)

 chrono/api/urls.py         |  5 ++++
 chrono/api/views.py        | 53 ++++++++++++++++++++++++++++++++++++++
 tests/api/test_fillslot.py | 36 ++++++++++++++++++++++++++
 3 files changed, 94 insertions(+)
chrono/api/urls.py
33 33
        name='api-fillslot',
34 34
    ),
35 35
    url(r'^agenda/(?P<agenda_identifier>[\w-]+)/fillslots/$', views.fillslots, name='api-agenda-fillslots'),
36
    url(
37
        r'^agenda/(?P<agenda_identifier>[\w-]+)/event_fillslots/$',
38
        views.event_fillslots,
39
        name='api-agenda-event-fillslots',
40
    ),
36 41
    url(
37 42
        r'^agenda/(?P<agenda_identifier>[\w-]+)/recurring_fillslots/$',
38 43
        views.recurring_fillslots,
chrono/api/views.py
1640 1640
recurring_fillslots = RecurringFillslots.as_view()
1641 1641

  
1642 1642

  
1643
class EventFillslots(APIView):
1644
    permission_classes = (permissions.IsAuthenticated,)
1645
    serializer_class = EventSlotsSerializer
1646

  
1647
    def post(self, request, agenda_identifier):
1648
        agenda = get_object_or_404(Agenda, slug=agenda_identifier, kind='events')
1649
        serializer = self.serializer_class(data=request.data, partial=True)
1650
        if not serializer.is_valid():
1651
            raise APIError(
1652
                _('invalid payload'),
1653
                err_class='invalid payload',
1654
                errors=serializer.errors,
1655
                http_status=status.HTTP_400_BAD_REQUEST,
1656
            )
1657
        payload = serializer.validated_data
1658

  
1659
        events = get_events_from_slots(payload['slots'], request, agenda, payload)
1660
        events = Event.annotate_queryset(events)
1661

  
1662
        full_events = [str(event) for event in events.filter(full=True)]
1663
        if full_events:
1664
            raise APIError(
1665
                _('some events are full: %s') % ', '.join(full_events), err_class='some events are full'
1666
            )
1667

  
1668
        events = events.annotate(
1669
            in_waiting_list=ExpressionWrapper(
1670
                Q(booked_places_count__gte=F('places')) | Q(waiting_list_count__gt=0),
1671
                output_field=BooleanField(),
1672
            )
1673
        )
1674

  
1675
        extra_data = {k: v for k, v in request.data.items() if k not in payload}
1676
        bookings = [make_booking(event, payload, extra_data) for event in events]
1677

  
1678
        with transaction.atomic():
1679
            Booking.objects.bulk_create(bookings)
1680
            events.update(
1681
                full=Q(booked_places_count__gte=F('places'), waiting_list_places=0)
1682
                | Q(waiting_list_places__gt=0, waiting_list_count__gte=F('waiting_list_places')),
1683
                almost_full=Q(booked_places_count__gte=0.9 * F('places')),
1684
            )
1685

  
1686
        response = {
1687
            'err': 0,
1688
            'booking_count': len(bookings),
1689
        }
1690
        return Response(response)
1691

  
1692

  
1693
event_fillslots = EventFillslots.as_view()
1694

  
1695

  
1643 1696
class BookingSerializer(serializers.ModelSerializer):
1644 1697
    user_absence_reason = serializers.CharField(required=False, allow_blank=True, allow_null=True)
1645 1698

  
tests/api/test_fillslot.py
2222 2222
    resp = app.post_json('/api/agenda/%s/recurring_fillslots/' % agenda.slug, params=params)
2223 2223
    assert resp.json['booking_count'] == 5
2224 2224
    assert events.filter(waiting_list_count=2).count() == 5
2225

  
2226

  
2227
def test_api_event_fillslots(app, user, freezer):
2228
    freezer.move_to('2021-09-06 12:00')
2229
    agenda = Agenda.objects.create(label='Foo bar', kind='events')
2230
    event = Event.objects.create(
2231
        label='Event',
2232
        start_datetime=now() + datetime.timedelta(days=1),
2233
        places=2,
2234
        waiting_list_places=1,
2235
        agenda=agenda,
2236
    )
2237
    second_event = Event.objects.create(
2238
        label='Event 2', start_datetime=now() + datetime.timedelta(days=2), places=2, agenda=agenda
2239
    )
2240

  
2241
    app.authorization = ('Basic', ('john.doe', 'password'))
2242
    fillslots_url = '/api/agenda/%s/event_fillslots/' % agenda.slug
2243
    params = {'user_external_id': 'user_id', 'slots': 'event,event-2'}
2244
    resp = app.post_json(fillslots_url, params=params)
2245
    assert resp.json['booking_count'] == 2
2246

  
2247
    events = Event.annotate_queryset(Event.objects.all())
2248
    assert events.filter(booked_places_count=1).count() == 2
2249

  
2250
    resp = app.post_json(fillslots_url, params=params)
2251
    assert resp.json['booking_count'] == 2
2252

  
2253
    resp = app.post_json(fillslots_url, params=params)
2254
    assert resp.json['err'] == 1
2255
    assert resp.json['err_desc'] == 'some events are full: Event 2'
2256

  
2257
    params['slots'] = 'event'
2258
    resp = app.post_json(fillslots_url, params=params)
2259
    assert resp.json['booking_count'] == 1
2260
    assert Booking.objects.filter(in_waiting_list=True, event=event).count() == 1
2225
-