Compare commits

..
1 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
13 changed files with 81 additions and 62 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,
})
-2
View File
@@ -197,8 +197,6 @@ class ReusableMediaSerializer(I18nAwareModelSerializer):
'linked_giftcard',
'info',
'notes',
# When adding fields, check if they should be hidden in ReusableMediaViewSet
# for cross-organizer lookups
)
-1
View File
@@ -117,7 +117,6 @@ class TransmissionInfoSerializer(serializers.Serializer):
super().__init__(*args, **kwargs)
for k, v in transmission_type.invoice_address_form_fields.items():
self.fields[k] = form_field_to_serializer_field(v)
self.fields[k].required = False # invoice_address_form_fields_required is checked by parent serializer
class InvoiceAddressSerializer(I18nAwareModelSerializer):
+2 -11
View File
@@ -183,18 +183,9 @@ class ReusableMediaViewSet(viewsets.ModelViewSet):
type=s.validated_data["type"],
identifier=s.validated_data["identifier"],
)
m.customer = None # not relevant for cross-organizer
s = self.get_serializer(m)
data = s.data
# Remove fields that are not relevant for cross-organizer usage
data["customer"] = None
data["linked_orderposition"] = None
data["linked_orderpositions"] = []
data["info"] = {}
data["notes"] = None
data["claim_token"] = None
data["label"] = None
return Response({"result": data})
return Response({"result": s.data})
except ReusableMedium.DoesNotExist:
mt = MEDIA_TYPES.get(s.validated_data["type"])
if mt:
+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
+17 -28
View File
@@ -27,7 +27,6 @@ from decimal import Decimal
from django import forms
from django.db.models import F, Sum
from django.db.models.aggregates import Min
from django.db.models.functions import Coalesce
from django.utils.formats import date_format
from django.utils.html import escape
@@ -42,8 +41,7 @@ from reportlab.platypus import (
from pretix.base.exporter import BaseExporter
from pretix.base.models import (
GiftCardTransaction, Order, OrderFee, OrderPayment, OrderRefund,
Transaction,
GiftCardTransaction, OrderFee, OrderPayment, OrderRefund, Transaction,
)
from pretix.base.templatetags.money import money_filter, tax_rate_format
from pretix.base.timeframes import (
@@ -118,34 +116,25 @@ class ReportExporter(ReportlabExportMixin, BaseExporter):
dt_start, df_end = resolve_timeframe_to_datetime_start_inclusive_end_exclusive(
now(), form_data["date_range"], self.timezone
)
else:
dt_start = Order.objects.filter(
event__in=self.events,
).aggregate(min_datetime=Min('datetime'))['min_datetime']
df_end = now()
if dt_start:
filters.append(
"{label}: {value}{hint}".format(
label=_("Begin"),
value=date_format(
if dt_start:
filters.append(
_("Begin")
+ ": "
+ date_format(
dt_start.astimezone(self.timezone), "SHORT_DATETIME_FORMAT"
),
hint="" if form_data["date_range"] else " ({})".format(_("first order received"))
)
)
)
if df_end:
filters.append(
_("End")
+ ": "
+ date_format(
(df_end - datetime.timedelta.resolution).astimezone(
self.timezone
),
"SHORT_DATETIME_FORMAT",
if df_end:
filters.append(
_("End")
+ ": "
+ date_format(
(df_end - datetime.timedelta.resolution).astimezone(
self.timezone
),
"SHORT_DATETIME_FORMAT",
)
)
)
if not form_data["no_testmode"]:
filters.append(_("Report includes test orders which may be deleted later!"))
-7
View File
@@ -75,7 +75,6 @@ class AuthenticationForm(forms.Form):
'unverified': _("You have not yet activated your account and set a password. Please click the link in the "
"email we sent you. In case you cannot find it, click \"Forgot your password?\" to receive "
"a new email."),
'rate_limit': _("For security reasons, please wait 5 minutes before you try again."),
}
def __init__(self, request=None, *args, **kwargs):
@@ -94,12 +93,6 @@ class AuthenticationForm(forms.Form):
email = self.cleaned_data.get('email')
password = self.cleaned_data.get('password')
if rate_limit("customer_login", include_ip_from_request=self.request, max_num=10, expire_time=300):
raise forms.ValidationError(
self.error_messages['rate_limit'],
code='rate_limit',
)
if email is not None and password:
try:
u = self.request.organizer.customers.get(email=email.lower(), provider__isnull=True)
@@ -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')
+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),
{
+1
View File
@@ -333,6 +333,7 @@ def test_order_update_transmission_validation(token_client, organizer, event, or
assert resp.status_code == 400
assert resp.data == {"invoice_address": {"transmission_info": {
"transmission_it_sdi_pec": ["Enter a valid email address.", "Enter a valid email address."],
"transmission_it_sdi_recipient_code": ["This field is required."]
}}}
resp = token_client.patch(
+1 -12
View File
@@ -696,7 +696,7 @@ def test_medium_autocreate_giftcard(token_client, organizer, team):
@pytest.mark.django_db
def test_medium_lookup_cross_organizer(token_client, organizer, customer, organizer2, org2_event, medium2, giftcard2):
def test_medium_lookup_cross_organizer(token_client, organizer, organizer2, org2_event, medium2, giftcard2):
with scopes_disabled():
o = Order.objects.create(
code='FOO', event=org2_event, email='dummy@dummy.test',
@@ -708,12 +708,7 @@ def test_medium_lookup_cross_organizer(token_client, organizer, customer, organi
personalized=True)
op = o.positions.create(item=ticket, price=Decimal("14"))
medium2.linked_orderpositions.add(op)
medium2.customer = customer
medium2.linked_giftcard = giftcard2
medium2.claim_token = "1234"
medium2.info = {"foo": "bar"}
medium2.notes = "Internal notes"
medium2.label = "Max Muster"
medium2.save()
resp = token_client.post(
@@ -760,9 +755,3 @@ def test_medium_lookup_cross_organizer(token_client, organizer, customer, organi
assert resp.data["result"]["organizer"] == "partner"
assert resp.data["result"]["linked_giftcard"] is not None
assert resp.data["result"]["linked_orderposition"] is None
assert resp.data["result"]["linked_orderpositions"] == []
assert resp.data["result"]["customer"] is None
assert resp.data["result"]["info"] == {}
assert resp.data["result"]["notes"] is None
assert resp.data["result"]["claim_token"] is None
assert resp.data["result"]["label"] is None