Projet

Général

Profil

0002-api-get-event-status-and-fillslot-with-event-pk-or-s.patch

Lauréline Guérin, 06 novembre 2019 18:39

Télécharger (11 ko)

Voir les différences:

Subject: [PATCH 2/2] api: get event status and fillslot with event pk or slug
 (#15726)

 chrono/api/urls.py  |  4 ++--
 chrono/api/views.py | 37 ++++++++++++++++++++++++++-----------
 tests/test_api.py   | 20 +++++++++++++++-----
 3 files changed, 43 insertions(+), 18 deletions(-)
chrono/api/urls.py
23 23
    url(r'agenda/(?P<agenda_identifier>[\w-]+)/$', views.agenda_detail),
24 24

  
25 25
    url(r'agenda/(?P<agenda_identifier>[\w-]+)/datetimes/$', views.datetimes, name='api-agenda-datetimes'),
26
    url(r'agenda/(?P<agenda_identifier>[\w-]+)/fillslot/(?P<event_pk>[\w:-]+)/$',
26
    url(r'agenda/(?P<agenda_identifier>[\w-]+)/fillslot/(?P<event_identifier>[\w:-]+)/$',
27 27
        views.fillslot, name='api-fillslot'),
28 28
    url(r'agenda/(?P<agenda_identifier>[\w-]+)/fillslots/$',
29 29
        views.fillslots, name='api-agenda-fillslots'),
30
    url(r'agenda/(?P<agenda_identifier>[\w-]+)/status/(?P<event_pk>\d+)/$', views.slot_status,
30
    url(r'agenda/(?P<agenda_identifier>[\w-]+)/status/(?P<event_identifier>[\w-]+)/$', views.slot_status,
31 31
        name='api-event-status'),
32 32

  
33 33
    url(r'agenda/meetings/(?P<meeting_identifier>[\w-]+)/datetimes/$',
chrono/api/views.py
185 185
                datetime.datetime.combine(parse_date(request.GET['date_end']), datetime.time(0, 0))))
186 186

  
187 187
        response = {'data': [{'id': x.id,
188
                              'slug': x.slug,
188 189
                              'text': force_text(x),
189 190
                              'datetime': format_response_datetime(x.start_datetime),
190 191
                              'description': x.description,
......
194 195
                                      reverse('api-fillslot',
195 196
                                          kwargs={
196 197
                                              'agenda_identifier': agenda.slug,
197
                                              'event_pk': x.id,
198
                                              'event_identifier': x.slug,
198 199
                                      })),
199 200
                                  'status_url': request.build_absolute_uri(
200 201
                                      reverse('api-event-status',
201 202
                                          kwargs={
202 203
                                              'agenda_identifier': agenda.slug,
203
                                              'event_pk': x.id,
204
                                              'event_identifier': x.slug,
204 205
                                      }))
205 206
                                  },
206 207
                              } for x in entries]}
......
240 241

  
241 242
        # create fillslot API URL as a template, to avoid expensive calls
242 243
        # to request.build_absolute_uri()
243
        fake_event_pk = '__event_id__'
244
        fake_event_identifier = '__event_identifier__'
244 245
        fillslot_url = request.build_absolute_uri(
245 246
                reverse('api-fillslot',
246 247
                    kwargs={
247 248
                        'agenda_identifier': agenda.slug,
248
                        'event_pk': fake_event_pk,
249
                        'event_identifier': fake_event_identifier,
249 250
                        }))
250 251

  
251 252
        response = {'data': [{'id': x.id,
......
253 254
                              'text': force_text(x),
254 255
                              'disabled': bool(x.full),
255 256
                              'api': {
256
                                'fillslot_url': fillslot_url.replace(fake_event_pk, str(x.id)),
257
                                'fillslot_url': fillslot_url.replace(fake_event_identifier, str(x.id)),
257 258
                              },
258 259
                             } for x in slots]}
259 260
        return Response(response)
......
333 334
    permission_classes = (permissions.IsAuthenticated,)
334 335
    serializer_class = SlotsSerializer
335 336

  
336
    def post(self, request, agenda_identifier=None, event_pk=None, format=None):
337
    def post(self, request, agenda_identifier=None, event_identifier=None, format=None):
337 338
        return self.fillslot(request=request, agenda_identifier=agenda_identifier,
338 339
                             format=format)
339 340

  
......
467 468
                        full=False, places=1,
468 469
                        desk=available_desk))
469 470
        else:
470
            events = Event.objects.filter(id__in=slots).order_by('start_datetime')
471
            try:
472
                events = Event.objects.filter(id__in=[int(s) for s in slots]).order_by('start_datetime')
473
            except ValueError:
474
                events = Event.objects.filter(slug__in=slots).order_by('start_datetime')
471 475

  
472 476
        # search free places. Switch to waiting list if necessary.
473 477
        in_waiting_list = False
......
538 542
class Fillslot(Fillslots):
539 543
    serializer_class = SlotSerializer
540 544

  
541
    def post(self, request, agenda_identifier=None, event_pk=None, format=None):
545
    def post(self, request, agenda_identifier=None, event_identifier=None, format=None):
542 546
        return self.fillslot(request=request,
543 547
                             agenda_identifier=agenda_identifier,
544
                             slots=[event_pk],  # fill a "list on one slot"
548
                             slots=[event_identifier],  # fill a "list on one slot"
545 549
                             format=format)
546 550

  
547 551
fillslot = Fillslot.as_view()
......
610 614
class SlotStatus(APIView):
611 615
    permission_classes = (permissions.IsAuthenticated,)
612 616

  
613
    def get(self, request, agenda_identifier=None, event_pk=None, format=None):
614
        event = get_object_or_404(Event, id=event_pk)
617
    def get_object(self, event_identifier):
618
        try:
619
            return Event.objects.get(slug=event_identifier)
620
        except Event.DoesNotExist:
621
            try:
622
                # legacy access by event id
623
                return Event.objects.get(pk=int(event_identifier))
624
            except (ValueError, Event.DoesNotExist):
625
                raise Http404()
626

  
627
    def get(self, request, agenda_identifier=None, event_identifier=None, format=None):
628
        event = self.get_object(event_identifier)
615 629
        response = {
616 630
            'err': 0,
617 631
            'places': {
......
626 640
            response['places']['waiting_list_available'] = (event.waiting_list_places - event.waiting_list)
627 641
        return Response(response)
628 642

  
643

  
629 644
slot_status = SlotStatus.as_view()
630 645

  
631 646

  
tests/test_api.py
225 225
    agenda = Agenda.objects.get(label=u'Foo bar2')
226 226
    resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
227 227
    for datum in resp.json['data']:
228
        assert urlparse.urlparse(datum['api']['status_url']).path == '/api/agenda/%s/status/%s/' % (agenda.slug, datum['id'])
228
        assert urlparse.urlparse(datum['api']['status_url']).path == '/api/agenda/%s/status/%s/' % (agenda.slug, datum['slug'])
229 229

  
230 230
def test_datetimes_api_meetings_agenda(app, meetings_agenda):
231 231
    meeting_type = MeetingType.objects.get(agenda=meetings_agenda)
......
333 333
    for agenda_key in (agenda.slug, agenda.id):  # acces datetimes via agenda slug or id (legacy)
334 334
        resp_datetimes = app.get('/api/agenda/%s/datetimes/' % agenda_key)
335 335
        event_fillslot_url = [x for x in resp_datetimes.json['data'] if x['id'] == event.id][0]['api']['fillslot_url']
336
        assert urlparse.urlparse(event_fillslot_url).path == '/api/agenda/%s/fillslot/%s/' % (agenda.slug, event.id)
336
        assert urlparse.urlparse(event_fillslot_url).path == '/api/agenda/%s/fillslot/%s/' % (agenda.slug, event.slug)
337 337

  
338 338
    app.authorization = ('Basic', ('john.doe', 'password'))
339 339
    resp = app.post('/api/agenda/%s/fillslot/%s/' % (agenda.slug, event.id))
......
346 346
    assert urlparse.urlparse(resp.json['api']['ics_url']).netloc
347 347
    assert Booking.objects.count() == 1
348 348

  
349
    resp = app.post('/api/agenda/%s/fillslot/%s/' % (agenda.id, event.id))
349
    # access by slug
350
    resp = app.post('/api/agenda/%s/fillslot/%s/' % (agenda.id, event.slug))
350 351
    assert Booking.objects.count() == 2
351 352
    assert Booking.objects.filter(event__agenda=agenda).count() == 2
352 353

  
......
467 468
def test_booking_api_fillslots(app, some_data, user):
468 469
    agenda = Agenda.objects.filter(label=u'Foo bar')[0]
469 470
    events_ids = [x.id for x in Event.objects.filter(agenda=agenda) if x.in_bookable_period()]
471
    events_slugs = [x.slug for x in Event.objects.filter(agenda=agenda) if x.in_bookable_period()]
470 472
    assert len(events_ids) == 3
471 473
    event = [x for x in Event.objects.filter(agenda=agenda) if x.in_bookable_period()][0]  # first event
472 474

  
......
495 497
    assert bookings[1].primary_booking.id == bookings[0].id == primary_booking_id
496 498
    assert bookings[2].primary_booking.id == bookings[0].id == primary_booking_id
497 499

  
498
    resp = app.post('/api/agenda/%s/fillslots/' % agenda.slug, params={'slots': events_ids})
500
    # access by slug
501
    resp = app.post('/api/agenda/%s/fillslots/' % agenda.slug, params={'slots': events_slugs})
499 502
    primary_booking_id_2 = resp.json['booking_id']
500 503
    assert Booking.objects.count() == 6
501 504
    assert Booking.objects.filter(event__agenda=agenda).count() == 6
......
915 918
    assert resp.json['places']['waiting_list_available'] == 4
916 919
    assert resp.json['places']['waiting_list_reserved'] == 1
917 920

  
921
    # access by slug
922
    resp = app.get('/api/agenda/%s/status/%s/' % (agenda_id, event.slug))
923
    # not found event
924
    resp = app.get('/api/agenda/%s/status/%s/' % (agenda_id, 'unknown'), status=404)
925

  
926

  
918 927
def test_waiting_list_datetimes(app, some_data, user):
919 928
    agenda_id = Agenda.objects.filter(label=u'Foo bar')[0].id
920 929
    event = Event.objects.filter(agenda_id=agenda_id).exclude(start_datetime__lt=now())[0]
......
1343 1352
        booking_url = event_data['api']['fillslot_url']
1344 1353
        with CaptureQueriesContext(connection) as ctx:
1345 1354
            app.post(booking_url)
1346
            assert len(ctx.captured_queries) == queries_count_fillslot1
1355
            # 2 + idx: because of slug unicity
1356
            assert len(ctx.captured_queries) == queries_count_fillslot1 + 2 + idx
1347 1357

  
1348 1358
    with CaptureQueriesContext(connection) as ctx:
1349 1359
        app.get('/api/agenda/meetings/%s/datetimes/' % meeting_type.id)
1350
-