Compare commits

..
Author SHA1 Message Date
Kara Engelhardt b730e372f5 subeventbulkeditform: only allow relative presale_start/_end
matches relative fields in SubEventBulkCreate
2026-10-22 17:25:51 +02:00
Richard Schreiber 5a2e615983 TODO: remove _day and _time fields? 2026-10-22 11:21:26 +02:00
Richard Schreiber 2b7a988693 Add reldate to subevent batch-edit 2026-10-22 11:21:03 +02:00
11 changed files with 290 additions and 246 deletions

No files matched your search

+2 -2
View File
@@ -57,7 +57,7 @@ dependencies = [
"django-redis==7.0.*",
"django-scopes==2.1.*",
"django-statici18n==2.8.*",
"djangorestframework>=3.18.2",
"djangorestframework==3.17.*",
"dnspython==2.8.*",
"drf_ujson2==1.7.*",
"geoip2==5.*",
@@ -77,7 +77,7 @@ dependencies = [
"paypal-checkout-serversdk==1.0.*",
"PyJWT==2.15.*",
"phonenumberslite==9.0.*",
"Pillow==13.0.*",
"Pillow==12.3.*",
"pretix-plugin-build",
"protobuf==7.36.*",
"psycopg2-binary",
+1 -1
View File
@@ -76,7 +76,7 @@ class DeviceTokenAuthentication(TokenAuthentication):
except DeviceLastSeen.DoesNotExist:
# First request from device, create model, ignore result. Use get_or_create to be safe
# against concurrent create requests
DeviceLastSeen.objects.get_or_create(device=device, defaults={"last_seen": now()})
DeviceLastSeen.objects.get_or_create(device=device, last_seen=now())
else:
if now() - last_seen_obj.last_seen < timedelta(seconds=10):
# We don't need to know the last seen info of a device to more precision than this,
+24 -1
View File
@@ -153,7 +153,7 @@ class SubEventBulkEditForm(I18nModelForm):
self.fields[k].widget.is_required = False
self.fields[k].required = False
for k in ('date_from', 'date_to', 'date_admission', 'presale_start', 'presale_end'):
for k in ('date_from', 'date_to', 'date_admission'):
self.fields[k + '_day'] = forms.DateField(
label=self._meta.model._meta.get_field(k).verbose_name,
help_text=self._meta.model._meta.get_field(k).help_text,
@@ -167,6 +167,17 @@ class SubEventBulkEditForm(I18nModelForm):
required=False,
)
for k in ('presale_start', 'presale_end'):
self.fields[k + '_rel'] = RelativeDateTimeField(
label=self._meta.model._meta.get_field(k).verbose_name,
help_text=(
self._meta.model._meta.get_field(k).help_text + " "
+ _("If base your relative date on one that is not defined on the event, it will fall back to the event's start.")
),
required=False,
limit_choices=('event__date_from', 'event__date_to'),
)
class Meta:
model = SubEvent
localized_fields = '__all__'
@@ -247,6 +258,18 @@ class SubEventBulkEditForm(I18nModelForm):
)
setattr(obj, k.replace('_time', ''), newval)
fields.add(k.replace('_time', ''))
elif k.endswith('_rel'):
target_key = k[:-4]
for obj in objs:
cval = self.cleaned_data[k]
if cval is None:
newval = None
if not self._meta.model._meta.get_field(target_key, '').null:
continue
else:
newval = cval.datetime(obj)
setattr(obj, target_key, newval)
fields.add(target_key)
else:
fields.add(k)
for obj in objs:
@@ -127,28 +127,8 @@
{% bootstrap_field form.date_admission_time layout="bulkedit_inline" form_group_class="" %}
</div>
</div>
<div class="form-group">
<label class="col-md-3 control-label" for="{{ form.presale_start_day.id_for_label }}">
{{ form.presale_start_day.label }}
</label>
<div class="col-md-5">
{% bootstrap_field form.presale_start_day layout="bulkedit_inline" form_group_class="" %}
</div>
<div class="col-md-4">
{% bootstrap_field form.presale_start_time layout="bulkedit_inline" form_group_class="" %}
</div>
</div>
<div class="form-group">
<label class="col-md-3 control-label" for="{{ form.presale_end_day.id_for_label }}">
{{ form.presale_end_day.label }}
</label>
<div class="col-md-5">
{% bootstrap_field form.presale_end_day layout="bulkedit_inline" form_group_class="" %}
</div>
<div class="col-md-4">
{% bootstrap_field form.presale_end_time layout="bulkedit_inline" form_group_class="" %}
</div>
</div>
{% bootstrap_field form.presale_start_rel layout="bulkedit" placeholder=datetime_sample %}
{% bootstrap_field form.presale_end_rel layout="bulkedit" placeholder=datetime_sample %}
</fieldset>
<fieldset>
<legend>{% trans "Item prices" %}</legend>
+50 -7
View File
@@ -44,7 +44,7 @@ from django.db import transaction
from django.db.models import (
Count, Exists, F, OuterRef, Prefetch, ProtectedError, Subquery,
)
from django.db.models.functions import Coalesce, TruncDate, TruncTime
from django.db.models.functions import Coalesce, TruncDate, TruncTime, Extract
from django.forms import inlineformset_factory
from django.http import Http404, HttpResponse, HttpResponseRedirect
from django.shortcuts import redirect, render
@@ -1590,12 +1590,20 @@ class SubEventBulkEdit(SubEventQueryMixin, EventPermissionRequiredMixin, FormVie
# as well in all cases we are concerned about
# See also: https://code.djangoproject.com/ticket/31948
k + '_day': TruncDate(k)
for k in ('date_from', 'date_to', 'date_admission', 'presale_start', 'presale_end')
for k in ('date_from', 'date_to', 'date_admission')
},
**{
k + '_time': TruncTime(k)
for k in ('date_from', 'date_to', 'date_admission', 'presale_start', 'presale_end')
for k in ('date_from', 'date_to', 'date_admission')
},
**{
k + '_rel_min': Extract(F('date_from') - F(k), 'epoch') / 60
for k in ['presale_start', "presale_end"]
},
**{
k + '_rel_days': Extract(F('date_from__date') - F(f"{k}__date"), 'days')
for k in ['presale_start', "presale_end"]
}
)
fields = {
@@ -1613,10 +1621,6 @@ class SubEventBulkEdit(SubEventQueryMixin, EventPermissionRequiredMixin, FormVie
'date_to_time',
'date_admission_day',
'date_admission_time',
'presale_start_day',
'presale_start_time',
'presale_end_day',
'presale_end_time',
}
for k in fields:
existing_values = list(qs.order_by(k).values(k).annotate(c=Count('*')))
@@ -1626,6 +1630,45 @@ class SubEventBulkEdit(SubEventQueryMixin, EventPermissionRequiredMixin, FormVie
mixed_values.add(k)
initial[k] = None
for k in ['presale_start', "presale_end"]:
existing_fixed_values = list(qs.order_by(k).values(k).annotate(c=Count('*')))
existing_rel_days_values = list(qs.order_by(f'{k}_rel_days').values(f'{k}_rel_days').annotate(c=Count("*")))
existing_rel_min_values = list(qs.order_by(f'{k}_rel_min').values(f'{k}_rel_min').annotate(c=Count("*")))
if len(existing_fixed_values) == 1:
if existing_fixed_values[0][k]:
initial[f"{k}_rel"] = RelativeDateWrapper(existing_fixed_values[0][k])
else:
initial[f"{k}_rel"] = None
elif len(existing_rel_min_values) == 1:
if rel_min := existing_rel_min_values[0][f'{k}_rel_min']:
initial[f"{k}_rel"] = RelativeDateWrapper(RelativeDate(
days=0,
base_date_name='event__date_from',
time=None,
minutes=abs(rel_min),
is_after=rel_min < 0,
))
else:
initial[f"{k}_rel"] = None
elif len(existing_rel_days_values) == 1:
if rel_days := existing_rel_days_values[0][f'{k}_rel_days']:
initial[f"{k}_rel"] = RelativeDateWrapper(RelativeDate(
days=abs(rel_days),
base_date_name='event__date_from',
time=None,
minutes=None,
is_after=rel_days < 0,
))
else:
initial[f"{k}_rel"] = None
elif len(existing_fixed_values) > 1 or len(existing_rel_days_values) > 1 or len(existing_rel_min_values) > 1:
mixed_values.add(k)
initial[k] = None
kwargs = super().get_form_kwargs()
kwargs['event'] = self.request.event
kwargs['prefix'] = 'bulkedit'
+26 -22
View File
@@ -8,16 +8,16 @@ msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-09-30 07:26+0000\n"
"PO-Revision-Date: 2026-10-23 13:02+0000\n"
"Last-Translator: Martin Gross <gross@rami.io>\n"
"Language-Team: Basque <https://translate.pretix.eu/projects/pretix/pretix/"
"eu/>\n"
"PO-Revision-Date: 2026-09-04 14:29+0000\n"
"Last-Translator: Albizuri <oier@puntu.eus>\n"
"Language-Team: Basque <https://translate.pretix.eu/projects/pretix/pretix/eu/"
">\n"
"Language: eu\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 2026.10.1\n"
"X-Generator: Weblate 2026.9\n"
#: pretix/_base_settings.py
msgid "English"
@@ -36,9 +36,8 @@ msgid "Arabic"
msgstr "Arabiera"
#: pretix/_base_settings.py
#, fuzzy
msgid "Basque"
msgstr "Euskera"
msgstr ""
#: pretix/_base_settings.py
msgid "Catalan"
@@ -1172,9 +1171,10 @@ msgid "Check-in datetime on list {}"
msgstr "Izen-emate zerrendak"
#: pretix/base/datasync/sourcefields.py
#, python-brace-format
#, fuzzy, python-brace-format
#| msgid "Question {val}"
msgid "Question: {name}"
msgstr "Galdera {name}"
msgstr "Galdera {val}"
#: pretix/base/datasync/sourcefields.py pretix/base/settings.py
msgid "Given name"
@@ -1295,7 +1295,7 @@ msgstr ""
#: pretix/control/navigation.py
#: pretix/control/templates/pretixcontrol/organizers/customers.html
msgid "Customers"
msgstr "Bezeroak"
msgstr ""
#: pretix/base/exporters/customers.py pretix/control/forms/filter.py
#: pretix/control/templates/pretixcontrol/organizers/customer.html
@@ -3096,7 +3096,7 @@ msgstr "Helbide elektronikoa"
#: pretix/base/forms/auth.py pretix/control/forms/orders.py
#: pretix/control/templates/pretixcontrol/shredder/download.html
msgid "Confirmation code"
msgstr "Baieztatze kodea"
msgstr ""
#: pretix/base/forms/questions.py
#, fuzzy
@@ -3162,7 +3162,7 @@ msgstr ""
#: pretix/base/forms/questions.py
msgid "Street"
msgstr "Kalea"
msgstr ""
#: pretix/base/forms/questions.py
msgid "State"
@@ -3430,9 +3430,11 @@ msgid "Exchange System (SdI)"
msgstr ""
#: pretix/base/invoicing/national.py
#, fuzzy
#| msgid "Gift card code"
msgctxt "italian_invoice"
msgid "Fiscal code"
msgstr "Kode fiskala"
msgstr "Opari-txartelaren kodea"
#: pretix/base/invoicing/national.py
msgctxt "italian_invoice"
@@ -3759,8 +3761,10 @@ msgid "The relevant plugin is currently not active."
msgstr "Produktu hau ez dago eskuragarri."
#: pretix/base/logentrytypes.py
#, fuzzy
#| msgid "Order deleted"
msgid "(deleted)"
msgstr "(Ezabatutako eskaera)"
msgstr "Ezabatutako eskaera"
#: pretix/base/logentrytypes.py
#, python-brace-format
@@ -6230,13 +6234,13 @@ msgstr "Amaiera"
#: pretix/control/templates/pretixcontrol/organizers/outgoing_mail.html
#: pretix/control/templates/pretixcontrol/organizers/outgoing_mails.html
msgid "queued"
msgstr "zerrendan"
msgstr ""
#: pretix/base/models/mail.py
#: pretix/control/templates/pretixcontrol/organizers/outgoing_mail.html
#: pretix/control/templates/pretixcontrol/organizers/outgoing_mails.html
msgid "being sent"
msgstr "bidaltzen"
msgstr ""
#: pretix/base/models/mail.py
#, fuzzy
@@ -6260,7 +6264,7 @@ msgstr ""
#: pretix/control/templates/pretixcontrol/organizers/outgoing_mail.html
#: pretix/control/templates/pretixcontrol/organizers/outgoing_mails.html
msgid "sent"
msgstr "bidalita"
msgstr ""
#: pretix/base/models/mail.py
#: pretix/control/templates/pretixcontrol/organizers/outgoing_mail.html
@@ -6638,7 +6642,7 @@ msgstr "Egiaztatzeak huts egin du"
#: pretix/base/models/orders.py pretix/control/views/event.py
#: pretix/control/views/organizer.py
msgid "Other"
msgstr "Beste bat"
msgstr ""
#: pretix/base/models/organizer.py
msgid ""
@@ -6795,7 +6799,7 @@ msgstr "Ordainketa itzuli"
#, fuzzy
#| msgid "Tax rate"
msgid "Tax free"
msgstr "Zergarik ez"
msgstr "Zerga-tasa"
#: pretix/base/models/tax.py
msgctxt "tax_code"
@@ -14803,7 +14807,7 @@ msgstr ""
#: pretix/control/forms/event.py
msgid "European Union"
msgstr "Europar Batasuna"
msgstr ""
#: pretix/control/forms/event.py
msgid "Any customer"
@@ -18745,7 +18749,7 @@ msgstr ""
#: pretix/control/templates/pretixcontrol/auth/login.html
#: pretix/control/templates/pretixcontrol/auth/register.html
msgid "Register"
msgstr "Berretsi"
msgstr ""
#: pretix/control/templates/pretixcontrol/auth/login.html
msgid ""
@@ -21605,7 +21609,7 @@ msgstr ""
#: pretix/control/templates/pretixcontrol/fragment_quota_box_paid.html
#, python-format
msgid "Currently available: %(num)s"
msgstr "Eskuragarri gaur egun: %(num)s"
msgstr ""
#: pretix/control/templates/pretixcontrol/global_license.html
msgid ""
+11 -11
View File
@@ -8,8 +8,8 @@ msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-09-30 07:26+0000\n"
"PO-Revision-Date: 2026-10-23 13:02+0000\n"
"Last-Translator: Martin Gross <gross@rami.io>\n"
"PO-Revision-Date: 2026-07-29 11:04+0000\n"
"Last-Translator: Albizuri <oier@puntu.eus>\n"
"Language-Team: Basque <https://translate.pretix.eu/projects/pretix/pretix-js/"
"eu/>\n"
"Language: eu\n"
@@ -17,7 +17,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 2026.10.1\n"
"X-Generator: Weblate 2026.7.1\n"
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js
msgid "Marked as paid"
@@ -870,7 +870,7 @@ msgstr ""
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Register"
msgstr "Erregistratu"
msgstr ""
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
@@ -917,7 +917,7 @@ msgstr ""
#, javascript-format
msgctxt "widget"
msgid "currently available: %s"
msgstr "Eskuragarri gaur egun: %s"
msgstr ""
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
@@ -1054,32 +1054,32 @@ msgstr ""
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Choose a different date"
msgstr "Beste data bat aukera"
msgstr ""
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Back"
msgstr "Atzera"
msgstr ""
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Next month"
msgstr "Hurrengo hilabetea"
msgstr ""
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Previous month"
msgstr "Aurreko hilabetea"
msgstr ""
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Next week"
msgstr "Hurrengo astea"
msgstr ""
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
msgid "Previous week"
msgstr "Aurreko astea"
msgstr ""
#: pretix/static/pretixpresale/widget/src/i18n.ts
msgctxt "widget"
File diff suppressed because it is too large. Load diff
+1 -2
View File
@@ -506,8 +506,7 @@ REST_FRAMEWORK = {
'pretix.testutils.api.UploadRenderer',
],
'EXCEPTION_HANDLER': 'pretix.api.exception.custom_exception_handler',
'UNICODE_JSON': False,
'LIST_SERIALIZER_ERRORS_AS_DICT': False
'UNICODE_JSON': False
}
-1
View File
@@ -57,7 +57,6 @@ 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]
-4
View File
@@ -642,8 +642,6 @@ def assert_mail_connection(res, should_connect, use_ssl):
True, False
])
def test_private_smtp_ip(res, use_ssl, settings):
settings.EMAIL_HOST_USER = ''
settings.EMAIL_HOST_PASSWORD = ''
settings.EMAIL_CUSTOM_SMTP_BACKEND = 'pretix.base.email.CheckPrivateNetworkSmtpBackend'
settings.MAIL_CUSTOM_SMTP_ALLOW_PRIVATE_NETWORKS = False
with assert_mail_connection(res=res, should_connect=False, use_ssl=use_ssl), pytest.raises(match="Request to .* blocked"):
@@ -667,8 +665,6 @@ def test_private_smtp_ip(res, use_ssl, settings):
True, False
])
def test_public_smtp_ip(use_ssl, allow_private, settings):
settings.EMAIL_HOST_USER = ''
settings.EMAIL_HOST_PASSWORD = ''
settings.EMAIL_CUSTOM_SMTP_BACKEND = 'pretix.base.email.CheckPrivateNetworkSmtpBackend'
settings.MAIL_CUSTOM_SMTP_ALLOW_PRIVATE_NETWORKS = allow_private