Compare commits

...

8 Commits

Author SHA1 Message Date
Raphael Michel
5094e5e4ec Bump to 3.14.2 2021-01-12 10:59:16 +01:00
Raphael Michel
222cab115e Fix UX quirk in phone number field triggered by American numbers 2021-01-12 10:58:57 +01:00
Raphael Michel
7809f8ac1a API: Fix CSS generation after change in event settings 2021-01-12 10:58:46 +01:00
Raphael Michel
839c76769c Fix duplicate listing of fonts in event settings 2021-01-12 10:58:16 +01:00
Raphael Michel
8b4cf9db70 Fix tests failing in 2021 2021-01-12 10:58:16 +01:00
Raphael Michel
099ab079f9 Fix geocoding with opencage 2021-01-12 10:58:16 +01:00
Raphael Michel
56c861036c Bump to 3.14.1 2020-12-22 13:19:59 +01:00
Raphael Michel
211fddf308 Fix #1888 -- UnknownLocaleError if locale is set 2020-12-22 13:19:51 +01:00
8 changed files with 68 additions and 33 deletions

View File

@@ -1 +1 @@
__version__ = "3.14.0" __version__ = "3.14.2"

View File

@@ -392,6 +392,6 @@ class EventSettingsView(views.APIView):
} }
) )
if any(p in s.changed_data for p in SETTINGS_AFFECTING_CSS): if any(p in s.changed_data for p in SETTINGS_AFFECTING_CSS):
regenerate_css.apply_async(args=(request.organizer.pk,)) regenerate_css.apply_async(args=(request.event.pk,))
s = EventSettingsSerializer(instance=request.event.settings, event=request.event) s = EventSettingsSerializer(instance=request.event.settings, event=request.event)
return Response(s.data) return Response(s.data)

View File

@@ -9,20 +9,19 @@ import pycountry
import pytz import pytz
import vat_moss.errors import vat_moss.errors
import vat_moss.id import vat_moss.id
from babel import localedata from babel import Locale
from django import forms from django import forms
from django.contrib import messages from django.contrib import messages
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.core.validators import MaxValueValidator, MinValueValidator from django.core.validators import MaxValueValidator, MinValueValidator
from django.db.models import QuerySet from django.db.models import QuerySet
from django.forms import Select from django.forms import Select
from django.utils import translation
from django.utils.formats import date_format from django.utils.formats import date_format
from django.utils.html import escape from django.utils.html import escape
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
from django.utils.timezone import get_current_timezone from django.utils.timezone import get_current_timezone
from django.utils.translation import ( from django.utils.translation import gettext_lazy as _, pgettext_lazy
get_language, gettext_lazy as _, pgettext_lazy,
)
from django_countries import countries from django_countries import countries
from django_countries.fields import Country, CountryField from django_countries.fields import Country, CountryField
from phonenumber_field.formfields import PhoneNumberField from phonenumber_field.formfields import PhoneNumberField
@@ -35,7 +34,9 @@ from pretix.base.forms.widgets import (
BusinessBooleanRadio, DatePickerWidget, SplitDateTimePickerWidget, BusinessBooleanRadio, DatePickerWidget, SplitDateTimePickerWidget,
TimePickerWidget, UploadedFileWidget, TimePickerWidget, UploadedFileWidget,
) )
from pretix.base.i18n import get_language_without_region, language from pretix.base.i18n import (
get_babel_locale, get_language_without_region, language,
)
from pretix.base.models import InvoiceAddress, Question, QuestionOption from pretix.base.models import InvoiceAddress, Question, QuestionOption
from pretix.base.models.tax import ( from pretix.base.models.tax import (
EU_COUNTRIES, cc_to_vat_prefix, is_eu_country, EU_COUNTRIES, cc_to_vat_prefix, is_eu_country,
@@ -204,7 +205,47 @@ class NamePartsFormField(forms.MultiValueField):
return value return value
class WrappedPhonePrefixSelect(Select):
initial = None
def __init__(self, initial=None):
choices = [("", "---------")]
language = get_babel_locale() # changed from default implementation that used the django locale
locale = Locale(translation.to_locale(language))
for prefix, values in _COUNTRY_CODE_TO_REGION_CODE.items():
prefix = "+%d" % prefix
if initial and initial in values:
self.initial = prefix
for country_code in values:
country_name = locale.territories.get(country_code)
if country_name:
choices.append((prefix, "{} {}".format(country_name, prefix)))
super().__init__(choices=sorted(choices, key=lambda item: item[1]))
def render(self, name, value, *args, **kwargs):
return super().render(name, value or self.initial, *args, **kwargs)
def get_context(self, name, value, attrs):
if value and self.choices[1][0] != value:
matching_choices = len([1 for p, c in self.choices if p == value])
if matching_choices > 1:
# Some countries share a phone pretix, for example +1 is used all over the Americas.
# This causes a UX problem: If the default value or the existing data is +12125552368,
# the widget will just show the first <option> entry with value="+1" as selected,
# which alphabetically is America Samoa, although most numbers statistically are from
# the US. As a workaround, we detect this case and add an aditional choice value with
# just <option value="+1">+1</option> without an explicit country.
self.choices.insert(1, (value, value))
context = super().get_context(name, value, attrs)
return context
class WrappedPhoneNumberPrefixWidget(PhoneNumberPrefixWidget): class WrappedPhoneNumberPrefixWidget(PhoneNumberPrefixWidget):
def __init__(self, attrs=None, initial=None):
widgets = (WrappedPhonePrefixSelect(initial), forms.TextInput())
super(PhoneNumberPrefixWidget, self).__init__(widgets, attrs)
def render(self, name, value, attrs=None, renderer=None): def render(self, name, value, attrs=None, renderer=None):
output = super().render(name, value, attrs, renderer) output = super().render(name, value, attrs, renderer)
return mark_safe(self.format_output(output)) return mark_safe(self.format_output(output))
@@ -564,13 +605,7 @@ class BaseQuestionsForm(forms.Form):
if q.valid_datetime_max: if q.valid_datetime_max:
field.validators.append(MaxDateTimeValidator(q.valid_datetime_max)) field.validators.append(MaxDateTimeValidator(q.valid_datetime_max))
elif q.type == Question.TYPE_PHONENUMBER: elif q.type == Question.TYPE_PHONENUMBER:
babel_locale = 'en' with language(get_babel_locale()):
# Babel, and therefore django-phonenumberfield, do not support our custom locales such das de_Informal
if localedata.exists(get_language()):
babel_locale = get_language()
elif localedata.exists(get_language()[:2]):
babel_locale = get_language()[:2]
with language(babel_locale):
default_country = guess_country(event) default_country = guess_country(event)
default_prefix = None default_prefix = None
for prefix, values in _COUNTRY_CODE_TO_REGION_CODE.items(): for prefix, values in _COUNTRY_CODE_TO_REGION_CODE.items():

View File

@@ -1,5 +1,6 @@
from contextlib import contextmanager from contextlib import contextmanager
from babel import localedata
from django.conf import settings from django.conf import settings
from django.utils import translation from django.utils import translation
from django.utils.formats import date_format, number_format from django.utils.formats import date_format, number_format
@@ -69,6 +70,16 @@ class LazyNumber:
ALLOWED_LANGUAGES = dict(settings.LANGUAGES) ALLOWED_LANGUAGES = dict(settings.LANGUAGES)
def get_babel_locale():
babel_locale = 'en'
# Babel, and therefore django-phonenumberfield, do not support our custom locales such das de_Informal
if localedata.exists(translation.get_language()):
babel_locale = translation.get_language()
elif localedata.exists(translation.get_language()[:2]):
babel_locale = translation.get_language()[:2]
return babel_locale
def get_language_without_region(lng=None): def get_language_without_region(lng=None):
""" """
Returns the currently active language, but strips what pretix calls a ``region``. For example, Returns the currently active language, but strips what pretix calls a ``region``. For example,

View File

@@ -35,7 +35,6 @@ from pretix.helpers.countries import CachedCountries
from pretix.multidomain.models import KnownDomain from pretix.multidomain.models import KnownDomain
from pretix.multidomain.urlreverse import build_absolute_uri from pretix.multidomain.urlreverse import build_absolute_uri
from pretix.plugins.banktransfer.payment import BankTransfer from pretix.plugins.banktransfer.payment import BankTransfer
from pretix.presale.style import get_fonts
class EventWizardFoundationForm(forms.Form): class EventWizardFoundationForm(forms.Form):
@@ -549,9 +548,6 @@ class EventSettingsForm(SettingsForm):
if not self.event.has_subevents: if not self.event.has_subevents:
del self.fields['frontpage_subevent_ordering'] del self.fields['frontpage_subevent_ordering']
del self.fields['event_list_type'] del self.fields['event_list_type']
self.fields['primary_font'].choices += [
(a, {"title": a, "data": v}) for a, v in get_fonts().items()
]
# create "virtual" fields for better UX when editing <name>_asked and <name>_required fields # create "virtual" fields for better UX when editing <name>_asked and <name>_required fields
self.virtual_keys = [] self.virtual_keys = []

View File

@@ -25,7 +25,7 @@ class GeoCodeView(LoginRequiredMixin, View):
gs = GlobalSettingsObject() gs = GlobalSettingsObject()
if gs.settings.opencagedata_apikey: if gs.settings.opencagedata_apikey:
res = self._use_opencage(q) res = self._use_opencage(q)
if gs.settings.mapquest_apikey: elif gs.settings.mapquest_apikey:
res = self._use_mapquest(q) res = self._use_mapquest(q)
else: else:
return JsonResponse({ return JsonResponse({

View File

@@ -1,10 +1,9 @@
from itertools import chain from itertools import chain
from babel import localedata
from django import forms from django import forms
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.utils.encoding import force_str from django.utils.encoding import force_str
from django.utils.translation import get_language, gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from phonenumber_field.formfields import PhoneNumberField from phonenumber_field.formfields import PhoneNumberField
from phonenumber_field.phonenumber import PhoneNumber from phonenumber_field.phonenumber import PhoneNumber
from phonenumbers import NumberParseException from phonenumbers import NumberParseException
@@ -14,7 +13,7 @@ from pretix.base.forms.questions import (
BaseInvoiceAddressForm, BaseQuestionsForm, WrappedPhoneNumberPrefixWidget, BaseInvoiceAddressForm, BaseQuestionsForm, WrappedPhoneNumberPrefixWidget,
guess_country, guess_country,
) )
from pretix.base.i18n import language from pretix.base.i18n import get_babel_locale, language
from pretix.base.validators import EmailBanlistValidator from pretix.base.validators import EmailBanlistValidator
from pretix.presale.signals import contact_form_fields from pretix.presale.signals import contact_form_fields
@@ -39,13 +38,7 @@ class ContactForm(forms.Form):
) )
if self.event.settings.order_phone_asked: if self.event.settings.order_phone_asked:
babel_locale = 'en' with language(get_babel_locale()):
# Babel, and therefore django-phonenumberfield, do not support our custom locales such as de_Informal
if localedata.exists(get_language()):
babel_locale = get_language()
elif localedata.exists(get_language()[:2]):
babel_locale = get_language()[:2]
with language(babel_locale):
default_country = guess_country(self.event) default_country = guess_country(self.event)
default_prefix = None default_prefix = None
for prefix, values in _COUNTRY_CODE_TO_REGION_CODE.items(): for prefix, values in _COUNTRY_CODE_TO_REGION_CODE.items():

View File

@@ -142,7 +142,7 @@ class WidgetCartTest(CartTestMixin, TestCase):
data = json.loads(response.content.decode()) data = json.loads(response.content.decode())
assert data == { assert data == {
"name": "30C3", "name": "30C3",
"date_range": "Dec. 26, 2021 00:00", "date_range": f"Dec. 26, {self.event.date_from.year} 00:00",
"currency": "EUR", "currency": "EUR",
"show_variations_expanded": False, "show_variations_expanded": False,
"display_net_prices": False, "display_net_prices": False,
@@ -276,7 +276,7 @@ class WidgetCartTest(CartTestMixin, TestCase):
data = json.loads(response.content.decode()) data = json.loads(response.content.decode())
assert data == { assert data == {
"name": "30C3", "name": "30C3",
"date_range": "Dec. 26, 2021 00:00", "date_range": f"Dec. 26, {self.event.date_from.year} 00:00",
"currency": "EUR", "currency": "EUR",
"show_variations_expanded": False, "show_variations_expanded": False,
"display_net_prices": False, "display_net_prices": False,
@@ -327,7 +327,7 @@ class WidgetCartTest(CartTestMixin, TestCase):
data = json.loads(response.content.decode()) data = json.loads(response.content.decode())
assert data == { assert data == {
"name": "30C3", "name": "30C3",
"date_range": "Dec. 26, 2021 00:00", "date_range": f"Dec. 26, {self.event.date_from.year} 00:00",
"currency": "EUR", "currency": "EUR",
"show_variations_expanded": False, "show_variations_expanded": False,
"display_net_prices": False, "display_net_prices": False,
@@ -394,7 +394,7 @@ class WidgetCartTest(CartTestMixin, TestCase):
data = json.loads(response.content.decode()) data = json.loads(response.content.decode())
assert data == { assert data == {
"name": "30C3", "name": "30C3",
"date_range": "Dec. 26, 2021 00:00", "date_range": f"Dec. 26, {self.event.date_from.year} 00:00",
"currency": "EUR", "currency": "EUR",
'poweredby': '<a href="https://pretix.eu" target="_blank" rel="noopener">event ticketing powered by pretix</a>', 'poweredby': '<a href="https://pretix.eu" target="_blank" rel="noopener">event ticketing powered by pretix</a>',
"show_variations_expanded": False, "show_variations_expanded": False,