Compare commits

..

1 Commits

Author SHA1 Message Date
Raphael Michel
37f48ffd49 Expose logs of all running processes to docker 2020-12-14 13:10:44 +01:00
164 changed files with 60199 additions and 69614 deletions

View File

@@ -1,10 +1,3 @@
doc/
env/
res/
local/
.git/
pretixeu/
src/data/
src/pretix/static.dist/
src/dist/

View File

@@ -1,13 +1,10 @@
user www-data www-data;
worker_processes auto;
worker_processes 1;
pid /var/run/nginx.pid;
daemon off;
worker_rlimit_nofile 262144;
events {
worker_connections 16384;
multi_accept on;
use epoll;
worker_connections 4096;
}
http {
@@ -27,8 +24,8 @@ http {
default_type application/octet-stream;
add_header X-Content-Type-Options nosniff;
access_log /var/log/nginx/access.log private;
error_log /var/log/nginx/error.log;
access_log /dev/stdout private;
error_log /dev/stderr;
add_header Referrer-Policy same-origin;
gzip on;

View File

@@ -3,10 +3,9 @@ cd /pretix/src
export DJANGO_SETTINGS_MODULE=production_settings
export DATA_DIR=/data/
export HOME=/pretix
export NUM_WORKERS=$((2 * $(nproc --all)))
AUTOMIGRATE=${AUTOMIGRATE:-yes}
NUM_WORKERS_DEFAULT=$((2 * $(nproc --all)))
export NUM_WORKERS=${NUM_WORKERS:-$NUM_WORKERS_DEFAULT}
if [ ! -d /data/logs ]; then
mkdir /data/logs;

View File

@@ -2,8 +2,8 @@
file=/tmp/supervisor.sock
[supervisord]
logfile=/tmp/supervisord.log
logfile_maxbytes=50MB
logfile=/dev/stderr
logfile_maxbytes=0
logfile_backups=10
loglevel=info
pidfile=/tmp/supervisord.pid

View File

@@ -5,3 +5,7 @@ autorestart=true
priority=10
stdout_events_enabled=true
stderr_events_enabled=true
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0

View File

@@ -4,3 +4,7 @@ autostart=true
autorestart=true
priority=5
user=pretixuser
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0

View File

@@ -5,3 +5,7 @@ autorestart=true
priority=5
user=pretixuser
environment=HOME=/pretix
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0

View File

@@ -105,12 +105,7 @@ Example::
``csp_log``
Log violations of the Content Security Policy (CSP). Defaults to ``on``.
``csp_additional_header``
Specifies a CSP header that will be **merged** with pretix's default header. For example, if you set this
to ``script-src https://mycdn.com``, pretix will add ``https://mycdn.com`` as an **additional** allowed source
to all CSP headers. Empty by default.
``loglevel``
Set console and file log level (``DEBUG``, ``INFO``, ``WARNING``, ``ERROR`` or ``CRITICAL``). Defaults to ``INFO``.

View File

@@ -295,9 +295,7 @@ on one machine after each upgrade manually, otherwise multiple containers might
database schema at the same time.
To run only the ``pretix-web`` component of pretix as well as a nginx server serving static files, you
can invoke the container with ``docker run … pretix/standalone:stable web`` (instead of ``all``). You
can adjust the number of ``gunicorn`` processes with the ``NUM_WORKERS`` environment variable (defaults to
two times the number of CPUs detected).
can invoke the container with ``docker run … pretix/standalone:stable web`` (instead of ``all``).
To run only ``pretix-worker``, you can run ``docker run … pretix/standalone:stable taskworker``. You can
also pass arguments to limit the worker to specific queues or to change the number of concurrent task

View File

@@ -30,7 +30,6 @@ testmode boolean If ``true``, th
test mode. Only orders in test mode can be deleted.
secret string The secret contained in the link sent to the customer
email string The customer email address
phone string The customer phone number
locale string The locale used for communication with this customer
sales_channel string Channel this sale was created through, such as
``"web"``.
@@ -168,10 +167,6 @@ last_modified datetime Last modificati
The ``subevent_before`` query parameter has been added.
.. versionchanged:: 3.14
The ``phone`` attribute has been added.
.. _order-position-resource:
@@ -377,7 +372,6 @@ List of all orders
"secret": "k24fiuwvu8kxz3y1",
"url": "https://test.pretix.eu/dummy/dummy/order/ABC12/k24fiuwvu8kxz3y1/",
"email": "tester@example.org",
"phone": "+491234567",
"locale": "en",
"sales_channel": "web",
"datetime": "2017-12-01T10:00:00Z",
@@ -545,7 +539,6 @@ Fetching individual orders
"secret": "k24fiuwvu8kxz3y1",
"url": "https://test.pretix.eu/dummy/dummy/order/ABC12/k24fiuwvu8kxz3y1/",
"email": "tester@example.org",
"phone": "+491234567",
"locale": "en",
"sales_channel": "web",
"datetime": "2017-12-01T10:00:00Z",
@@ -712,8 +705,6 @@ Updating order fields
* ``email``
* ``phone``
* ``checkin_attention``
* ``locale``

View File

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

View File

@@ -574,7 +574,6 @@ class EventSettingsSerializer(serializers.Serializer):
'presale_start_show_date',
'locales',
'locale',
'region',
'last_order_modification_date',
'show_quota_left',
'waiting_list_enabled',
@@ -601,9 +600,6 @@ class EventSettingsSerializer(serializers.Serializer):
'attendee_data_explanation_text',
'confirm_texts',
'order_email_asked_twice',
'order_phone_asked',
'order_phone_required',
'checkout_phone_helptext',
'payment_term_mode',
'payment_term_days',
'payment_term_weekdays',

View File

@@ -180,7 +180,7 @@ class PdfDataSerializer(serializers.Field):
res = {}
ev = instance.subevent or instance.order.event
with language(instance.order.locale, instance.order.event.settings.region):
with language(instance.order.locale):
# This needs to have some extra performance improvements to avoid creating hundreds of queries when
# we serialize a list.
@@ -361,7 +361,7 @@ class OrderSerializer(I18nAwareModelSerializer):
class Meta:
model = Order
fields = (
'code', 'status', 'testmode', 'secret', 'email', 'phone', 'locale', 'datetime', 'expires', 'payment_date',
'code', 'status', 'testmode', 'secret', 'email', 'locale', 'datetime', 'expires', 'payment_date',
'payment_provider', 'fees', 'total', 'comment', 'invoice_address', 'positions', 'downloads',
'checkin_attention', 'last_modified', 'payments', 'refunds', 'require_approval', 'sales_channel',
'url'
@@ -393,7 +393,7 @@ class OrderSerializer(I18nAwareModelSerializer):
def update(self, instance, validated_data):
# Even though all fields that shouldn't be edited are marked as read_only in the serializer
# (hopefully), we'll be extra careful here and be explicit about the model fields we update.
update_fields = ['comment', 'checkin_attention', 'email', 'locale', 'phone']
update_fields = ['comment', 'checkin_attention', 'email', 'locale']
if 'invoice_address' in validated_data:
iadata = validated_data.pop('invoice_address')
@@ -691,7 +691,7 @@ class OrderCreateSerializer(I18nAwareModelSerializer):
class Meta:
model = Order
fields = ('code', 'status', 'testmode', 'email', 'phone', 'locale', 'payment_provider', 'fees', 'comment', 'sales_channel',
fields = ('code', 'status', 'testmode', 'email', 'locale', 'payment_provider', 'fees', 'comment', 'sales_channel',
'invoice_address', 'positions', 'checkin_attention', 'payment_info', 'payment_date', 'consume_carts',
'force', 'send_email', 'simulate')

View File

@@ -1,7 +1,7 @@
from decimal import Decimal
from django.db.models import Q
from django.utils.translation import gettext_lazy as _
from django.utils.translation import get_language, gettext_lazy as _
from hierarkey.proxy import HierarkeyProxy
from rest_framework import serializers
from rest_framework.exceptions import ValidationError
@@ -9,7 +9,6 @@ from rest_framework.exceptions import ValidationError
from pretix.api.serializers.i18n import I18nAwareModelSerializer
from pretix.api.serializers.order import CompatibleJSONField
from pretix.base.auth import get_auth_backends
from pretix.base.i18n import get_language_without_region
from pretix.base.models import (
Device, GiftCard, GiftCardTransaction, Organizer, SeatingPlan, Team,
TeamAPIToken, TeamInvite, User,
@@ -146,7 +145,7 @@ class TeamInviteSerializer(serializers.ModelSerializer):
})
},
event=None,
locale=get_language_without_region() # TODO: expose?
locale=get_language() # TODO: expose?
)
except SendMailException:
pass # Already logged
@@ -218,7 +217,6 @@ class OrganizerSettingsSerializer(serializers.Serializer):
'giftcard_length',
'giftcard_expiry_years',
'locales',
'region',
'event_team_provisioning',
'primary_color',
'theme_color_success',

View File

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

View File

@@ -81,9 +81,9 @@ class ExportersMixin:
serializer = JobRunSerializer(exporter=instance, data=self.request.data, **self.get_serializer_kwargs())
serializer.is_valid(raise_exception=True)
cf = CachedFile(web_download=False)
cf = CachedFile()
cf.date = now()
cf.expires = now() + timedelta(hours=24)
cf.expires = now() + timedelta(days=3)
cf.save()
d = serializer.data
for k, v in d.items():

View File

@@ -582,7 +582,7 @@ class OrderViewSet(viewsets.ModelViewSet):
auth=request.auth,
)
with language(order.locale, self.request.event.settings.region):
with language(order.locale):
order_placed.send(self.request.event, order=order)
if order.status == Order.STATUS_PAID:
order_paid.send(self.request.event, order=order)
@@ -674,17 +674,6 @@ class OrderViewSet(viewsets.ModelViewSet):
}
)
if 'phone' in self.request.data and serializer.instance.phone != self.request.data.get('phone'):
serializer.instance.log_action(
'pretix.event.order.phone.changed',
user=self.request.user,
auth=self.request.auth,
data={
'old_phone': serializer.instance.phone,
'new_phone': self.request.data.get('phone'),
}
)
if 'locale' in self.request.data and serializer.instance.locale != self.request.data.get('locale'):
serializer.instance.log_action(
'pretix.event.order.locale.changed',
@@ -897,7 +886,7 @@ class OrderPositionViewSet(mixins.DestroyModelMixin, viewsets.ReadOnlyModelViewS
price = get_price(**kwargs)
tr = kwargs.get('tax_rule', kwargs.get('item').tax_rule)
with language(data.get('locale') or self.request.event.settings.locale, self.request.event.settings.region):
with language(data.get('locale') or self.request.event.settings.locale):
return Response({
'gross': price.gross,
'gross_formatted': money_filter(price.gross, self.request.event.currency, hide_currency=True),

View File

@@ -115,7 +115,7 @@ class TemplateBasedMailRenderer(BaseHTMLMailRenderer):
'body': body_md,
'subject': str(subject),
'color': settings.PRETIX_PRIMARY_COLOR,
'rtl': get_language() in settings.LANGUAGES_RTL or get_language().split('-')[0] in settings.LANGUAGES_RTL,
'rtl': get_language() in settings.LANGUAGES_RTL
}
if self.event:
htmlctx['event'] = self.event

View File

@@ -139,7 +139,7 @@ class OrderListExporter(MultiSheetListExporter):
tax_rates = self._get_all_tax_rates(qs)
headers = [
_('Event slug'), _('Order code'), _('Order total'), _('Status'), _('Email'), _('Phone number'), _('Order date'),
_('Event slug'), _('Order code'), _('Order total'), _('Status'), _('Email'), _('Order date'),
_('Order time'), _('Company'), _('Name'),
]
name_scheme = PERSON_NAME_SCHEMES[self.event.settings.name_scheme] if not self.is_multievent else None
@@ -215,7 +215,6 @@ class OrderListExporter(MultiSheetListExporter):
order.total,
order.get_status_display(),
order.email,
str(order.phone) if order.phone else '',
order.datetime.astimezone(tz).strftime('%Y-%m-%d'),
order.datetime.astimezone(tz).strftime('%H:%M:%S'),
]
@@ -304,7 +303,6 @@ class OrderListExporter(MultiSheetListExporter):
_('Order code'),
_('Status'),
_('Email'),
_('Phone number'),
_('Order date'),
_('Order time'),
_('Fee type'),
@@ -336,7 +334,6 @@ class OrderListExporter(MultiSheetListExporter):
order.code,
order.get_status_display(),
order.email,
str(order.phone) if order.phone else '',
order.datetime.astimezone(tz).strftime('%Y-%m-%d'),
order.datetime.astimezone(tz).strftime('%H:%M:%S'),
op.get_fee_type_display(),
@@ -405,7 +402,6 @@ class OrderListExporter(MultiSheetListExporter):
_('Position ID'),
_('Status'),
_('Email'),
_('Phone number'),
_('Order date'),
_('Order time'),
]
@@ -485,7 +481,6 @@ class OrderListExporter(MultiSheetListExporter):
op.positionid,
order.get_status_display(),
order.email,
str(order.phone) if order.phone else '',
order.datetime.astimezone(tz).strftime('%Y-%m-%d'),
order.datetime.astimezone(tz).strftime('%H:%M:%S'),
]

View File

@@ -1,17 +1,12 @@
import hashlib
import ipaddress
from django import forms
from django.conf import settings
from django.contrib.auth.password_validation import (
password_validators_help_texts, validate_password,
)
from django.utils.functional import cached_property
from django.utils.translation import gettext_lazy as _
from pretix.base.models import User
from pretix.helpers.dicts import move_to_end
from pretix.helpers.http import get_client_ip
class LoginForm(forms.Form):
@@ -23,7 +18,6 @@ class LoginForm(forms.Form):
error_messages = {
'invalid_login': _("This combination of credentials is not known to our system."),
'rate_limit': _("For security reasons, please wait 5 minutes before you try again."),
'inactive': _("This account is inactive.")
}
@@ -45,36 +39,10 @@ class LoginForm(forms.Form):
else:
move_to_end(self.fields, 'keep_logged_in')
@cached_property
def ratelimit_key(self):
if not settings.HAS_REDIS:
return None
client_ip = get_client_ip(self.request)
if not client_ip:
return None
try:
client_ip = ipaddress.ip_address(client_ip)
except ValueError:
# Web server not set up correctly
return None
if client_ip.is_private:
# This is the private IP of the server, web server not set up correctly
return None
return 'pretix_login_{}'.format(hashlib.sha1(str(client_ip).encode()).hexdigest())
def clean(self):
if all(k in self.cleaned_data for k, f in self.fields.items() if f.required):
if self.ratelimit_key:
from django_redis import get_redis_connection
rc = get_redis_connection("redis")
cnt = rc.get(self.ratelimit_key)
if cnt and int(cnt) > 10:
raise forms.ValidationError(self.error_messages['rate_limit'], code='rate_limit')
self.user_cache = self.backend.form_authenticate(self.request, self.cleaned_data)
if self.user_cache is None:
if self.ratelimit_key:
rc.incr(self.ratelimit_key)
rc.expire(self.ratelimit_key, 300)
raise forms.ValidationError(
self.error_messages['invalid_login'],
code='invalid_login'

View File

@@ -9,34 +9,33 @@ import pycountry
import pytz
import vat_moss.errors
import vat_moss.id
from babel import Locale
from babel import localedata
from django import forms
from django.contrib import messages
from django.core.exceptions import ValidationError
from django.core.validators import MaxValueValidator, MinValueValidator
from django.db.models import QuerySet
from django.forms import Select
from django.utils import translation
from django.utils.formats import date_format
from django.utils.html import escape
from django.utils.safestring import mark_safe
from django.utils.timezone import get_current_timezone
from django.utils.translation import gettext_lazy as _, pgettext_lazy
from django.utils.translation import (
get_language, gettext_lazy as _, pgettext_lazy,
)
from django_countries import countries
from django_countries.fields import Country, CountryField
from phonenumber_field.formfields import PhoneNumberField
from phonenumber_field.phonenumber import PhoneNumber
from phonenumber_field.widgets import PhoneNumberPrefixWidget
from phonenumbers import NumberParseException, national_significant_number
from phonenumbers import NumberParseException
from phonenumbers.data import _COUNTRY_CODE_TO_REGION_CODE
from pretix.base.forms.widgets import (
BusinessBooleanRadio, DatePickerWidget, SplitDateTimePickerWidget,
TimePickerWidget, UploadedFileWidget,
)
from pretix.base.i18n import (
get_babel_locale, get_language_without_region, language,
)
from pretix.base.i18n import language
from pretix.base.models import InvoiceAddress, Question, QuestionOption
from pretix.base.models.tax import (
EU_COUNTRIES, cc_to_vat_prefix, is_eu_country,
@@ -205,47 +204,7 @@ class NamePartsFormField(forms.MultiValueField):
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):
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):
output = super().render(name, value, attrs, renderer)
return mark_safe(self.format_output(output))
@@ -253,44 +212,12 @@ class WrappedPhoneNumberPrefixWidget(PhoneNumberPrefixWidget):
def format_output(self, rendered_widgets) -> str:
return '<div class="nameparts-form-group">%s</div>' % ''.join(rendered_widgets)
def decompress(self, value):
"""
If an incomplete phone number (e.g. without country prefix) is currently entered,
the default implementation just discards the value and shows nothing at all.
Let's rather show something invalid, so the user is prompted to fix it, instead of
silently deleting data.
"""
if value:
if type(value) == PhoneNumber:
if value.country_code and value.national_number:
return [
"+%d" % value.country_code,
national_significant_number(value),
]
return [
None,
str(value)
]
elif "." in value:
return value.split(".")
else:
return [None, value]
return [None, ""]
def value_from_datadict(self, data, files, name):
# In contrast to defualt implementation, do not silently fail if a number without
# country prefix is entered
values = super(PhoneNumberPrefixWidget, self).value_from_datadict(data, files, name)
if values[1]:
return "%s.%s" % tuple(values)
return ""
def guess_country(event):
# Try to guess the initial country from either the country of the merchant
# or the locale. This will hopefully save at least some users some scrolling :)
locale = get_language_without_region()
country = event.settings.region or event.settings.invoice_address_from_country
locale = get_language()
country = event.settings.invoice_address_from_country
if not country:
valid_countries = countries.countries
if '-' in locale:
@@ -605,7 +532,13 @@ class BaseQuestionsForm(forms.Form):
if q.valid_datetime_max:
field.validators.append(MaxDateTimeValidator(q.valid_datetime_max))
elif q.type == Question.TYPE_PHONENUMBER:
with language(get_babel_locale()):
babel_locale = 'en'
# 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_prefix = None
for prefix, values in _COUNTRY_CODE_TO_REGION_CODE.items():

View File

@@ -1,5 +1,4 @@
from django import forms
from django.conf import settings
from django.contrib.auth.hashers import check_password
from django.contrib.auth.password_validation import (
password_validators_help_texts, validate_password,
@@ -20,7 +19,6 @@ class UserSettingsForm(forms.ModelForm):
"address or password."),
'pw_current_wrong': _("The current password you entered was not correct."),
'pw_mismatch': _("Please enter the same password twice"),
'rate_limit': _("For security reasons, please wait 5 minutes before you try again."),
}
old_pw = forms.CharField(max_length=255,
@@ -66,18 +64,6 @@ class UserSettingsForm(forms.ModelForm):
def clean_old_pw(self):
old_pw = self.cleaned_data.get('old_pw')
if old_pw and settings.HAS_REDIS:
from django_redis import get_redis_connection
rc = get_redis_connection("redis")
cnt = rc.incr('pretix_pwchange_%s' % self.user.pk)
rc.expire('pretix_pwchange_%s' % self.user.pk, 300)
if cnt > 10:
raise forms.ValidationError(
self.error_messages['rate_limit'],
code='rate_limit',
)
if old_pw and not check_password(old_pw, self.user.password):
raise forms.ValidationError(
self.error_messages['pw_current_wrong'],

View File

@@ -1,6 +1,5 @@
from contextlib import contextmanager
from babel import localedata
from django.conf import settings
from django.utils import translation
from django.utils.formats import date_format, number_format
@@ -67,52 +66,10 @@ class LazyNumber:
return number_format(self.value, decimal_pos=self.decimal_pos)
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):
"""
Returns the currently active language, but strips what pretix calls a ``region``. For example,
if the currently active language is ``en-us``, you will be returned ``en`` since pretix does not
ship with separate language files for ``en-us``. If the currently active language is ``pt-br``,
you will be returned ``pt-br`` since there are separate language files for ``pt-br``.
tl;dr: You will be always passed a language that is defined in settings.LANGUAGES.
"""
lng = lng or translation.get_language() or settings.LANGUAGE_CODE
if lng not in ALLOWED_LANGUAGES:
lng = lng.split('-')[0]
if lng not in ALLOWED_LANGUAGES:
lng = settings.LANGUAGE_CODE
return lng
@contextmanager
def language(lng, region=None):
"""
Temporarily change the active language to ``lng``. Will automatically be rolled back when the
context manager returns.
You can optionally pass a "region". For example, if you pass ``en`` as ``lng`` and ``US`` as
``region``, the active language will be ``en-us``, which will mostly affect date/time
formatting. If you pass a ``lng`` that already contains a region, e.g. ``pt-br``, the ``region``
attribute will be ignored.
"""
def language(lng):
_lng = translation.get_language()
lng = lng or settings.LANGUAGE_CODE
if '-' not in lng and region:
lng += '-' + region.lower()
translation.activate(lng)
translation.activate(lng or settings.LANGUAGE_CODE)
try:
yield
finally:

View File

@@ -144,7 +144,7 @@ class BaseReportlabInvoiceRenderer(BaseInvoiceRenderer):
def _upper(self, val):
# We uppercase labels, but not in every language
if get_language().startswith('el'):
if get_language() == 'el':
return val
return val.upper()

View File

@@ -15,8 +15,7 @@ from django.utils.translation.trans_real import (
parse_accept_lang_header,
)
from pretix.base.i18n import get_language_without_region
from pretix.base.settings import global_settings_object
from pretix.base.settings import GlobalSettingsObject
from pretix.multidomain.urlreverse import (
get_event_domain, get_organizer_domain,
)
@@ -36,30 +35,19 @@ class LocaleMiddleware(MiddlewareMixin):
# Normally, this middleware runs *before* the event is set. However, on event frontend pages it
# might be run a second time by pretix.presale.EventMiddleware and in this case the event is already
# set and can be taken into account for the decision.
if not request.path.startswith(get_script_prefix() + 'control'):
if hasattr(request, 'event'):
if language not in request.event.settings.locales:
firstpart = language.split('-')[0]
if firstpart in request.event.settings.locales:
language = firstpart
else:
language = request.event.settings.locale
for lang in request.event.settings.locales:
if lang.startswith(firstpart + '-'):
language = lang
break
if '-' not in language and request.event.settings.region:
language += '-' + request.event.settings.region
elif hasattr(request, 'organizer'):
if '-' not in language and request.organizer.settings.region:
language += '-' + request.organizer.settings.region
else:
gs = global_settings_object(request)
if '-' not in language and gs.settings.region:
language += '-' + gs.settings.region
if hasattr(request, 'event') and not request.path.startswith(get_script_prefix() + 'control'):
if language not in request.event.settings.locales:
firstpart = language.split('-')[0]
if firstpart in request.event.settings.locales:
language = firstpart
else:
language = request.event.settings.locale
for lang in request.event.settings.locales:
if lang.startswith(firstpart + '-'):
language = lang
break
translation.activate(language)
request.LANGUAGE_CODE = get_language_without_region()
request.LANGUAGE_CODE = translation.get_language()
tzname = None
if hasattr(request, 'event'):
@@ -204,7 +192,7 @@ class SecurityMiddleware(MiddlewareMixin):
resp['P3P'] = 'CP=\"ALL DSP COR CUR ADM TAI OUR IND COM NAV INT\"'
img_src = []
gs = global_settings_object(request)
gs = GlobalSettingsObject()
if gs.settings.leaflet_tiles:
img_src.append(gs.settings.leaflet_tiles[:gs.settings.leaflet_tiles.index("/", 10)].replace("{s}", "*"))
@@ -228,8 +216,6 @@ class SecurityMiddleware(MiddlewareMixin):
h['report-uri'] = ["/csp_report/"]
if 'Content-Security-Policy' in resp:
_merge_csp(h, _parse_csp(resp['Content-Security-Policy']))
if settings.CSP_ADDITIONAL_HEADER:
_merge_csp(h, _parse_csp(settings.CSP_ADDITIONAL_HEADER))
staticdomain = "'self'"
dynamicdomain = "'self'"

View File

@@ -1,23 +0,0 @@
# Generated by Django 3.0.11 on 2020-12-18 18:10
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('pretixbase', '0162_remove_seat_name'),
]
operations = [
migrations.AddField(
model_name='cachedfile',
name='session_key',
field=models.TextField(null=True),
),
migrations.AddField(
model_name='cachedfile',
name='web_download',
field=models.BooleanField(default=True),
),
]

View File

@@ -1,51 +0,0 @@
# Generated by Django 3.0.11 on 2020-12-11 16:48
import json
import phonenumber_field.modelfields
from django.db import migrations
import pretix.base.models.fields
def migrate_settings(apps, schema_editor):
Order = apps.get_model('pretixbase', 'Order')
Event = apps.get_model('pretixbase', 'Event')
Event_SettingsStore = apps.get_model('pretixbase', 'Event_SettingsStore')
Event_SettingsStore.objects.filter(key='telephone_field_required').update(key='order_phone_required')
Event_SettingsStore.objects.filter(key='telephone_field_help_text').update(key='checkout_phone_helptext')
for e in Event.objects.filter(plugins__icontains="pretix_telephone"):
plugins = e.plugins.split(",")
plugins.remove("pretix_telephone")
e.plugins = ",".join(plugins)
e.save()
Event_SettingsStore.objects.create(object=e, key='order_phone_asked', value='True')
for o in Order.objects.filter(meta_info__icontains='"telephone"'):
mi = json.loads(o.meta_info)
if 'telephone' in mi.get('contact_form_data', {}):
mi['phone'] = mi['contact_form_data'].pop('telephone')
o.phone = mi['phone']
o.meta_info = json.dumps(mi)
o.save(update_fields=['meta_info', 'phone'])
class Migration(migrations.Migration):
dependencies = [
('pretixbase', '0172_event_sales_channels'),
]
operations = [
migrations.AddField(
model_name='order',
name='phone',
field=phonenumber_field.modelfields.PhoneNumberField(max_length=128, null=True, region=None),
),
migrations.AlterField(
model_name='event',
name='sales_channels',
field=pretix.base.models.fields.MultiStringField(default=['web']),
),
migrations.RunPython(
migrate_settings, migrations.RunPython.noop,
)
]

View File

@@ -1,14 +0,0 @@
# Generated by Django 3.0.11 on 2020-12-22 10:31
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('pretixbase', '0173_auto_20201211_1648'),
('pretixbase', '0162b_auto_20201218_1810'),
]
operations = [
]

View File

@@ -28,8 +28,6 @@ class CachedFile(models.Model):
filename = models.CharField(max_length=255)
type = models.CharField(max_length=255)
file = models.FileField(null=True, blank=True, upload_to=cachedfile_name, max_length=255)
web_download = models.BooleanField(default=True) # allow web download, True for backwards compatibility in plugins
session_key = models.TextField(null=True, blank=True) # only allow download in this session
@receiver(post_delete, sender=CachedFile)

View File

@@ -528,7 +528,7 @@ class Event(EventMixin, LoggedModel):
return locking.LockManager(self)
def get_mail_backend(self, timeout=None, force_custom=False):
def get_mail_backend(self, force_custom=False):
"""
Returns an email server connection, either by using the system-wide connection
or by returning a custom one based on the event's settings.
@@ -542,7 +542,7 @@ class Event(EventMixin, LoggedModel):
password=self.settings.smtp_password,
use_tls=self.settings.smtp_use_tls,
use_ssl=self.settings.smtp_use_ssl,
fail_silently=False, timeout=timeout)
fail_silently=False)
else:
return get_connection(fail_silently=False)

View File

@@ -31,7 +31,6 @@ from django_countries.fields import Country
from django_scopes import ScopedManager, scopes_disabled
from i18nfield.strings import LazyI18nString
from jsonfallback.fields import FallbackJSONField
from phonenumber_field.modelfields import PhoneNumberField
from phonenumber_field.phonenumber import PhoneNumber
from phonenumbers import NumberParseException
@@ -87,8 +86,6 @@ class Order(LockModel, LoggedModel):
:type event: Event
:param email: The email of the person who ordered this
:type email: str
:param phone: The phone number of the person who ordered this
:type phone: str
:param testmode: Whether this is a test mode order
:type testmode: bool
:param locale: The locale of this order
@@ -147,10 +144,6 @@ class Order(LockModel, LoggedModel):
null=True, blank=True,
verbose_name=_('E-mail')
)
phone = PhoneNumberField(
null=True, blank=True,
verbose_name=_('Phone number'),
)
locale = models.CharField(
null=True, blank=True, max_length=32,
verbose_name=_('Locale')
@@ -333,9 +326,6 @@ class Order(LockModel, LoggedModel):
payment_sum=payment_sum_sq,
refund_sum=refund_sum_sq,
)
qs = qs.annotate(
computed_payment_refund_sum=Coalesce(payment_sum_sq, 0) - Coalesce(refund_sum_sq, 0),
)
qs = qs.annotate(
pending_sum_t=F('total') - Coalesce(payment_sum_sq, 0) + Coalesce(refund_sum_sq, 0),
@@ -867,7 +857,7 @@ class Order(LockModel, LoggedModel):
for k, v in self.event.meta_data.items():
context['meta_' + k] = v
with language(self.locale, self.event.settings.region):
with language(self.locale):
recipient = self.email
if position and position.attendee_email:
recipient = position.attendee_email
@@ -900,7 +890,7 @@ class Order(LockModel, LoggedModel):
)
def resend_link(self, user=None, auth=None):
with language(self.locale, self.event.settings.region):
with language(self.locale):
email_template = self.event.settings.mail_text_resend_link
email_context = get_email_context(event=self.event, order=self)
email_subject = _('Your order: %(code)s') % {'code': self.code}
@@ -912,7 +902,7 @@ class Order(LockModel, LoggedModel):
@property
def positions_with_tickets(self):
for op in self.positions.select_related('item'):
for op in self.positions.all():
if not op.generate_ticket:
continue
yield op
@@ -1165,7 +1155,7 @@ class AbstractPosition(models.Model):
(2) questions: a list of Question objects, extended by an 'answer' property
"""
self.answ = {}
for a in getattr(self, 'answerlist', self.answers.all()): # use prefetch_related cache from get_cart
for a in self.answers.all():
self.answ[a.question_id] = a
# We need to clone our question objects, otherwise we will override the cached
@@ -1524,7 +1514,7 @@ class OrderPayment(models.Model):
def _send_paid_mail_attendee(self, position, user):
from pretix.base.services.mail import SendMailException
with language(self.order.locale, self.order.event.settings.region):
with language(self.order.locale):
email_template = self.order.event.settings.mail_text_order_paid_attendee
email_context = get_email_context(event=self.order.event, order=self.order, position=position)
email_subject = _('Event registration confirmed: %(code)s') % {'code': self.order.code}
@@ -1542,7 +1532,7 @@ class OrderPayment(models.Model):
def _send_paid_mail(self, invoice, user, mail_text):
from pretix.base.services.mail import SendMailException
with language(self.order.locale, self.order.event.settings.region):
with language(self.order.locale):
email_template = self.order.event.settings.mail_text_order_paid
email_context = get_email_context(event=self.order.event, order=self.order, payment_info=mail_text)
email_subject = _('Payment received for your order: %(code)s') % {'code': self.order.code}
@@ -2114,7 +2104,7 @@ class OrderPosition(AbstractPosition):
for k, v in self.event.meta_data.items():
context['meta_' + k] = v
with language(self.order.locale, self.order.event.settings.region):
with language(self.order.locale):
recipient = self.attendee_email
try:
email_content = render_mail(template, context)
@@ -2142,7 +2132,7 @@ class OrderPosition(AbstractPosition):
def resend_link(self, user=None, auth=None):
with language(self.order.locale, self.order.event.settings.region):
with language(self.order.locale):
email_template = self.event.settings.mail_text_resend_link
email_context = get_email_context(event=self.order.event, order=self.order, position=self)
email_subject = _('Your event registration: %(code)s') % {'code': self.order.code}

View File

@@ -125,7 +125,7 @@ class WaitingListEntry(LoggedModel):
self.voucher = v
self.save()
with language(self.locale, self.event.settings.region):
with language(self.locale):
mail(
self.email,
_('You have been selected from the waitinglist for {event}').format(event=str(self.event)),

View File

@@ -39,7 +39,6 @@ from pretix.base.models import Order, OrderPosition
from pretix.base.settings import PERSON_NAME_SCHEMES
from pretix.base.signals import layout_text_variables
from pretix.base.templatetags.money import money_filter
from pretix.base.templatetags.phone_format import phone_format
from pretix.presale.style import get_fonts
logger = logging.getLogger(__name__)
@@ -230,11 +229,6 @@ DEFAULT_VARIABLES = OrderedDict((
"editor_sample": _("Random City"),
"evaluate": lambda op, order, ev: str(ev.location)
}),
("telephone", {
"label": _("Phone number"),
"editor_sample": "+01 1234 567890",
"evaluate": lambda op, order, ev: phone_format(order.phone)
}),
("invoice_name", {
"label": _("Invoice address name"),
"editor_sample": _("John Doe"),
@@ -427,7 +421,6 @@ class Renderer:
self.layout = layout
self.background_file = background_file
self.variables = get_variables(event)
self.event = event
if self.background_file:
self.bg_bytes = self.background_file.read()
self.bg_pdf = PdfFileReader(BytesIO(self.bg_bytes), strict=False)
@@ -494,7 +487,7 @@ class Renderer:
def _get_text_content(self, op: OrderPosition, order: Order, o: dict, inner=False):
if o.get('locale', None) and not inner:
with language(o['locale'], self.event.settings.region):
with language(o['locale']):
return self._get_text_content(op, order, o, True)
ev = self._get_ev(op, order)

View File

@@ -24,7 +24,7 @@ logger = logging.getLogger(__name__)
def _send_wle_mail(wle: WaitingListEntry, subject: LazyI18nString, message: LazyI18nString, subevent: SubEvent):
with language(wle.locale, wle.event.settings.region):
with language(wle.locale):
email_context = get_email_context(event_or_subevent=subevent or wle.event, event=wle.event)
try:
mail(
@@ -41,7 +41,7 @@ def _send_wle_mail(wle: WaitingListEntry, subject: LazyI18nString, message: Lazy
def _send_mail(order: Order, subject: LazyI18nString, message: LazyI18nString, subevent: SubEvent,
refund_amount: Decimal, user: User, positions: list):
with language(order.locale, order.event.settings.region):
with language(order.locale):
try:
ia = order.invoice_address
except InvoiceAddress.DoesNotExist:

View File

@@ -32,7 +32,7 @@ def export(self, event: Event, fileid: str, provider: str, form_data: Dict[str,
)
file = CachedFile.objects.get(id=fileid)
with language(event.settings.locale, event.settings.region), override(event.settings.timezone):
with language(event.settings.locale), override(event.settings.timezone):
responses = register_data_exporters.send(event)
for receiver, response in responses:
ex = response(event, set_progress)
@@ -67,18 +67,15 @@ def multiexport(self, organizer: Organizer, user: User, device: int, token: int,
if user:
locale = user.locale
timezone = user.timezone
region = None # todo: add to user?
else:
e = allowed_events.first()
if e:
locale = e.settings.locale
timezone = e.settings.timezone
region = e.settings.region
else:
locale = settings.LANGUAGE_CODE
timezone = settings.TIME_ZONE
region = None
with language(locale, region), override(timezone):
with language(locale), override(timezone):
if isinstance(form_data['events'][0], str):
events = allowed_events.filter(slug__in=form_data.get('events'), organizer=organizer)
else:

View File

@@ -43,7 +43,7 @@ def build_invoice(invoice: Invoice) -> Invoice:
lp = invoice.order.payments.last()
with language(invoice.locale, invoice.event.settings.region):
with language(invoice.locale):
invoice.invoice_from = invoice.event.settings.get('invoice_address_from')
invoice.invoice_from_name = invoice.event.settings.get('invoice_address_from_name')
invoice.invoice_from_zipcode = invoice.event.settings.get('invoice_address_from_zipcode')
@@ -244,7 +244,7 @@ def generate_cancellation(invoice: Invoice, trigger_pdf=True):
cancellation.date = timezone.now().date()
cancellation.payment_provider_text = ''
cancellation.file = None
with language(invoice.locale, invoice.event.settings.region):
with language(invoice.locale):
cancellation.invoice_from = invoice.event.settings.get('invoice_address_from')
cancellation.invoice_from_name = invoice.event.settings.get('invoice_address_from_name')
cancellation.invoice_from_zipcode = invoice.event.settings.get('invoice_address_from_zipcode')
@@ -297,7 +297,7 @@ def invoice_pdf_task(invoice: int):
return None
if i.file:
i.file.delete()
with language(i.locale, i.event.settings.region):
with language(i.locale):
fname, ftype, fcontent = i.event.invoice_renderer.generate(i)
i.file.save(fname, ContentFile(fcontent))
i.save()
@@ -328,7 +328,7 @@ def build_preview_invoice_pdf(event):
if not locale or locale == '__user__':
locale = event.settings.locale
with rolledback_transaction(), language(locale, event.settings.region):
with rolledback_transaction(), language(locale):
order = event.orders.create(status=Order.STATUS_PENDING, datetime=timezone.now(),
expires=timezone.now(), code="PREVIEW", total=100 * event.tax_rules.count())
invoice = Invoice(

View File

@@ -290,7 +290,7 @@ def mail_send_task(self, *args, to: List[str], subject: str, body: str, html: st
except Order.DoesNotExist:
order = None
else:
with language(order.locale, event.settings.region):
with language(order.locale):
if position:
try:
position = order.positions.get(pk=position)

View File

@@ -65,7 +65,7 @@ def import_orders(event: Event, fileid: str, settings: dict, locale: str, user)
# TODO: quotacheck?
cf = CachedFile.objects.get(id=fileid)
user = User.objects.get(pk=user)
with language(locale, event.settings.region):
with language(locale):
cols = get_all_columns(event)
parsed = parse_csv(cf.file)
orders = []
@@ -163,7 +163,7 @@ def import_orders(event: Event, fileid: str, settings: dict, locale: str, user)
)
for o in orders:
with language(o.locale, event.settings.region):
with language(o.locale):
order_placed.send(event, order=o)
if o.status == Order.STATUS_PAID:
order_paid.send(event, order=o)

View File

@@ -23,9 +23,7 @@ from django_scopes import scopes_disabled
from pretix.api.models import OAuthApplication
from pretix.base.channels import get_all_sales_channels
from pretix.base.email import get_email_context
from pretix.base.i18n import (
LazyLocaleException, get_language_without_region, language,
)
from pretix.base.i18n import LazyLocaleException, language
from pretix.base.models import (
CartPosition, Device, Event, GiftCard, Item, ItemVariation, Order,
OrderPayment, OrderPosition, Quota, Seat, SeatCategoryMapping, User,
@@ -262,7 +260,7 @@ def approve_order(order, user=None, send_mail: bool=True, auth=None, force=False
# send_mail will trigger PDF generation later
if send_mail:
with language(order.locale, order.event.settings.region):
with language(order.locale):
if order.total == Decimal('0.00'):
email_template = order.event.settings.mail_text_order_approved_free
email_subject = _('Order approved and confirmed: %(code)s') % {'code': order.code}
@@ -313,7 +311,7 @@ def deny_order(order, comment='', user=None, send_mail: bool=True, auth=None):
if send_mail:
email_template = order.event.settings.mail_text_order_denied
email_context = get_email_context(event=order.event, order=order, comment=comment)
with language(order.locale, order.event.settings.region):
with language(order.locale):
email_subject = _('Order denied: %(code)s') % {'code': order.code}
try:
order.send_mail(
@@ -424,7 +422,7 @@ def _cancel_order(order, user=None, send_mail: bool=True, api_token=None, device
if send_mail:
email_template = order.event.settings.mail_text_order_canceled
with language(order.locale, order.event.settings.region):
with language(order.locale):
email_context = get_email_context(event=order.event, order=order)
email_subject = _('Order canceled: %(code)s') % {'code': order.code}
try:
@@ -778,9 +776,8 @@ def _create_order(event: Event, email: str, positions: List[CartPosition], now_d
status=Order.STATUS_PENDING,
event=event,
email=email,
phone=(meta_info or {}).get('contact_form_data', {}).get('phone'),
datetime=now_dt,
locale=get_language_without_region(locale),
locale=locale,
total=total,
testmode=True if sales_channel.testmode_supported and event.testmode else False,
meta_info=json.dumps(meta_info or {}),
@@ -1036,7 +1033,7 @@ def send_expiry_warnings(sender, **kwargs):
# Race condition
continue
with language(o.locale, settings.region):
with language(o.locale):
o.expiry_reminder_sent = True
o.save(update_fields=['expiry_reminder_sent'])
email_template = settings.mail_text_order_expire_warning
@@ -1113,7 +1110,7 @@ def send_download_reminders(sender, **kwargs):
if not send:
continue
with language(o.locale, o.event.settings.region):
with language(o.locale):
o.download_reminder_sent = True
o.save(update_fields=['download_reminder_sent'])
email_template = event.settings.mail_text_download_reminder
@@ -1153,7 +1150,7 @@ def send_download_reminders(sender, **kwargs):
def notify_user_changed_order(order, user=None, auth=None, invoices=[]):
with language(order.locale, order.event.settings.region):
with language(order.locale):
email_template = order.event.settings.mail_text_order_changed
email_context = get_email_context(event=order.event, order=order)
email_subject = _('Your order has been changed: %(code)s') % {'code': order.code}

View File

@@ -113,11 +113,10 @@ class QuotaAvailability:
raise e
def _write_cache(self, quotas, now_dt):
# We used to also delete item_quota_cache:* from the event cache here, but as the cache
# gets more complex, this does not seem worth it. The cache is only present for up to
# 5 seconds to prevent high peaks, and a 5-second delay in availability is usually
# tolerable
events = {q.event for q in quotas}
update = []
for e in events:
e.cache.delete('item_quota_cache')
for q in quotas:
rewrite_cache = self._count_waitinglist and (
not q.cache_is_hot(now_dt) or self.results[q][0] > q.cached_availability_state

View File

@@ -17,7 +17,7 @@ from pretix.celery_app import app
@app.task(base=ProfiledEventTask)
def export(event: Event, shredders: List[str], session_key=None) -> None:
def export(event: Event, shredders: List[str]) -> None:
known_shredders = event.get_data_shredders()
with NamedTemporaryFile() as rawfile:
@@ -55,8 +55,6 @@ def export(event: Event, shredders: List[str], session_key=None) -> None:
cf.date = now()
cf.filename = event.slug + '.zip'
cf.type = 'application/zip'
cf.session_key = session_key
cf.web_download = True
cf.expires = now() + timedelta(hours=1)
cf.save()
cf.file.save(cachedfile_name(cf, cf.filename), rawfile)

View File

@@ -23,7 +23,7 @@ logger = logging.getLogger(__name__)
def generate_orderposition(order_position: int, provider: str):
order_position = OrderPosition.objects.select_related('order', 'order__event').get(id=order_position)
with language(order_position.order.locale, order_position.order.event.settings.region):
with language(order_position.order.locale):
responses = register_ticket_outputs.send(order_position.order.event)
for receiver, response in responses:
prov = response(order_position.order.event)
@@ -41,7 +41,7 @@ def generate_orderposition(order_position: int, provider: str):
def generate_order(order: int, provider: str):
order = Order.objects.select_related('event').get(id=order)
with language(order.locale, order.event.settings.region):
with language(order.locale):
responses = register_ticket_outputs.send(order.event)
for receiver, response in responses:
prov = response(order.event)
@@ -75,7 +75,7 @@ class DummyRollbackException(Exception):
def preview(event: int, provider: str):
event = Event.objects.get(id=event)
with rolledback_transaction(), language(event.settings.locale, event.settings.region):
with rolledback_transaction(), language(event.settings.locale):
item = event.items.create(name=_("Sample product"), default_price=42.23,
description=_("Sample product description"))
item2 = event.items.create(name=_("Sample workshop"), default_price=23.40)

View File

@@ -193,25 +193,6 @@ DEFAULTS = {
help_text=_("Require customers to fill in the primary email address twice to avoid errors."),
)
},
'order_phone_asked': {
'default': 'False',
'type': bool,
'form_class': forms.BooleanField,
'serializer_class': serializers.BooleanField,
'form_kwargs': dict(
label=_("Ask for a phone number per order"),
)
},
'order_phone_required': {
'default': 'False',
'type': bool,
'form_class': forms.BooleanField,
'serializer_class': serializers.BooleanField,
'form_kwargs': dict(
label=_("Require a phone number per order"),
widget=forms.CheckboxInput(attrs={'data-checkbox-dependency': '#id_settings-order_phone_asked'}),
)
},
'invoice_address_asked': {
'default': 'True',
'type': bool,
@@ -851,20 +832,6 @@ DEFAULTS = {
label=_("Default language"),
)
},
'region': {
'default': None,
'type': str,
'form_class': forms.ChoiceField,
'serializer_class': serializers.ChoiceField,
'serializer_kwargs': lambda: dict(**country_choice_kwargs()),
'form_kwargs': lambda: dict(
label=_('Region'),
help_text=_('Will be used to determine date and time formatting as well as default country for customer '
'addresses and phone numbers. For formatting, this takes less priority than the language and '
'is therefore mostly relevant for languages used in different regions globally (like English).'),
**country_choice_kwargs()
),
},
'show_dates_on_frontpage': {
'default': 'True',
'type': bool,
@@ -1878,17 +1845,6 @@ Your {event} team"""))
"why you need information from them.")
)
},
'checkout_phone_helptext': {
'default': '',
'type': LazyI18nString,
'serializer_class': I18nField,
'form_class': I18nFormField,
'form_kwargs': dict(
label=_("Help text of the phone number field"),
widget_kwargs={'attrs': {'rows': '2'}},
widget=I18nTextarea
)
},
'checkout_email_helptext': {
'default': LazyI18nString.from_gettext(gettext_noop(
'Make sure to enter a valid email address. We will send you an order '
@@ -2447,9 +2403,3 @@ def validate_organizer_settings(organizer, settings_dict):
#
# N.B.: When actually fleshing out this stub, adding it to the OrganizerUpdateForm should be considered.
pass
def global_settings_object(holder):
if not hasattr(holder, '_global_settings_object'):
holder._global_settings_object = GlobalSettingsObject()
return holder._global_settings_object

View File

@@ -20,7 +20,6 @@ from pretix.base.models import (
)
from pretix.base.services.invoices import invoice_pdf_task
from pretix.base.signals import register_data_shredders
from pretix.helpers.json import CustomJSONEncoder
class ShredError(LazyLocaleException):
@@ -122,31 +121,6 @@ def shred_log_fields(logentry, banlist=None, whitelist=None):
logentry.save(update_fields=['data', 'shredded'])
class PhoneNumberShredder(BaseDataShredder):
verbose_name = _('Phone numbers')
identifier = 'phone_numbers'
description = _('This will remove all phone numbers from orders.')
def generate_files(self) -> List[Tuple[str, str, str]]:
yield 'phone-by-order.json', 'application/json', json.dumps({
o.code: o.phone for o in self.event.orders.filter(phone__isnull=False)
}, cls=CustomJSONEncoder, indent=4)
@transaction.atomic
def shred_data(self):
for o in self.event.orders.all():
o.phone = None
d = o.meta_info_data
if d:
if 'contact_form_data' in d and 'phone' in d['contact_form_data']:
del d['contact_form_data']['phone']
o.meta_info = json.dumps(d)
o.save(update_fields=['meta_info', 'phone'])
for le in self.event.logentry_set.filter(action_type="pretix.event.order.phone.changed"):
shred_log_fields(le, banlist=['old_phone', 'new_phone'])
class EmailAddressShredder(BaseDataShredder):
verbose_name = _('E-mails')
identifier = 'order_emails'
@@ -398,10 +372,9 @@ class PaymentInfoShredder(BaseDataShredder):
@receiver(register_data_shredders, dispatch_uid="shredders_builtin")
def register_core_shredders(sender, **kwargs):
def register_payment_provider(sender, **kwargs):
return [
EmailAddressShredder,
PhoneNumberShredder,
AttendeeInfoShredder,
InvoiceAddressShredder,
QuestionAnswerShredder,

View File

@@ -1,22 +0,0 @@
from django import template
from phonenumber_field.phonenumber import PhoneNumber
from phonenumbers import NumberParseException
register = template.Library()
@register.filter("phone_format")
def phone_format(value: str):
if not value:
return ""
if isinstance(value, str):
try:
return PhoneNumber.from_string(value).as_international
except NumberParseException:
return value
if isinstance(value, PhoneNumber) and value.national_number:
return value.as_international
return str(value)

View File

@@ -1,4 +1,3 @@
import re
import urllib.parse
import bleach
@@ -72,10 +71,6 @@ EMAIL_RE = build_email_re(tlds=sorted(tld_set, key=len, reverse=True))
def safelink_callback(attrs, new=False):
"""
Makes sure that all links to a different domain are passed through a redirection handler
to ensure there's no passing of referers with secrets inside them.
"""
url = attrs.get((None, 'href'), '/')
if not url_has_allowed_host_and_scheme(url, allowed_hosts=None) and not url.startswith('mailto:') and not url.startswith('tel:'):
signer = signing.Signer(salt='safe-redirect')
@@ -85,42 +80,7 @@ def safelink_callback(attrs, new=False):
return attrs
def truelink_callback(attrs, new=False):
"""
Tries to prevent "phishing" attacks in which a link looks like it points to a safe place but instead
points somewhere else, e.g.
<a href="https://evilsite.com">https://google.com</a>
At the same time, custom texts are still allowed:
<a href="https://maps.google.com">Get to the event</a>
Suffixes are also allowed:
<a href="https://maps.google.com/location/foo">https://maps.google.com</a>
"""
text = re.sub('[^a-zA-Z0-9.-/_]', '', attrs.get('_text')) # clean up link text
if URL_RE.match(text):
# link text looks like a url
if text.startswith('//'):
text = 'https:' + text
elif not text.startswith('http'):
text = 'https://' + text
text_url = urllib.parse.urlparse(text)
href_url = urllib.parse.urlparse(attrs[None, 'href'])
if text_url.netloc != href_url.netloc or not href_url.path.startswith(href_url.path):
# link text contains an URL that has a different base than the actual URL
attrs['_text'] = attrs[None, 'href']
return attrs
def abslink_callback(attrs, new=False):
"""
Makes sure that all links will be absolute links and will be opened in a new page with no
window.opener attribute.
"""
url = attrs.get((None, 'href'), '/')
if not url.startswith('mailto:') and not url.startswith('tel:'):
attrs[None, 'href'] = urllib.parse.urljoin(settings.SITE_URL, url)
@@ -133,7 +93,6 @@ def markdown_compile_email(source):
linker = bleach.Linker(
url_re=URL_RE,
email_re=EMAIL_RE,
callbacks=DEFAULT_CALLBACKS + [truelink_callback, abslink_callback],
parse_email=True
)
return linker.linkify(bleach.clean(
@@ -186,7 +145,7 @@ def rich_text(text: str, **kwargs):
linker = bleach.Linker(
url_re=URL_RE,
email_re=EMAIL_RE,
callbacks=DEFAULT_CALLBACKS + ([truelink_callback, safelink_callback] if kwargs.get('safelinks', True) else [truelink_callback, abslink_callback]),
callbacks=DEFAULT_CALLBACKS + ([safelink_callback] if kwargs.get('safelinks', True) else [abslink_callback]),
parse_email=True
)
body_md = linker.linkify(markdown_compile(text))
@@ -202,7 +161,7 @@ def rich_text_snippet(text: str, **kwargs):
linker = bleach.Linker(
url_re=URL_RE,
email_re=EMAIL_RE,
callbacks=DEFAULT_CALLBACKS + ([truelink_callback, safelink_callback] if kwargs.get('safelinks', True) else [truelink_callback, abslink_callback]),
callbacks=DEFAULT_CALLBACKS + ([safelink_callback] if kwargs.get('safelinks', True) else [abslink_callback]),
parse_email=True
)
body_md = linker.linkify(markdown_compile(text, snippet=True))

View File

@@ -13,11 +13,7 @@ class DownloadView(TemplateView):
@cached_property
def object(self) -> CachedFile:
try:
o = get_object_or_404(CachedFile, id=self.kwargs['id'], web_download=True)
if o.session_key:
if o.session_key != self.request.session.session_key:
raise Http404()
return o
return get_object_or_404(CachedFile, id=self.kwargs['id'])
except ValueError: # Invalid URLs
raise Http404()

View File

@@ -203,7 +203,6 @@ class CachedFileField(ExtFileField):
cf = CachedFile.objects.create(
expires=now() + datetime.timedelta(days=1),
date=now(),
web_download=True,
filename=data.name,
type=data.content_type,
)
@@ -219,7 +218,6 @@ class CachedFileField(ExtFileField):
if isinstance(data, File):
cf = CachedFile.objects.create(
expires=now() + datetime.timedelta(days=1),
web_download=True,
date=now(),
filename=data.name,
type=data.content_type,

View File

@@ -19,7 +19,9 @@ from pytz import common_timezones, timezone
from pretix.base.channels import get_all_sales_channels
from pretix.base.email import get_available_placeholders
from pretix.base.forms import I18nModelForm, PlaceholderValidator, SettingsForm
from pretix.base.forms import (
I18nModelForm, PlaceholderValidator, SettingsForm,
)
from pretix.base.models import Event, Organizer, TaxRule, Team
from pretix.base.models.event import EventMetaValue, SubEvent
from pretix.base.reldate import RelativeDateField, RelativeDateTimeField
@@ -35,6 +37,7 @@ from pretix.helpers.countries import CachedCountries
from pretix.multidomain.models import KnownDomain
from pretix.multidomain.urlreverse import build_absolute_uri
from pretix.plugins.banktransfer.payment import BankTransfer
from pretix.presale.style import get_fonts
class EventWizardFoundationForm(forms.Form):
@@ -456,7 +459,6 @@ class EventSettingsForm(SettingsForm):
'presale_start_show_date',
'locales',
'locale',
'region',
'show_quota_left',
'waiting_list_enabled',
'waiting_list_hours',
@@ -480,9 +482,6 @@ class EventSettingsForm(SettingsForm):
'attendee_addresses_asked',
'attendee_addresses_required',
'attendee_data_explanation_text',
'order_phone_asked',
'order_phone_required',
'checkout_phone_helptext',
'banner_text',
'banner_text_bottom',
'order_email_asked_twice',
@@ -500,31 +499,6 @@ class EventSettingsForm(SettingsForm):
data = super().clean()
settings_dict = self.event.settings.freeze()
settings_dict.update(data)
# set all dependants of virtual_keys and
# delete all virtual_fields to prevent them from being saved
for virtual_key in self.virtual_keys:
if virtual_key not in data:
continue
base_key = virtual_key.rsplit('_', 2)[0]
asked_key = base_key + '_asked'
required_key = base_key + '_required'
if data[virtual_key] == 'optional':
data[asked_key] = True
data[required_key] = False
elif data[virtual_key] == 'required':
data[asked_key] = True
data[required_key] = True
# Explicitly check for 'do_not_ask'.
# Do not overwrite as default-behaviour when no value for virtual field is transmitted!
elif data[virtual_key] == 'do_not_ask':
data[asked_key] = False
data[required_key] = False
# hierarkey.forms cannot handle non-existent keys in cleaned_data => do not delete, but set to None
data[virtual_key] = None
validate_event_settings(self.event, data)
return data
@@ -548,39 +522,9 @@ class EventSettingsForm(SettingsForm):
if not self.event.has_subevents:
del self.fields['frontpage_subevent_ordering']
del self.fields['event_list_type']
# create "virtual" fields for better UX when editing <name>_asked and <name>_required fields
self.virtual_keys = []
for asked_key in [key for key in self.fields.keys() if key.endswith('_asked')]:
required_key = asked_key.rsplit('_', 1)[0] + '_required'
virtual_key = asked_key + '_required'
if required_key not in self.fields or virtual_key in self.fields:
# either no matching required key or
# there already is a field with virtual_key defined manually, so do not overwrite
continue
asked_field = self.fields[asked_key]
self.fields[virtual_key] = forms.ChoiceField(
label=asked_field.label,
help_text=asked_field.help_text,
required=True,
widget=forms.RadioSelect,
choices=[
# default key needs a value other than '' because with '' it would also overwrite even if combi-field is not transmitted
('do_not_ask', _('Do not ask')),
('optional', _('Ask, but do not require input')),
('required', _('Ask and require input'))
]
)
self.virtual_keys.append(virtual_key)
if self.initial[required_key]:
self.initial[virtual_key] = 'required'
elif self.initial[asked_key]:
self.initial[virtual_key] = 'optional'
else:
self.initial[virtual_key] = 'do_not_ask'
self.fields['primary_font'].choices += [
(a, {"title": a, "data": v}) for a, v in get_fonts().items()
]
class CancelSettingsForm(SettingsForm):

View File

@@ -150,8 +150,8 @@ class OrderFilterForm(FilterForm):
(Order.STATUS_PENDING + Order.STATUS_PAID, _('Pending or paid')),
)),
(_('Cancellations'), (
(Order.STATUS_CANCELED, _('Canceled (fully)')),
('cp', _('Canceled (fully or with paid fee)')),
(Order.STATUS_CANCELED, _('Canceled')),
('cp', _('Canceled (or with paid fee)')),
('rc', _('Cancellation requested')),
)),
(_('Payment process'), (
@@ -159,8 +159,7 @@ class OrderFilterForm(FilterForm):
(Order.STATUS_PENDING + Order.STATUS_EXPIRED, _('Pending or expired')),
('o', _('Pending (overdue)')),
('overpaid', _('Overpaid')),
('partially_paid', _('Partially paid')),
('underpaid', _('Underpaid (but confirmed)')),
('underpaid', _('Underpaid')),
('pendingpaid', _('Pending (but fully paid)')),
)),
(_('Approval process'), (
@@ -246,14 +245,6 @@ class OrderFilterForm(FilterForm):
Q(status__in=(Order.STATUS_EXPIRED, Order.STATUS_PENDING)) & Q(pending_sum_t__lte=0)
& Q(require_approval=False)
)
elif s == 'partially_paid':
qs = Order.annotate_overpayments(qs, refunds=False, results=False, sums=True)
qs = qs.filter(
computed_payment_refund_sum__lt=F('total'),
computed_payment_refund_sum__gt=Decimal('0.00')
).exclude(
status=Order.STATUS_CANCELED
)
elif s == 'underpaid':
qs = Order.annotate_overpayments(qs, refunds=False, results=False, sums=True)
qs = qs.filter(

View File

@@ -10,15 +10,11 @@ from pretix.base.signals import register_global_settings
class GlobalSettingsForm(SettingsForm):
auto_fields = [
'region'
]
def __init__(self, *args, **kwargs):
self.obj = GlobalSettingsObject()
super().__init__(*args, obj=self.obj, **kwargs)
self.fields = OrderedDict(list(self.fields.items()) + [
self.fields = OrderedDict([
('footer_text', I18nFormField(
widget=I18nTextInput,
required=False,

View File

@@ -16,7 +16,6 @@ from i18nfield.strings import LazyI18nString
from pretix.base.email import get_available_placeholders
from pretix.base.forms import I18nModelForm, PlaceholderValidator
from pretix.base.forms.questions import WrappedPhoneNumberPrefixWidget
from pretix.base.forms.widgets import (
DatePickerWidget, SplitDateTimePickerWidget,
)
@@ -461,15 +460,7 @@ class OrderContactForm(forms.ModelForm):
class Meta:
model = Order
fields = ['email', 'email_known_to_work', 'phone']
widgets = {
'phone': WrappedPhoneNumberPrefixWidget()
}
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if not self.instance.event.settings.order_phone_asked and not self.instance.phone:
del self.fields['phone']
fields = ['email', 'email_known_to_work']
class OrderLocaleForm(forms.ModelForm):

View File

@@ -223,7 +223,6 @@ class OrganizerSettingsForm(SettingsForm):
'giftcard_length',
'giftcard_expiry_years',
'locales',
'region',
'event_team_provisioning',
'primary_color',
'theme_color_success',

View File

@@ -292,8 +292,6 @@ def pretixcontrol_logentry_display(sender: Event, logentry: LogEntry, **kwargs):
'pretix.event.order.denied': _('The order has been denied.'),
'pretix.event.order.contact.changed': _('The email address has been changed from "{old_email}" '
'to "{new_email}".'),
'pretix.event.order.phone.changed': _('The phone number has been changed from "{old_phone}" '
'to "{new_phone}".'),
'pretix.event.order.locale.changed': _('The order locale has been changed.'),
'pretix.event.order.invoice.generated': _('The invoice has been generated.'),
'pretix.event.order.invoice.regenerated': _('The invoice has been regenerated.'),

View File

@@ -18,7 +18,7 @@
<script type="text/javascript" src="{% url 'javascript-catalog' lang=request.LANGUAGE_CODE %}"
defer></script>
{% else %}
<script src="{% statici18n request.LANGUAGE_CODE %}" async></script>
<script src="{% statici18n LANGUAGE_CODE %}" async></script>
{% endif %}
{% compress js %}
<script type="text/javascript" src="{% static "jquery/js/jquery-2.1.1.min.js" %}"></script>

View File

@@ -83,61 +83,22 @@
{% bootstrap_field sform.locales layout="control" %}
{% bootstrap_field sform.locale layout="control" %}
{% bootstrap_field sform.timezone layout="control" %}
{% bootstrap_field sform.region layout="control" %}
</fieldset>
<fieldset>
<legend>{% trans "Customer and attendee data" %}</legend>
<h4>{% trans "Customer data (once per order)" %}</h4>
<div class="form-group">
<label class="control-label col-md-3">
{% trans "E-mail" %}
</label>
<div class="col-md-9">
<div class="checkbox">
<label><input type="checkbox" checked="checked" disabled="disabled"> {% trans "Ask and require input" %}</label>
</div>
</div>
</div>
{% bootstrap_field sform.order_email_asked_twice layout="control" %}
{% bootstrap_field sform.order_phone_asked_required layout="control" %}
<div class="form-group">
<label class="control-label col-md-3">
{% trans "Name and address" %}
</label>
<div class="col-md-9 static-form-row">
<p>
<a href="{% url "control:event.settings.invoice" event=request.event.slug organizer=request.organizer.slug %}#tab-0-1-open" target="_blank">
{% trans "See invoice settings" %}
</a>
</p>
</div>
</div>
<h4>{% trans "Attendee data (once per admission ticket)" %}</h4>
{% bootstrap_field sform.attendee_names_asked_required layout="control" %}
{% bootstrap_field sform.attendee_emails_asked_required layout="control" %}
{% bootstrap_field sform.attendee_company_asked_required layout="control" %}
{% bootstrap_field sform.attendee_addresses_asked_required layout="control" %}
<div class="form-group">
<label class="control-label col-md-3">
{% trans "Custom fields" %}
</label>
<div class="col-md-9 static-form-row">
<p>
<a href="{% url "control:event.items.questions" event=request.event.slug organizer=request.organizer.slug %}" target="_blank">
{% trans "Manage questions" %}
</a>
</p>
</div>
</div>
{% bootstrap_field sform.attendee_data_explanation_text layout="control" %}
<h4>{% trans "Other settings" %}</h4>
<legend>{% trans "Attendee data" %}</legend>
{% bootstrap_field sform.attendee_names_asked layout="control" %}
{% bootstrap_field sform.attendee_names_required layout="control" %}
{% bootstrap_field sform.name_scheme layout="control" %}
{% bootstrap_field sform.name_scheme_titles layout="control" %}
{% bootstrap_field sform.order_email_asked_twice layout="control" %}
{% bootstrap_field sform.attendee_emails_asked layout="control" %}
{% bootstrap_field sform.attendee_emails_required layout="control" %}
{% bootstrap_field sform.attendee_company_asked layout="control" %}
{% bootstrap_field sform.attendee_company_required layout="control" %}
{% bootstrap_field sform.attendee_addresses_asked layout="control" %}
{% bootstrap_field sform.attendee_addresses_required layout="control" %}
{% bootstrap_field sform.checkout_show_copy_answers_button layout="control" %}
{% bootstrap_field sform.attendee_data_explanation_text layout="control" %}
</fieldset>
<fieldset>
<legend>{% trans "Texts" %}</legend>
@@ -216,7 +177,6 @@
</div>
{% bootstrap_field sform.checkout_email_helptext layout="control" %}
{% bootstrap_field sform.checkout_phone_helptext layout="control" %}
{% bootstrap_field sform.banner_text layout="control" %}
{% bootstrap_field sform.banner_text_bottom layout="control" %}
</fieldset>

View File

@@ -6,7 +6,6 @@
{% load rich_text %}
{% load safelink %}
{% load eventsignal %}
{% load phone_format %}
{% block title %}
{% blocktrans trimmed with code=order.code %}
Order details: {{ code }}
@@ -202,15 +201,6 @@
{% endif %}
{% endif %}
</dd>
{% if order.phone or request.event.settings.order_phone_asked %}
<dt>{% trans "Phone number" %}</dt>
<dd>
{{ order.phone|default_if_none:""|phone_format }}
<a href="{% url "control:event.order.contact" event=request.event.slug organizer=request.event.organizer.slug code=order.code %}" class="btn btn-default btn-xs">
<span class="fa fa-edit"></span>
</a>
</dd>
{% endif %}
{% if invoices %}
<dt>{% trans "Invoices" %}</dt>
<dd>
@@ -570,26 +560,6 @@
</div>
<div class="clearfix"></div>
</div>
{% if order.status != "c" and order.total != payment_refund_sum %}
<div class="row-fluid product-row cart-row">
<div class="col-md-4 col-xs-6">
{% trans "Successful payments" %}
</div>
<div class="col-md-3 col-xs-6 col-md-offset-5 price">
{{ payment_refund_sum|money:event.currency }}
</div>
<div class="clearfix"></div>
</div>
<div class="row-fluid product-row total text-danger">
<div class="col-md-4 col-xs-6">
<strong>{% trans "Pending total" %}</strong>
</div>
<div class="col-md-3 col-xs-6 col-md-offset-5 price">
<strong>{{ order.pending_sum|money:event.currency }}</strong>
</div>
<div class="clearfix"></div>
</div>
{% endif %}
</div>
</div>
{% eventsignal event "pretix.control.signals.order_info" order=order request=request %}

View File

@@ -113,7 +113,7 @@
<a href="?{% url_replace request 'ordering' '-datetime' %}"><i class="fa fa-caret-down"></i></a>
<a href="?{% url_replace request 'ordering' 'datetime' %}"><i class="fa fa-caret-up"></i></a>
</th>
<th class="text-right flip">{% trans "Order paid / total" %}
<th class="text-right flip">{% trans "Order total" %}
<a href="?{% url_replace request 'ordering' '-total' %}"><i class="fa fa-caret-down"></i></a>
<a href="?{% url_replace request 'ordering' 'total' %}"><i class="fa fa-caret-up"></i></a></th>
<th class="text-right flip">{% trans "Positions" %}</th>
@@ -141,11 +141,7 @@
<br>{{ o.invoice_address.name }}
{% endif %}
</td>
<td>
<span class="fa fa-{{ o.sales_channel_obj.icon }} text-muted"
data-toggle="tooltip" title="{% trans o.sales_channel_obj.verbose_name %}"></span>
{{ o.datetime|date:"SHORT_DATETIME_FORMAT" }}
</td>
<td>{{ o.datetime|date:"SHORT_DATETIME_FORMAT" }}</td>
<td class="text-right flip">
{% if o.has_cancellation_request %}
<span class="label label-warning">{% trans "CANCELLATION REQUESTED" %}</span>
@@ -162,13 +158,6 @@
{% elif o.is_pending_with_full_payment %}
<span class="label label-danger">{% trans "FULLY PAID" %}</span>
{% endif %}
{% if o.computed_payment_refund_sum == o.total or o.computed_payment_refund_sum == 0 %}
<span class="text-muted">
{% endif %}
{{ o.computed_payment_refund_sum|money:request.event.currency }} /
{% if o.computed_payment_refund_sum == o.total or o.computed_payment_refund_sum == 0 %}
</span>
{% endif %}
{{ o.total|money:request.event.currency }}
</td>
<td class="text-right flip">{{ o.pcnt|default_if_none:"0" }}</td>

View File

@@ -45,7 +45,6 @@
<fieldset>
<legend>{% trans "Localization" %}</legend>
{% bootstrap_field sform.locales layout="control" %}
{% bootstrap_field sform.region layout="control" %}
</fieldset>
<fieldset>
<legend>{% trans "Shop design" %}</legend>

View File

@@ -32,7 +32,7 @@
<label class="col-md-3 control-label" for="id_url">{% trans "Voucher link" %}</label>
<div class="col-md-9">
<input type="text" name="url"
value="{% abseventurl request.event "presale:event.redeem" %}?voucher={{ voucher.code }}{% if voucher.subevent_id %}&subevent={{ voucher.subevent_id }}{% endif %}"
value="{% abseventurl request.event "presale:event.redeem" %}?voucher={{ voucher.code }}&subevent={{ voucher.subevent_id }}"
class="form-control"
id="id_url" readonly>
</div>

View File

@@ -74,15 +74,13 @@ def login(request):
backend = [b for b in backends if b.visible][0]
if request.user.is_authenticated:
next_url = backend.get_next_url(request) or 'control:index'
if next_url and url_has_allowed_host_and_scheme(next_url, allowed_hosts=None):
return redirect(next_url)
return redirect(reverse('control:index'))
return redirect(next_url)
if request.method == 'POST':
form = LoginForm(backend=backend, data=request.POST, request=request)
form = LoginForm(backend=backend, data=request.POST)
if form.is_valid() and form.user_cache and form.user_cache.auth_backend == backend.identifier:
return process_login(request, form.user_cache, form.cleaned_data.get('keep_logged_in', False))
else:
form = LoginForm(backend=backend, request=request)
form = LoginForm(backend=backend)
ctx['form'] = form
ctx['can_register'] = settings.PRETIX_REGISTRATION
ctx['can_reset'] = settings.PRETIX_PASSWORD_RESET

View File

@@ -19,6 +19,7 @@ from django.http import (
)
from django.shortcuts import get_object_or_404, redirect
from django.urls import reverse
from django.utils import translation
from django.utils.functional import cached_property
from django.utils.timezone import now
from django.utils.translation import gettext, gettext_lazy as _
@@ -54,7 +55,6 @@ from pretix.multidomain.urlreverse import get_event_domain
from pretix.plugins.stripe.payment import StripeSettingsHolder
from pretix.presale.style import regenerate_css
from ...base.i18n import language
from ...base.models.items import ItemMetaProperty
from ...base.settings import SETTINGS_AFFECTING_CSS, LazyI18nStringList
from ..logdisplay import OVERVIEW_BANLIST
@@ -594,7 +594,7 @@ class MailSettings(EventSettingsViewMixin, EventSettingsFormView):
)
if request.POST.get('test', '0').strip() == '1':
backend = self.request.event.get_mail_backend(force_custom=True, timeout=10)
backend = self.request.event.get_mail_backend(force_custom=True)
try:
backend.test(self.request.event.settings.mail_from)
except Exception as e:
@@ -659,7 +659,7 @@ class MailSettingsPreview(EventPermissionRequiredMixin, View):
if matched is not None:
idx = matched.group('idx')
if idx in self.supported_locale:
with language(self.supported_locale[idx], self.request.event.settings.region):
with translation.override(self.supported_locale[idx]):
msgs[self.supported_locale[idx]] = markdown_compile_email(
v.format_map(self.placeholders(preview_item))
)

View File

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

View File

@@ -153,18 +153,17 @@ class OrderList(OrderSearchMixin, EventPermissionRequiredMixin, PaginationMixin,
annotated = {
o['pk']: o
for o in
Order.annotate_overpayments(Order.objects, sums=True).filter(
Order.annotate_overpayments(Order.objects).filter(
pk__in=[o.pk for o in ctx['orders']]
).annotate(
pcnt=Subquery(s, output_field=IntegerField()),
has_cancellation_request=Exists(CancellationRequest.objects.filter(order=OuterRef('pk')))
).values(
'pk', 'pcnt', 'is_overpaid', 'is_underpaid', 'is_pending_with_full_payment', 'has_external_refund',
'has_pending_refund', 'has_cancellation_request', 'computed_payment_refund_sum'
'has_pending_refund', 'has_cancellation_request'
)
}
scs = get_all_sales_channels()
for o in ctx['orders']:
if o.pk not in annotated:
continue
@@ -175,8 +174,6 @@ class OrderList(OrderSearchMixin, EventPermissionRequiredMixin, PaginationMixin,
o.has_external_refund = annotated.get(o.pk)['has_external_refund']
o.has_pending_refund = annotated.get(o.pk)['has_pending_refund']
o.has_cancellation_request = annotated.get(o.pk)['has_cancellation_request']
o.computed_payment_refund_sum = annotated.get(o.pk)['computed_payment_refund_sum']
o.sales_channel_obj = scs[o.sales_channel]
if ctx['page_obj'].paginator.count < 1000:
# Performance safeguard: Only count positions if the data set is small
@@ -265,8 +262,6 @@ class OrderDetail(OrderView):
ctx['overpaid'] = self.order.pending_sum * -1
ctx['sales_channel'] = get_all_sales_channels().get(self.order.sales_channel)
ctx['download_buttons'] = self.download_buttons
ctx['payment_refund_sum'] = self.order.payment_refund_sum
ctx['pending_sum'] = self.order.pending_sum
return ctx
@cached_property
@@ -671,7 +666,7 @@ class OrderCancellationRequestDelete(OrderView):
}, user=self.request.user)
messages.success(self.request, _('The request has been removed. If you want, you can now inform the user.'))
with language(self.order.locale, self.request.event.settings.region):
with language(self.order.locale):
return redirect(reverse('control:event.order.sendmail', kwargs={
'event': self.request.event.slug,
'organizer': self.request.event.organizer.slug,
@@ -942,7 +937,7 @@ class OrderRefundView(OrderView):
if giftcard_value and self.order.email:
messages.success(self.request, _('A new gift card was created. You can now send the user their '
'gift card code.'))
with language(self.order.locale, self.request.event.settings.region):
with language(self.order.locale):
return redirect(reverse('control:event.order.sendmail', kwargs={
'event': self.request.event.slug,
'organizer': self.request.event.organizer.slug,
@@ -1668,7 +1663,6 @@ class OrderContactChange(OrderView):
def post(self, *args, **kwargs):
old_email = self.order.email
old_phone = self.order.phone
changed = False
if self.form.is_valid():
new_email = self.form.cleaned_data['email']
@@ -1683,18 +1677,6 @@ class OrderContactChange(OrderView):
user=self.request.user,
)
new_phone = self.form.cleaned_data.get('phone')
if new_phone != old_phone:
changed = True
self.order.log_action(
'pretix.event.order.phone.changed',
data={
'old_phone': old_phone,
'new_phone': self.form.cleaned_data['phone'],
},
user=self.request.user,
)
if self.form.cleaned_data['regenerate_secrets']:
changed = True
self.order.secret = generate_secret()
@@ -1797,7 +1779,7 @@ class OrderSendMail(EventPermissionRequiredMixin, OrderViewMixin, FormView):
code=self.kwargs['code'].upper()
)
self.preview_output = {}
with language(order.locale, self.request.event.settings.region):
with language(order.locale):
email_context = get_email_context(event=order.event, order=order)
email_template = LazyI18nString(form.cleaned_data['message'])
email_subject = str(form.cleaned_data['subject']).format_map(TolerantDict(email_context))
@@ -1860,7 +1842,7 @@ class OrderPositionSendMail(OrderSendMail):
attendee_email__isnull=False
)
self.preview_output = {}
with language(position.order.locale, self.request.event.settings.region):
with language(position.order.locale):
email_context = get_email_context(event=position.order.event, order=position.order, position=position)
email_template = LazyI18nString(form.cleaned_data['message'])
email_subject = str(form.cleaned_data['subject']).format_map(TolerantDict(email_context))
@@ -2064,9 +2046,9 @@ class ExportDoView(EventPermissionRequiredMixin, ExportMixin, AsyncAction, View)
messages.error(self.request, _('There was a problem processing your input. See below for error details.'))
return self.get(request, *args, **kwargs)
cf = CachedFile(web_download=True, session_key=request.session.session_key)
cf = CachedFile()
cf.date = now()
cf.expires = now() + timedelta(hours=24)
cf.expires = now() + timedelta(days=3)
cf.save()
return self.do(self.request.event.id, str(cf.id), self.exporter.identifier, self.exporter.form.cleaned_data)

View File

@@ -1242,9 +1242,9 @@ class ExportDoView(OrganizerPermissionRequiredMixin, ExportMixin, AsyncAction, V
messages.error(self.request, _('There was a problem processing your input. See below for error details.'))
return self.get(request, *args, **kwargs)
cf = CachedFile(web_download=True, session_key=request.session.session_key)
cf = CachedFile()
cf.date = now()
cf.expires = now() + timedelta(hours=24)
cf.expires = now() + timedelta(days=3)
cf.save()
return self.do(
organizer=self.request.organizer.id,

View File

@@ -137,7 +137,7 @@ class BaseEditorView(EventPermissionRequiredMixin, TemplateView):
buffer = BytesIO()
p.write(buffer)
buffer.seek(0)
c = CachedFile(web_download=True)
c = CachedFile()
c.expires = now() + timedelta(days=7)
c.date = now()
c.filename = 'background_preview.pdf'
@@ -162,7 +162,7 @@ class BaseEditorView(EventPermissionRequiredMixin, TemplateView):
"status": "error",
"error": error
})
c = CachedFile(web_download=True)
c = CachedFile()
c.expires = now() + timedelta(days=7)
c.date = now()
c.filename = 'background_preview.pdf'
@@ -188,7 +188,7 @@ class BaseEditorView(EventPermissionRequiredMixin, TemplateView):
pass
if "preview" in request.POST:
with rolledback_transaction(), language(request.event.settings.locale, request.event.settings.region):
with rolledback_transaction(), language(request.event.settings.locale):
p = self._get_preview_position()
fname, mimet, data = self.generate(
p,

View File

@@ -75,7 +75,7 @@ class ShredExportView(RecentAuthenticationRequiredMixin, EventPermissionRequired
if constr:
return self.error(ShredError(self.get_error_url()))
return self.do(self.request.event.id, request.POST.getlist("shredder"), self.request.session.session_key)
return self.do(self.request.event.id, request.POST.getlist("shredder"))
class ShredDoView(RecentAuthenticationRequiredMixin, EventPermissionRequiredMixin, ShredderMixin, AsyncAction, View):

View File

@@ -1,9 +1,8 @@
from django.core.cache import cache
from django.utils.translation import get_language
from django_countries import Countries
from django_countries.fields import CountryField
from pretix.base.i18n import get_language_without_region
class CachedCountries(Countries):
_cached_lists = {}
@@ -15,7 +14,7 @@ class CachedCountries(Countries):
django-countries performs a unicode-aware sorting based on pyuca which is incredibly
slow.
"""
cache_key = "countries:all:{}".format(get_language_without_region())
cache_key = "countries:all:{}".format(get_language())
if self.cache_subkey:
cache_key += ":" + self.cache_subkey
if cache_key in self._cached_lists:

View File

@@ -1,18 +0,0 @@
# Date according to https://docs.djangoproject.com/en/dev/ref/templates/builtins/#date
SHORT_DATE_FORMAT = 'm/d/Y'
SHORT_DATETIME_FORMAT = 'm/d/Y P'
TIME_FORMAT = 'P'
WEEK_FORMAT = '\\W W, o'
WEEK_DAY_FORMAT = 'D, M jS'
DATE_INPUT_FORMATS = [
'%m/%d/%Y',
'%Y-%m-%d',
'%m/%d/%y',
]
TIME_INPUT_FORMATS = [
'%I:%M %p',
'%H:%M:%S', # '14:30:59'
'%H:%M:%S.%f', # '14:30:59.000200'
'%H:%M', # '14:30'
]

View File

@@ -126,7 +126,6 @@ def get_javascript_format_without_seconds(format_name):
def get_moment_locale(locale=None):
cur_lang = locale or translation.get_language()
cur_lang = cur_lang.lower()
if cur_lang in moment_locales:
return cur_lang
if '-' in cur_lang or '_' in cur_lang:

File diff suppressed because it is too large Load Diff

View File

@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-12-22 11:06+0000\n"
"POT-Creation-Date: 2020-11-27 17:32+0000\n"
"PO-Revision-Date: 2020-07-30 19:00+0000\n"
"Last-Translator: Abdullah <abdullah.gumaijan@gmail.com>\n"
"Language-Team: Arabic <https://translate.pretix.eu/projects/pretix/pretix-js/"
@@ -302,15 +302,15 @@ msgstr "الكل"
msgid "None"
msgstr "لا شيء"
#: pretix/static/pretixcontrol/js/ui/main.js:709
#: pretix/static/pretixcontrol/js/ui/main.js:706
msgid "Use a different name internally"
msgstr "استخدام اسم مختلف داخليا"
#: pretix/static/pretixcontrol/js/ui/main.js:766
#: pretix/static/pretixcontrol/js/ui/main.js:763
msgid "Click to close"
msgstr "انقر لقريب"
#: pretix/static/pretixcontrol/js/ui/main.js:781
#: pretix/static/pretixcontrol/js/ui/main.js:778
msgid "You have unsaved changes!"
msgstr ""

File diff suppressed because it is too large Load Diff

View File

@@ -7,17 +7,15 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-12-22 11:06+0000\n"
"PO-Revision-Date: 2020-12-19 07:00+0000\n"
"Last-Translator: albert <albert.serra.monner@gmail.com>\n"
"Language-Team: Catalan <https://translate.pretix.eu/projects/pretix/pretix-"
"js/ca/>\n"
"POT-Creation-Date: 2020-11-27 17:32+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: Automatically generated\n"
"Language-Team: none\n"
"Language: ca\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 3.10.3\n"
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:56
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:62
@@ -27,7 +25,7 @@ msgstr ""
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:76
msgid "Comment:"
msgstr "Comentari:"
msgstr ""
#: pretix/plugins/statistics/static/pretixplugins/statistics/statistics.js:15
#: pretix/plugins/statistics/static/pretixplugins/statistics/statistics.js:39
@@ -106,7 +104,7 @@ msgstr ""
#: pretix/static/pretixbase/js/asynctask.js:189
msgid "We are processing your request …"
msgstr "Estem processant la vostra sol·licitud …"
msgstr ""
#: pretix/static/pretixbase/js/asynctask.js:197
msgid ""
@@ -232,7 +230,7 @@ msgstr ""
#: pretix/static/pretixcontrol/js/ui/editor.js:477
msgid "Ticket design"
msgstr "Disseny del tiquet"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/editor.js:734
msgid "Saving failed."
@@ -281,15 +279,15 @@ msgstr ""
msgid "None"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:709
#: pretix/static/pretixcontrol/js/ui/main.js:706
msgid "Use a different name internally"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:766
#: pretix/static/pretixcontrol/js/ui/main.js:763
msgid "Click to close"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:781
#: pretix/static/pretixcontrol/js/ui/main.js:778
msgid "You have unsaved changes!"
msgstr ""
@@ -303,7 +301,7 @@ msgstr ""
#: pretix/static/pretixcontrol/js/ui/question.js:82
msgid "Count"
msgstr "Quantitat"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/question.js:135
msgid "Yes"
@@ -321,11 +319,11 @@ msgstr[1] ""
#: pretix/static/pretixpresale/js/ui/cart.js:39
msgid "The items in your cart are no longer reserved for you."
msgstr "El contingut de la cistella ja no el teniu reservat."
msgstr ""
#: pretix/static/pretixpresale/js/ui/cart.js:41
msgid "Cart expired"
msgstr "Cistella expirada"
msgstr ""
#: pretix/static/pretixpresale/js/ui/cart.js:46
msgid "The items in your cart are reserved for you for one minute."

File diff suppressed because it is too large Load Diff

View File

@@ -7,17 +7,15 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-12-22 11:06+0000\n"
"PO-Revision-Date: 2020-12-14 10:00+0000\n"
"Last-Translator: Ondřej Sokol <osokol@treesoft.cz>\n"
"Language-Team: Czech <https://translate.pretix.eu/projects/pretix/pretix-js/"
"cs/>\n"
"POT-Creation-Date: 2020-11-27 17:32+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: Automatically generated\n"
"Language-Team: none\n"
"Language: cs\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
"X-Generator: Weblate 3.10.3\n"
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:56
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:62
@@ -281,15 +279,15 @@ msgstr ""
msgid "None"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:709
#: pretix/static/pretixcontrol/js/ui/main.js:706
msgid "Use a different name internally"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:766
#: pretix/static/pretixcontrol/js/ui/main.js:763
msgid "Click to close"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:781
#: pretix/static/pretixcontrol/js/ui/main.js:778
msgid "You have unsaved changes!"
msgstr ""
@@ -299,19 +297,19 @@ msgstr ""
#: pretix/static/pretixcontrol/js/ui/question.js:42
msgid "Others"
msgstr "Další"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/question.js:82
msgid "Count"
msgstr "Počet"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/question.js:135
msgid "Yes"
msgstr "Ano"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/question.js:136
msgid "No"
msgstr "Ne"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/subevent.js:111
msgid "(one more date)"
@@ -363,12 +361,12 @@ msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js:17
msgctxt "widget"
msgid "Sold out"
msgstr "Vyprodáno"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js:18
msgctxt "widget"
msgid "Buy"
msgstr "Koupit"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js:19
msgctxt "widget"
@@ -457,62 +455,62 @@ msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js:36
msgctxt "widget"
msgid "Resume checkout"
msgstr "Obnovit checkout"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js:37
msgctxt "widget"
msgid "Redeem a voucher"
msgstr "Uplatnit poukázku"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js:38
msgctxt "widget"
msgid "Redeem"
msgstr "Uplatnit"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js:39
msgctxt "widget"
msgid "Voucher code"
msgstr "Kód poukázky"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js:40
msgctxt "widget"
msgid "Close"
msgstr "Zavřít"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js:41
msgctxt "widget"
msgid "Continue"
msgstr "Pokračovat"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js:42
msgctxt "widget"
msgid "See variations"
msgstr "Zobrazit možnosti"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js:43
msgctxt "widget"
msgid "Choose a different event"
msgstr "Vybrat jinou událost"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js:44
msgctxt "widget"
msgid "Choose a different date"
msgstr "Vybrat jiný datum"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js:45
msgctxt "widget"
msgid "Back"
msgstr "Zpět"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js:46
msgctxt "widget"
msgid "Next month"
msgstr "Následující měsíc"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js:47
msgctxt "widget"
msgid "Previous month"
msgstr "Předchozí měsíc"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js:48
msgctxt "widget"
@@ -531,76 +529,76 @@ msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js:52
msgid "Mo"
msgstr "Po"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js:53
msgid "Tu"
msgstr "Út"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js:54
msgid "We"
msgstr "St"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js:55
msgid "Th"
msgstr "Čt"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js:56
msgid "Fr"
msgstr ""
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js:57
msgid "Sa"
msgstr "So"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js:58
msgid "Su"
msgstr "Ne"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js:61
msgid "January"
msgstr "Leden"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js:62
msgid "February"
msgstr "Únor"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js:63
msgid "March"
msgstr "Březen"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js:64
msgid "April"
msgstr "Duben"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js:65
msgid "May"
msgstr "Květen"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js:66
msgid "June"
msgstr "červen"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js:67
msgid "July"
msgstr "Červenec"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js:68
msgid "August"
msgstr "Srpen"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js:69
msgid "September"
msgstr "Září"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js:70
msgid "October"
msgstr "Říjen"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js:71
msgid "November"
msgstr "Listopad"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js:72
msgid "December"
msgstr "Prosinec"
msgstr ""

File diff suppressed because it is too large Load Diff

View File

@@ -6,7 +6,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-12-22 11:06+0000\n"
"POT-Creation-Date: 2020-11-27 17:32+0000\n"
"PO-Revision-Date: 2020-09-15 02:00+0000\n"
"Last-Translator: Mie Frydensbjerg <mif@aarhus.dk>\n"
"Language-Team: Danish <https://translate.pretix.eu/projects/pretix/pretix-js/"
@@ -306,15 +306,15 @@ msgstr "Alle"
msgid "None"
msgstr "Ingen"
#: pretix/static/pretixcontrol/js/ui/main.js:709
#: pretix/static/pretixcontrol/js/ui/main.js:706
msgid "Use a different name internally"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:766
#: pretix/static/pretixcontrol/js/ui/main.js:763
msgid "Click to close"
msgstr "Klik for at lukke"
#: pretix/static/pretixcontrol/js/ui/main.js:781
#: pretix/static/pretixcontrol/js/ui/main.js:778
msgid "You have unsaved changes!"
msgstr "Du har ændringer, der ikke er gemt!"

File diff suppressed because it is too large Load Diff

View File

@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-12-22 11:06+0000\n"
"POT-Creation-Date: 2020-11-27 17:32+0000\n"
"PO-Revision-Date: 2020-08-25 02:00+0000\n"
"Last-Translator: Dennis Lichtenthäler <lichtenthaeler@rami.io>\n"
"Language-Team: German <https://translate.pretix.eu/projects/pretix/pretix-js/"
@@ -301,15 +301,15 @@ msgstr "Alle"
msgid "None"
msgstr "Keine"
#: pretix/static/pretixcontrol/js/ui/main.js:709
#: pretix/static/pretixcontrol/js/ui/main.js:706
msgid "Use a different name internally"
msgstr "Intern einen anderen Namen verwenden"
#: pretix/static/pretixcontrol/js/ui/main.js:766
#: pretix/static/pretixcontrol/js/ui/main.js:763
msgid "Click to close"
msgstr "Klicken zum Schließen"
#: pretix/static/pretixcontrol/js/ui/main.js:781
#: pretix/static/pretixcontrol/js/ui/main.js:778
msgid "You have unsaved changes!"
msgstr "Sie haben ungespeicherte Änderungen!"

File diff suppressed because it is too large Load Diff

View File

@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-12-22 11:06+0000\n"
"POT-Creation-Date: 2020-11-27 17:32+0000\n"
"PO-Revision-Date: 2020-08-25 02:00+0000\n"
"Last-Translator: Dennis Lichtenthäler <lichtenthaeler@rami.io>\n"
"Language-Team: German (informal) <https://translate.pretix.eu/projects/"
@@ -300,15 +300,15 @@ msgstr "Alle"
msgid "None"
msgstr "Keine"
#: pretix/static/pretixcontrol/js/ui/main.js:709
#: pretix/static/pretixcontrol/js/ui/main.js:706
msgid "Use a different name internally"
msgstr "Intern einen anderen Namen verwenden"
#: pretix/static/pretixcontrol/js/ui/main.js:766
#: pretix/static/pretixcontrol/js/ui/main.js:763
msgid "Click to close"
msgstr "Klicken zum Schließen"
#: pretix/static/pretixcontrol/js/ui/main.js:781
#: pretix/static/pretixcontrol/js/ui/main.js:778
msgid "You have unsaved changes!"
msgstr "Du hast ungespeicherte Änderungen!"

File diff suppressed because it is too large Load Diff

View File

@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-12-22 11:06+0000\n"
"POT-Creation-Date: 2020-11-27 17:32+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -280,15 +280,15 @@ msgstr ""
msgid "None"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:709
#: pretix/static/pretixcontrol/js/ui/main.js:706
msgid "Use a different name internally"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:766
#: pretix/static/pretixcontrol/js/ui/main.js:763
msgid "Click to close"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:781
#: pretix/static/pretixcontrol/js/ui/main.js:778
msgid "You have unsaved changes!"
msgstr ""

File diff suppressed because it is too large Load Diff

View File

@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-12-22 11:06+0000\n"
"POT-Creation-Date: 2020-11-27 17:32+0000\n"
"PO-Revision-Date: 2019-10-03 19:00+0000\n"
"Last-Translator: Chris Spy <chrispiropoulou@hotmail.com>\n"
"Language-Team: Greek <https://translate.pretix.eu/projects/pretix/pretix-js/"
@@ -320,15 +320,15 @@ msgstr "Όλα"
msgid "None"
msgstr "Κανένας"
#: pretix/static/pretixcontrol/js/ui/main.js:709
#: pretix/static/pretixcontrol/js/ui/main.js:706
msgid "Use a different name internally"
msgstr "Χρησιμοποιήστε διαφορετικό όνομα εσωτερικά"
#: pretix/static/pretixcontrol/js/ui/main.js:766
#: pretix/static/pretixcontrol/js/ui/main.js:763
msgid "Click to close"
msgstr "Κάντε κλικ για να κλείσετε"
#: pretix/static/pretixcontrol/js/ui/main.js:781
#: pretix/static/pretixcontrol/js/ui/main.js:778
msgid "You have unsaved changes!"
msgstr ""

File diff suppressed because it is too large Load Diff

View File

@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-12-22 11:06+0000\n"
"POT-Creation-Date: 2020-11-27 17:32+0000\n"
"PO-Revision-Date: 2020-04-27 20:00+0000\n"
"Last-Translator: Gonzalo Gabriel Perez <zalitoar@gmail.com>\n"
"Language-Team: Spanish <https://translate.pretix.eu/projects/pretix/pretix-"
@@ -315,15 +315,15 @@ msgstr "Todos"
msgid "None"
msgstr "Ninguno"
#: pretix/static/pretixcontrol/js/ui/main.js:709
#: pretix/static/pretixcontrol/js/ui/main.js:706
msgid "Use a different name internally"
msgstr "Usar un nombre diferente internamente"
#: pretix/static/pretixcontrol/js/ui/main.js:766
#: pretix/static/pretixcontrol/js/ui/main.js:763
msgid "Click to close"
msgstr "Click para cerrar"
#: pretix/static/pretixcontrol/js/ui/main.js:781
#: pretix/static/pretixcontrol/js/ui/main.js:778
msgid "You have unsaved changes!"
msgstr "¡Tienes cambios sin guardar!"

File diff suppressed because it is too large Load Diff

View File

@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-12-22 11:06+0000\n"
"POT-Creation-Date: 2020-11-27 17:32+0000\n"
"PO-Revision-Date: 2020-10-17 20:00+0000\n"
"Last-Translator: Jaakko Rinta-Filppula <jaakko@r-f.fi>\n"
"Language-Team: Finnish <https://translate.pretix.eu/projects/pretix/pretix-"
@@ -283,15 +283,15 @@ msgstr "Kaikki"
msgid "None"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:709
#: pretix/static/pretixcontrol/js/ui/main.js:706
msgid "Use a different name internally"
msgstr "Käytä toista nimeä sisäisesti"
#: pretix/static/pretixcontrol/js/ui/main.js:766
#: pretix/static/pretixcontrol/js/ui/main.js:763
msgid "Click to close"
msgstr "Sulje klikkaamalla"
#: pretix/static/pretixcontrol/js/ui/main.js:781
#: pretix/static/pretixcontrol/js/ui/main.js:778
msgid "You have unsaved changes!"
msgstr "Sinulla on tallentamattomia muutoksia!"

File diff suppressed because it is too large Load Diff

View File

@@ -6,7 +6,7 @@ msgid ""
msgstr ""
"Project-Id-Version: French\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-12-22 11:06+0000\n"
"POT-Creation-Date: 2020-11-27 17:32+0000\n"
"PO-Revision-Date: 2020-09-15 17:00+0000\n"
"Last-Translator: Martin Gross <martin@pc-coholic.de>\n"
"Language-Team: French <https://translate.pretix.eu/projects/pretix/pretix-js/"
@@ -313,15 +313,15 @@ msgstr "Tous"
msgid "None"
msgstr "Aucun"
#: pretix/static/pretixcontrol/js/ui/main.js:709
#: pretix/static/pretixcontrol/js/ui/main.js:706
msgid "Use a different name internally"
msgstr "Utiliser un nom différent en interne"
#: pretix/static/pretixcontrol/js/ui/main.js:766
#: pretix/static/pretixcontrol/js/ui/main.js:763
msgid "Click to close"
msgstr "Cliquez pour fermer"
#: pretix/static/pretixcontrol/js/ui/main.js:781
#: pretix/static/pretixcontrol/js/ui/main.js:778
msgid "You have unsaved changes!"
msgstr "Vous avez des modifications non sauvegardées !"

File diff suppressed because it is too large Load Diff

View File

@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-12-22 11:06+0000\n"
"POT-Creation-Date: 2020-11-27 17:32+0000\n"
"PO-Revision-Date: 2020-01-24 08:00+0000\n"
"Last-Translator: Prokaj Miklós <mixolid0@gmail.com>\n"
"Language-Team: Hungarian <https://translate.pretix.eu/projects/pretix/pretix-"
@@ -308,15 +308,15 @@ msgstr "Összes"
msgid "None"
msgstr "Semmi"
#: pretix/static/pretixcontrol/js/ui/main.js:709
#: pretix/static/pretixcontrol/js/ui/main.js:706
msgid "Use a different name internally"
msgstr "Használj másik nevet"
#: pretix/static/pretixcontrol/js/ui/main.js:766
#: pretix/static/pretixcontrol/js/ui/main.js:763
msgid "Click to close"
msgstr "Bezárásért kattints"
#: pretix/static/pretixcontrol/js/ui/main.js:781
#: pretix/static/pretixcontrol/js/ui/main.js:778
msgid "You have unsaved changes!"
msgstr "Mentetlen változtatások!"

File diff suppressed because it is too large Load Diff

View File

@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-12-22 11:06+0000\n"
"POT-Creation-Date: 2020-11-27 17:32+0000\n"
"PO-Revision-Date: 2020-06-12 20:00+0000\n"
"Last-Translator: Frank <webappconcept@gmail.com>\n"
"Language-Team: Italian <https://translate.pretix.eu/projects/pretix/pretix-"
@@ -307,15 +307,15 @@ msgstr "Tutto"
msgid "None"
msgstr "Nessuno"
#: pretix/static/pretixcontrol/js/ui/main.js:709
#: pretix/static/pretixcontrol/js/ui/main.js:706
msgid "Use a different name internally"
msgstr "Utilizza un nome diverso internamente"
#: pretix/static/pretixcontrol/js/ui/main.js:766
#: pretix/static/pretixcontrol/js/ui/main.js:763
msgid "Click to close"
msgstr "Clicca per chiudere"
#: pretix/static/pretixcontrol/js/ui/main.js:781
#: pretix/static/pretixcontrol/js/ui/main.js:778
msgid "You have unsaved changes!"
msgstr "Hai cambiamenti non salvati!"

File diff suppressed because it is too large Load Diff

View File

@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-12-22 11:06+0000\n"
"POT-Creation-Date: 2020-11-27 17:32+0000\n"
"PO-Revision-Date: 2019-11-13 06:00+0000\n"
"Last-Translator: Zane Smite <z.smite@riga-jurmala.com>\n"
"Language-Team: Latvian <https://translate.pretix.eu/projects/pretix/pretix-"
@@ -316,15 +316,15 @@ msgstr "Visi"
msgid "None"
msgstr "Neviens"
#: pretix/static/pretixcontrol/js/ui/main.js:709
#: pretix/static/pretixcontrol/js/ui/main.js:706
msgid "Use a different name internally"
msgstr "Izmantojiet citu nosaukumu iekšēji"
#: pretix/static/pretixcontrol/js/ui/main.js:766
#: pretix/static/pretixcontrol/js/ui/main.js:763
msgid "Click to close"
msgstr "Noklikšķiniet, lai aizvērtu"
#: pretix/static/pretixcontrol/js/ui/main.js:781
#: pretix/static/pretixcontrol/js/ui/main.js:778
msgid "You have unsaved changes!"
msgstr ""

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More