Projet

Général

Profil

0002-api-add-a-meta-dict-on-datetimes-endpoints-50278.patch

Nicolas Roche, 19 janvier 2021 17:56

Télécharger (13 ko)

Voir les différences:

Subject: [PATCH 2/2] api: add a meta dict on datetimes endpoints (#50278)

 chrono/api/views.py |  34 +++++++
 tests/test_api.py   | 210 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 244 insertions(+)
chrono/api/views.py
393 393
                    kwargs={'agenda_identifier': agenda.slug, 'event_identifier': event.slug},
394 394
                )
395 395
            ),
396 396
        },
397 397
        'places': get_event_places(event),
398 398
    }
399 399

  
400 400

  
401
def get_events_meta_detail(events):
402
    bookable_datetimes_number_total = 0
403
    bookable_datetimes_number_available = 0
404
    bookable_datetimes_first = None
405
    for event in events:
406
        bookable_datetimes_number_total += 1
407
        if not bool(event.full):
408
            bookable_datetimes_number_available += 1
409
            if not bookable_datetimes_first:
410
                bookable_datetimes_first = format_response_datetime(event.start_datetime)
411
    return {
412
        'no_bookable_datetimes': bookable_datetimes_number_available == 0,
413
        'bookable_datetimes_number_total': bookable_datetimes_number_total,
414
        'bookable_datetimes_number_available': bookable_datetimes_number_available,
415
        'bookable_datetimes_first': bookable_datetimes_first
416
    }
417

  
418

  
401 419
def get_resources_from_request(request, agenda):
402 420
    if agenda.kind != 'meetings' or 'resources' not in request.GET:
403 421
        return []
404 422
    resources_slugs = [s for s in request.GET['resources'].split(',') if s]
405 423
    resources = list(agenda.resources.filter(slug__in=resources_slugs))
406 424
    if len(resources) != len(resources_slugs):
407 425
        unknown_slugs = set(resources_slugs) - set([r.slug for r in resources])
408 426
        unknown_slugs = sorted(list(unknown_slugs))
......
499 517
            entries = entries.filter(
500 518
                start_datetime__lt=make_aware(
501 519
                    datetime.datetime.combine(parse_date(request.GET['date_end']), datetime.time(0, 0))
502 520
                )
503 521
            )
504 522

  
505 523
        response = {
506 524
            'data': [get_event_detail(request, x, agenda=agenda) for x in entries],
525
            'meta': get_events_meta_detail(entries),
507 526
        }
508 527
        return Response(response)
509 528

  
510 529

  
511 530
datetimes = Datetimes.as_view()
512 531

  
513 532

  
514 533
class MeetingDatetimes(APIView):
......
613 632
            It MUST be a garanty of SharedTimePeriod.get_time_slots(),
614 633
            !!!
615 634
            """
616 635
            return '%s:%s' % (
617 636
                meeting_type.slug,
618 637
                start_datetime.strftime('%Y-%m-%d-%H%M'),
619 638
            )
620 639

  
640
        bookable_datetimes_number_total = 0
641
        bookable_datetimes_number_available = 0
642
        bookable_datetimes_first = None
621 643
        data = []
622 644
        for slot in generator_of_unique_slots:
645
            bookable_datetimes_number_total += 1
646
            if not bool(slot.full):
647
                bookable_datetimes_number_available += 1
648
                if not bookable_datetimes_first:
649
                    bookable_datetimes_first = format_response_datetime(slot.start_datetime)
650

  
623 651
            # we do not have the := operator, so we do that
624 652
            for slot_id in [make_id(slot.start_datetime, meeting_type)]:
625 653
                data.append({
626 654
                    'id': slot_id,
627 655
                    'datetime': format_response_datetime(slot.start_datetime),
628 656
                    'text': date_format(slot.start_datetime, format='DATETIME_FORMAT'),
629 657
                    'disabled': bool(slot.full),
630 658
                    'api': {'fillslot_url': fillslot_url.replace(fake_event_identifier, slot_id)},
631 659
                })
632 660

  
633 661
        response = {
634 662
            'data': data,
663
            'meta': {
664
                'no_bookable_datetimes': bookable_datetimes_number_available == 0,
665
                'bookable_datetimes_number_total': bookable_datetimes_number_total,
666
                'bookable_datetimes_number_available': bookable_datetimes_number_available,
667
                'bookable_datetimes_first': bookable_datetimes_first,
668
            },
635 669
        }
636 670
        return Response(response)
637 671

  
638 672

  
639 673
meeting_datetimes = MeetingDatetimes.as_view()
640 674

  
641 675

  
642 676
class MeetingList(APIView):
tests/test_api.py
4812 4812
    agenda_foo.save()
4813 4813
    resp = app.get(foo_api_url, params=params)
4814 4814
    assert len(resp.json['data']) == 16
4815 4815
    # also on virtual agenda
4816 4816
    virtual_agenda.maximal_booking_delay = 5
4817 4817
    virtual_agenda.save()
4818 4818
    resp = app.get(virtual_api_url, params=params)
4819 4819
    assert len(resp.json['data']) == 16
4820

  
4821

  
4822
def test_datetimes_api_meta(app, some_data):
4823
    agenda = Agenda.objects.filter(label=u'Foo bar')[0]
4824
    events = Event.objects.filter(agenda_id=agenda.id).exclude(start_datetime__lt=now())
4825
    assert len(events) == 3
4826
    api_url = '/api/agenda/%s/datetimes/' % agenda.slug
4827
    resp = app.get(api_url)
4828
    assert len(resp.json['data']) == 3
4829
    assert resp.json['meta'] == {
4830
        'no_bookable_datetimes': False,
4831
        'bookable_datetimes_number_total': 3,
4832
        'bookable_datetimes_number_available': 3,
4833
        'bookable_datetimes_first': '2017-05-21 17:00:00'
4834
    }
4835

  
4836
    def simulate_booking(event, nb_places):
4837
        for i in range(nb_places):
4838
            Booking(event=event).save()
4839

  
4840
    simulate_booking(events[0], 10)
4841
    resp = app.get(api_url)
4842
    assert len(resp.json['data']) == 3
4843
    assert resp.json['meta'] == {
4844
        'no_bookable_datetimes': False,
4845
        'bookable_datetimes_number_total': 3,
4846
        'bookable_datetimes_number_available': 3,
4847
        'bookable_datetimes_first': '2017-05-21 17:00:00',
4848
    }
4849

  
4850
    simulate_booking(events[0], 10)
4851
    resp = app.get(api_url)
4852
    assert len(resp.json['data']) == 3
4853
    assert resp.json['meta'] == {
4854
        'no_bookable_datetimes': False,
4855
        'bookable_datetimes_number_total': 3,
4856
        'bookable_datetimes_number_available': 2,
4857
        'bookable_datetimes_first': '2017-05-22 17:00:00',
4858
    }
4859

  
4860
    simulate_booking(events[1], 20)
4861
    simulate_booking(events[2], 20)
4862
    resp = app.get(api_url)
4863
    assert len(resp.json['data']) == 3
4864
    assert resp.json['meta'] == {
4865
        'no_bookable_datetimes': True,
4866
        'bookable_datetimes_number_total': 3,
4867
        'bookable_datetimes_number_available': 0,
4868
        'bookable_datetimes_first': None,
4869
    }
4870

  
4871

  
4872
def test_datetimes_api_meetings_agenda_meta(app, mock_now):
4873
    meetings_agenda = Agenda.objects.create(
4874
        label=u'Foo bar Meeting', kind='meetings', maximal_booking_delay=3)
4875
    meeting_type = MeetingType(agenda=meetings_agenda, label='Blah', duration=30)
4876
    meeting_type.save()
4877

  
4878
    desk1 = Desk.objects.create(agenda=meetings_agenda, label='Desk 1')
4879
    desk2 = Desk.objects.create(agenda=meetings_agenda, label='Desk 2')
4880
    test_1st_weekday = (localtime(now()).weekday() + 2) % 7
4881
    for desk in desk1, desk2:
4882
        TimePeriod(
4883
            weekday=test_1st_weekday,
4884
            start_time=datetime.time(10, 0),
4885
            end_time=datetime.time(12, 0),
4886
            desk=desk).save()
4887

  
4888
    meeting_type = MeetingType.objects.get(agenda=meetings_agenda)
4889
    api_url = '/api/agenda/%s/meetings/%s/datetimes/' % (meeting_type.agenda.slug, meeting_type.slug)
4890
    resp = app.get(api_url)
4891
    assert len(resp.json['data']) == 4
4892
    assert resp.json['data'][2]['disabled'] is False
4893
    assert resp.json['meta'] == {
4894
        'no_bookable_datetimes': False,
4895
        'bookable_datetimes_number_total': 4,
4896
        'bookable_datetimes_number_available': 4,
4897
        'bookable_datetimes_first': '2017-05-22 10:00:00',
4898
    }
4899

  
4900
    def simulate_booking(slot, desk):
4901
        dt = datetime.datetime.strptime(slot['id'].split(':')[1], '%Y-%m-%d-%H%M')
4902
        ev = Event(
4903
            agenda=meetings_agenda,
4904
            meeting_type=meeting_type,
4905
            places=1,
4906
            full=False,
4907
            start_datetime=make_aware(dt),
4908
            desk=desk,
4909
        )
4910
        ev.save()
4911
        booking = Booking(event=ev)
4912
        booking.save()
4913

  
4914
    simulate_booking(resp.json['data'][0], desk1)
4915
    resp = app.get(api_url)
4916
    assert len(resp.json['data']) == 4
4917
    assert resp.json['data'][0]['disabled'] is False
4918
    assert resp.json['meta'] == {
4919
        'no_bookable_datetimes': False,
4920
        'bookable_datetimes_number_total': 4,
4921
        'bookable_datetimes_number_available': 4,
4922
        'bookable_datetimes_first': '2017-05-22 10:00:00',
4923
    }
4924

  
4925
    simulate_booking(resp.json['data'][0], desk2)
4926
    resp = app.get(api_url)
4927
    assert len(resp.json['data']) == 4
4928
    assert resp.json['data'][0]['disabled'] is True
4929
    assert resp.json['meta'] == {
4930
        'no_bookable_datetimes': False,
4931
        'bookable_datetimes_number_total': 4,
4932
        'bookable_datetimes_number_available': 3,
4933
        'bookable_datetimes_first': '2017-05-22 10:30:00',
4934
    }
4935

  
4936
    for idx in range(1,4):
4937
        simulate_booking(resp.json['data'][idx], desk1)
4938
        simulate_booking(resp.json['data'][idx], desk2)
4939
    resp = app.get(api_url)
4940
    assert len(resp.json['data']) == 4
4941
    assert resp.json['meta'] == {
4942
        'no_bookable_datetimes': True,
4943
        'bookable_datetimes_number_total': 4,
4944
        'bookable_datetimes_number_available': 0,
4945
        'bookable_datetimes_first': None,
4946
    }
4947

  
4948

  
4949
def test_datetimes_api_virtual_meetings_agenda_meta(app, virtual_meetings_agenda):
4950
    meetings_agenda1 = Agenda.objects.create(
4951
        label=u'Foo Meeting', kind='meetings', maximal_booking_delay=3)
4952
    meetings_agenda2 = Agenda.objects.create(
4953
        label=u'Bar Meeting', kind='meetings', maximal_booking_delay=3)
4954
    virtual_agenda = Agenda.objects.create(
4955
        label=u'Agenda Virtual', kind='virtual', maximal_booking_delay=3)
4956
    VirtualMember.objects.create(virtual_agenda=virtual_agenda, real_agenda=meetings_agenda1)
4957
    VirtualMember.objects.create(virtual_agenda=virtual_agenda, real_agenda=meetings_agenda2)
4958
    desk1 = Desk.objects.create(agenda=meetings_agenda1, label='Desk 1')
4959
    desk2 = Desk.objects.create(agenda=meetings_agenda2, label='Desk 2')
4960

  
4961
    test_1st_weekday = (localtime(now()).weekday() + 2) % 7
4962
    for agenda, desk in zip((meetings_agenda1, meetings_agenda2), (desk1, desk2)):
4963
        meeting_type = MeetingType.objects.create(agenda=agenda, label='Blah', duration=30)
4964
        TimePeriod(
4965
            weekday=test_1st_weekday,
4966
            start_time=datetime.time(10, 0),
4967
            end_time=datetime.time(12, 0),
4968
            desk=desk).save()
4969

  
4970
    virt_meeting_type = virtual_agenda.iter_meetingtypes()[0]
4971
    api_url = '/api/agenda/%s/meetings/%s/datetimes/' % (
4972
        virtual_agenda.slug, virt_meeting_type.slug)
4973
    resp = app.get(api_url)
4974
    assert len(resp.json['data']) == 4
4975
    assert resp.json['data'][2]['disabled'] is False
4976
    assert resp.json['meta'] == {
4977
        'no_bookable_datetimes': False,
4978
        'bookable_datetimes_number_total': 4,
4979
        'bookable_datetimes_number_available': 4,
4980
        'bookable_datetimes_first': '2017-05-22 10:00:00',
4981
    }
4982

  
4983
    def simulate_booking(slot, agenda, desk):
4984
        dt = datetime.datetime.strptime(slot['id'].split(':')[1], '%Y-%m-%d-%H%M')
4985
        ev = Event(
4986
            agenda=agenda,
4987
            meeting_type=meeting_type,
4988
            places=1,
4989
            full=False,
4990
            start_datetime=make_aware(dt),
4991
            desk=desk,
4992
        )
4993
        ev.save()
4994
        booking = Booking(event=ev)
4995
        booking.save()
4996

  
4997
    simulate_booking(resp.json['data'][0], meetings_agenda1, desk1)
4998
    resp = app.get(api_url)
4999
    assert len(resp.json['data']) == 4
5000
    assert resp.json['data'][0]['disabled'] is False
5001
    assert resp.json['meta'] == {
5002
        'no_bookable_datetimes': False,
5003
        'bookable_datetimes_number_total': 4,
5004
        'bookable_datetimes_number_available': 4,
5005
        'bookable_datetimes_first': '2017-05-22 10:00:00',
5006
    }
5007

  
5008
    simulate_booking(resp.json['data'][0], meetings_agenda2, desk2)
5009
    resp = app.get(api_url)
5010
    assert len(resp.json['data']) == 4
5011
    assert resp.json['data'][0]['disabled'] is True
5012
    assert resp.json['meta'] == {
5013
        'no_bookable_datetimes': False,
5014
        'bookable_datetimes_number_total': 4,
5015
        'bookable_datetimes_number_available': 3,
5016
        'bookable_datetimes_first': '2017-05-22 10:30:00',
5017
    }
5018

  
5019
    for idx in range(1,4):
5020
        simulate_booking(resp.json['data'][idx], meetings_agenda1, desk1)
5021
        simulate_booking(resp.json['data'][idx], meetings_agenda2, desk2)
5022
    resp = app.get(api_url)
5023
    assert len(resp.json['data']) == 4
5024
    assert resp.json['meta'] == {
5025
        'no_bookable_datetimes': True,
5026
        'bookable_datetimes_number_total': 4,
5027
        'bookable_datetimes_number_available': 0,
5028
        'bookable_datetimes_first': None,
5029
    }
4820
-