Projet

Général

Profil

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

Nicolas Roche, 19 janvier 2021 18:50

Télécharger (13,8 ko)

Voir les différences:

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

 chrono/api/views.py |  65 +++++++++++---
 tests/test_api.py   | 209 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 261 insertions(+), 13 deletions(-)
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': bool(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))
......
497 515

  
498 516
        if 'date_end' in request.GET:
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
        response = {'data': [get_event_detail(request, x, agenda=agenda) for x in entries]}
523
        response = {
524
            'data': [get_event_detail(request, x, agenda=agenda) for x in entries],
525
            'meta': get_events_meta_detail(entries),
526
        }
506 527
        return Response(response)
507 528

  
508 529

  
509 530
datetimes = Datetimes.as_view()
510 531

  
511 532

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

  
640
        bookable_datetimes_number_total = 0
641
        bookable_datetimes_number_available = 0
642
        bookable_datetimes_first = None
643
        data = []
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

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

  
619 663
        response = {
620
            'data': [
621
                {
622
                    'id': slot_id,
623
                    'datetime': format_response_datetime(slot.start_datetime),
624
                    'text': date_format(slot.start_datetime, format='DATETIME_FORMAT'),
625
                    'disabled': bool(slot.full),
626
                    'api': {'fillslot_url': fillslot_url.replace(fake_event_identifier, slot_id)},
627
                }
628
                for slot in generator_of_unique_slots
629
                # we do not have the := operator, so we do that
630
                for slot_id in [make_id(slot.start_datetime, meeting_type)]
631
            ]
664
            'data': data,
665
            'meta': {
666
                'no_bookable_datetimes': bool(bookable_datetimes_number_available == 0),
667
                'bookable_datetimes_number_total': bookable_datetimes_number_total,
668
                'bookable_datetimes_number_available': bookable_datetimes_number_available,
669
                'bookable_datetimes_first': bookable_datetimes_first,
670
            },
632 671
        }
633 672
        return Response(response)
634 673

  
635 674

  
636 675
meeting_datetimes = MeetingDatetimes.as_view()
637 676

  
638 677

  
639 678
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
    )
4876
    meeting_type = MeetingType(agenda=meetings_agenda, label='Blah', duration=30)
4877
    meeting_type.save()
4878

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

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

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

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

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

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

  
4950

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

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

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

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

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

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

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