Projet

Général

Profil

0003-api-bypass_delays-parameter-for-event-fillslot-endpo.patch

Lauréline Guérin, 29 octobre 2021 10:42

Télécharger (9,85 ko)

Voir les différences:

Subject: [PATCH 3/3] api: bypass_delays parameter for event fillslot endpoints
 (#57961)

 chrono/agendas/models.py   |  16 +++--
 chrono/api/serializers.py  |   3 +-
 chrono/api/views.py        |   3 +-
 tests/api/test_fillslot.py | 131 +++++++++++++++++++++++++++++++++++++
 4 files changed, 146 insertions(+), 7 deletions(-)
chrono/agendas/models.py
1451 1451
        self.checked = True
1452 1452
        self.save(update_fields=['checked'])
1453 1453

  
1454
    def in_bookable_period(self):
1454
    def in_bookable_period(self, bypass_delays=False):
1455 1455
        if self.publication_datetime and now() < self.publication_datetime:
1456 1456
            return False
1457
        if self.agenda.maximal_booking_delay and self.start_datetime > self.agenda.max_booking_datetime:
1457
        if (
1458
            not bypass_delays
1459
            and self.agenda.maximal_booking_delay
1460
            and self.start_datetime > self.agenda.max_booking_datetime
1461
        ):
1458 1462
            return False
1459 1463
        if self.recurrence_days is not None:
1460 1464
            # bookable recurrences probably exist
1461 1465
            return True
1462
        if self.agenda.minimal_booking_delay and self.start_datetime < self.agenda.min_booking_datetime:
1466
        if (
1467
            not bypass_delays
1468
            and self.agenda.minimal_booking_delay
1469
            and self.start_datetime < self.agenda.min_booking_datetime
1470
        ):
1463 1471
            return False
1464 1472
        if self.start_datetime < now():
1465
            # past the event date, we may want in the future to allow for some
1466
            # extra late booking but it's forbidden for now.
1467 1473
            return False
1468 1474
        return True
1469 1475

  
chrono/api/serializers.py
33 33
    user_phone_number = serializers.CharField(max_length=16, allow_blank=True)
34 34
    exclude_user = serializers.BooleanField(default=False)
35 35
    events = serializers.CharField(max_length=16, allow_blank=True)
36
    bypass_delays = serializers.BooleanField(default=False)
36 37
    form_url = serializers.CharField(max_length=250, allow_blank=True)
37 38
    backoffice_url = serializers.URLField(allow_blank=True)
38 39
    cancel_callback_url = serializers.URLField(allow_blank=True)
......
57 58

  
58 59
    def validate(self, attrs):
59 60
        super().validate(attrs)
60
        if not 'slots' in attrs:
61
        if 'slots' not in attrs:
61 62
            raise serializers.ValidationError({'slots': _('This field is required.')})
62 63
        if not attrs.get('user_external_id'):
63 64
            raise serializers.ValidationError({'user_external_id': _('This field is required.')})
chrono/api/views.py
598 598
    book_events = payload.get('events') or request.query_params.get('events') or 'future'
599 599
    book_past = book_events in ['all', 'past']
600 600
    book_future = book_events in ['all', 'future']
601
    bypass_delays = payload.get('bypass_delays')
601 602

  
602 603
    # convert event recurrence identifiers to real event slugs
603 604
    for i, slot in enumerate(slots.copy()):
......
613 614

  
614 615
    for event in events:
615 616
        if event.start_datetime >= now():
616
            if not book_future or not event.in_bookable_period():
617
            if not book_future or not event.in_bookable_period(bypass_delays=bypass_delays):
617 618
                raise APIError(_('event %s is not bookable') % event.slug, err_class='event not bookable')
618 619
        else:
619 620
            if not book_past:
tests/api/test_fillslot.py
168 168
    resp = app.post('/api/agenda/0/fillslot/%s/' % event.id, status=404)
169 169

  
170 170

  
171
def test_booking_api_check_delays(app, user):
172
    agenda = Agenda.objects.create(
173
        label='Foo bar', kind='events', minimal_booking_delay=0, maximal_booking_delay=7
174
    )
175
    event = Event.objects.create(
176
        slug='event-slug',
177
        start_datetime=localtime() + datetime.timedelta(days=5),
178
        places=5,
179
        agenda=agenda,
180
    )
181

  
182
    app.authorization = ('Basic', ('john.doe', 'password'))
183
    resp = app.post('/api/agenda/%s/fillslot/%s/' % (agenda.slug, event.slug))
184
    assert resp.json['err'] == 0
185

  
186
    # test minimal_booking_delay
187
    agenda.minimal_booking_delay = 6
188
    agenda.save()
189
    resp = app.post('/api/agenda/%s/fillslot/%s/' % (agenda.slug, event.slug))
190
    assert resp.json['err'] == 1
191
    assert resp.json['err_class'] == 'event not bookable'
192
    agenda.save()
193
    resp = app.post('/api/agenda/%s/fillslot/%s/' % (agenda.slug, event.slug), params={'bypass_delays': True})
194
    assert resp.json['err'] == 0
195

  
196
    # test maximal_booking_delay
197
    agenda.minimal_booking_delay = 0
198
    agenda.maximal_booking_delay = 3
199
    agenda.save()
200
    resp = app.post('/api/agenda/%s/fillslot/%s/' % (agenda.slug, event.slug))
201
    assert resp.json['err'] == 1
202
    assert resp.json['err_class'] == 'event not bookable'
203
    agenda.save()
204
    resp = app.post('/api/agenda/%s/fillslot/%s/' % (agenda.slug, event.slug), params={'bypass_delays': True})
205
    assert resp.json['err'] == 0
206

  
207

  
171 208
@pytest.mark.freeze_time('2021-02-23')
172 209
def test_booking_api_exclude_slots(app, user):
173 210
    agenda = Agenda.objects.create(
......
2398 2435
    resp = app.post('/api/agenda/0/events/fillslots/', status=404)
2399 2436

  
2400 2437

  
2438
def test_api_events_fillslots_check_delays(app, user):
2439
    agenda = Agenda.objects.create(
2440
        label='Foo bar', kind='events', minimal_booking_delay=0, maximal_booking_delay=7
2441
    )
2442
    Event.objects.create(
2443
        slug='event-slug',
2444
        start_datetime=localtime() + datetime.timedelta(days=5),
2445
        places=5,
2446
        agenda=agenda,
2447
    )
2448

  
2449
    app.authorization = ('Basic', ('john.doe', 'password'))
2450
    fillslots_url = '/api/agenda/%s/events/fillslots/' % agenda.slug
2451
    resp = app.post(fillslots_url, params={'user_external_id': 'user_id', 'slots': 'event-slug'})
2452
    assert resp.json['err'] == 0
2453

  
2454
    # test minimal_booking_delay
2455
    agenda.minimal_booking_delay = 6
2456
    agenda.save()
2457
    resp = app.post(fillslots_url, params={'user_external_id': 'user_id', 'slots': 'event-slug'})
2458
    assert resp.json['err'] == 1
2459
    assert resp.json['err_class'] == 'event not bookable'
2460
    agenda.save()
2461
    resp = app.post(
2462
        fillslots_url, params={'user_external_id': 'user_id', 'slots': 'event-slug', 'bypass_delays': True}
2463
    )
2464
    assert resp.json['err'] == 0
2465

  
2466
    # test maximal_booking_delay
2467
    agenda.minimal_booking_delay = 0
2468
    agenda.maximal_booking_delay = 3
2469
    agenda.save()
2470
    resp = app.post(fillslots_url, params={'user_external_id': 'user_id', 'slots': 'event-slug'})
2471
    assert resp.json['err'] == 1
2472
    assert resp.json['err_class'] == 'event not bookable'
2473
    agenda.save()
2474
    resp = app.post(
2475
        fillslots_url, params={'user_external_id': 'user_id', 'slots': 'event-slug', 'bypass_delays': True}
2476
    )
2477
    assert resp.json['err'] == 0
2478

  
2479

  
2401 2480
@pytest.mark.freeze_time('2021-09-06 12:00')
2402 2481
def test_api_events_fillslots_past_event(app, user):
2403 2482
    app.authorization = ('Basic', ('john.doe', 'password'))
......
2512 2591
    )
2513 2592

  
2514 2593

  
2594
def test_api_events_fillslots_multiple_agendas_check_delays(app, user):
2595
    agenda = Agenda.objects.create(
2596
        label='Foo bar', kind='events', minimal_booking_delay=0, maximal_booking_delay=7
2597
    )
2598
    Event.objects.create(
2599
        slug='event-slug',
2600
        start_datetime=localtime() + datetime.timedelta(days=5),
2601
        places=5,
2602
        agenda=agenda,
2603
    )
2604

  
2605
    app.authorization = ('Basic', ('john.doe', 'password'))
2606
    resp = app.post(
2607
        '/api/agendas/events/fillslots/?agendas=foo-bar',
2608
        params={'user_external_id': 'user_id', 'slots': 'foo-bar@event-slug'},
2609
    )
2610
    assert resp.json['err'] == 0
2611

  
2612
    # test minimal_booking_delay
2613
    agenda.minimal_booking_delay = 6
2614
    agenda.save()
2615
    resp = app.post(
2616
        '/api/agendas/events/fillslots/?agendas=foo-bar',
2617
        params={'user_external_id': 'user_id', 'slots': 'foo-bar@event-slug'},
2618
    )
2619
    assert resp.json['err'] == 1
2620
    assert resp.json['err_class'] == 'event not bookable'
2621
    agenda.save()
2622
    resp = app.post(
2623
        '/api/agendas/events/fillslots/?agendas=foo-bar',
2624
        params={'user_external_id': 'user_id', 'slots': 'foo-bar@event-slug', 'bypass_delays': True},
2625
    )
2626
    assert resp.json['err'] == 0
2627

  
2628
    # test maximal_booking_delay
2629
    agenda.minimal_booking_delay = 0
2630
    agenda.maximal_booking_delay = 3
2631
    agenda.save()
2632
    resp = app.post(
2633
        '/api/agendas/events/fillslots/?agendas=foo-bar',
2634
        params={'user_external_id': 'user_id', 'slots': 'foo-bar@event-slug'},
2635
    )
2636
    assert resp.json['err'] == 1
2637
    assert resp.json['err_class'] == 'event not bookable'
2638
    agenda.save()
2639
    resp = app.post(
2640
        '/api/agendas/events/fillslots/?agendas=foo-bar',
2641
        params={'user_external_id': 'user_id', 'slots': 'foo-bar@event-slug', 'bypass_delays': True},
2642
    )
2643
    assert resp.json['err'] == 0
2644

  
2645

  
2515 2646
def test_url_translation(app, some_data, user):
2516 2647
    app.authorization = ('Basic', ('john.doe', 'password'))
2517 2648
    agenda_id = Agenda.objects.filter(label='Foo bar')[0].id
2518
-