Projet

Général

Profil

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

Lauréline Guérin, 18 mai 2020 09:41

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
566 566
        )
567 567

  
568 568
    def in_bookable_period(self):
569
        if self.publication_date and localtime(now()).date() < self.publication_date:
570
            return False
569 571
        if (
570 572
            localtime(now()).date()
571 573
            > 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(
......
709 715
            except ValueError:
710 716
                events = Event.objects.filter(slug__in=slots).order_by('start_datetime')
711 717

  
718
            for event in events:
719
                if not event.in_bookable_period():
720
                    return Response(
721
                        {'err': 1, 'err_class': 'event not bookable', 'err_desc': _('event not bookable')}
722
                    )
723

  
712 724
            if not events.count():
713 725
                return Response(
714 726
                    {
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]
......
970 999

  
971 1000

  
972 1001
def test_booking_api_with_data(app, some_data, user):
973
    agenda_id = Agenda.objects.filter(label=u'Foo bar')[0].id
974
    event = Event.objects.filter(agenda_id=agenda_id)[0]
1002
    agenda = Agenda.objects.filter(label=u'Foo bar')[0]
1003
    event = [x for x in Event.objects.filter(agenda=agenda) if x.in_bookable_period()][0]
975 1004

  
976 1005
    app.authorization = ('Basic', ('john.doe', 'password'))
977
    resp = app.post_json('/api/agenda/%s/fillslot/%s/' % (agenda_id, event.id), params={'hello': 'world'})
1006
    app.post_json('/api/agenda/%s/fillslot/%s/' % (agenda.id, event.id), params={'hello': 'world'})
978 1007
    assert Booking.objects.count() == 1
979 1008
    assert Booking.objects.all()[0].extra_data == {'hello': 'world'}
980 1009

  
981 1010

  
982 1011
def test_booking_api_available(app, some_data, meetings_agenda, user):
983 1012
    agenda = Agenda.objects.filter(label=u'Foo bar')[0]
984
    event = Event.objects.filter(agenda=agenda)[0]
1013
    event = [x for x in Event.objects.filter(agenda=agenda) if x.in_bookable_period()][0]
985 1014

  
986 1015
    app.authorization = ('Basic', ('john.doe', 'password'))
987 1016
    resp = app.post_json('/api/agenda/%s/fillslot/%s/' % (agenda.pk, event.pk))
988 1017
    assert resp.json['err'] == 0
989
    assert resp.json['places']['total'] == 10
990
    assert resp.json['places']['available'] == 9
1018
    assert resp.json['places']['total'] == 20
1019
    assert resp.json['places']['available'] == 19
991 1020
    assert resp.json['places']['reserved'] == 1
992 1021
    assert resp.json['places']['full'] is False
993 1022
    assert 'waiting_list_total' not in resp.json['places']
......
998 1027

  
999 1028
    resp = app.post_json('/api/agenda/%s/fillslot/%s/' % (agenda.pk, event.pk))
1000 1029
    assert resp.json['err'] == 0
1001
    assert resp.json['places']['total'] == 10
1002
    assert resp.json['places']['available'] == 9
1030
    assert resp.json['places']['total'] == 20
1031
    assert resp.json['places']['available'] == 19
1003 1032
    assert resp.json['places']['reserved'] == 1
1004 1033
    assert resp.json['places']['full'] is False
1005 1034
    assert resp.json['places']['waiting_list_total'] == 5
......
1028 1057

  
1029 1058
def test_booking_api_force_waiting_list(app, some_data, user):
1030 1059
    agenda = Agenda.objects.filter(label=u'Foo bar')[0]
1031
    event = Event.objects.filter(agenda=agenda)[0]
1060
    event = [x for x in Event.objects.filter(agenda=agenda) if x.in_bookable_period()][0]
1032 1061

  
1033 1062
    app.authorization = ('Basic', ('john.doe', 'password'))
1034 1063

  
......
1047 1076
    # add a booking
1048 1077
    resp = app.post_json('/api/agenda/%s/fillslot/%s/' % (agenda.pk, event.pk))
1049 1078
    assert resp.json['err'] == 0
1050
    assert resp.json['places']['total'] == 10
1051
    assert resp.json['places']['available'] == 9
1079
    assert resp.json['places']['total'] == 20
1080
    assert resp.json['places']['available'] == 19
1052 1081
    assert resp.json['places']['reserved'] == 1
1053 1082
    assert resp.json['places']['full'] is False
1054 1083
    assert resp.json['places']['waiting_list_total'] == 2
......
1061 1090
        '/api/agenda/%s/fillslot/%s/' % (agenda.pk, event.pk), params={'force_waiting_list': False}
1062 1091
    )
1063 1092
    assert resp.json['err'] == 0
1064
    assert resp.json['places']['total'] == 10
1065
    assert resp.json['places']['available'] == 8
1093
    assert resp.json['places']['total'] == 20
1094
    assert resp.json['places']['available'] == 18
1066 1095
    assert resp.json['places']['reserved'] == 2
1067 1096
    assert resp.json['places']['full'] is False
1068 1097
    assert resp.json['places']['waiting_list_total'] == 2
......
1075 1104
        '/api/agenda/%s/fillslot/%s/' % (agenda.pk, event.pk), params={'force_waiting_list': True}
1076 1105
    )
1077 1106
    assert resp.json['err'] == 0
1078
    assert resp.json['places']['total'] == 10
1079
    assert resp.json['places']['available'] == 8
1107
    assert resp.json['places']['total'] == 20
1108
    assert resp.json['places']['available'] == 18
1080 1109
    assert resp.json['places']['reserved'] == 2
1081 1110
    assert resp.json['places']['full'] is False
1082 1111
    assert resp.json['places']['waiting_list_total'] == 2
......
1087 1116
    # add a booking => booked in waiting list
1088 1117
    resp = app.post_json('/api/agenda/%s/fillslot/%s/' % (agenda.pk, event.pk))
1089 1118
    assert resp.json['err'] == 0
1090
    assert resp.json['places']['total'] == 10
1091
    assert resp.json['places']['available'] == 8
1119
    assert resp.json['places']['total'] == 20
1120
    assert resp.json['places']['available'] == 18
1092 1121
    assert resp.json['places']['reserved'] == 2
1093 1122
    assert resp.json['places']['full'] is True
1094 1123
    assert resp.json['places']['waiting_list_total'] == 2
......
1107 1136

  
1108 1137

  
1109 1138
def test_booking_api_with_cancel_booking(app, some_data, user):
1110
    agenda_id = Agenda.objects.filter(label=u'Foo bar')[0].id
1111
    event_0, event_1, event_2, event_3 = Event.objects.filter(agenda_id=agenda_id)[0:4]
1139
    agenda = Agenda.objects.filter(label=u'Foo bar')[0]
1140
    event_0, event_1, event_2 = [x for x in Event.objects.filter(agenda=agenda) if x.in_bookable_period()][
1141
        0:4
1142
    ]
1112 1143

  
1113 1144
    app.authorization = ('Basic', ('john.doe', 'password'))
1114
    app.post_json('/api/agenda/%s/fillslot/%s/' % (agenda_id, event_0.id))
1145
    app.post_json('/api/agenda/%s/fillslot/%s/' % (agenda.id, event_0.id))
1115 1146
    assert Booking.objects.count() == 1
1116 1147
    first_booking = Booking.objects.first()
1117 1148

  
1118 1149
    # Book a new event and cancel previous booking
1119 1150
    resp = app.post_json(
1120
        '/api/agenda/%s/fillslot/%s/' % (agenda_id, event_1.id),
1151
        '/api/agenda/%s/fillslot/%s/' % (agenda.id, event_1.id),
1121 1152
        params={'cancel_booking_id': first_booking.pk},
1122 1153
    )
1123 1154
    assert resp.json['err'] == 0
......
1128 1159

  
1129 1160
    # Cancelling an already cancelled booking returns an error
1130 1161
    resp = app.post_json(
1131
        '/api/agenda/%s/fillslot/%s/' % (agenda_id, event_1.id),
1162
        '/api/agenda/%s/fillslot/%s/' % (agenda.id, event_1.id),
1132 1163
        params={'cancel_booking_id': first_booking.pk},
1133 1164
    )
1134 1165
    assert resp.json['err'] == 1
......
1139 1170

  
1140 1171
    # Cancelling a non existent booking returns an error
1141 1172
    resp = app.post_json(
1142
        '/api/agenda/%s/fillslot/%s/' % (agenda_id, event_1.id), params={'cancel_booking_id': '-1'}
1173
        '/api/agenda/%s/fillslot/%s/' % (agenda.id, event_1.id), params={'cancel_booking_id': '-1'}
1143 1174
    )
1144 1175
    assert resp.json['err'] == 1
1145 1176
    assert resp.json['reason'] == 'cancel booking: booking does no exist'  # legacy
......
1148 1179
    assert Booking.objects.count() == 2
1149 1180

  
1150 1181
    # Cancelling booking with different count than new booking
1151
    resp = app.post_json('/api/agenda/%s/fillslot/%s/' % (agenda_id, event_2.id), params={'count': 2})
1182
    resp = app.post_json('/api/agenda/%s/fillslot/%s/' % (agenda.id, event_2.id), params={'count': 2})
1152 1183
    assert resp.json['err'] == 0
1153 1184
    assert Booking.objects.count() == 4
1154 1185
    booking_id = resp.json['booking_id']
1155 1186

  
1156 1187
    resp = app.post_json(
1157
        '/api/agenda/%s/fillslot/%s/' % (agenda_id, event_3.id),
1188
        '/api/agenda/%s/fillslot/%s/' % (agenda.id, event_1.id),
1158 1189
        params={'cancel_booking_id': booking_id, 'count': 1},
1159 1190
    )
1160 1191
    assert resp.json['err'] == 1
......
1165 1196

  
1166 1197
    # cancel_booking_id must be an integer
1167 1198
    app.post_json(
1168
        '/api/agenda/%s/fillslot/%s/' % (agenda_id, event_0.id),
1199
        '/api/agenda/%s/fillslot/%s/' % (agenda.id, event_0.id),
1169 1200
        params={'cancel_booking_id': 'no an integer'},
1170 1201
        status=400,
1171 1202
    )
1172 1203

  
1173 1204
    # cancel_booking_id can be empty or null
1174 1205
    resp = app.post_json(
1175
        '/api/agenda/%s/fillslot/%s/' % (agenda_id, event_0.id), params={'cancel_booking_id': ''}
1206
        '/api/agenda/%s/fillslot/%s/' % (agenda.id, event_0.id), params={'cancel_booking_id': ''}
1176 1207
    )
1177 1208
    assert resp.json['err'] == 0
1178 1209
    assert 'cancelled_booking_id' not in resp.json
1179 1210
    assert Booking.objects.count() == 5
1180 1211

  
1181 1212
    resp = app.post_json(
1182
        '/api/agenda/%s/fillslot/%s/' % (agenda_id, event_0.id), params={'cancel_booking_id': None}
1213
        '/api/agenda/%s/fillslot/%s/' % (agenda.id, event_0.id), params={'cancel_booking_id': None}
1183 1214
    )
1184 1215
    assert resp.json['err'] == 0
1185 1216
    assert 'cancelled_booking_id' not in resp.json
......
1187 1218

  
1188 1219

  
1189 1220
def test_booking_cancellation_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
    resp = app.delete('/api/booking/%s/' % booking_id)
......
1200 1231

  
1201 1232

  
1202 1233
def test_booking_cancellation_post_api(app, some_data, user):
1203
    agenda_id = Agenda.objects.filter(label=u'Foo bar')[0].id
1204
    event = Event.objects.filter(agenda_id=agenda_id)[0]
1205
    resp = app.post('/api/agenda/%s/fillslot/%s/' % (agenda_id, event.id), status=401)
1234
    agenda = Agenda.objects.filter(label=u'Foo bar')[0]
1235
    event = [x for x in Event.objects.filter(agenda=agenda) if x.in_bookable_period()][0]
1236
    resp = app.post('/api/agenda/%s/fillslot/%s/' % (agenda.id, event.id), status=401)
1206 1237

  
1207 1238
    app.authorization = ('Basic', ('john.doe', 'password'))
1208
    resp = app.post('/api/agenda/%s/fillslot/%s/' % (agenda_id, event.id))
1239
    resp = app.post('/api/agenda/%s/fillslot/%s/' % (agenda.id, event.id))
1209 1240
    booking_id = resp.json['booking_id']
1210 1241
    assert Booking.objects.count() == 1
1211 1242
    assert urlparse.urlparse(resp.json['api']['cancel_url']).path == '/api/booking/%s/cancel/' % booking_id
1212
-