Compare commits

..
Author SHA1 Message Date
Raphael Michel b382f30995 Make it harder for dates way in the past to enter the system
The input components even allow adding setting dates before christus,
but then retrieving the rows back from the DB is impossible:

    File "django/db/models/sql/compiler.py", line 1661, in execute_sql
      return list(result)
    File "django/db/models/sql/compiler.py", line 2171, in cursor_iter
      for rows in iter((lambda: cursor.fetchmany(itersize)), sentinel):
    File "django/db/models/sql/compiler.py", line 2171, in <lambda>
      for rows in iter((lambda: cursor.fetchmany(itersize)), sentinel):
    File "django/db/utils.py", line 98, in inner
      return func(*args, **kwargs)
    ValueError: year -1 is out of range
2026-11-13 10:11:44 +01:00
16 changed files with 245 additions and 128 deletions

No files matched your search

+1 -1
View File
@@ -27,4 +27,4 @@ class PretixApiConfig(AppConfig):
label = 'pretixapi'
def ready(self):
from . import signals, webhooks # noqa
from . import monkeypatches, signals, webhooks # noqa
+27
View File
@@ -0,0 +1,27 @@
import datetime
from django.db import models
from rest_framework import serializers
from rest_framework.exceptions import ValidationError
class CustomDateField(serializers.DateField):
def to_internal_value(self, value):
val = super().to_internal_value(value)
if val < datetime.date(1900, 1, 1):
raise ValidationError("Do not pass dates before 1900-01-01")
return val
class CustomDateTimeField(serializers.DateTimeField):
def to_internal_value(self, value):
val = super().to_internal_value(value)
if val < datetime.datetime(1900, 1, 1, tzinfo=datetime.timezone.utc):
raise ValidationError("Do not pass dates before 1900-01-01")
return val
serializers.ModelSerializer.serializer_field_mapping.update({
models.DateField: CustomDateField,
models.DateTimeField: CustomDateTimeField,
})
+9 -9
View File
@@ -1282,7 +1282,7 @@ class OrderCreateSerializer(I18nAwareModelSerializer):
raise ValidationError(
'Orders cannot have more than %(max)s positions.' % {'max': settings.PRETIX_MAX_ORDER_SIZE}
)
errs = defaultdict(dict)
errs = [{} for p in data]
if any([p.get('positionid') for p in data]):
if not all([p.get('positionid') for p in data]):
for i, p in enumerate(data):
@@ -1311,16 +1311,16 @@ class OrderCreateSerializer(I18nAwareModelSerializer):
last_posid = p['positionid']
elif any([p.get('addon_to') for p in data]):
errs = {
i: {'positionid': ["If you set addon_to on any position, you need to specify position IDs manually."]}
for i, p in enumerate(data)
}
errs = [
{'positionid': ["If you set addon_to on any position, you need to specify position IDs manually."]}
for p in data
]
else:
for i, p in enumerate(data):
p['positionid'] = i + 1
if errs:
raise ValidationError(dict(errs))
if any(errs):
raise ValidationError(errs)
return data
def create(self, validated_data):
@@ -1437,7 +1437,7 @@ class OrderCreateSerializer(I18nAwareModelSerializer):
# use further down
del quota_diff_for_locking, voucher_diff_for_locking, seat_diff_for_locking
errs = defaultdict(dict)
errs = [{} for p in positions_data]
for i, pos_data in enumerate(positions_data):
if pos_data.get('voucher'):
@@ -1566,7 +1566,7 @@ class OrderCreateSerializer(I18nAwareModelSerializer):
)
]
if errs:
if any(errs):
raise ValidationError({'positions': errs})
if validated_data.get('locale', None) is None:
+9 -7
View File
@@ -19,7 +19,6 @@
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>.
#
from collections import defaultdict
from decimal import Decimal
from rest_framework import serializers
@@ -39,20 +38,23 @@ class VoucherListSerializer(serializers.ListSerializer):
codes = set()
seats = set()
errs = defaultdict(dict)
for i, voucher_data in enumerate(validated_data):
errs = []
err = False
for voucher_data in validated_data:
if voucher_data.get('seat') and (voucher_data.get('seat'), voucher_data.get('subevent')) in seats:
errs[i] = {'code': ['Duplicate seat ID in request.']}
err = True
errs.append({'code': ['Duplicate seat ID in request.']})
continue
else:
seats.add((voucher_data.get('seat'), voucher_data.get('subevent')))
if voucher_data['code'] in codes:
errs[i] = {'code': ['Duplicate voucher code in request.']}
err = True
errs.append({'code': ['Duplicate voucher code in request.']})
else:
codes.add(voucher_data['code'])
if errs:
errs.append({})
if err:
raise ValidationError(errs)
return super().create(validated_data)
+2
View File
@@ -424,6 +424,8 @@ class SplitDateTimeField(forms.SplitDateTimeField):
return None
if data_list[1] in self.empty_values:
raise ValidationError(self.error_messages['invalid_date'], code='invalid_date')
if data_list[0] < datetime.date(1900, 1, 1):
raise ValidationError(self.error_messages['invalid_date'], code='invalid_date')
result = datetime.datetime.combine(*data_list)
return from_current_timezone(result)
return None
+1
View File
@@ -507,6 +507,7 @@ REST_FRAMEWORK = {
],
'EXCEPTION_HANDLER': 'pretix.api.exception.custom_exception_handler',
'UNICODE_JSON': False,
'LIST_SERIALIZER_ERRORS_AS_DICT': False
}
@@ -166,6 +166,8 @@ let form_handlers = function (el) {
if ($(this).is('[data-min]')) {
opts['minDate'] = $(this).attr('data-min')
opts['viewDate'] = $(this).attr('data-min')
} else {
opts['minDate'] = '1900-01-01'
}
if ($(this).is('[data-max]')) {
opts['maxDate'] = $(this).attr('data-max')
@@ -54,6 +54,8 @@ let form_handlers = function (el) {
if ($(this).is('[data-min]')) {
opts['minDate'] = $(this).attr('data-min')
opts['viewDate'] = $(this).attr('data-min')
} else {
opts['minDate'] = '1900-01-01'
}
if ($(this).is('[data-max]')) {
opts['maxDate'] = $(this).attr('data-max')
+1
View File
@@ -57,6 +57,7 @@ filterwarnings =
ignore:teardown:pytest.PytestWarning
ignore:avoid running initialization queries:RuntimeWarning
ignore:.*The 'strip_cdata' option of HTMLParser.*:DeprecationWarning:
ignore:The list-based error format for `ListSerializer`:rest_framework.deprecation.RemovedInDRF320Warning
[coverage:run]
+13 -16
View File
@@ -424,7 +424,7 @@ def test_cartpos_create_answer_validation(token_client, organizer, event, item,
), format='json', data=res
)
assert resp.status_code == 400
assert resp.data == {'answers': {0: {'question': ['The specified question does not belong to this event.']}}}
assert resp.data == {'answers': [{'question': ['The specified question does not belong to this event.']}]}
res['answers'][0]['question'] = question.pk
res['answers'][0]['options'] = [question.options.first().pk]
@@ -434,9 +434,8 @@ def test_cartpos_create_answer_validation(token_client, organizer, event, item,
), format='json', data=res
)
assert resp.status_code == 400
assert resp.data == {'answers': {
0: {'non_field_errors': ['You should not specify options if the question is not of a choice type.']}
}}
assert resp.data == {
'answers': [{'non_field_errors': ['You should not specify options if the question is not of a choice type.']}]}
question.type = Question.TYPE_CHOICE
question.save()
@@ -448,7 +447,7 @@ def test_cartpos_create_answer_validation(token_client, organizer, event, item,
)
assert resp.status_code == 400
assert resp.data == {
'answers': {0: {'non_field_errors': ['You need to specify options if the question is of a choice type.']}}}
'answers': [{'non_field_errors': ['You need to specify options if the question is of a choice type.']}]}
with scopes_disabled():
question.options.create(answer="L")
@@ -462,8 +461,7 @@ def test_cartpos_create_answer_validation(token_client, organizer, event, item,
), format='json', data=res
)
assert resp.status_code == 400
assert resp.data == {
'answers': {0: {'non_field_errors': ['You can specify at most one option for this question.']}}}
assert resp.data == {'answers': [{'non_field_errors': ['You can specify at most one option for this question.']}]}
r = token_client.post(
'/api/v1/upload',
@@ -535,7 +533,7 @@ def test_cartpos_create_answer_validation(token_client, organizer, event, item,
), format='json', data=res
)
assert resp.status_code == 400
assert resp.data == {'answers': {0: {'non_field_errors': ['A valid number is required.']}}}
assert resp.data == {'answers': [{'non_field_errors': ['A valid number is required.']}]}
question.type = Question.TYPE_BOOLEAN
question.save()
@@ -575,8 +573,7 @@ def test_cartpos_create_answer_validation(token_client, organizer, event, item,
), format='json', data=res
)
assert resp.status_code == 400
assert resp.data == {
'answers': {0: {'non_field_errors': ['Please specify "true" or "false" for boolean questions.']}}}
assert resp.data == {'answers': [{'non_field_errors': ['Please specify "true" or "false" for boolean questions.']}]}
question.type = Question.TYPE_DATE
question.save()
@@ -602,7 +599,7 @@ def test_cartpos_create_answer_validation(token_client, organizer, event, item,
)
assert resp.status_code == 400
assert resp.data == {
'answers': {0: {'non_field_errors': ['Date has wrong format. Use one of these formats instead: YYYY-MM-DD.']}}}
'answers': [{'non_field_errors': ['Date has wrong format. Use one of these formats instead: YYYY-MM-DD.']}]}
question.type = Question.TYPE_DATETIME
question.save()
@@ -627,9 +624,9 @@ def test_cartpos_create_answer_validation(token_client, organizer, event, item,
), format='json', data=res
)
assert resp.status_code == 400
assert resp.data == {'answers': {0: {'non_field_errors': [
assert resp.data == {'answers': [{'non_field_errors': [
'Datetime has wrong format. Use one of these formats instead: '
'YYYY-MM-DDThh:mm[:ss[.uuuuuu]][+HH:MM|-HH:MM|Z].']}}}
'YYYY-MM-DDThh:mm[:ss[.uuuuuu]][+HH:MM|-HH:MM|Z].']}]}
question.type = Question.TYPE_TIME
question.save()
@@ -654,8 +651,8 @@ def test_cartpos_create_answer_validation(token_client, organizer, event, item,
), format='json', data=res
)
assert resp.status_code == 400
assert resp.data == {'answers': {0: {'non_field_errors': [
'Time has wrong format. Use one of these formats instead: hh:mm[:ss[.uuuuuu]].']}}}
assert resp.data == {'answers': [
{'non_field_errors': ['Time has wrong format. Use one of these formats instead: hh:mm[:ss[.uuuuuu]].']}]}
@pytest.mark.django_db
@@ -1390,7 +1387,7 @@ def test_cartpos_create_bulk_validation_error_in_addon(token_client, organizer,
'data': None,
'success': False,
'errors': {
'addons': {0: {'item': ['Invalid pk "-1" - object does not exist.']}}
'addons': [{'item': ['Invalid pk "-1" - object does not exist.']}]
}
}
]
+26
View File
@@ -365,6 +365,32 @@ def test_event_create(team, token_client, organizer, event, meta_prop):
assert resp.status_code == 400
assert resp.content.decode() == '{"slug":["This slug has already been used for a different event."]}'
resp = token_client.post(
'/api/v1/organizers/{}/events/'.format(organizer.slug),
{
"name": {
"de": "Demo Konference 2020 Test",
"en": "Demo Conference 2020 Test"
},
"live": False,
"currency": "EUR",
"date_from": "1817-12-27T10:00:00Z",
"date_to": "1817-12-28T10:00:00Z",
"date_admission": None,
"is_public": False,
"presale_start": None,
"presale_end": None,
"location": None,
"slug": "newslug",
"meta_data": {
"type": "Conference"
}
},
format='json'
)
assert resp.status_code == 400
assert resp.content.decode() == '{"date_from":["Do not pass dates before 1900-01-01"],"date_to":["Do not pass dates before 1900-01-01"]}'
resp = token_client.post(
'/api/v1/organizers/{}/events/'.format(organizer.slug),
{
+3 -3
View File
@@ -958,9 +958,9 @@ def test_item_create_with_addon(token_client, organizer, event, item, category,
format='json'
)
assert resp.status_code == 400
assert resp.data in [
{"addons": {0: "The minimum count needs to be equal to or greater than zero."}},
{"addons": {0: {"min_count": ["Ensure this value is greater than or equal to 0."]}}},
assert resp.content.decode() in [
'{"addons":["The minimum count needs to be equal to or greater than zero."]}',
'{"addons":[{"min_count":["Ensure this value is greater than or equal to 0."]}]}',
]
with scopes_disabled():
assert 2 == Item.objects.all().count()
+140 -82
View File
@@ -978,7 +978,7 @@ def test_order_create_position_secret_optional(token_client, organizer, event, i
)
assert resp.status_code == 400
assert resp.data == {'positions': {0: {'secret': ['You cannot assign a position secret that already exists.']}}}
assert resp.data == {'positions': [{'secret': ['You cannot assign a position secret that already exists.']}]}
@pytest.mark.django_db
@@ -1024,7 +1024,7 @@ def test_order_create_fee_type_validation(token_client, organizer, event, item,
), format='json', data=res
)
assert resp.status_code == 400
assert resp.data == {'fees': {0: {'fee_type': ['"unknown" is not a valid choice.']}}}
assert resp.data == {'fees': [{'fee_type': ['"unknown" is not a valid choice.']}]}
@pytest.mark.django_db
@@ -1143,7 +1143,7 @@ def test_order_create_tax_rule_wrong_event(token_client, organizer, event, item,
), format='json', data=res
)
assert resp.status_code == 400
assert resp.data == {'fees': {0: {'tax_rule': ['The specified tax rate does not belong to this event.']}}}
assert resp.data == {'fees': [{'tax_rule': ['The specified tax rate does not belong to this event.']}]}
@pytest.mark.django_db
@@ -1158,7 +1158,7 @@ def test_order_create_subevent_not_allowed(token_client, organizer, event, item,
), format='json', data=res
)
assert resp.status_code == 400
assert resp.data == {'positions': {0: {'subevent': ['You cannot set a subevent for this event.']}}}
assert resp.data == {'positions': [{'subevent': ['You cannot set a subevent for this event.']}]}
@pytest.mark.django_db
@@ -1185,7 +1185,7 @@ def test_order_create_subevent_validation(token_client, organizer, event, item,
), format='json', data=res
)
assert resp.status_code == 400
assert resp.data == {'positions': {0: {'subevent': ['You need to set a subevent.']}}}
assert resp.data == {'positions': [{'subevent': ['You need to set a subevent.']}]}
res['positions'][0]['subevent'] = subevent2.pk
resp = token_client.post(
@@ -1194,7 +1194,7 @@ def test_order_create_subevent_validation(token_client, organizer, event, item,
), format='json', data=res
)
assert resp.status_code == 400
assert resp.data == {'positions': {0: {'subevent': ['The specified subevent does not belong to this event.']}}}
assert resp.data == {'positions': [{'subevent': ['The specified subevent does not belong to this event.']}]}
@pytest.mark.django_db
@@ -1210,7 +1210,7 @@ def test_order_create_item_validation(token_client, organizer, event, item, item
), format='json', data=res
)
assert resp.status_code == 400
assert resp.data == {'positions': {0: {'item': ['The specified item is not active.']}}}
assert resp.data == {'positions': [{'item': ['The specified item is not active.']}]}
item.active = True
item.save()
@@ -1222,7 +1222,7 @@ def test_order_create_item_validation(token_client, organizer, event, item, item
), format='json', data=res
)
assert resp.status_code == 400
assert resp.data == {'positions': {0: {'item': ['The specified item does not belong to this event.']}}}
assert resp.data == {'positions': [{'item': ['The specified item does not belong to this event.']}]}
with scopes_disabled():
var2 = item2.variations.create(value="A")
@@ -1236,7 +1236,7 @@ def test_order_create_item_validation(token_client, organizer, event, item, item
), format='json', data=res
)
assert resp.status_code == 400
assert resp.data == {'positions': {0: {'variation': ['You cannot specify a variation for this item.']}}}
assert resp.data == {'positions': [{'variation': ['You cannot specify a variation for this item.']}]}
with scopes_disabled():
var1 = item.variations.create(value="A")
@@ -1248,7 +1248,7 @@ def test_order_create_item_validation(token_client, organizer, event, item, item
), format='json', data=res
)
assert resp.status_code == 400
assert resp.data == {'positions': {0: {'item': ['The product "Budget Ticket" is not assigned to a quota.']}}}
assert resp.data == {'positions': [{'item': ['The product "Budget Ticket" is not assigned to a quota.']}]}
with scopes_disabled():
quota.variations.add(var1)
@@ -1267,7 +1267,7 @@ def test_order_create_item_validation(token_client, organizer, event, item, item
)
assert resp.status_code == 400
assert resp.data == {
'positions': {0: {'variation': ['The specified variation does not belong to the specified item.']}}}
'positions': [{'variation': ['The specified variation does not belong to the specified item.']}]}
res['positions'][0]['variation'] = None
resp = token_client.post(
@@ -1276,7 +1276,7 @@ def test_order_create_item_validation(token_client, organizer, event, item, item
), format='json', data=res
)
assert resp.status_code == 400
assert resp.data == {'positions': {0: {'variation': ['You should specify a variation for this item.']}}}
assert resp.data == {'positions': [{'variation': ['You should specify a variation for this item.']}]}
@pytest.mark.django_db
@@ -1294,7 +1294,7 @@ def test_order_create_subevent_disabled(token_client, organizer, event, item, su
), format='json', data=res
)
assert resp.status_code == 400
assert resp.data == {'positions': {0: {'item': ['The product "Budget Ticket" is not available on this date.']}}}
assert resp.data == {'positions': [{'item': ['The product "Budget Ticket" is not available on this date.']}]}
s.delete()
resp = token_client.post(
@@ -1326,7 +1326,7 @@ def test_order_create_subevent_variation_disabled(token_client, organizer, event
), format='json', data=res
)
assert resp.status_code == 400
assert resp.data == {'positions': {0: {'item': ['The product "Budget Ticket" is not available on this date.']}}}
assert resp.data == {'positions': [{'item': ['The product "Budget Ticket" is not available on this date.']}]}
s.delete()
resp = token_client.post(
@@ -1453,15 +1453,16 @@ def test_order_create_positionid_validation(token_client, organizer, event, item
)
assert resp.status_code == 400
assert resp.data == {
'positions': {
1: {
'positions': [
{},
{
'addon_to': [
'If you set addon_to, you need to make sure that the '
'referenced position ID exists and is transmitted directly '
'before its add-ons.'
]
}
}
]
}
res['positions'] = [
@@ -1492,14 +1493,10 @@ def test_order_create_positionid_validation(token_client, organizer, event, item
), format='json', data=res
)
assert resp.status_code == 400
assert resp.data == {'positions': {
0:
{'positionid': [
"If you set addon_to on any position, you need to specify position IDs manually."]},
1:
{'positionid': [
"If you set addon_to on any position, you need to specify position IDs manually."]}
}}
assert resp.data == {'positions': [
{'positionid': ["If you set addon_to on any position, you need to specify position IDs manually."]},
{'positionid': ["If you set addon_to on any position, you need to specify position IDs manually."]}
]}
res['positions'] = [
{
@@ -1529,11 +1526,12 @@ def test_order_create_positionid_validation(token_client, organizer, event, item
)
assert resp.status_code == 400
assert resp.data == {
'positions': {
1: {
'positions': [
{},
{
'positionid': ['If you set position IDs manually, you need to do so for all positions.']
}
}
]
}
res['positions'] = [
@@ -1565,11 +1563,12 @@ def test_order_create_positionid_validation(token_client, organizer, event, item
)
assert resp.status_code == 400
assert resp.data == {
'positions': {
1: {
'positions': [
{},
{
'positionid': ['Position IDs need to be consecutive.']
}
}
]
}
res['positions'] = [
@@ -1616,7 +1615,7 @@ def test_order_create_answer_validation(token_client, organizer, event, item, qu
)
assert resp.status_code == 400
assert resp.data == {
'positions': {0: {'answers': {0: {'question': ['The specified question does not belong to this event.']}}}}}
'positions': [{'answers': [{'question': ['The specified question does not belong to this event.']}]}]}
res['positions'][0]['answers'][0]['question'] = question.pk
res['positions'][0]['answers'][0]['options'] = [question.options.first().pk]
@@ -1626,8 +1625,8 @@ def test_order_create_answer_validation(token_client, organizer, event, item, qu
), format='json', data=res
)
assert resp.status_code == 400
assert resp.data == {'positions': {0: {'answers': {
0: {'non_field_errors': ['You should not specify options if the question is not of a choice type.']}}}}}
assert resp.data == {'positions': [{'answers': [
{'non_field_errors': ['You should not specify options if the question is not of a choice type.']}]}]}
question.type = Question.TYPE_CHOICE
question.save()
@@ -1638,8 +1637,8 @@ def test_order_create_answer_validation(token_client, organizer, event, item, qu
), format='json', data=res
)
assert resp.status_code == 400
assert resp.data == {'positions': {0: {
'answers': {0: {'non_field_errors': ['You need to specify options if the question is of a choice type.']}}}}}
assert resp.data == {'positions': [
{'answers': [{'non_field_errors': ['You need to specify options if the question is of a choice type.']}]}]}
with scopes_disabled():
question2.options.create(answer="L")
@@ -1654,8 +1653,7 @@ def test_order_create_answer_validation(token_client, organizer, event, item, qu
)
assert resp.status_code == 400
assert resp.data == {
'positions': {
0: {'answers': {0: {'non_field_errors': ['The specified option does not belong to this question.']}}}}}
'positions': [{'answers': [{'non_field_errors': ['The specified option does not belong to this question.']}]}]}
with scopes_disabled():
question.options.create(answer="L")
@@ -1671,8 +1669,7 @@ def test_order_create_answer_validation(token_client, organizer, event, item, qu
)
assert resp.status_code == 400
assert resp.data == {
'positions': {
0: {'answers': {0: {'non_field_errors': ['You can specify at most one option for this question.']}}}}}
'positions': [{'answers': [{'non_field_errors': ['You can specify at most one option for this question.']}]}]}
r = token_client.post(
'/api/v1/upload',
@@ -1748,7 +1745,7 @@ def test_order_create_answer_validation(token_client, organizer, event, item, qu
), format='json', data=res
)
assert resp.status_code == 400
assert resp.data == {'positions': {0: {'answers': {0: {'non_field_errors': ['A valid number is required.']}}}}}
assert resp.data == {'positions': [{'answers': [{'non_field_errors': ['A valid number is required.']}]}]}
question.type = Question.TYPE_BOOLEAN
question.save()
@@ -1790,8 +1787,8 @@ def test_order_create_answer_validation(token_client, organizer, event, item, qu
), format='json', data=res
)
assert resp.status_code == 400
assert resp.data == {'positions': {
0: {'answers': {0: {'non_field_errors': ['Please specify "true" or "false" for boolean questions.']}}}}}
assert resp.data == {
'positions': [{'answers': [{'non_field_errors': ['Please specify "true" or "false" for boolean questions.']}]}]}
question.type = Question.TYPE_DATE
question.save()
@@ -1817,8 +1814,8 @@ def test_order_create_answer_validation(token_client, organizer, event, item, qu
), format='json', data=res
)
assert resp.status_code == 400
assert resp.data == {'positions': {0: {'answers': {
0: {'non_field_errors': ['Date has wrong format. Use one of these formats instead: YYYY-MM-DD.']}}}}}
assert resp.data == {'positions': [{'answers': [
{'non_field_errors': ['Date has wrong format. Use one of these formats instead: YYYY-MM-DD.']}]}]}
question.type = Question.TYPE_DATETIME
question.save()
@@ -1844,9 +1841,9 @@ def test_order_create_answer_validation(token_client, organizer, event, item, qu
), format='json', data=res
)
assert resp.status_code == 400
assert resp.data == {'positions': {0: {'answers': {0: {'non_field_errors': [
assert resp.data == {'positions': [{'answers': [{'non_field_errors': [
'Datetime has wrong format. Use one of these formats instead: '
'YYYY-MM-DDThh:mm[:ss[.uuuuuu]][+HH:MM|-HH:MM|Z].']}}}}}
'YYYY-MM-DDThh:mm[:ss[.uuuuuu]][+HH:MM|-HH:MM|Z].']}]}]}
question.type = Question.TYPE_TIME
question.save()
@@ -1872,8 +1869,8 @@ def test_order_create_answer_validation(token_client, organizer, event, item, qu
), format='json', data=res
)
assert resp.status_code == 400
assert resp.data == {'positions': {0: {'answers': {
0: {'non_field_errors': ['Time has wrong format. Use one of these formats instead: hh:mm[:ss[.uuuuuu]].']}}}}}
assert resp.data == {'positions': [{'answers': [
{'non_field_errors': ['Time has wrong format. Use one of these formats instead: hh:mm[:ss[.uuuuuu]].']}]}]}
@pytest.mark.django_db
@@ -1913,10 +1910,10 @@ def test_order_create_quota_validation(token_client, organizer, event, item, quo
)
assert resp.status_code == 400
assert resp.data == {
'positions': {
0: {'item': ['There is not enough quota available on quota "Budget Quota" to perform the operation.']},
1: {'item': ['There is not enough quota available on quota "Budget Quota" to perform the operation.']},
}
'positions': [
{'item': ['There is not enough quota available on quota "Budget Quota" to perform the operation.']},
{'item': ['There is not enough quota available on quota "Budget Quota" to perform the operation.']},
]
}
quota.size = 1
@@ -1927,8 +1924,12 @@ def test_order_create_quota_validation(token_client, organizer, event, item, quo
), format='json', data=res
)
assert resp.status_code == 400
assert resp.data == {'positions': {
1: {'item': ['There is not enough quota available on quota "Budget Quota" to perform the operation.']}}}
assert resp.data == {
'positions': [
{},
{'item': ['There is not enough quota available on quota "Budget Quota" to perform the operation.']},
]
}
res['force'] = True
resp = token_client.post(
@@ -1960,8 +1961,11 @@ def test_order_create_quota_consume_cart(token_client, organizer, event, item, q
), format='json', data=res
)
assert resp.status_code == 400
assert resp.data == {'positions': {
0: {'item': ['There is not enough quota available on quota "Budget Quota" to perform the operation.']}}}
assert resp.data == {
'positions': [
{'item': ['There is not enough quota available on quota "Budget Quota" to perform the operation.']},
]
}
res['consume_carts'] = [cr.cart_id]
resp = token_client.post(
@@ -1996,8 +2000,11 @@ def test_order_create_quota_consume_cart_expired(token_client, organizer, event,
), format='json', data=res
)
assert resp.status_code == 400
assert resp.data == {'positions': {
0: {'item': ['There is not enough quota available on quota "Budget Quota" to perform the operation.']}}}
assert resp.data == {
'positions': [
{'item': ['There is not enough quota available on quota "Budget Quota" to perform the operation.']},
]
}
@pytest.mark.django_db
@@ -2169,7 +2176,11 @@ def test_order_create_with_blocked_seat(token_client, organizer, event, item, qu
), format='json', data=res
)
assert resp.status_code == 400
assert resp.data == {'positions': {0: {'seat': ['The selected seat "Seat A1" is not available.']}}}
assert resp.data == {
'positions': [
{'seat': ['The selected seat "Seat A1" is not available.']},
]
}
@pytest.mark.django_db
@@ -2188,7 +2199,11 @@ def test_order_create_with_used_seat(token_client, organizer, event, item, quota
), format='json', data=res
)
assert resp.status_code == 400
assert resp.data == {'positions': {0: {'seat': ['The selected seat "Seat A1" is not available.']}}}
assert resp.data == {
'positions': [
{'seat': ['The selected seat "Seat A1" is not available.']},
]
}
@pytest.mark.django_db
@@ -2203,7 +2218,11 @@ def test_order_create_with_unknown_seat(token_client, organizer, event, item, qu
), format='json', data=res
)
assert resp.status_code == 400
assert resp.data == {'positions': {0: {'seat': ['The specified seat does not exist.']}}}
assert resp.data == {
'positions': [
{'seat': ['The specified seat does not exist.']},
]
}
@pytest.mark.django_db
@@ -2217,7 +2236,11 @@ def test_order_create_require_seat(token_client, organizer, event, item, quota,
), format='json', data=res
)
assert resp.status_code == 400
assert resp.data == {'positions': {0: {'seat': ['The specified product requires to choose a seat.']}}}
assert resp.data == {
'positions': [
{'seat': ['The specified product requires to choose a seat.']},
]
}
@pytest.mark.django_db
@@ -2235,7 +2258,11 @@ def test_order_create_unseated(token_client, organizer, event, item, quota, seat
), format='json', data=res
)
assert resp.status_code == 400
assert resp.data == {'positions': {0: {'seat': ['The specified product does not allow to choose a seat.']}}}
assert resp.data == {
'positions': [
{'seat': ['The specified product does not allow to choose a seat.']},
]
}
@pytest.mark.django_db
@@ -2273,7 +2300,12 @@ def test_order_create_with_duplicate_seat(token_client, organizer, event, item,
), format='json', data=res
)
assert resp.status_code == 400
assert resp.data == {'positions': {1: {'seat': ['The selected seat "Seat A1" is not available.']}}}
assert resp.data == {
'positions': [
{},
{'seat': ['The selected seat "Seat A1" is not available.']},
]
}
@pytest.mark.django_db
@@ -2778,8 +2810,8 @@ def test_order_create_autopricing_voucher_budget_full(token_client, organizer, e
), format='json', data=res
)
assert resp.status_code == 400
assert resp.data == {'positions': {1: {'voucher': ['The voucher has a remaining budget of 0.00, therefore a '
'discount of 1.50 can not be given.']}}}
assert resp.data == {'positions': [{}, {'voucher': ['The voucher has a remaining budget of 0.00, therefore a '
'discount of 1.50 can not be given.']}]}
@pytest.mark.django_db
@@ -2800,8 +2832,8 @@ def test_order_create_voucher_budget_exceeded(token_client, organizer, event, it
), format='json', data=res
)
assert resp.status_code == 400
assert resp.data == {'positions': {0: {'voucher': ['The voucher has a remaining budget of 3.00, therefore a '
'discount of 4.00 can not be given.']}}}
assert resp.data == {'positions': [{'voucher': ['The voucher has a remaining budget of 3.00, therefore a '
'discount of 4.00 can not be given.']}]}
@pytest.mark.django_db
@@ -2844,7 +2876,11 @@ def test_order_create_voucher_unknown_code(token_client, organizer, event, item,
), format='json', data=res
)
assert resp.status_code == 400
assert resp.data == {'positions': {0: {'voucher': ['Object with code=FOOBAR does not exist.']}}}
assert resp.data == {
'positions': [
{'voucher': ['Object with code=FOOBAR does not exist.']},
]
}
@pytest.mark.django_db
@@ -2863,7 +2899,9 @@ def test_order_create_voucher_redeemed(token_client, organizer, event, item, quo
)
assert resp.status_code == 400
assert resp.data == {
'positions': {0: {'voucher': ['The voucher has already been used the maximum number of times.']}}
'positions': [
{'voucher': ['The voucher has already been used the maximum number of times.']},
]
}
@@ -2886,10 +2924,11 @@ def test_order_create_voucher_redeemed_partially(token_client, organizer, event,
)
assert resp.status_code == 400
assert resp.data == {
'positions': {
1: {'voucher': ['The voucher has already been used the maximum number of times.']},
2: {'voucher': ['The voucher has already been used the maximum number of times.']},
}
'positions': [
{},
{'voucher': ['The voucher has already been used the maximum number of times.']},
{'voucher': ['The voucher has already been used the maximum number of times.']},
]
}
@@ -2910,7 +2949,10 @@ def test_order_create_voucher_item_mismatch(token_client, organizer, event, item
)
assert resp.status_code == 400
assert resp.data == {
'positions': {0: {'voucher': ['This voucher is not valid for this product.']}}}
'positions': [
{'voucher': ['This voucher is not valid for this product.']},
]
}
@pytest.mark.django_db
@@ -2930,7 +2972,10 @@ def test_order_create_voucher_expired(token_client, organizer, event, item, quot
)
assert resp.status_code == 400
assert resp.data == {
'positions': {0: {'voucher': ['This voucher is expired.']}}}
'positions': [
{'voucher': ['This voucher is expired.']},
]
}
@pytest.mark.django_db
@@ -3058,8 +3103,10 @@ def test_create_cart_and_consume_cart_with_addons(token_client, organizer, event
)
assert resp.status_code == 400
assert resp.data == {
'positions': {
1: {'item': ['There is not enough quota available on quota "Addon Quota" to perform the operation.']}}
'positions': [
{},
{'item': ['There is not enough quota available on quota "Addon Quota" to perform the operation.']},
]
}
res['consume_carts'] = ['aaa@api']
@@ -3167,7 +3214,12 @@ def test_order_create_use_medium_other_organizer(token_client, organizer, event,
), format='json', data=res
)
assert resp.data == {
"positions": {0: {"use_reusable_medium": ["The specified medium does not belong to this organizer."]}}}
"positions": [
{
"use_reusable_medium": ["The specified medium does not belong to this organizer."]
}
]
}
assert resp.status_code == 400
@@ -3309,8 +3361,14 @@ def test_order_create_auto_pricing_explicit_discount_not_allowed(token_client, o
), format='json', data=res
)
assert resp.status_code == 400
assert resp.data == {"positions": {
1: {"discount": ["You can only specify a discount if you do the price computation, but price is not set."]}}}
assert resp.data == {
"positions": [
{},
{
"discount": ["You can only specify a discount if you do the price computation, but price is not set."]
}
]
}
@pytest.mark.django_db
+3 -4
View File
@@ -409,7 +409,7 @@ def test_subevent_create(team, token_client, organizer, event, subevent, meta_pr
format='json'
)
assert resp.status_code == 400
assert resp.data == {"item_price_overrides": {0: {"item": ["Invalid pk \"555\" - object does not exist."]}}}
assert resp.content.decode() == '{"item_price_overrides":[{"item":["Invalid pk \\"555\\" - object does not exist."]}]}'
@pytest.mark.django_db
@@ -580,7 +580,7 @@ def test_subevent_update(token_client, organizer, event, subevent, item, item2,
format='json'
)
assert resp.status_code == 400
assert resp.data == {"item_price_overrides": {0: {"item": ["Invalid pk \"123\" - object does not exist."]}}}
assert resp.content.decode() == '{"item_price_overrides":[{"item":["Invalid pk \\"123\\" - object does not exist."]}]}'
resp = token_client.patch(
'/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug, subevent.pk),
@@ -686,8 +686,7 @@ def test_subevent_update(token_client, organizer, event, subevent, item, item2,
format='json'
)
assert resp.status_code == 400
assert resp.data == {
"variation_price_overrides": {0: {"variation": ["Invalid pk \"123\" - object does not exist."]}}}
assert resp.content.decode() == '{"variation_price_overrides":[{"variation":["Invalid pk \\"123\\" - object does not exist."]}]}'
resp = token_client.patch(
'/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug, subevent.pk),
+3 -3
View File
@@ -1061,7 +1061,7 @@ def test_create_multiple_vouchers_one_invalid(token_client, organizer, event, it
], format='json'
)
assert resp.status_code == 400
assert resp.data == {1: {'code': ['Ensure this field has at least 5 characters.']}}
assert resp.data == [{}, {'code': ['Ensure this field has at least 5 characters.']}]
with scopes_disabled():
assert Voucher.objects.count() == 0
@@ -1106,7 +1106,7 @@ def test_create_multiple_vouchers_duplicate_code(token_client, organizer, event,
], format='json'
)
assert resp.status_code == 400
assert resp.data == {1: {'code': ['Duplicate voucher code in request.']}}
assert resp.data == [{}, {'code': ['Duplicate voucher code in request.']}]
with scopes_disabled():
assert Voucher.objects.count() == 0
@@ -1214,7 +1214,7 @@ def test_create_multiple_vouchers_duplicate_seat(token_client, organizer, event,
], format='json'
)
assert resp.status_code == 400
assert resp.data == {1: {'code': ['Duplicate seat ID in request.']}}
assert resp.data == [{}, {'code': ['Duplicate seat ID in request.']}]
with scopes_disabled():
assert Voucher.objects.count() == 0
@@ -311,7 +311,7 @@ def test_renderer_batch_invalid(env, token_client, position):
format='json',
)
assert resp.status_code == 400
assert resp.data == {"parts": {0: {"orderposition": ["Invalid pk \"-2\" - object does not exist."]}}}
assert resp.data == {"parts": [{"orderposition": ["Invalid pk \"-2\" - object does not exist."]}]}
resp = token_client.post(
'/api/v1/organizers/{}/events/{}/ticketpdfrenderer/render_batch/'.format(env[0].slug, env[0].slug),
@@ -326,7 +326,7 @@ def test_renderer_batch_invalid(env, token_client, position):
format='json',
)
assert resp.status_code == 400
assert resp.data == {"parts": {0: {"override_layout": ["Invalid pk \"-2\" - object does not exist."]}}}
assert resp.data == {"parts": [{"override_layout": ["Invalid pk \"-2\" - object does not exist."]}]}
resp = token_client.post(
'/api/v1/organizers/{}/events/{}/ticketpdfrenderer/render_batch/'.format(env[0].slug, env[0].slug),
@@ -341,7 +341,7 @@ def test_renderer_batch_invalid(env, token_client, position):
format='json',
)
assert resp.status_code == 400
assert resp.data == {"parts": {0: {"override_channel": ["Object with identifier=magic does not exist."]}}}
assert resp.data == {"parts": [{"override_channel": ["Object with identifier=magic does not exist."]}]}
resp = token_client.post(
'/api/v1/organizers/{}/events/{}/ticketpdfrenderer/render_batch/'.format(env[0].slug, env[0].slug),