Projet

Général

Profil

0002-api-exclude-slots-already-booked-by-user-events-5134.patch

Lauréline Guérin, 25 février 2021 10:58

Télécharger (7,41 ko)

Voir les différences:

Subject: [PATCH 2/3] api: exclude slots already booked by user - events
 (#51341)

 chrono/agendas/models.py | 31 +++++++++++++++++++
 chrono/api/views.py      | 12 ++++++--
 tests/test_api.py        | 65 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 106 insertions(+), 2 deletions(-)
chrono/agendas/models.py
513 513
        include_full=True,
514 514
        min_start=None,
515 515
        max_start=None,
516
        excluded_user_external_id=None,
516 517
    ):
517 518
        assert self.kind == 'events'
518 519

  
......
556 557
            else:
557 558
                entries = entries.filter(start_datetime__lt=max_start)
558 559

  
560
        if excluded_user_external_id and not prefetched_queryset:
561
            entries = Event.annotate_queryset_for_user(entries, excluded_user_external_id)
562

  
559 563
        if annotate_queryset and not prefetched_queryset:
560 564
            entries = Event.annotate_queryset(entries)
561 565

  
......
1153 1157
                ),
1154 1158
            )
1155 1159

  
1160
    @staticmethod
1161
    def annotate_queryset_for_user(qs, excluded_user_external_id):
1162
        if django.VERSION < (2, 0):
1163
            return qs.annotate(
1164
                user_places_count=Count(
1165
                    Case(
1166
                        When(
1167
                            booking__cancellation_datetime__isnull=True,
1168
                            booking__in_waiting_list=False,
1169
                            booking__user_external_id=excluded_user_external_id,
1170
                            then='booking',
1171
                        )
1172
                    )
1173
                ),
1174
            )
1175
        else:
1176
            return qs.annotate(
1177
                user_places_count=Count(
1178
                    'booking',
1179
                    filter=Q(
1180
                        booking__cancellation_datetime__isnull=True,
1181
                        booking__in_waiting_list=False,
1182
                        booking__user_external_id=excluded_user_external_id,
1183
                    ),
1184
                ),
1185
            )
1186

  
1156 1187
    @property
1157 1188
    def booked_places(self):
1158 1189
        if hasattr(self, 'booked_places_count'):
chrono/api/views.py
378 378
        'description': event.description,
379 379
        'pricing': event.pricing,
380 380
        'url': event.url,
381
        'disabled': bool(event.full),
381
        'disabled': bool(event.full) or getattr(event, 'user_places_count', 0) > 0,
382 382
        'api': {
383 383
            'bookings_url': request.build_absolute_uri(
384 384
                reverse(
......
556 556
        if date_end:
557 557
            date_end = make_aware(datetime.datetime.combine(parse_date(date_end), datetime.time(0, 0)))
558 558

  
559
        entries = agenda.get_open_events(annotate_queryset=True, min_start=date_start, max_start=date_end)
559
        user_external_id = request.GET.get('exclude_user_external_id') or None
560

  
561
        entries = agenda.get_open_events(
562
            annotate_queryset=True,
563
            min_start=date_start,
564
            max_start=date_end,
565
            excluded_user_external_id=user_external_id,
566
        )
560 567

  
561 568
        response = {
562 569
            'data': [get_event_detail(request, x, agenda=agenda) for x in entries],
......
1287 1294
            'in_waiting_list': self.booking.in_waiting_list,
1288 1295
            'user_was_present': self.booking.user_was_present,
1289 1296
            'user_absence_reason': self.booking.user_absence_reason,
1297
            'user_external_id': self.booking.user_external_id,
1290 1298
        }
1291 1299
        return Response(response)
1292 1300

  
tests/test_api.py
499 499
        )
500 500

  
501 501

  
502
@pytest.mark.freeze_time('2021-02-23')
503
def test_datetimes_api_exclude_slots(app):
504
    agenda = Agenda.objects.create(
505
        label='Foo bar', kind='events', minimal_booking_delay=0, maximal_booking_delay=7
506
    )
507
    event = Event.objects.create(
508
        slug='event-slug',
509
        start_datetime=localtime().replace(hour=10, minute=0),
510
        places=5,
511
        agenda=agenda,
512
    )
513
    Booking.objects.create(event=event, user_external_id='42')
514
    cancelled = Booking.objects.create(event=event, user_external_id='35')
515
    cancelled.cancel()
516

  
517
    resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
518
    assert resp.json['data'][0]['disabled'] is False
519

  
520
    resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'exclude_user_external_id': '35'})
521
    assert resp.json['data'][0]['disabled'] is False
522

  
523
    resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'exclude_user_external_id': '42'})
524
    assert resp.json['data'][0]['disabled'] is True
525

  
526
    event.delete()
527

  
528
    # recurrent event
529
    event = Event.objects.create(
530
        slug='recurrent',
531
        start_datetime=localtime().replace(hour=12, minute=0),
532
        repeat='weekly',
533
        places=2,
534
        agenda=agenda,
535
    )
536
    resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
537
    assert resp.json['data'][0]['id'] == 'recurrent:2021-02-23-1200'
538
    assert resp.json['data'][0]['places']['full'] is False
539
    assert resp.json['data'][0]['disabled'] is False
540
    resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'exclude_user_external_id': '42'})
541
    assert resp.json['data'][0]['id'] == 'recurrent:2021-02-23-1200'
542
    assert resp.json['data'][0]['places']['full'] is False
543
    assert resp.json['data'][0]['disabled'] is False
544

  
545
    first_recurrence = event.get_or_create_event_recurrence(event.start_datetime)
546
    Booking.objects.create(event=first_recurrence, user_external_id='42')
547
    resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
548
    assert resp.json['data'][0]['id'] == 'recurrent--2021-02-23-1200'
549
    assert resp.json['data'][0]['places']['full'] is False
550
    assert resp.json['data'][0]['disabled'] is False
551
    resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'exclude_user_external_id': '42'})
552
    assert resp.json['data'][0]['id'] == 'recurrent--2021-02-23-1200'
553
    assert resp.json['data'][0]['places']['full'] is False
554
    assert resp.json['data'][0]['disabled'] is True
555

  
556
    Booking.objects.create(event=first_recurrence)
557
    resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
558
    assert resp.json['data'][0]['id'] == 'recurrent--2021-02-23-1200'
559
    assert resp.json['data'][0]['places']['full'] is True
560
    assert resp.json['data'][0]['disabled'] is True
561
    resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'exclude_user_external_id': '42'})
562
    assert resp.json['data'][0]['id'] == 'recurrent--2021-02-23-1200'
563
    assert resp.json['data'][0]['places']['full'] is True
564
    assert resp.json['data'][0]['disabled'] is True
565

  
566

  
502 567
def test_datetimes_api_meetings_agenda(app, meetings_agenda):
503 568
    meeting_type = MeetingType.objects.get(agenda=meetings_agenda)
504 569
    api_url = '/api/agenda/%s/meetings/%s/datetimes/' % (meeting_type.agenda.slug, meeting_type.slug)
505
-