Projet

Général

Profil

0001-api-datetimes-past-events-48397.patch

Lauréline Guérin, 04 juin 2021 10:51

Télécharger (23,8 ko)

Voir les différences:

Subject: [PATCH 1/2] api: datetimes & past events (#48397)

 chrono/agendas/models.py    |  39 ++-
 chrono/api/views.py         |  33 ++-
 tests/api/test_datetimes.py | 508 ++++++++++++++++++++++++++++++++++++
 3 files changed, 570 insertions(+), 10 deletions(-)
chrono/agendas/models.py
655 655
        if max_start:
656 656
            entries = self.add_event_recurrences(
657 657
                entries,
658
                min_start or localtime(now()),
658
                max(min_start or localtime(now()), localtime(now())),
659 659
                max_start,
660 660
                include_full=include_full,
661 661
                prefetched_queryset=prefetched_queryset,
......
663 663

  
664 664
        return entries
665 665

  
666
    def get_past_events(
667
        self,
668
        annotate_queryset=False,
669
        min_start=None,
670
        max_start=None,
671
        excluded_user_external_id=None,
672
    ):
673
        assert self.kind == 'events'
674

  
675
        # recurring events are never opened
676
        entries = self.event_set.filter(recurrence_rule__isnull=True)
677
        # exclude canceled events except for event recurrences
678
        entries = entries.filter(Q(cancelled=False) | Q(primary_event__isnull=False))
679
        # we want only past events
680
        entries = entries.filter(start_datetime__lt=localtime(now()))
681

  
682
        if min_start:
683
            entries = entries.filter(start_datetime__gte=min_start)
684

  
685
        if max_start:
686
            entries = entries.filter(start_datetime__lt=max_start)
687

  
688
        if excluded_user_external_id:
689
            entries = Event.annotate_queryset_for_user(entries, excluded_user_external_id)
690

  
691
        if annotate_queryset:
692
            entries = Event.annotate_queryset(entries)
693

  
694
        if min_start:
695
            entries = self.add_event_recurrences(
696
                entries,
697
                min_start,
698
                min(max_start or localtime(now()), localtime(now())),
699
            )
700

  
701
        return entries
702

  
666 703
    def add_event_recurrences(
667 704
        self,
668 705
        events,
chrono/api/views.py
406 406

  
407 407

  
408 408
def is_event_disabled(event, min_places=1):
409
    if event.remaining_places < min_places and event.remaining_waiting_list_places < min_places:
410
        return True
411 409
    if getattr(event, 'user_places_count', 0) > 0:
412 410
        return True
411
    if event.start_datetime < now():
412
        # event is past, it's alway ok
413
        return False
414
    if event.remaining_places < min_places and event.remaining_waiting_list_places < min_places:
415
        return True
413 416
    return False
414 417

  
415 418

  
......
682 685

  
683 686
        start_datetime, end_datetime = get_start_and_end_datetime_from_request(request)
684 687
        user_external_id = request.GET.get('exclude_user_external_id') or None
685

  
686
        entries = agenda.get_open_events(
687
            annotate_queryset=True,
688
            min_start=start_datetime,
689
            max_start=end_datetime,
690
            excluded_user_external_id=user_external_id,
691
        )
688
        show_events = request.GET.get('events') or 'future'
689
        show_past = show_events in ['all', 'past']
690
        show_future = show_events in ['all', 'future']
691

  
692
        entries = []
693
        if show_past:
694
            entries += agenda.get_past_events(
695
                annotate_queryset=True,
696
                min_start=start_datetime,
697
                max_start=end_datetime,
698
                excluded_user_external_id=user_external_id,
699
            )
700
        if show_future:
701
            entries += agenda.get_open_events(
702
                annotate_queryset=True,
703
                min_start=start_datetime,
704
                max_start=end_datetime,
705
                excluded_user_external_id=user_external_id,
706
            )
692 707

  
693 708
        if request.GET.get('hide_disabled'):
694 709
            entries = [e for e in entries if not is_event_disabled(e, min_places)]
tests/api/test_datetimes.py
627 627
    app.authorization = ('Basic', ('john.doe', 'password'))
628 628
    resp = app.post(fillslot_url, status=400)
629 629
    assert resp.json['err'] == 1
630

  
631

  
632
def test_past_datetimes(app, user):
633
    agenda = Agenda.objects.create(
634
        label='Foo bar', kind='events', minimal_booking_delay=0, maximal_booking_delay=30
635
    )
636
    event1 = Event.objects.create(
637
        label='Today before now',
638
        start_datetime=localtime(now() - datetime.timedelta(hours=1)),
639
        places=5,
640
        agenda=agenda,
641
    )
642
    event2 = Event.objects.create(
643
        label='Today after now',
644
        start_datetime=localtime(now() + datetime.timedelta(hours=1)),
645
        places=5,
646
        agenda=agenda,
647
    )
648

  
649
    resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
650
    data = resp.json['data']
651
    assert len(data) == 1
652
    assert data[0]['id'] == 'today-after-now'
653
    assert data[0]['disabled'] is False
654

  
655
    resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'events': 'future'})
656
    data = resp.json['data']
657
    assert len(data) == 1
658
    assert data[0]['id'] == 'today-after-now'
659
    assert data[0]['disabled'] is False
660

  
661
    resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'events': 'past'})
662
    data = resp.json['data']
663
    assert len(data) == 1
664
    assert data[0]['id'] == 'today-before-now'
665
    assert data[0]['disabled'] is False
666

  
667
    resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'events': 'all'})
668
    data = resp.json['data']
669
    assert len(data) == 2
670
    assert data[0]['id'] == 'today-before-now'
671
    assert data[1]['id'] == 'today-after-now'
672
    assert data[0]['disabled'] is False
673
    assert data[1]['disabled'] is False
674

  
675
    # check canceled
676
    event1.cancel()
677
    event2.cancel()
678
    resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'events': 'all'})
679
    data = resp.json['data']
680
    assert len(data) == 0
681

  
682

  
683
def test_past_datetimes_meta(app, user):
684
    agenda = Agenda.objects.create(
685
        label='Foo bar', kind='events', minimal_booking_delay=0, maximal_booking_delay=30
686
    )
687
    Event.objects.create(
688
        label='Today before now',
689
        start_datetime=localtime(now() - datetime.timedelta(hours=1)),
690
        places=5,
691
        agenda=agenda,
692
    )
693
    Event.objects.create(
694
        label='Today after now',
695
        start_datetime=localtime(now() + datetime.timedelta(hours=1)),
696
        places=5,
697
        agenda=agenda,
698
    )
699

  
700
    resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'events': 'future'})
701
    assert len(resp.json['data']) == 1
702
    assert resp.json['meta'] == {
703
        'no_bookable_datetimes': False,
704
        'bookable_datetimes_number_total': 1,
705
        'bookable_datetimes_number_available': 1,
706
        'first_bookable_slot': resp.json['data'][0],
707
    }
708

  
709
    resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'events': 'past'})
710
    assert len(resp.json['data']) == 1
711
    assert resp.json['data'][0]['id'] == 'today-before-now'
712
    assert resp.json['meta'] == {
713
        'no_bookable_datetimes': False,
714
        'bookable_datetimes_number_total': 1,
715
        'bookable_datetimes_number_available': 1,
716
        'first_bookable_slot': resp.json['data'][0],
717
    }
718

  
719
    resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'events': 'all'})
720
    assert len(resp.json['data']) == 2
721
    assert resp.json['data'][0]['id'] == 'today-before-now'
722
    assert resp.json['data'][1]['id'] == 'today-after-now'
723
    assert resp.json['meta'] == {
724
        'no_bookable_datetimes': False,
725
        'bookable_datetimes_number_total': 2,
726
        'bookable_datetimes_number_available': 2,
727
        'first_bookable_slot': resp.json['data'][0],
728
    }
729

  
730

  
731
def test_past_datetimes_date_range(app, user):
732
    agenda = Agenda.objects.create(
733
        label='Foo bar', kind='events', minimal_booking_delay=0, maximal_booking_delay=30
734
    )
735
    Event.objects.create(
736
        label='Yesterday 18H',
737
        start_datetime=localtime(now() - datetime.timedelta(days=1)).replace(hour=18, minute=0),
738
        places=5,
739
        agenda=agenda,
740
    )
741
    Event.objects.create(
742
        label='Today before now',
743
        start_datetime=localtime(now() - datetime.timedelta(hours=1)),
744
        places=5,
745
        agenda=agenda,
746
    )
747
    Event.objects.create(
748
        label='Today after now',
749
        start_datetime=localtime(now() + datetime.timedelta(hours=1)),
750
        places=5,
751
        agenda=agenda,
752
    )
753
    Event.objects.create(
754
        label='Tomorrow 16H',
755
        start_datetime=localtime(now() + datetime.timedelta(days=1)).replace(hour=16, minute=0),
756
        places=5,
757
        agenda=agenda,
758
    )
759

  
760
    # check date_start
761
    params = {'date_start': localtime(now() - datetime.timedelta(hours=2)), 'events': 'future'}
762
    resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params=params)
763
    data = resp.json['data']
764
    assert len(data) == 2
765
    assert data[0]['id'] == 'today-after-now'
766
    assert data[1]['id'] == 'tomorrow-16h'
767
    assert data[0]['disabled'] is False
768
    assert data[1]['disabled'] is False
769

  
770
    params = {'date_start': localtime(now() - datetime.timedelta(hours=2)), 'events': 'past'}
771
    resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params=params)
772
    data = resp.json['data']
773
    assert len(data) == 1
774
    assert data[0]['id'] == 'today-before-now'
775
    assert data[0]['disabled'] is False
776

  
777
    params = {'date_start': localtime(now() - datetime.timedelta(hours=2)), 'events': 'all'}
778
    resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params=params)
779
    data = resp.json['data']
780
    assert len(data) == 3
781
    assert data[0]['id'] == 'today-before-now'
782
    assert data[1]['id'] == 'today-after-now'
783
    assert data[2]['id'] == 'tomorrow-16h'
784
    assert data[0]['disabled'] is False
785
    assert data[1]['disabled'] is False
786
    assert data[2]['disabled'] is False
787

  
788
    params = {'date_start': localtime(now() + datetime.timedelta(hours=2)), 'events': 'future'}
789
    resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params=params)
790
    data = resp.json['data']
791
    assert len(data) == 1
792
    assert data[0]['id'] == 'tomorrow-16h'
793
    assert data[0]['disabled'] is False
794

  
795
    params = {'date_start': localtime(now() + datetime.timedelta(hours=2)), 'events': 'past'}
796
    resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params=params)
797
    data = resp.json['data']
798
    assert len(data) == 0
799

  
800
    params = {'date_start': localtime(now() + datetime.timedelta(hours=2)), 'events': 'all'}
801
    resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params=params)
802
    data = resp.json['data']
803
    assert len(data) == 1
804
    assert data[0]['id'] == 'tomorrow-16h'
805
    assert data[0]['disabled'] is False
806

  
807
    # check date_end
808
    params = {'date_end': localtime(now() + datetime.timedelta(hours=2)), 'events': 'future'}
809
    resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params=params)
810
    data = resp.json['data']
811
    assert len(data) == 1
812
    assert data[0]['id'] == 'today-after-now'
813
    assert data[0]['disabled'] is False
814

  
815
    params = {'date_end': localtime(now() + datetime.timedelta(hours=2)), 'events': 'past'}
816
    resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params=params)
817
    data = resp.json['data']
818
    assert len(data) == 2
819
    assert data[0]['id'] == 'yesterday-18h'
820
    assert data[1]['id'] == 'today-before-now'
821
    assert data[0]['disabled'] is False
822
    assert data[1]['disabled'] is False
823

  
824
    params = {'date_end': localtime(now() + datetime.timedelta(hours=2)), 'events': 'all'}
825
    resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params=params)
826
    data = resp.json['data']
827
    assert len(data) == 3
828
    assert data[0]['id'] == 'yesterday-18h'
829
    assert data[1]['id'] == 'today-before-now'
830
    assert data[2]['id'] == 'today-after-now'
831
    assert data[0]['disabled'] is False
832
    assert data[1]['disabled'] is False
833
    assert data[2]['disabled'] is False
834

  
835
    params = {'date_end': localtime(now() - datetime.timedelta(hours=2)), 'events': 'future'}
836
    resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params=params)
837
    data = resp.json['data']
838
    assert len(data) == 0
839

  
840
    params = {'date_end': localtime(now() - datetime.timedelta(hours=2)), 'events': 'past'}
841
    resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params=params)
842
    data = resp.json['data']
843
    assert len(data) == 1
844
    assert data[0]['id'] == 'yesterday-18h'
845
    assert data[0]['disabled'] is False
846

  
847
    params = {'date_end': localtime(now() - datetime.timedelta(hours=2)), 'events': 'all'}
848
    resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params=params)
849
    data = resp.json['data']
850
    assert len(data) == 1
851
    assert data[0]['id'] == 'yesterday-18h'
852
    assert data[0]['disabled'] is False
853

  
854
    # mix
855
    params = {
856
        'date_start': localtime(now() - datetime.timedelta(hours=2)),
857
        'date_end': localtime(now() + datetime.timedelta(hours=2)),
858
        'events': 'future',
859
    }
860
    resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params=params)
861
    data = resp.json['data']
862
    assert len(data) == 1
863
    assert data[0]['id'] == 'today-after-now'
864
    assert data[0]['disabled'] is False
865

  
866
    params = {
867
        'date_start': localtime(now() - datetime.timedelta(hours=2)),
868
        'date_end': localtime(now() + datetime.timedelta(hours=2)),
869
        'events': 'past',
870
    }
871
    resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params=params)
872
    data = resp.json['data']
873
    assert len(data) == 1
874
    assert data[0]['id'] == 'today-before-now'
875
    assert data[0]['disabled'] is False
876

  
877
    params = {
878
        'date_start': localtime(now() - datetime.timedelta(hours=2)),
879
        'date_end': localtime(now() + datetime.timedelta(hours=2)),
880
        'events': 'all',
881
    }
882
    resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params=params)
883
    data = resp.json['data']
884
    assert len(data) == 2
885
    assert data[0]['id'] == 'today-before-now'
886
    assert data[1]['id'] == 'today-after-now'
887
    assert data[0]['disabled'] is False
888
    assert data[1]['disabled'] is False
889

  
890

  
891
def test_past_datetimes_places(app, user):
892
    agenda = Agenda.objects.create(
893
        label='Foo bar', kind='events', minimal_booking_delay=0, maximal_booking_delay=30
894
    )
895
    event1 = Event.objects.create(
896
        label='Today before now',
897
        start_datetime=localtime(now() - datetime.timedelta(hours=1)),
898
        places=1,
899
        agenda=agenda,
900
    )
901
    event2 = Event.objects.create(
902
        label='Today after now',
903
        start_datetime=localtime(now() + datetime.timedelta(hours=1)),
904
        places=1,
905
        agenda=agenda,
906
    )
907
    Booking.objects.create(event=event1)
908
    Booking.objects.create(event=event2)
909

  
910
    resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'events': 'future'})
911
    data = resp.json['data']
912
    assert len(data) == 1
913
    assert data[0]['id'] == 'today-after-now'
914
    assert resp.json['data'][0]['places']['full'] is True
915
    assert data[0]['disabled'] is True
916

  
917
    resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'events': 'past'})
918
    data = resp.json['data']
919
    assert len(data) == 1
920
    assert data[0]['id'] == 'today-before-now'
921
    assert resp.json['data'][0]['places']['full'] is True
922
    assert data[0]['disabled'] is False  # always available if past
923
    assert resp.json['meta']['first_bookable_slot']['id'] == 'today-before-now'
924

  
925
    event1.waiting_list_places = 1
926
    event1.save()
927
    event2.waiting_list_places = 1
928
    event2.save()
929
    Booking.objects.create(event=event1, in_waiting_list=True)
930
    Booking.objects.create(event=event2, in_waiting_list=True)
931

  
932
    resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'events': 'future'})
933
    data = resp.json['data']
934
    assert len(data) == 1
935
    assert data[0]['id'] == 'today-after-now'
936
    assert resp.json['data'][0]['places']['full'] is True
937
    assert data[0]['disabled'] is True
938

  
939
    resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'events': 'past'})
940
    data = resp.json['data']
941
    assert len(data) == 1
942
    assert data[0]['id'] == 'today-before-now'
943
    assert resp.json['data'][0]['places']['full'] is True
944
    assert data[0]['disabled'] is False  # always available if past
945
    assert resp.json['meta']['first_bookable_slot']['id'] == 'today-before-now'
946

  
947

  
948
def test_past_datetimes_min_places(app, user):
949
    agenda = Agenda.objects.create(
950
        label='Foo bar', kind='events', minimal_booking_delay=0, maximal_booking_delay=30
951
    )
952
    Event.objects.create(
953
        label='Today before now',
954
        start_datetime=localtime(now() - datetime.timedelta(hours=1)),
955
        places=1,
956
        agenda=agenda,
957
    )
958
    Event.objects.create(
959
        label='Today after now',
960
        start_datetime=localtime(now() + datetime.timedelta(hours=1)),
961
        places=1,
962
        agenda=agenda,
963
    )
964

  
965
    resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'events': 'future', 'min_places': 2})
966
    data = resp.json['data']
967
    assert len(data) == 1
968
    assert data[0]['id'] == 'today-after-now'
969
    assert data[0]['disabled'] is True
970

  
971
    resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'events': 'past', 'min_places': 2})
972
    data = resp.json['data']
973
    assert len(data) == 1
974
    assert data[0]['id'] == 'today-before-now'
975
    assert data[0]['disabled'] is False  # always available if past
976
    assert resp.json['meta']['first_bookable_slot']['id'] == 'today-before-now'
977

  
978

  
979
def test_past_datetimes_exclude_slots(app, user):
980
    agenda = Agenda.objects.create(
981
        label='Foo bar', kind='events', minimal_booking_delay=0, maximal_booking_delay=30
982
    )
983
    event1 = Event.objects.create(
984
        label='Today before now',
985
        start_datetime=localtime(now() - datetime.timedelta(hours=1)),
986
        places=5,
987
        agenda=agenda,
988
    )
989
    event2 = Event.objects.create(
990
        label='Today after now',
991
        start_datetime=localtime(now() + datetime.timedelta(hours=1)),
992
        places=5,
993
        agenda=agenda,
994
    )
995
    Booking.objects.create(event=event1, user_external_id='42')
996
    Booking.objects.create(event=event2, user_external_id='42')
997

  
998
    resp = app.get(
999
        '/api/agenda/%s/datetimes/' % agenda.slug,
1000
        params={'events': 'future', 'exclude_user_external_id': '35'},
1001
    )
1002
    data = resp.json['data']
1003
    assert len(data) == 1
1004
    assert data[0]['id'] == 'today-after-now'
1005
    assert data[0]['disabled'] is False
1006
    assert resp.json['meta']['first_bookable_slot']['id'] == 'today-after-now'
1007

  
1008
    resp = app.get(
1009
        '/api/agenda/%s/datetimes/' % agenda.slug, params={'events': 'past', 'exclude_user_external_id': '35'}
1010
    )
1011
    data = resp.json['data']
1012
    assert len(data) == 1
1013
    assert data[0]['id'] == 'today-before-now'
1014
    assert data[0]['disabled'] is False
1015
    assert resp.json['meta']['first_bookable_slot']['id'] == 'today-before-now'
1016

  
1017
    resp = app.get(
1018
        '/api/agenda/%s/datetimes/' % agenda.slug,
1019
        params={'events': 'future', 'exclude_user_external_id': '42'},
1020
    )
1021
    data = resp.json['data']
1022
    assert len(data) == 1
1023
    assert data[0]['id'] == 'today-after-now'
1024
    assert data[0]['disabled'] is True
1025

  
1026
    resp = app.get(
1027
        '/api/agenda/%s/datetimes/' % agenda.slug, params={'events': 'past', 'exclude_user_external_id': '42'}
1028
    )
1029
    data = resp.json['data']
1030
    assert len(data) == 1
1031
    assert data[0]['id'] == 'today-before-now'
1032
    assert data[0]['disabled'] is True
1033

  
1034

  
1035
def test_past_datetimes_recurring_event(app, user):
1036
    agenda = Agenda.objects.create(
1037
        label='Foo bar', kind='events', minimal_booking_delay=0, maximal_booking_delay=30
1038
    )
1039
    event = Event.objects.create(
1040
        label='Recurring',
1041
        start_datetime=localtime(now() - datetime.timedelta(days=3 * 7)),
1042
        repeat='weekly',
1043
        places=5,
1044
        agenda=agenda,
1045
    )
1046

  
1047
    resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'events': 'future'})
1048
    data = resp.json['data']
1049
    assert len(data) == 4
1050
    assert data[0]['disabled'] is False
1051
    assert data[1]['disabled'] is False
1052
    assert data[2]['disabled'] is False
1053
    assert data[3]['disabled'] is False
1054

  
1055
    resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'events': 'past'})
1056
    data = resp.json['data']
1057
    assert len(data) == 0  # no date_start, not possible to compute recurring events in past
1058

  
1059
    resp = app.get(
1060
        '/api/agenda/%s/datetimes/' % agenda.slug,
1061
        params={'events': 'past', 'date_start': localtime(now() - datetime.timedelta(days=6 * 7))},
1062
    )
1063
    data = resp.json['data']
1064
    assert len(data) == 4
1065
    assert data[0]['disabled'] is False
1066
    assert data[1]['disabled'] is False
1067
    assert data[2]['disabled'] is False
1068
    assert data[3]['disabled'] is False
1069

  
1070
    resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug, params={'events': 'all'})
1071
    data = resp.json['data']
1072
    assert len(data) == 4  # no date_start, not possible to compute recurring events in past
1073
    assert data[0]['disabled'] is False
1074
    assert data[1]['disabled'] is False
1075
    assert data[2]['disabled'] is False
1076
    assert data[3]['disabled'] is False
1077

  
1078
    resp = app.get(
1079
        '/api/agenda/%s/datetimes/' % agenda.slug,
1080
        params={'events': 'all', 'date_start': localtime(now() - datetime.timedelta(days=6 * 7))},
1081
    )
1082
    data = resp.json['data']
1083
    assert len(data) == 8
1084
    assert data[0]['disabled'] is False
1085
    assert data[1]['disabled'] is False
1086
    assert data[2]['disabled'] is False
1087
    assert data[3]['disabled'] is False
1088
    assert data[4]['disabled'] is False
1089
    assert data[5]['disabled'] is False
1090
    assert data[6]['disabled'] is False
1091
    assert data[7]['disabled'] is False
1092

  
1093
    resp = app.get(
1094
        '/api/agenda/%s/datetimes/' % agenda.slug,
1095
        params={
1096
            'events': 'all',
1097
            'date_start': localtime(now() - datetime.timedelta(days=6 * 7)),
1098
            'date_end': localtime(now() + datetime.timedelta(days=6 * 7)),
1099
        },
1100
    )
1101
    data = resp.json['data']
1102
    assert len(data) == 8
1103
    assert data[0]['disabled'] is False
1104
    assert data[1]['disabled'] is False
1105
    assert data[2]['disabled'] is False
1106
    assert data[3]['disabled'] is False
1107
    assert data[4]['disabled'] is False
1108
    assert data[5]['disabled'] is False
1109
    assert data[6]['disabled'] is False
1110
    assert data[7]['disabled'] is False
1111

  
1112
    # check exclude_user_external_id
1113
    first_recurrence = event.get_or_create_event_recurrence(event.start_datetime)
1114
    Booking.objects.create(event=first_recurrence, user_external_id='42')
1115
    resp = app.get(
1116
        '/api/agenda/%s/datetimes/' % agenda.slug,
1117
        params={
1118
            'events': 'past',
1119
            'exclude_user_external_id': '42',
1120
            'date_start': localtime(now() - datetime.timedelta(days=6 * 7)),
1121
        },
1122
    )
1123
    data = resp.json['data']
1124
    assert len(data) == 4
1125
    assert data[0]['disabled'] is True
1126
    assert data[1]['disabled'] is False
1127
    assert data[2]['disabled'] is False
1128
    assert data[3]['disabled'] is False
1129

  
1130
    # check canceled
1131
    first_recurrence.cancel()
1132
    resp = app.get(
1133
        '/api/agenda/%s/datetimes/' % agenda.slug,
1134
        params={'events': 'all', 'date_start': localtime(now() - datetime.timedelta(days=6 * 7))},
1135
    )
1136
    data = resp.json['data']
1137
    assert len(data) == 7
630
-