Projet

Général

Profil

0002-api-check-publication_date-in-datetimes-fillslots-ap.patch

Lauréline Guérin, 13 mai 2020 18:26

Télécharger (17,4 ko)

Voir les différences:

Subject: [PATCH 2/2] api: check publication_date in datetimes & fillslots api
 (#40728)

 chrono/agendas/models.py |   2 +
 chrono/api/views.py      |  12 +++++
 tests/test_agendas.py    |  52 +++++++++++---------
 tests/test_api.py        | 103 +++++++++++++++++++++++++--------------
 4 files changed, 109 insertions(+), 60 deletions(-)
chrono/agendas/models.py
551 551
        )
552 552

  
553 553
    def in_bookable_period(self):
554
        if self.publication_date and localtime(now()).date() < self.publication_date:
555
            return False
554 556
        if (
555 557
            localtime(now()).date()
556 558
            > localtime(
chrono/api/views.py
18 18
import datetime
19 19

  
20 20
from django.db import transaction
21
from django.db.models import Q
21 22
from django.http import Http404, HttpResponse
22 23
from django.shortcuts import get_object_or_404
23 24
from django.urls import reverse
......
256 257
        # we never want to allow booking for past events.
257 258
        entries = entries.filter(start_datetime__gte=localtime(now()))
258 259

  
260
        # exclude non published events
261
        entries = entries.filter(
262
            Q(publication_date__isnull=True) | Q(publication_date__lte=localtime(now()).date())
263
        )
264

  
259 265
        if agenda.minimal_booking_delay:
260 266
            entries = entries.filter(
261 267
                start_datetime__gte=localtime(
......
698 704
            except ValueError:
699 705
                events = Event.objects.filter(slug__in=slots).order_by('start_datetime')
700 706

  
707
            for event in events:
708
                if not event.in_bookable_period():
709
                    return Response(
710
                        {'err': 1, 'err_class': 'event not bookable', 'err_desc': _('event not bookable')}
711
                    )
712

  
701 713
            if not events.count():
702 714
                return Response(
703 715
                    {
tests/test_agendas.py
142 142
    assert Event.objects.all()[0].booked_places == 0
143 143

  
144 144

  
145
def test_event_bookable_period():
146
    agenda = Agenda(label=u'Foo bar')
147
    agenda.save()
148
    event = Event(start_datetime=now() + datetime.timedelta(days=10), places=10, agenda=agenda)
149
    event.save()
150
    assert event.in_bookable_period() is True
151
    agenda.minimal_booking_delay = 20
152
    assert event.in_bookable_period() is False
153
    agenda.minimal_booking_delay = 1
154
    agenda.maximal_booking_delay = 5
155
    assert event.in_bookable_period() is False
156
    agenda.maximal_booking_delay = 20
157
    assert event.in_bookable_period() is True
158

  
159
    # special case for events that happens today
160
    agenda.minimal_booking_delay = 0
161
    agenda.save()
162
    event = Event(start_datetime=now() + datetime.timedelta(minutes=10), places=10, agenda=agenda)
163
    event.save()
164
    assert event.in_bookable_period() is True
165

  
166
    event = Event(start_datetime=now() - datetime.timedelta(minutes=10), places=10, agenda=agenda)
167
    event.save()
168
    assert event.in_bookable_period() is False
145
@pytest.mark.parametrize(
146
    'start_days, start_minutes, min_delay, max_delay, pub_days, expected',
147
    [
148
        # no delay
149
        (10, 0, 0, 0, None, True),
150
        # test publication_date
151
        (10, 0, 0, 0, 1, False),
152
        (10, 0, 0, 0, 0, True),
153
        # test min and max delays
154
        (10, 0, 20, 0, None, False),
155
        (10, 0, 1, 5, None, False),
156
        (10, 0, 1, 20, None, True),
157
        # special case for events that happens today
158
        (0, 10, 0, 20, None, True),
159
        (0, -10, 0, 20, None, False),
160
    ],
161
)
162
def test_event_bookable_period(start_days, start_minutes, min_delay, max_delay, pub_days, expected):
163
    agenda = Agenda.objects.create(
164
        label=u'Foo bar', minimal_booking_delay=min_delay, maximal_booking_delay=max_delay
165
    )
166
    event = Event.objects.create(
167
        start_datetime=now() + datetime.timedelta(days=start_days, minutes=start_minutes),
168
        publication_date=(now().date() + datetime.timedelta(days=pub_days)) if pub_days else None,
169
        places=10,
170
        agenda=agenda,
171
    )
172
    assert event.in_bookable_period() == expected
169 173

  
170 174

  
171 175
def test_meeting_type_slugs():
tests/test_api.py
1 1
# -*- coding: utf-8 -*-
2 2

  
3 3
import datetime
4
import mock
4 5
import urllib.parse as urlparse
5 6
import pytest
6 7
import sys
......
269 270
    check_bookability(resp.json['data'])
270 271
    assert resp.json['data'][0]['description'] is None
271 272

  
273
    agenda.event_set.update(publication_date=now().date() + datetime.timedelta(days=1))
274
    resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
275
    assert len(resp.json['data']) == 0
276
    check_bookability(resp.json['data'])
277

  
278
    agenda.event_set.update(publication_date=now().date())
279
    resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
280
    assert len(resp.json['data']) == 2
281
    check_bookability(resp.json['data'])
282

  
272 283
    # add description, URL and pricing to events
273 284
    for i, event in enumerate(agenda.event_set.all()):
274 285
        event.description = 'Description %s' % i
......
745 756
    resp = app.post('/api/agenda/foobar/fillslots/', status=404)
746 757
    resp = app.post('/api/agenda/0/fillslots/', status=404)
747 758

  
759
    # check bookable period
760
    with mock.patch('chrono.agendas.models.Event.in_bookable_period') as in_bookable_period:
761
        in_bookable_period.return_value = True
762
        resp = app.post_json(
763
            '/api/agenda/%s/fillslots/' % agenda.id,
764
            params={'slots': events_ids, 'label': 'l', 'user_name': 'u', 'backoffice_url': '', 'foo': 'bar'},
765
        )
766
        assert resp.json['err'] == 0
767
        in_bookable_period.return_value = False
768
        resp = app.post_json(
769
            '/api/agenda/%s/fillslots/' % agenda.id,
770
            params={'slots': events_ids, 'label': 'l', 'user_name': 'u', 'backoffice_url': '', 'foo': 'bar'},
771
        )
772
        assert resp.json['err'] == 1
773
        assert resp.json['reason'] == 'event not bookable'  # legacy
774
        assert resp.json['err_class'] == 'event not bookable'
775
        assert resp.json['err_desc'] == 'event not bookable'
776

  
748 777

  
749 778
def test_booking_api_fillslots_slots_string_param(app, some_data, user):
750 779
    agenda = Agenda.objects.filter(label=u'Foo bar')[0]
......
957 986

  
958 987

  
959 988
def test_booking_api_with_data(app, some_data, user):
960
    agenda_id = Agenda.objects.filter(label=u'Foo bar')[0].id
961
    event = Event.objects.filter(agenda_id=agenda_id)[0]
989
    agenda = Agenda.objects.filter(label=u'Foo bar')[0]
990
    event = [x for x in Event.objects.filter(agenda=agenda) if x.in_bookable_period()][0]
962 991

  
963 992
    app.authorization = ('Basic', ('john.doe', 'password'))
964
    resp = app.post_json('/api/agenda/%s/fillslot/%s/' % (agenda_id, event.id), params={'hello': 'world'})
993
    app.post_json('/api/agenda/%s/fillslot/%s/' % (agenda.id, event.id), params={'hello': 'world'})
965 994
    assert Booking.objects.count() == 1
966 995
    assert Booking.objects.all()[0].extra_data == {'hello': 'world'}
967 996

  
968 997

  
969 998
def test_booking_api_available(app, some_data, meetings_agenda, user):
970 999
    agenda = Agenda.objects.filter(label=u'Foo bar')[0]
971
    event = Event.objects.filter(agenda=agenda)[0]
1000
    event = [x for x in Event.objects.filter(agenda=agenda) if x.in_bookable_period()][0]
972 1001

  
973 1002
    app.authorization = ('Basic', ('john.doe', 'password'))
974 1003
    resp = app.post_json('/api/agenda/%s/fillslot/%s/' % (agenda.pk, event.pk))
975 1004
    assert resp.json['err'] == 0
976
    assert resp.json['places']['total'] == 10
977
    assert resp.json['places']['available'] == 9
1005
    assert resp.json['places']['total'] == 20
1006
    assert resp.json['places']['available'] == 19
978 1007
    assert resp.json['places']['reserved'] == 1
979 1008
    assert resp.json['places']['full'] is False
980 1009
    assert 'waiting_list_total' not in resp.json['places']
......
985 1014

  
986 1015
    resp = app.post_json('/api/agenda/%s/fillslot/%s/' % (agenda.pk, event.pk))
987 1016
    assert resp.json['err'] == 0
988
    assert resp.json['places']['total'] == 10
989
    assert resp.json['places']['available'] == 9
1017
    assert resp.json['places']['total'] == 20
1018
    assert resp.json['places']['available'] == 19
990 1019
    assert resp.json['places']['reserved'] == 1
991 1020
    assert resp.json['places']['full'] is False
992 1021
    assert resp.json['places']['waiting_list_total'] == 5
......
1015 1044

  
1016 1045
def test_booking_api_force_waiting_list(app, some_data, user):
1017 1046
    agenda = Agenda.objects.filter(label=u'Foo bar')[0]
1018
    event = Event.objects.filter(agenda=agenda)[0]
1047
    event = [x for x in Event.objects.filter(agenda=agenda) if x.in_bookable_period()][0]
1019 1048

  
1020 1049
    app.authorization = ('Basic', ('john.doe', 'password'))
1021 1050

  
......
1034 1063
    # add a booking
1035 1064
    resp = app.post_json('/api/agenda/%s/fillslot/%s/' % (agenda.pk, event.pk))
1036 1065
    assert resp.json['err'] == 0
1037
    assert resp.json['places']['total'] == 10
1038
    assert resp.json['places']['available'] == 9
1066
    assert resp.json['places']['total'] == 20
1067
    assert resp.json['places']['available'] == 19
1039 1068
    assert resp.json['places']['reserved'] == 1
1040 1069
    assert resp.json['places']['full'] is False
1041 1070
    assert resp.json['places']['waiting_list_total'] == 2
......
1048 1077
        '/api/agenda/%s/fillslot/%s/' % (agenda.pk, event.pk), params={'force_waiting_list': False}
1049 1078
    )
1050 1079
    assert resp.json['err'] == 0
1051
    assert resp.json['places']['total'] == 10
1052
    assert resp.json['places']['available'] == 8
1080
    assert resp.json['places']['total'] == 20
1081
    assert resp.json['places']['available'] == 18
1053 1082
    assert resp.json['places']['reserved'] == 2
1054 1083
    assert resp.json['places']['full'] is False
1055 1084
    assert resp.json['places']['waiting_list_total'] == 2
......
1062 1091
        '/api/agenda/%s/fillslot/%s/' % (agenda.pk, event.pk), params={'force_waiting_list': True}
1063 1092
    )
1064 1093
    assert resp.json['err'] == 0
1065
    assert resp.json['places']['total'] == 10
1066
    assert resp.json['places']['available'] == 8
1094
    assert resp.json['places']['total'] == 20
1095
    assert resp.json['places']['available'] == 18
1067 1096
    assert resp.json['places']['reserved'] == 2
1068 1097
    assert resp.json['places']['full'] is False
1069 1098
    assert resp.json['places']['waiting_list_total'] == 2
......
1074 1103
    # add a booking => booked in waiting list
1075 1104
    resp = app.post_json('/api/agenda/%s/fillslot/%s/' % (agenda.pk, event.pk))
1076 1105
    assert resp.json['err'] == 0
1077
    assert resp.json['places']['total'] == 10
1078
    assert resp.json['places']['available'] == 8
1106
    assert resp.json['places']['total'] == 20
1107
    assert resp.json['places']['available'] == 18
1079 1108
    assert resp.json['places']['reserved'] == 2
1080 1109
    assert resp.json['places']['full'] is True
1081 1110
    assert resp.json['places']['waiting_list_total'] == 2
......
1094 1123

  
1095 1124

  
1096 1125
def test_booking_api_with_cancel_booking(app, some_data, user):
1097
    agenda_id = Agenda.objects.filter(label=u'Foo bar')[0].id
1098
    event_0, event_1, event_2, event_3 = Event.objects.filter(agenda_id=agenda_id)[0:4]
1126
    agenda = Agenda.objects.filter(label=u'Foo bar')[0]
1127
    event_0, event_1, event_2 = [x for x in Event.objects.filter(agenda=agenda) if x.in_bookable_period()][
1128
        0:4
1129
    ]
1099 1130

  
1100 1131
    app.authorization = ('Basic', ('john.doe', 'password'))
1101
    app.post_json('/api/agenda/%s/fillslot/%s/' % (agenda_id, event_0.id))
1132
    app.post_json('/api/agenda/%s/fillslot/%s/' % (agenda.id, event_0.id))
1102 1133
    assert Booking.objects.count() == 1
1103 1134
    first_booking = Booking.objects.first()
1104 1135

  
1105 1136
    # Book a new event and cancel previous booking
1106 1137
    resp = app.post_json(
1107
        '/api/agenda/%s/fillslot/%s/' % (agenda_id, event_1.id),
1138
        '/api/agenda/%s/fillslot/%s/' % (agenda.id, event_1.id),
1108 1139
        params={'cancel_booking_id': first_booking.pk},
1109 1140
    )
1110 1141
    assert resp.json['err'] == 0
......
1115 1146

  
1116 1147
    # Cancelling an already cancelled booking returns an error
1117 1148
    resp = app.post_json(
1118
        '/api/agenda/%s/fillslot/%s/' % (agenda_id, event_1.id),
1149
        '/api/agenda/%s/fillslot/%s/' % (agenda.id, event_1.id),
1119 1150
        params={'cancel_booking_id': first_booking.pk},
1120 1151
    )
1121 1152
    assert resp.json['err'] == 1
......
1126 1157

  
1127 1158
    # Cancelling a non existent booking returns an error
1128 1159
    resp = app.post_json(
1129
        '/api/agenda/%s/fillslot/%s/' % (agenda_id, event_1.id), params={'cancel_booking_id': '-1'}
1160
        '/api/agenda/%s/fillslot/%s/' % (agenda.id, event_1.id), params={'cancel_booking_id': '-1'}
1130 1161
    )
1131 1162
    assert resp.json['err'] == 1
1132 1163
    assert resp.json['reason'] == 'cancel booking: booking does no exist'  # legacy
......
1135 1166
    assert Booking.objects.count() == 2
1136 1167

  
1137 1168
    # Cancelling booking with different count than new booking
1138
    resp = app.post_json('/api/agenda/%s/fillslot/%s/' % (agenda_id, event_2.id), params={'count': 2})
1169
    resp = app.post_json('/api/agenda/%s/fillslot/%s/' % (agenda.id, event_2.id), params={'count': 2})
1139 1170
    assert resp.json['err'] == 0
1140 1171
    assert Booking.objects.count() == 4
1141 1172
    booking_id = resp.json['booking_id']
1142 1173

  
1143 1174
    resp = app.post_json(
1144
        '/api/agenda/%s/fillslot/%s/' % (agenda_id, event_3.id),
1175
        '/api/agenda/%s/fillslot/%s/' % (agenda.id, event_1.id),
1145 1176
        params={'cancel_booking_id': booking_id, 'count': 1},
1146 1177
    )
1147 1178
    assert resp.json['err'] == 1
......
1152 1183

  
1153 1184
    # cancel_booking_id must be an integer
1154 1185
    app.post_json(
1155
        '/api/agenda/%s/fillslot/%s/' % (agenda_id, event_0.id),
1186
        '/api/agenda/%s/fillslot/%s/' % (agenda.id, event_0.id),
1156 1187
        params={'cancel_booking_id': 'no an integer'},
1157 1188
        status=400,
1158 1189
    )
1159 1190

  
1160 1191
    # cancel_booking_id can be empty or null
1161 1192
    resp = app.post_json(
1162
        '/api/agenda/%s/fillslot/%s/' % (agenda_id, event_0.id), params={'cancel_booking_id': ''}
1193
        '/api/agenda/%s/fillslot/%s/' % (agenda.id, event_0.id), params={'cancel_booking_id': ''}
1163 1194
    )
1164 1195
    assert resp.json['err'] == 0
1165 1196
    assert 'cancelled_booking_id' not in resp.json
1166 1197
    assert Booking.objects.count() == 5
1167 1198

  
1168 1199
    resp = app.post_json(
1169
        '/api/agenda/%s/fillslot/%s/' % (agenda_id, event_0.id), params={'cancel_booking_id': None}
1200
        '/api/agenda/%s/fillslot/%s/' % (agenda.id, event_0.id), params={'cancel_booking_id': None}
1170 1201
    )
1171 1202
    assert resp.json['err'] == 0
1172 1203
    assert 'cancelled_booking_id' not in resp.json
......
1174 1205

  
1175 1206

  
1176 1207
def test_booking_cancellation_api(app, some_data, user):
1177
    agenda_id = Agenda.objects.filter(label=u'Foo bar')[0].id
1178
    event = Event.objects.filter(agenda_id=agenda_id)[0]
1179
    resp = app.post('/api/agenda/%s/fillslot/%s/' % (agenda_id, event.id), status=401)
1208
    agenda = Agenda.objects.filter(label=u'Foo bar')[0]
1209
    event = [x for x in Event.objects.filter(agenda=agenda) if x.in_bookable_period()][0]
1210
    resp = app.post('/api/agenda/%s/fillslot/%s/' % (agenda.id, event.id), status=401)
1180 1211

  
1181 1212
    app.authorization = ('Basic', ('john.doe', 'password'))
1182
    resp = app.post('/api/agenda/%s/fillslot/%s/' % (agenda_id, event.id))
1213
    resp = app.post('/api/agenda/%s/fillslot/%s/' % (agenda.id, event.id))
1183 1214
    booking_id = resp.json['booking_id']
1184 1215
    assert Booking.objects.count() == 1
1185 1216
    resp = app.delete('/api/booking/%s/' % booking_id)
......
1187 1218

  
1188 1219

  
1189 1220
def test_booking_cancellation_post_api(app, some_data, user):
1190
    agenda_id = Agenda.objects.filter(label=u'Foo bar')[0].id
1191
    event = Event.objects.filter(agenda_id=agenda_id)[0]
1192
    resp = app.post('/api/agenda/%s/fillslot/%s/' % (agenda_id, event.id), status=401)
1221
    agenda = Agenda.objects.filter(label=u'Foo bar')[0]
1222
    event = [x for x in Event.objects.filter(agenda=agenda) if x.in_bookable_period()][0]
1223
    resp = app.post('/api/agenda/%s/fillslot/%s/' % (agenda.id, event.id), status=401)
1193 1224

  
1194 1225
    app.authorization = ('Basic', ('john.doe', 'password'))
1195
    resp = app.post('/api/agenda/%s/fillslot/%s/' % (agenda_id, event.id))
1226
    resp = app.post('/api/agenda/%s/fillslot/%s/' % (agenda.id, event.id))
1196 1227
    booking_id = resp.json['booking_id']
1197 1228
    assert Booking.objects.count() == 1
1198 1229
    assert urlparse.urlparse(resp.json['api']['cancel_url']).path == '/api/booking/%s/cancel/' % booking_id
1199
-