Booking: n'importe quoi dans extra_data (TypeError: unhashable type: 'list') (#74872) #43
|
@ -721,6 +721,16 @@ def make_booking(event, payload, extra_data, primary_booking=None, in_waiting_li
|
|||
)
|
||||
|
||||
|
||||
def get_extra_data(request, payload):
|
||||
extra_data = {}
|
||||
for k, v in request.data.items():
|
||||
if k not in payload:
|
||||
if isinstance(v, (list, dict)):
|
||||
raise APIErrorBadRequest(N_('wrong type for extra_data %s value') % k)
|
||||
extra_data[k] = v
|
||||
return extra_data
|
||||
|
||||
|
||||
class Agendas(APIView):
|
||||
serializer_class = serializers.AgendaSerializer
|
||||
|
||||
|
@ -1412,10 +1422,7 @@ class Fillslots(APIView):
|
|||
if cancel_error:
|
||||
raise APIError(N_(cancel_error))
|
||||
|
||||
extra_data = {}
|
||||
for k, v in request.data.items():
|
||||
if k not in serializer.validated_data:
|
||||
extra_data[k] = v
|
||||
extra_data = get_extra_data(request, serializer.validated_data)
|
||||
|
||||
available_desk = None
|
||||
color = None
|
||||
|
@ -1791,7 +1798,7 @@ class RecurringFillslots(APIView):
|
|||
)
|
||||
)
|
||||
|
||||
extra_data = {k: v for k, v in request.data.items() if k not in payload}
|
||||
extra_data = get_extra_data(request, payload)
|
||||
# don't reload agendas and events types
|
||||
for event in events_to_book:
|
||||
event.agenda = agendas_by_id[event.agenda_id]
|
||||
|
@ -2001,7 +2008,7 @@ class EventsFillslots(APIView):
|
|||
)
|
||||
waiting_list_event_ids = [event.pk for event in events if event.in_waiting_list]
|
||||
|
||||
extra_data = {k: v for k, v in request.data.items() if k not in payload}
|
||||
extra_data = get_extra_data(request, payload)
|
||||
bookings = [make_booking(event, payload, extra_data) for event in events]
|
||||
|
||||
bookings_to_cancel_out_of_min_delay = Booking.objects.filter(
|
||||
|
@ -2336,7 +2343,7 @@ class SubscriptionsAPI(ListAPIView):
|
|||
serializer = self.serializer_class(data=request.data)
|
||||
if not serializer.is_valid():
|
||||
raise APIErrorBadRequest(N_('invalid payload'), errors=serializer.errors)
|
||||
extra_data = {k: v for k, v in request.data.items() if k not in serializer.validated_data}
|
||||
extra_data = get_extra_data(request, serializer.validated_data)
|
||||
|
||||
date_start = serializer.validated_data['date_start']
|
||||
date_end = serializer.validated_data['date_end']
|
||||
|
@ -2607,7 +2614,7 @@ class BookingAPI(APIView):
|
|||
raise APIErrorBadRequest(N_('user is marked as absent, can not set presence reason'), err=6)
|
||||
|
||||
serializer.save()
|
||||
extra_data = {k: v for k, v in request.data.items() if k not in serializer.validated_data}
|
||||
extra_data = get_extra_data(request, serializer.validated_data)
|
||||
if extra_data:
|
||||
self.booking.extra_data = self.booking.extra_data or {}
|
||||
self.booking.extra_data.update(extra_data)
|
||||
|
|
|
@ -2543,7 +2543,7 @@ class EventCheckView(ViewableAgendaMixin, DetailView):
|
|||
).values_list('extra_data', flat=True)
|
||||
for extra_data in list(extra_data_from_booked) + list(extra_data_from_subscriptions):
|
||||
for k, v in extra_data.items():
|
||||
if k in agenda_filters:
|
||||
if k in agenda_filters and not isinstance(v, (list, dict)):
|
||||
filters[k].add(v)
|
||||
filters = sorted(filters.items())
|
||||
filters = {k: sorted(list(v)) for k, v in filters}
|
||||
|
|
|
@ -152,6 +152,22 @@ def test_booking_api(app, user):
|
|||
assert len(resp.json['errors']) == 1
|
||||
assert 'user_last_name' in resp.json['errors']
|
||||
|
||||
# extra_data list/dict values are refused
|
||||
resp = app.post_json(
|
||||
'/api/agenda/%s/fillslot/%s/' % (agenda.id, event.id),
|
||||
params={'foo': ['bar', 'baz']},
|
||||
status=400,
|
||||
)
|
||||
assert resp.json['err'] == 1
|
||||
assert resp.json['err_class'] == 'wrong type for extra_data foo value'
|
||||
resp = app.post_json(
|
||||
'/api/agenda/%s/fillslot/%s/' % (agenda.id, event.id),
|
||||
params={'foo': {'bar': 'baz'}},
|
||||
status=400,
|
||||
)
|
||||
assert resp.json['err'] == 1
|
||||
assert resp.json['err_class'] == 'wrong type for extra_data foo value'
|
||||
|
||||
# test parameters wrongly passed in query are refused
|
||||
resp = app.post_json(
|
||||
'/api/agenda/%s/fillslot/%s/?backoffice_url=https://example.com&label=test' % (agenda.id, event.id),
|
||||
|
@ -540,6 +556,22 @@ def test_booking_api_fillslots(app, user):
|
|||
assert len(resp.json['errors']) == 1
|
||||
assert 'user_last_name' in resp.json['errors']
|
||||
|
||||
# extra_data list/dict values are refused
|
||||
resp = app.post_json(
|
||||
'/api/agenda/%s/fillslots/' % agenda.id,
|
||||
params={'slots': events_ids, 'foo': ['bar', 'baz']},
|
||||
status=400,
|
||||
)
|
||||
assert resp.json['err'] == 1
|
||||
assert resp.json['err_class'] == 'wrong type for extra_data foo value'
|
||||
resp = app.post_json(
|
||||
'/api/agenda/%s/fillslots/' % agenda.id,
|
||||
params={'slots': events_ids, 'foo': {'bar': 'baz'}},
|
||||
status=400,
|
||||
)
|
||||
assert resp.json['err'] == 1
|
||||
assert resp.json['err_class'] == 'wrong type for extra_data foo value'
|
||||
|
||||
# empty or missing slots
|
||||
resp = app.post_json('/api/agenda/%s/fillslots/' % agenda.id, params={'slots': []}, status=400)
|
||||
assert resp.json['err'] == 1
|
||||
|
|
|
@ -122,6 +122,21 @@ def test_api_events_fillslots(app, user):
|
|||
resp = app.post('/api/agenda/foobar/events/fillslots/', status=404)
|
||||
resp = app.post('/api/agenda/0/events/fillslots/', status=404)
|
||||
|
||||
params = {'user_external_id': 'user_id', 'slots': 'event,event-2', 'foo': 'bar'}
|
||||
resp = app.post_json(fillslots_url, params=params)
|
||||
assert resp.json['booking_count'] == 2
|
||||
assert [b.extra_data for b in Booking.objects.order_by('-pk')[:2]] == [{'foo': 'bar'}, {'foo': 'bar'}]
|
||||
|
||||
params.update({'foo': ['bar', 'baz']})
|
||||
resp = app.post_json(fillslots_url, params=params, status=400)
|
||||
assert resp.json['err'] == 1
|
||||
assert resp.json['err_class'] == 'wrong type for extra_data foo value'
|
||||
|
||||
params.update({'foo': {'bar': 'baz'}})
|
||||
resp = app.post_json(fillslots_url, params=params, status=400)
|
||||
assert resp.json['err'] == 1
|
||||
assert resp.json['err_class'] == 'wrong type for extra_data foo value'
|
||||
|
||||
|
||||
@pytest.mark.freeze_time('2021-09-06 12:00')
|
||||
def test_api_events_fillslots_with_cancelled(app, user):
|
||||
|
|
|
@ -251,6 +251,25 @@ def test_api_events_fillslots_multiple_agendas(app, user):
|
|||
resp = app.post_json('/api/agendas/events/fillslots/?agendas=first-agenda', params=params, status=400)
|
||||
assert resp.json['errors']['slots'] == ['Missing agenda slug in slot @event']
|
||||
|
||||
params = {'user_external_id': 'user_id', 'slots': event_slugs, 'foo': 'bar'}
|
||||
resp = app.post_json('/api/agendas/events/fillslots/?agendas=%s' % agenda_slugs, params=params)
|
||||
assert resp.json['booking_count'] == 1
|
||||
assert Booking.objects.order_by('-pk')[0].extra_data == {'foo': 'bar'}
|
||||
|
||||
params.update({'foo': ['bar', 'baz']})
|
||||
resp = app.post_json(
|
||||
'/api/agendas/events/fillslots/?agendas=%s' % agenda_slugs, params=params, status=400
|
||||
)
|
||||
assert resp.json['err'] == 1
|
||||
assert resp.json['err_class'] == 'wrong type for extra_data foo value'
|
||||
|
||||
params.update({'foo': {'bar': 'baz'}})
|
||||
resp = app.post_json(
|
||||
'/api/agendas/events/fillslots/?agendas=%s' % agenda_slugs, params=params, status=400
|
||||
)
|
||||
assert resp.json['err'] == 1
|
||||
assert resp.json['err_class'] == 'wrong type for extra_data foo value'
|
||||
|
||||
|
||||
@pytest.mark.freeze_time('2021-09-06 12:00')
|
||||
def test_api_events_fillslots_multiple_agendas_with_cancelled(app, user):
|
||||
|
|
|
@ -169,6 +169,25 @@ def test_recurring_events_api_fillslots(app, user, freezer, action):
|
|||
assert resp.json['err_desc'] == 'invalid payload'
|
||||
assert resp.json['errors']['action'] == ['"invalid" is not a valid choice.']
|
||||
|
||||
params = {
|
||||
'user_external_id': 'user_id',
|
||||
'slots': 'foo-bar@event:1',
|
||||
'foo': 'bar',
|
||||
}
|
||||
resp = app.post_json(fillslots_url, params=params)
|
||||
assert resp.json['booking_count'] == 2
|
||||
assert [b.extra_data for b in Booking.objects.order_by('-pk')[:2]] == [{'foo': 'bar'}, {'foo': 'bar'}]
|
||||
|
||||
params.update({'foo': ['bar', 'baz']})
|
||||
resp = app.post_json(fillslots_url, params=params, status=400)
|
||||
assert resp.json['err'] == 1
|
||||
assert resp.json['err_class'] == 'wrong type for extra_data foo value'
|
||||
|
||||
params.update({'foo': {'bar': 'baz'}})
|
||||
resp = app.post_json(fillslots_url, params=params, status=400)
|
||||
assert resp.json['err'] == 1
|
||||
assert resp.json['err_class'] == 'wrong type for extra_data foo value'
|
||||
|
||||
|
||||
def test_recurring_events_api_fillslots_waiting_list(app, user, freezer):
|
||||
freezer.move_to('2021-09-06 12:00')
|
||||
|
|
|
@ -1021,6 +1021,11 @@ def test_booking_patch_api_extra_data(app, user):
|
|||
assert booking.user_was_present is True # not changed
|
||||
assert booking.extra_data == {'foo': None, 'foooo': 'baz'} # not changed
|
||||
|
||||
resp = app.patch_json('/api/booking/%s/' % booking.pk, params={'foo': ['bar', 'baz']}, status=400)
|
||||
assert resp.json['err_desc'] == 'wrong type for extra_data foo value'
|
||||
resp = app.patch_json('/api/booking/%s/' % booking.pk, params={'foo': {'bar': 'baz'}}, status=400)
|
||||
assert resp.json['err_desc'] == 'wrong type for extra_data foo value'
|
||||
|
||||
|
||||
def test_booking_cancellation_api(app, user):
|
||||
agenda = Agenda.objects.create(kind='events')
|
||||
|
|
|
@ -224,6 +224,20 @@ def test_api_create_subscription(app, user):
|
|||
resp = app.post('/api/agenda/%s/subscription/' % agenda.slug, params=params, status=400)
|
||||
assert resp.json['errors']['non_field_errors'][0] == 'start_datetime must be before end_datetime'
|
||||
|
||||
params = {
|
||||
'user_external_id': 'xxx',
|
||||
'user_first_name': 'Foo',
|
||||
'user_last_name': 'BAR',
|
||||
'date_start': '2021-10-01',
|
||||
'date_end': '2021-11-01',
|
||||
'foo': ['bar', 'baz'],
|
||||
}
|
||||
resp = app.post_json('/api/agenda/%s/subscription/' % agenda.slug, params=params, status=400)
|
||||
assert resp.json['err_desc'] == 'wrong type for extra_data foo value'
|
||||
params.update({'foo': {'bar': 'baz'}})
|
||||
resp = app.post_json('/api/agenda/%s/subscription/' % agenda.slug, params=params, status=400)
|
||||
assert resp.json['err_desc'] == 'wrong type for extra_data foo value'
|
||||
|
||||
|
||||
def test_api_create_subscription_check_dates(app, user):
|
||||
agenda = Agenda.objects.create(label='Foo bar', kind='events')
|
||||
|
|
|
@ -1758,7 +1758,7 @@ def test_event_check_filters(check_types, app, admin_user):
|
|||
user_external_id='user:1',
|
||||
user_first_name='User',
|
||||
user_last_name='foo-val1 bar-none presence',
|
||||
extra_data={'foo': 'val1'},
|
||||
extra_data={'foo': 'val1', 'bar': ['val1']}, # bar is ignored, wrong value
|
||||
user_was_present=True,
|
||||
)
|
||||
Booking.objects.create(
|
||||
|
@ -1837,7 +1837,7 @@ def test_event_check_filters(check_types, app, admin_user):
|
|||
user_external_id='subscription:1',
|
||||
user_first_name='Subscription',
|
||||
user_last_name='foo-val1 bar-none',
|
||||
extra_data={'foo': 'val1'},
|
||||
extra_data={'foo': 'val1', 'bar': ['val1']}, # bar is ignored, wrong value
|
||||
date_start=event.start_datetime,
|
||||
date_end=event.start_datetime + datetime.timedelta(days=1),
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue