forked from CGM_Public/pretix_original
Compare commits
6 Commits
pdf-bulk-v
...
release/20
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bb30c23341 | ||
|
|
edac1cf55b | ||
|
|
18ce0b3446 | ||
|
|
8583bfb7d9 | ||
|
|
34d1d3fa6e | ||
|
|
ccdce2ccb8 |
2
.github/workflows/tests.yml
vendored
2
.github/workflows/tests.yml
vendored
@@ -35,7 +35,7 @@ jobs:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: harmon758/postgresql-action@v1
|
||||
with:
|
||||
postgresql version: '15'
|
||||
postgresql version: '11'
|
||||
postgresql db: 'pretix'
|
||||
postgresql user: 'postgres'
|
||||
postgresql password: 'postgres'
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from pretix.settings import *
|
||||
|
||||
LOGGING['handlers']['mail_admins']['include_html'] = True
|
||||
STORAGES["staticfiles"]["BACKEND"] = 'django.contrib.staticfiles.storage.ManifestStaticFilesStorage'
|
||||
STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.ManifestStaticFilesStorage'
|
||||
|
||||
@@ -37,7 +37,7 @@ you to execute a piece of code with a different locale:
|
||||
This is very useful e.g. when sending an email to a user that has a different language than the user performing the
|
||||
action that causes the mail to be sent.
|
||||
|
||||
.. _translation features: https://docs.djangoproject.com/en/4.2/topics/i18n/translation/
|
||||
.. _translation features: https://docs.djangoproject.com/en/1.9/topics/i18n/translation/
|
||||
.. _GNU gettext: https://www.gnu.org/software/gettext/
|
||||
.. _strings: https://django-i18nfield.readthedocs.io/en/latest/strings.html
|
||||
.. _database fields: https://django-i18nfield.readthedocs.io/en/latest/quickstart.html
|
||||
|
||||
@@ -15,33 +15,25 @@ and the admin panel is available at ``https://pretix.eu/control/event/bigorg/awe
|
||||
|
||||
If the organizer now configures a custom domain like ``tickets.bigorg.com``, his event will
|
||||
from now on be available on ``https://tickets.bigorg.com/awesomecon/``. The former URL at
|
||||
``pretix.eu`` will redirect there. It's also possible to do this for just an event, in which
|
||||
case the event will be available on ``https://tickets.awesomecon.org/``.
|
||||
|
||||
However, the admin panel will still only be available on ``pretix.eu`` for convenience and security reasons.
|
||||
``pretix.eu`` will redirect there. However, the admin panel will still only be available
|
||||
on ``pretix.eu`` for convenience and security reasons.
|
||||
|
||||
URL routing
|
||||
-----------
|
||||
|
||||
The hard part about implementing this URL routing in Django is that
|
||||
``https://pretix.eu/bigorg/awesomecon/`` contains two parameters of nearly arbitrary content
|
||||
and ``https://tickets.bigorg.com/awesomecon/`` contains only one and ``https://tickets.awesomecon.org/`` does not contain any.
|
||||
The only robust way to do this is by having *separate* URL configuration for those three cases.
|
||||
and ``https://tickets.bigorg.com/awesomecon/`` contains only one. The only robust way to do
|
||||
this is by having *separate* URL configuration for those two cases. In pretix, we call the
|
||||
former our ``maindomain`` config and the latter our ``subdomain`` config. For pretix's core
|
||||
modules we do some magic to avoid duplicate configuration, but for a fairly simple plugin with
|
||||
only a handful of routes, we recommend just configuring the two URL sets separately.
|
||||
|
||||
In pretix, we therefore do not have a global URL configuration, but three, living in the following modules:
|
||||
|
||||
- ``pretix.multidomain.maindomain_urlconf``
|
||||
- ``pretix.multidomain.organizer_domain_urlconf``
|
||||
- ``pretix.multidomain.event_domain_urlconf``
|
||||
|
||||
We provide some helper utilities to work with these to avoid duplicate configuration of the individual URLs.
|
||||
The file ``urls.py`` inside your plugin package will be loaded and scanned for URL configuration
|
||||
automatically and should be provided by any plugin that provides any view.
|
||||
However, unlike plain Django, we look not only for a ``urlpatterns`` attribute on the module but support other
|
||||
attributes like ``event_patterns`` and ``organizer_patterns`` as well.
|
||||
|
||||
For example, for a simple plugin that adds one URL to the backend and one event-level URL to the frontend, you can
|
||||
create the following configuration in your ``urls.py``::
|
||||
A very basic example that provides one view in the admin panel and one view in the frontend
|
||||
could look like this::
|
||||
|
||||
from django.urls import re_path
|
||||
|
||||
@@ -60,7 +52,7 @@ create the following configuration in your ``urls.py``::
|
||||
As you can see, the view in the frontend is not included in the standard Django ``urlpatterns``
|
||||
setting but in a separate list with the name ``event_patterns``. This will automatically prepend
|
||||
the appropriate parameters to the regex (e.g. the event or the event and the organizer, depending
|
||||
on the called domain). For organizer-level views, ``organizer_patterns`` works the same way.
|
||||
on the called domain).
|
||||
|
||||
If you only provide URLs in the admin area, you do not need to provide a ``event_patterns`` attribute.
|
||||
|
||||
@@ -79,16 +71,11 @@ is a python method that emulates a behavior similar to ``reverse``:
|
||||
|
||||
.. autofunction:: pretix.multidomain.urlreverse.eventreverse
|
||||
|
||||
If you need to communicate the URL externally, you can use a different method to ensure that it is always an absolute URL:
|
||||
|
||||
.. autofunction:: pretix.multidomain.urlreverse.build_absolute_uri
|
||||
|
||||
In addition, there is a template tag that works similar to ``url`` but takes an event or organizer object
|
||||
as its first argument and can be used like this::
|
||||
|
||||
{% load eventurl %}
|
||||
<a href="{% eventurl request.event "presale:event.checkout" step="payment" %}">Pay</a>
|
||||
<a href="{% abseventurl request.event "presale:event.checkout" step="payment" %}">Pay</a>
|
||||
|
||||
|
||||
Implementation details
|
||||
|
||||
@@ -36,7 +36,7 @@ dependencies = [
|
||||
"css-inline==0.8.*",
|
||||
"defusedcsv>=1.1.0",
|
||||
"dj-static",
|
||||
"Django==4.2.*",
|
||||
"Django==4.1.*",
|
||||
"django-bootstrap3==23.1.*",
|
||||
"django-compressor==4.3.*",
|
||||
"django-countries==7.5.*",
|
||||
|
||||
@@ -19,4 +19,4 @@
|
||||
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
|
||||
# <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
__version__ = "2023.8.0.dev0"
|
||||
__version__ = "2023.7.3"
|
||||
|
||||
@@ -196,14 +196,7 @@ STATICFILES_DIRS = [
|
||||
|
||||
STATICI18N_ROOT = os.path.join(BASE_DIR, "pretix/static")
|
||||
|
||||
STORAGES = {
|
||||
"default": {
|
||||
"BACKEND": "django.core.files.storage.FileSystemStorage",
|
||||
},
|
||||
"staticfiles": {
|
||||
"BACKEND": "django.contrib.staticfiles.storage.ManifestStaticFilesStorage",
|
||||
},
|
||||
}
|
||||
STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.ManifestStaticFilesStorage'
|
||||
|
||||
# if os.path.exists(os.path.join(DATA_DIR, 'static')):
|
||||
# STATICFILES_DIRS.insert(0, os.path.join(DATA_DIR, 'static'))
|
||||
@@ -259,3 +252,20 @@ PRETIX_PRIMARY_COLOR = '#8E44B3'
|
||||
# stressful for some cache setups so it is enabled by default and currently can't be enabled through pretix.cfg
|
||||
CACHE_LARGE_VALUES_ALLOWED = False
|
||||
CACHE_LARGE_VALUES_ALIAS = 'default'
|
||||
|
||||
# Allowed file extensions for various places plus matching Pillow formats.
|
||||
# Never allow EPS, it is full of dangerous bugs.
|
||||
FILE_UPLOAD_EXTENSIONS_IMAGE = (".png", ".jpg", ".gif", ".jpeg")
|
||||
PILLOW_FORMATS_IMAGE = ('PNG', 'GIF', 'JPEG')
|
||||
|
||||
FILE_UPLOAD_EXTENSIONS_FAVICON = (".ico", ".png", "jpg", ".gif", ".jpeg")
|
||||
|
||||
FILE_UPLOAD_EXTENSIONS_QUESTION_IMAGE = (".png", "jpg", ".gif", ".jpeg", ".bmp", ".tif", ".tiff", ".jfif")
|
||||
PILLOW_FORMATS_QUESTIONS_IMAGE = ('PNG', 'GIF', 'JPEG', 'BMP', 'TIFF')
|
||||
|
||||
FILE_UPLOAD_EXTENSIONS_EMAIL_ATTACHMENT = (
|
||||
".png", ".jpg", ".gif", ".jpeg", ".pdf", ".txt", ".docx", ".gif", ".svg",
|
||||
".pptx", ".ppt", ".doc", ".xlsx", ".xls", ".jfif", ".heic", ".heif", ".pages",
|
||||
".bmp", ".tif", ".tiff"
|
||||
)
|
||||
FILE_UPLOAD_EXTENSIONS_OTHER = FILE_UPLOAD_EXTENSIONS_EMAIL_ATTACHMENT
|
||||
|
||||
@@ -27,7 +27,6 @@ from decimal import Decimal
|
||||
import pycountry
|
||||
from django.conf import settings
|
||||
from django.core.files import File
|
||||
from django.db import models
|
||||
from django.db.models import F, Q
|
||||
from django.utils.encoding import force_str
|
||||
from django.utils.timezone import now
|
||||
@@ -373,15 +372,11 @@ class PdfDataSerializer(serializers.Field):
|
||||
self.context['vars_images'] = get_images(self.context['event'])
|
||||
|
||||
for k, f in self.context['vars'].items():
|
||||
if 'evaluate_bulk' in f:
|
||||
# Will be evaluated later by our list serializers
|
||||
res[k] = (f['evaluate_bulk'], instance)
|
||||
else:
|
||||
try:
|
||||
res[k] = f['evaluate'](instance, instance.order, ev)
|
||||
except:
|
||||
logger.exception('Evaluating PDF variable failed')
|
||||
res[k] = '(error)'
|
||||
try:
|
||||
res[k] = f['evaluate'](instance, instance.order, ev)
|
||||
except:
|
||||
logger.exception('Evaluating PDF variable failed')
|
||||
res[k] = '(error)'
|
||||
|
||||
if not hasattr(ev, '_cached_meta_data'):
|
||||
ev._cached_meta_data = ev.meta_data
|
||||
@@ -434,38 +429,6 @@ class PdfDataSerializer(serializers.Field):
|
||||
return res
|
||||
|
||||
|
||||
class OrderPositionListSerializer(serializers.ListSerializer):
|
||||
|
||||
def to_representation(self, data):
|
||||
# We have a custom implementation of this method because PdfDataSerializer() might keep some elements unevaluated
|
||||
# with a (callable, input) tuple. We'll loop over these entries and evaluate them bulk-wise to save on SQL queries.
|
||||
|
||||
if isinstance(self.parent, OrderSerializer) and isinstance(self.parent.parent, OrderListSerializer):
|
||||
# Do not execute our custom code because it will be executed by OrderListSerializer later for the
|
||||
# full result set.
|
||||
return super().to_representation(data)
|
||||
|
||||
iterable = data.all() if isinstance(data, models.Manager) else data
|
||||
|
||||
data = []
|
||||
evaluate_queue = defaultdict(list)
|
||||
|
||||
for item in iterable:
|
||||
entry = self.child.to_representation(item)
|
||||
if "pdf_data" in entry:
|
||||
for k, v in entry["pdf_data"].items():
|
||||
if isinstance(v, tuple) and callable(v[0]):
|
||||
evaluate_queue[v[0]].append((v[1], entry, k))
|
||||
data.append(entry)
|
||||
|
||||
for func, entries in evaluate_queue.items():
|
||||
results = func([item for (item, entry, k) in entries])
|
||||
for (item, entry, k), result in zip(entries, results):
|
||||
entry["pdf_data"][k] = result
|
||||
|
||||
return data
|
||||
|
||||
|
||||
class OrderPositionSerializer(I18nAwareModelSerializer):
|
||||
checkins = CheckinSerializer(many=True, read_only=True)
|
||||
answers = AnswerSerializer(many=True)
|
||||
@@ -477,7 +440,6 @@ class OrderPositionSerializer(I18nAwareModelSerializer):
|
||||
attendee_name = serializers.CharField(required=False)
|
||||
|
||||
class Meta:
|
||||
list_serializer_class = OrderPositionListSerializer
|
||||
model = OrderPosition
|
||||
fields = ('id', 'order', 'positionid', 'item', 'variation', 'price', 'attendee_name', 'attendee_name_parts',
|
||||
'company', 'street', 'zipcode', 'city', 'country', 'state', 'discount',
|
||||
@@ -506,20 +468,6 @@ class OrderPositionSerializer(I18nAwareModelSerializer):
|
||||
def validate(self, data):
|
||||
raise TypeError("this serializer is readonly")
|
||||
|
||||
def to_representation(self, data):
|
||||
if isinstance(self.parent, (OrderListSerializer, OrderPositionListSerializer)):
|
||||
# Do not execute our custom code because it will be executed by OrderListSerializer later for the
|
||||
# full result set.
|
||||
return super().to_representation(data)
|
||||
|
||||
entry = super().to_representation(data)
|
||||
if "pdf_data" in entry:
|
||||
for k, v in entry["pdf_data"].items():
|
||||
if isinstance(v, tuple) and callable(v[0]):
|
||||
entry["pdf_data"][k] = v[0]([v[1]])[0]
|
||||
|
||||
return entry
|
||||
|
||||
|
||||
class RequireAttentionField(serializers.Field):
|
||||
def to_representation(self, instance: OrderPosition):
|
||||
@@ -665,34 +613,6 @@ class OrderURLField(serializers.URLField):
|
||||
})
|
||||
|
||||
|
||||
class OrderListSerializer(serializers.ListSerializer):
|
||||
|
||||
def to_representation(self, data):
|
||||
# We have a custom implementation of this method because PdfDataSerializer() might keep some elements
|
||||
# unevaluated with a (callable, input) tuple. We'll loop over these entries and evaluate them bulk-wise to
|
||||
# save on SQL queries.
|
||||
iterable = data.all() if isinstance(data, models.Manager) else data
|
||||
|
||||
data = []
|
||||
evaluate_queue = defaultdict(list)
|
||||
|
||||
for item in iterable:
|
||||
entry = self.child.to_representation(item)
|
||||
for p in entry.get("positions", []):
|
||||
if "pdf_data" in p:
|
||||
for k, v in p["pdf_data"].items():
|
||||
if isinstance(v, tuple) and callable(v[0]):
|
||||
evaluate_queue[v[0]].append((v[1], p, k))
|
||||
data.append(entry)
|
||||
|
||||
for func, entries in evaluate_queue.items():
|
||||
results = func([item for (item, entry, k) in entries])
|
||||
for (item, entry, k), result in zip(entries, results):
|
||||
entry["pdf_data"][k] = result
|
||||
|
||||
return data
|
||||
|
||||
|
||||
class OrderSerializer(I18nAwareModelSerializer):
|
||||
invoice_address = InvoiceAddressSerializer(allow_null=True)
|
||||
positions = OrderPositionSerializer(many=True, read_only=True)
|
||||
@@ -707,7 +627,6 @@ class OrderSerializer(I18nAwareModelSerializer):
|
||||
|
||||
class Meta:
|
||||
model = Order
|
||||
list_serializer_class = OrderListSerializer
|
||||
fields = (
|
||||
'code', 'status', 'testmode', 'secret', 'email', 'phone', 'locale', 'datetime', 'expires', 'payment_date',
|
||||
'payment_provider', 'fees', 'total', 'comment', 'custom_followup_at', 'invoice_address', 'positions', 'downloads',
|
||||
|
||||
@@ -166,6 +166,7 @@ class InitializeView(APIView):
|
||||
device.software_brand = serializer.validated_data.get('software_brand')
|
||||
device.software_version = serializer.validated_data.get('software_version')
|
||||
device.info = serializer.validated_data.get('info')
|
||||
print(serializer.validated_data, request.data)
|
||||
device.rsa_pubkey = serializer.validated_data.get('rsa_pubkey')
|
||||
device.api_token = generate_api_token()
|
||||
device.save()
|
||||
|
||||
@@ -26,6 +26,7 @@ from decimal import Decimal
|
||||
from zoneinfo import ZoneInfo
|
||||
|
||||
import django_filters
|
||||
from django.conf import settings
|
||||
from django.db import transaction
|
||||
from django.db.models import (
|
||||
Exists, F, OuterRef, Prefetch, Q, Subquery, prefetch_related_objects,
|
||||
@@ -1191,7 +1192,7 @@ class OrderPositionViewSet(viewsets.ModelViewSet):
|
||||
ftype, ignored = mimetypes.guess_type(image_file.name)
|
||||
extension = os.path.basename(image_file.name).split('.')[-1]
|
||||
else:
|
||||
img = Image.open(image_file)
|
||||
img = Image.open(image_file, formats=settings.PILLOW_FORMATS_QUESTIONS_IMAGE)
|
||||
ftype = Image.MIME[img.format]
|
||||
extensions = {
|
||||
'GIF': 'gif', 'TIFF': 'tif', 'BMP': 'bmp', 'JPEG': 'jpg', 'PNG': 'png'
|
||||
|
||||
@@ -500,14 +500,14 @@ class PortraitImageField(SizeValidationMixin, ExtValidationMixin, forms.FileFiel
|
||||
file = BytesIO(data['content'])
|
||||
|
||||
try:
|
||||
image = Image.open(file)
|
||||
image = Image.open(file, formats=settings.PILLOW_FORMATS_QUESTIONS_IMAGE)
|
||||
# verify() must be called immediately after the constructor.
|
||||
image.verify()
|
||||
|
||||
# We want to do more than just verify(), so we need to re-open the file
|
||||
if hasattr(file, 'seek'):
|
||||
file.seek(0)
|
||||
image = Image.open(file)
|
||||
image = Image.open(file, formats=settings.PILLOW_FORMATS_QUESTIONS_IMAGE)
|
||||
|
||||
# load() is a potential DoS vector (see Django bug #18520), so we verify the size first
|
||||
if image.width > 10_000 or image.height > 10_000:
|
||||
@@ -566,7 +566,7 @@ class PortraitImageField(SizeValidationMixin, ExtValidationMixin, forms.FileFiel
|
||||
return f
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
kwargs.setdefault('ext_whitelist', (".png", ".jpg", ".jpeg", ".jfif", ".tif", ".tiff", ".bmp"))
|
||||
kwargs.setdefault('ext_whitelist', settings.FILE_UPLOAD_EXTENSIONS_QUESTION_IMAGE)
|
||||
kwargs.setdefault('max_size', settings.FILE_UPLOAD_MAX_SIZE_IMAGE)
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
@@ -826,11 +826,7 @@ class BaseQuestionsForm(forms.Form):
|
||||
help_text=help_text,
|
||||
initial=initial.file if initial else None,
|
||||
widget=UploadedFileWidget(position=pos, event=event, answer=initial),
|
||||
ext_whitelist=(
|
||||
".png", ".jpg", ".gif", ".jpeg", ".pdf", ".txt", ".docx", ".gif", ".svg",
|
||||
".pptx", ".ppt", ".doc", ".xlsx", ".xls", ".jfif", ".heic", ".heif", ".pages",
|
||||
".bmp", ".tif", ".tiff"
|
||||
),
|
||||
ext_whitelist=settings.FILE_UPLOAD_EXTENSIONS_OTHER,
|
||||
max_size=settings.FILE_UPLOAD_MAX_SIZE_OTHER,
|
||||
)
|
||||
elif q.type == Question.TYPE_DATE:
|
||||
|
||||
@@ -271,8 +271,6 @@ class SecurityMiddleware(MiddlewareMixin):
|
||||
(url.url_name == "event.checkout" and url.kwargs['step'] == "payment")
|
||||
):
|
||||
h['script-src'].append('https://pay.google.com')
|
||||
h['frame-src'].append('https://pay.google.com')
|
||||
h['connect-src'].append('https://google.com/pay')
|
||||
if settings.LOG_CSP:
|
||||
h['report-uri'] = ["/csp_report/"]
|
||||
if 'Content-Security-Policy' in resp:
|
||||
|
||||
@@ -97,7 +97,7 @@ def _transactions_mark_order_dirty(order_id, using=None):
|
||||
if getattr(dirty_transactions, 'order_ids', None) is None:
|
||||
dirty_transactions.order_ids = set()
|
||||
|
||||
if _check_for_dirty_orders not in [func for (savepoint_id, func, *__) in conn.run_on_commit]:
|
||||
if _check_for_dirty_orders not in [func for savepoint_id, func in conn.run_on_commit]:
|
||||
transaction.on_commit(_check_for_dirty_orders, using)
|
||||
dirty_transactions.order_ids.clear() # This is necessary to clean up after old threads with rollbacked transactions
|
||||
|
||||
|
||||
@@ -88,7 +88,9 @@ class LogEntry(models.Model):
|
||||
|
||||
class Meta:
|
||||
ordering = ('-datetime', '-id')
|
||||
indexes = [models.Index(fields=["datetime", "id"])]
|
||||
index_together = [
|
||||
['datetime', 'id']
|
||||
]
|
||||
|
||||
def display(self):
|
||||
from ..signals import logentry_display
|
||||
|
||||
@@ -121,10 +121,7 @@ class ReusableMedium(LoggedModel):
|
||||
|
||||
class Meta:
|
||||
unique_together = (("identifier", "type", "organizer"),)
|
||||
indexes = [
|
||||
models.Index(fields=("identifier", "type", "organizer")),
|
||||
models.Index(fields=("updated", "id")),
|
||||
]
|
||||
index_together = (("identifier", "type", "organizer"), ("updated", "id"))
|
||||
ordering = "identifier", "type", "organizer"
|
||||
|
||||
|
||||
|
||||
@@ -270,9 +270,9 @@ class Order(LockModel, LoggedModel):
|
||||
verbose_name = _("Order")
|
||||
verbose_name_plural = _("Orders")
|
||||
ordering = ("-datetime", "-pk")
|
||||
indexes = [
|
||||
models.Index(fields=["datetime", "id"]),
|
||||
models.Index(fields=["last_modified", "id"]),
|
||||
index_together = [
|
||||
["datetime", "id"],
|
||||
["last_modified", "id"],
|
||||
]
|
||||
|
||||
def __str__(self):
|
||||
@@ -1246,7 +1246,7 @@ class QuestionAnswer(models.Model):
|
||||
|
||||
@property
|
||||
def is_image(self):
|
||||
return any(self.file.name.lower().endswith(e) for e in ('.jpg', '.png', '.gif', '.tiff', '.bmp', '.jpeg'))
|
||||
return any(self.file.name.lower().endswith(e) for e in settings.FILE_UPLOAD_EXTENSIONS_QUESTION_IMAGE)
|
||||
|
||||
@property
|
||||
def file_name(self):
|
||||
@@ -1676,7 +1676,7 @@ class OrderPayment(models.Model):
|
||||
"""
|
||||
Marks the order as failed and sets info to ``info``, but only if the order is in ``created`` or ``pending``
|
||||
state. This is equivalent to setting ``state`` to ``OrderPayment.PAYMENT_STATE_FAILED`` and logging a failure,
|
||||
but it adds strong database locking since we do not want to report a failure for an order that has just
|
||||
but it adds strong database logging since we do not want to report a failure for an order that has just
|
||||
been marked as paid.
|
||||
:param send_mail: Whether an email should be sent to the user about this event (default: ``True``).
|
||||
"""
|
||||
@@ -2756,8 +2756,8 @@ class Transaction(models.Model):
|
||||
|
||||
class Meta:
|
||||
ordering = 'datetime', 'pk'
|
||||
indexes = [
|
||||
models.Index(fields=['datetime', 'id'])
|
||||
index_together = [
|
||||
['datetime', 'id']
|
||||
]
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
|
||||
@@ -805,7 +805,7 @@ class QuestionColumn(ImportColumn):
|
||||
return self.q.clean_answer(value)
|
||||
|
||||
def assign(self, value, order, position, invoice_address, **kwargs):
|
||||
if value is not None:
|
||||
if value:
|
||||
if not hasattr(order, '_answers'):
|
||||
order._answers = []
|
||||
if isinstance(value, QuestionOption):
|
||||
|
||||
@@ -108,10 +108,7 @@ DEFAULT_VARIABLES = OrderedDict((
|
||||
("positionid", {
|
||||
"label": _("Order position number"),
|
||||
"editor_sample": "1",
|
||||
"evaluate": lambda orderposition, order, event: str(orderposition.positionid),
|
||||
# There is no performance gain in using evaluate_bulk here, but we want to make sure it is used somewhere
|
||||
# in core to make sure we notice if the implementation of the API breaks.
|
||||
"evaluate_bulk": lambda orderpositions: [str(p.positionid) for p in orderpositions],
|
||||
"evaluate": lambda orderposition, order, event: str(orderposition.positionid)
|
||||
}),
|
||||
("order_positionid", {
|
||||
"label": _("Order code and position number"),
|
||||
@@ -524,7 +521,7 @@ def images_from_questions(sender, *args, **kwargs):
|
||||
else:
|
||||
a = op.answers.filter(question_id=question_id).first() or a
|
||||
|
||||
if not a or not a.file or not any(a.file.name.lower().endswith(e) for e in (".jpg", ".jpeg", ".png", ".gif", ".bmp", ".tif", ".tiff")):
|
||||
if not a or not a.file or not any(a.file.name.lower().endswith(e) for e in settings.FILE_UPLOAD_EXTENSIONS_QUESTION_IMAGE):
|
||||
return None
|
||||
else:
|
||||
if etag:
|
||||
|
||||
@@ -2476,11 +2476,6 @@ class OrderChangeManager:
|
||||
split_order.status = Order.STATUS_PAID
|
||||
else:
|
||||
split_order.status = Order.STATUS_PENDING
|
||||
if self.order.status == Order.STATUS_PAID:
|
||||
split_order.set_expires(
|
||||
now(),
|
||||
list(set(p.subevent_id for p in split_positions))
|
||||
)
|
||||
split_order.save()
|
||||
|
||||
if offset_amount > Decimal('0.00'):
|
||||
|
||||
@@ -2793,7 +2793,7 @@ Your {organizer} team""")) # noqa: W291
|
||||
'form_class': ExtFileField,
|
||||
'form_kwargs': dict(
|
||||
label=_('Header image'),
|
||||
ext_whitelist=(".png", ".jpg", ".gif", ".jpeg"),
|
||||
ext_whitelist=settings.FILE_UPLOAD_EXTENSIONS_IMAGE,
|
||||
max_size=settings.FILE_UPLOAD_MAX_SIZE_IMAGE,
|
||||
help_text=_('If you provide a logo image, we will by default not show your event name and date '
|
||||
'in the page header. By default, we show your logo with a size of up to 1140x120 pixels. You '
|
||||
@@ -2836,7 +2836,7 @@ Your {organizer} team""")) # noqa: W291
|
||||
'form_class': ExtFileField,
|
||||
'form_kwargs': dict(
|
||||
label=_('Header image'),
|
||||
ext_whitelist=(".png", ".jpg", ".gif", ".jpeg"),
|
||||
ext_whitelist=settings.FILE_UPLOAD_EXTENSIONS_IMAGE,
|
||||
max_size=settings.FILE_UPLOAD_MAX_SIZE_IMAGE,
|
||||
help_text=_('If you provide a logo image, we will by default not show your organization name '
|
||||
'in the page header. By default, we show your logo with a size of up to 1140x120 pixels. You '
|
||||
@@ -2876,7 +2876,7 @@ Your {organizer} team""")) # noqa: W291
|
||||
'form_class': ExtFileField,
|
||||
'form_kwargs': dict(
|
||||
label=_('Social media image'),
|
||||
ext_whitelist=(".png", ".jpg", ".gif", ".jpeg"),
|
||||
ext_whitelist=settings.FILE_UPLOAD_EXTENSIONS_IMAGE,
|
||||
max_size=settings.FILE_UPLOAD_MAX_SIZE_IMAGE,
|
||||
help_text=_('This picture will be used as a preview if you post links to your ticket shop on social media. '
|
||||
'Facebook advises to use a picture size of 1200 x 630 pixels, however some platforms like '
|
||||
@@ -2897,7 +2897,7 @@ Your {organizer} team""")) # noqa: W291
|
||||
'form_class': ExtFileField,
|
||||
'form_kwargs': dict(
|
||||
label=_('Logo image'),
|
||||
ext_whitelist=(".png", ".jpg", ".gif", ".jpeg"),
|
||||
ext_whitelist=settings.FILE_UPLOAD_EXTENSIONS_IMAGE,
|
||||
required=False,
|
||||
max_size=settings.FILE_UPLOAD_MAX_SIZE_IMAGE,
|
||||
help_text=_('We will show your logo with a maximal height and width of 2.5 cm.')
|
||||
|
||||
@@ -683,16 +683,12 @@ dictionaries as values that contain keys like in the following example::
|
||||
"product": {
|
||||
"label": _("Product name"),
|
||||
"editor_sample": _("Sample product"),
|
||||
"evaluate": lambda orderposition, order, event: str(orderposition.item),
|
||||
"evaluate_bulk": lambda orderpositions: [str(op.item) for op in orderpositions],
|
||||
"evaluate": lambda orderposition, order, event: str(orderposition.item)
|
||||
}
|
||||
}
|
||||
|
||||
The ``evaluate`` member will be called with the order position, order and event as arguments. The event might
|
||||
also be a subevent, if applicable.
|
||||
|
||||
The ``evaluate_bulk`` member is optional but can significantly improve performance in some situations because you
|
||||
can perform database fetches in bulk instead of single queries for every position.
|
||||
"""
|
||||
|
||||
|
||||
|
||||
@@ -127,7 +127,7 @@ class ClearableBasenameFileInput(forms.ClearableFileInput):
|
||||
|
||||
@property
|
||||
def is_img(self):
|
||||
return any(self.file.name.lower().endswith(e) for e in ('.jpg', '.jpeg', '.png', '.gif'))
|
||||
return any(self.file.name.lower().endswith(e) for e in settings.FILE_UPLOAD_EXTENSIONS_IMAGE)
|
||||
|
||||
def __str__(self):
|
||||
if hasattr(self.file, 'display_name'):
|
||||
|
||||
@@ -1732,8 +1732,8 @@ class CheckinListAttendeeFilterForm(FilterForm):
|
||||
'-timestamp': (OrderBy(F('last_entry'), nulls_last=True, descending=True), '-order__code'),
|
||||
'item': ('item__name', 'variation__value', 'order__code'),
|
||||
'-item': ('-item__name', '-variation__value', '-order__code'),
|
||||
'seat': ('seat__sorting_rank', 'seat__seat_guid'),
|
||||
'-seat': ('-seat__sorting_rank', '-seat__seat_guid'),
|
||||
'seat': ('seat__sorting_rank', 'seat__guid'),
|
||||
'-seat': ('-seat__sorting_rank', '-seat__guid'),
|
||||
'date': ('subevent__date_from', 'subevent__id', 'order__code'),
|
||||
'-date': ('-subevent__date_from', 'subevent__id', '-order__code'),
|
||||
'name': {'_order': F('display_name').asc(nulls_first=True),
|
||||
@@ -1940,7 +1940,7 @@ class VoucherFilterForm(FilterForm):
|
||||
'item__category__position',
|
||||
'item__category',
|
||||
'item__position',
|
||||
'variation__position',
|
||||
'item__variation__position',
|
||||
'quota__name',
|
||||
),
|
||||
'subevent': 'subevent__date_from',
|
||||
@@ -1950,7 +1950,7 @@ class VoucherFilterForm(FilterForm):
|
||||
'-item__category__position',
|
||||
'-item__category',
|
||||
'-item__position',
|
||||
'-variation__position',
|
||||
'-item__variation__position',
|
||||
'-quota__name',
|
||||
)
|
||||
}
|
||||
|
||||
@@ -420,7 +420,7 @@ class OrganizerSettingsForm(SettingsForm):
|
||||
|
||||
organizer_logo_image = ExtFileField(
|
||||
label=_('Header image'),
|
||||
ext_whitelist=(".png", ".jpg", ".gif", ".jpeg"),
|
||||
ext_whitelist=settings.FILE_UPLOAD_EXTENSIONS_IMAGE,
|
||||
max_size=settings.FILE_UPLOAD_MAX_SIZE_IMAGE,
|
||||
required=False,
|
||||
help_text=_('If you provide a logo image, we will by default not show your organization name '
|
||||
@@ -430,7 +430,7 @@ class OrganizerSettingsForm(SettingsForm):
|
||||
)
|
||||
favicon = ExtFileField(
|
||||
label=_('Favicon'),
|
||||
ext_whitelist=(".ico", ".png", ".jpg", ".gif", ".jpeg"),
|
||||
ext_whitelist=settings.FILE_UPLOAD_EXTENSIONS_FAVICON,
|
||||
required=False,
|
||||
max_size=settings.FILE_UPLOAD_MAX_SIZE_FAVICON,
|
||||
help_text=_('If you provide a favicon, we will show it instead of the default pretix icon. '
|
||||
|
||||
@@ -341,7 +341,6 @@ def pretixcontrol_logentry_display(sender: Event, logentry: LogEntry, **kwargs):
|
||||
'pretix.giftcards.acceptance.added': _('Gift card acceptance for another organizer has been added.'),
|
||||
'pretix.giftcards.acceptance.removed': _('Gift card acceptance for another organizer has been removed.'),
|
||||
'pretix.giftcards.acceptance.acceptor.invited': _('A new gift card acceptor has been invited.'),
|
||||
'pretix.giftcards.acceptance.acceptor.removed': _('A gift card acceptor has been removed.'),
|
||||
'pretix.giftcards.acceptance.issuer.removed': _('A gift card issuer has been removed or declined.'),
|
||||
'pretix.giftcards.acceptance.issuer.accepted': _('A new gift card issuer has been accepted.'),
|
||||
'pretix.webhook.created': _('The webhook has been created.'),
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
{% load i18n %}
|
||||
<ul class="dropdown-menu dropdown-menu-right">
|
||||
<li>
|
||||
<a href="{% url "control:event.qrcode" event=request.event.slug organizer=request.organizer.slug filetype="png" %}{% if url %}?url={{ url|urlencode }}{% endif %}"
|
||||
target="_blank" download>
|
||||
{% blocktrans with filetype="PNG" %}Download QR code as {{ filetype }} image{% endblocktrans %}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{% url "control:event.qrcode" event=request.event.slug organizer=request.organizer.slug filetype="svg" %}{% if url %}?url={{ url|urlencode }}{% endif %}"
|
||||
target="_blank" download>
|
||||
{% blocktrans with filetype="SVG" %}Download QR code as {{ filetype }} image{% endblocktrans %}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{% url "control:event.qrcode" event=request.event.slug organizer=request.organizer.slug filetype="jpeg" %}{% if url %}?url={{ url|urlencode }}{% endif %}"
|
||||
target="_blank" download>
|
||||
{% blocktrans with filetype="JPG" %}Download QR code as {{ filetype }} image{% endblocktrans %}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{% url "control:event.qrcode" event=request.event.slug organizer=request.organizer.slug filetype="gif" %}{% if url %}?url={{ url|urlencode }}{% endif %}"
|
||||
target="_blank" download>
|
||||
{% blocktrans with filetype="GIF" %}Download QR code as {{ filetype }} image{% endblocktrans %}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -27,7 +27,28 @@
|
||||
<button type="button" class="btn btn-default btn-xs dropdown-toggle" data-toggle="dropdown" title="{% trans "Create QR code" %}" aria-haspopup="true" aria-expanded="false">
|
||||
<i class="fa fa-qrcode" aria-hidden="true"></i>
|
||||
</button>
|
||||
{% include "pretixcontrol/event/fragment_qr_dropdown.html" with url=0 %}
|
||||
<ul class="dropdown-menu dropdown-menu-right">
|
||||
<li>
|
||||
<a href="{% url "control:event.qrcode" event=request.event.slug organizer=request.organizer.slug filetype="png" %}" target="_blank" download>
|
||||
{% blocktrans with filetype="PNG" %}Download QR code as {{ filetype }} image{% endblocktrans %}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{% url "control:event.qrcode" event=request.event.slug organizer=request.organizer.slug filetype="svg" %}" target="_blank" download>
|
||||
{% blocktrans with filetype="SVG" %}Download QR code as {{ filetype }} image{% endblocktrans %}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{% url "control:event.qrcode" event=request.event.slug organizer=request.organizer.slug filetype="jpeg" %}" target="_blank" download>
|
||||
{% blocktrans with filetype="JPG" %}Download QR code as {{ filetype }} image{% endblocktrans %}
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="{% url "control:event.qrcode" event=request.event.slug organizer=request.organizer.slug filetype="gif" %}" target="_blank" download>
|
||||
{% blocktrans with filetype="GIF" %}Download QR code as {{ filetype }} image{% endblocktrans %}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
|
||||
@@ -337,7 +337,7 @@
|
||||
<div class="alert alert-info">
|
||||
{% blocktrans trimmed %}
|
||||
The waiting list currently is not compatible with some advanced features of pretix such as
|
||||
hidden products, add-on products or product bundles.
|
||||
add-on products or product bundles.
|
||||
{% endblocktrans %}
|
||||
</div>
|
||||
<div class="alert alert-info">
|
||||
|
||||
@@ -69,7 +69,7 @@
|
||||
<td></td>
|
||||
<td class="text-right flip">
|
||||
<strong>
|
||||
{{ sums.sum_count }}
|
||||
{{ sums.count }}
|
||||
</strong>
|
||||
</td>
|
||||
<td></td>
|
||||
|
||||
@@ -295,11 +295,6 @@
|
||||
{% bootstrap_field sform.invoice_regenerate_allowed layout="control" %}
|
||||
</fieldset>
|
||||
</div>
|
||||
<div class="form-group submit-group">
|
||||
<button type="submit" class="btn btn-primary btn-save">
|
||||
{% trans "Save" %}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-12 col-lg-2">
|
||||
<div class="panel panel-default">
|
||||
@@ -312,5 +307,10 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group submit-group">
|
||||
<button type="submit" class="btn btn-primary btn-save">
|
||||
{% trans "Save" %}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
||||
@@ -42,18 +42,10 @@
|
||||
<div class="form-group">
|
||||
<label class="col-md-3 control-label" for="id_url">{% trans "Voucher link" %}</label>
|
||||
<div class="col-md-9">
|
||||
<div class="input-group">
|
||||
<input type="text" name="url"
|
||||
value="{{ url }}"
|
||||
class="form-control"
|
||||
id="id_url" readonly>
|
||||
<div class="input-group-btn">
|
||||
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" title="{% trans "Create QR code" %}" aria-haspopup="true" aria-expanded="false">
|
||||
<i class="fa fa-qrcode" aria-hidden="true"></i>
|
||||
</button>
|
||||
{% include "pretixcontrol/event/fragment_qr_dropdown.html" with url=url %}
|
||||
</div>
|
||||
</div>
|
||||
<input type="text" name="url"
|
||||
value="{% abseventurl request.event "presale:event.redeem" %}?voucher={{ voucher.code|urlencode }}{% if voucher.subevent_id %}&subevent={{ voucher.subevent_id }}{% endif %}"
|
||||
class="form-control"
|
||||
id="id_url" readonly>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
@@ -40,7 +40,7 @@ from collections import OrderedDict
|
||||
from decimal import Decimal
|
||||
from io import BytesIO
|
||||
from itertools import groupby
|
||||
from urllib.parse import urlparse, urlsplit
|
||||
from urllib.parse import urlsplit
|
||||
from zoneinfo import ZoneInfo
|
||||
|
||||
import bleach
|
||||
@@ -50,7 +50,6 @@ from django.apps import apps
|
||||
from django.conf import settings
|
||||
from django.contrib import messages
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.core.files import File
|
||||
from django.db import transaction
|
||||
from django.db.models import ProtectedError
|
||||
@@ -62,7 +61,6 @@ from django.http import (
|
||||
from django.shortcuts import get_object_or_404, redirect
|
||||
from django.urls import reverse
|
||||
from django.utils.functional import cached_property
|
||||
from django.utils.http import url_has_allowed_host_and_scheme
|
||||
from django.utils.timezone import now
|
||||
from django.utils.translation import gettext, gettext_lazy as _, gettext_noop
|
||||
from django.views.generic import FormView, ListView
|
||||
@@ -1532,12 +1530,6 @@ class EventQRCode(EventPermissionRequiredMixin, View):
|
||||
def get(self, request, *args, filetype, **kwargs):
|
||||
url = build_absolute_uri(request.event, 'presale:event.index')
|
||||
|
||||
if "url" in request.GET:
|
||||
if url_has_allowed_host_and_scheme(request.GET["url"], allowed_hosts=[urlparse(url).netloc]):
|
||||
url = request.GET["url"]
|
||||
else:
|
||||
raise PermissionDenied("Untrusted URL")
|
||||
|
||||
qr = qrcode.QRCode(
|
||||
version=1,
|
||||
error_correction=qrcode.constants.ERROR_CORRECT_M,
|
||||
|
||||
@@ -418,7 +418,7 @@ class OrderTransactions(OrderView):
|
||||
'item', 'variation', 'subevent'
|
||||
).order_by('datetime')
|
||||
ctx['sums'] = self.order.transactions.aggregate(
|
||||
sum_count=Sum('count'),
|
||||
count=Sum('count'),
|
||||
full_price=Sum(F('count') * F('price')),
|
||||
full_tax_value=Sum(F('count') * F('tax_value')),
|
||||
)
|
||||
|
||||
@@ -546,7 +546,7 @@ def variations_select2(request, **kwargs):
|
||||
F('item__category__position').asc(nulls_first=True),
|
||||
'item__category_id',
|
||||
'item__position',
|
||||
'item__pk',
|
||||
'item__pk'
|
||||
'position',
|
||||
'value'
|
||||
).select_related('item')
|
||||
@@ -718,7 +718,7 @@ def itemvarquota_select2(request, **kwargs):
|
||||
itemqs = request.event.items.prefetch_related('variations').filter(
|
||||
Q(name__icontains=i18ncomp(query)) | Q(internal_name__icontains=query)
|
||||
)
|
||||
quotaqs = request.event.quotas.filter(quotaf).select_related('subevent').order_by('-subevent__date_from', 'name')
|
||||
quotaqs = request.event.quotas.filter(quotaf).select_related('subevent')
|
||||
more = False
|
||||
else:
|
||||
if page == 1:
|
||||
@@ -727,7 +727,7 @@ def itemvarquota_select2(request, **kwargs):
|
||||
)
|
||||
else:
|
||||
itemqs = request.event.items.none()
|
||||
quotaqs = request.event.quotas.filter(name__icontains=query).select_related('subevent').order_by('-subevent__date_from', 'name')
|
||||
quotaqs = request.event.quotas.filter(name__icontains=query).select_related('subevent')
|
||||
total = quotaqs.count()
|
||||
pagesize = 20
|
||||
offset = (page - 1) * pagesize
|
||||
|
||||
@@ -34,7 +34,6 @@
|
||||
# License for the specific language governing permissions and limitations under the License.
|
||||
|
||||
import io
|
||||
from urllib.parse import urlencode
|
||||
|
||||
import bleach
|
||||
from defusedcsv import csv
|
||||
@@ -76,7 +75,6 @@ from pretix.control.views import PaginationMixin
|
||||
from pretix.helpers.compat import CompatDeleteView
|
||||
from pretix.helpers.format import format_map
|
||||
from pretix.helpers.models import modelcopy
|
||||
from pretix.multidomain.urlreverse import build_absolute_uri
|
||||
|
||||
|
||||
class VoucherList(PaginationMixin, EventPermissionRequiredMixin, ListView):
|
||||
@@ -317,13 +315,6 @@ class VoucherUpdate(EventPermissionRequiredMixin, UpdateView):
|
||||
expires__gte=now()
|
||||
).count()
|
||||
ctx['redeemed_in_carts'] = redeemed_in_carts
|
||||
|
||||
url_params = {
|
||||
'voucher': self.object.code
|
||||
}
|
||||
if self.object.subevent_id:
|
||||
url_params['subevent'] = self.object.subevent_id
|
||||
ctx['url'] = build_absolute_uri(self.request.event, "presale:event.redeem") + "?" + urlencode(url_params)
|
||||
return ctx
|
||||
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
import logging
|
||||
from io import BytesIO
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from PIL.Image import MAX_IMAGE_PIXELS, DecompressionBombError
|
||||
@@ -51,7 +52,7 @@ def validate_uploaded_file_for_valid_image(f):
|
||||
|
||||
try:
|
||||
try:
|
||||
image = Image.open(file)
|
||||
image = Image.open(file, formats=settings.PILLOW_FORMATS_QUESTIONS_IMAGE)
|
||||
# verify() must be called immediately after the constructor.
|
||||
image.verify()
|
||||
except DecompressionBombError:
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
#
|
||||
from datetime import datetime
|
||||
|
||||
from PIL import Image
|
||||
|
||||
|
||||
def monkeypatch_vobject_performance():
|
||||
"""
|
||||
@@ -52,5 +54,19 @@ def monkeypatch_vobject_performance():
|
||||
icalendar.tzinfo_eq = new_tzinfo_eq
|
||||
|
||||
|
||||
def monkeypatch_pillow_safer():
|
||||
"""
|
||||
Pillow supports many file formats, among them EPS. For EPS, Pillow loads GhostScript whenever GhostScript
|
||||
is installed (cannot officially be disabled). However, GhostScript is known for regular security vulnerabilities.
|
||||
We have no use of reading EPS files and usually prevent this by using `Image.open(…, formats=[…])` to disable EPS
|
||||
support explicitly. However, we are worried about our dependencies like reportlab using `Image.open` without the
|
||||
`formats=` parameter. Therefore, as a defense in depth approach, we monkeypatch EPS support away by modifying the
|
||||
internal image format registry of Pillow.
|
||||
"""
|
||||
if "EPS" in Image.ID:
|
||||
Image.ID.remove("EPS")
|
||||
|
||||
|
||||
def monkeypatch_all_at_ready():
|
||||
monkeypatch_vobject_performance()
|
||||
monkeypatch_pillow_safer()
|
||||
|
||||
@@ -20,8 +20,9 @@
|
||||
# <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
from arabic_reshaper import ArabicReshaper
|
||||
from django.conf import settings
|
||||
from django.utils.functional import SimpleLazyObject
|
||||
from PIL.Image import Resampling
|
||||
from PIL import Image
|
||||
from reportlab.lib.utils import ImageReader
|
||||
|
||||
|
||||
@@ -33,7 +34,7 @@ class ThumbnailingImageReader(ImageReader):
|
||||
height = width * self._image.size[1] / self._image.size[0]
|
||||
self._image.thumbnail(
|
||||
size=(int(width * dpi / 72), int(height * dpi / 72)),
|
||||
resample=Resampling.BICUBIC
|
||||
resample=Image.Resampling.BICUBIC
|
||||
)
|
||||
self._data = None
|
||||
return width, height
|
||||
@@ -44,6 +45,9 @@ class ThumbnailingImageReader(ImageReader):
|
||||
# (smaller) size of the modified image.
|
||||
return None
|
||||
|
||||
def _read_image(self, fp):
|
||||
return Image.open(fp, formats=settings.PILLOW_FORMATS_IMAGE)
|
||||
|
||||
|
||||
reshaper = SimpleLazyObject(lambda: ArabicReshaper(configuration={
|
||||
'delete_harakat': True,
|
||||
|
||||
@@ -23,6 +23,7 @@ import hashlib
|
||||
import math
|
||||
from io import BytesIO
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.files.base import ContentFile
|
||||
from django.core.files.storage import default_storage
|
||||
from PIL import Image, ImageOps, ImageSequence
|
||||
@@ -165,7 +166,7 @@ def resize_image(image, size):
|
||||
|
||||
def create_thumbnail(sourcename, size):
|
||||
source = default_storage.open(sourcename)
|
||||
image = Image.open(BytesIO(source.read()))
|
||||
image = Image.open(BytesIO(source.read()), formats=settings.PILLOW_FORMATS_QUESTIONS_IMAGE)
|
||||
try:
|
||||
image.load()
|
||||
except:
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -8,7 +8,7 @@ msgstr ""
|
||||
"Project-Id-Version: 1\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2023-07-27 11:49+0000\n"
|
||||
"PO-Revision-Date: 2023-07-28 09:11+0000\n"
|
||||
"PO-Revision-Date: 2023-07-27 11:58+0000\n"
|
||||
"Last-Translator: Raphael Michel <michel@rami.io>\n"
|
||||
"Language-Team: German (informal) <https://translate.pretix.eu/projects/"
|
||||
"pretix/pretix/de_Informal/>\n"
|
||||
@@ -16172,7 +16172,7 @@ msgstr "Kontoeinstellungen"
|
||||
#: pretix/presale/templates/pretixpresale/fragment_login_status.html:13
|
||||
#: pretix/presale/templates/pretixpresale/fragment_login_status.html:14
|
||||
msgid "Log out"
|
||||
msgstr "Abmelden"
|
||||
msgstr "Anmelden"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/base.html:245
|
||||
msgid "Organizer account"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -8,8 +8,8 @@ msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2023-07-27 11:49+0000\n"
|
||||
"PO-Revision-Date: 2023-08-02 02:00+0000\n"
|
||||
"Last-Translator: Patrizia Cotza <str.cotza@gmail.com>\n"
|
||||
"PO-Revision-Date: 2023-07-13 07:22+0000\n"
|
||||
"Last-Translator: Martin Gross <gross@rami.io>\n"
|
||||
"Language-Team: Spanish <https://translate.pretix.eu/projects/pretix/pretix/"
|
||||
"es/>\n"
|
||||
"Language: es\n"
|
||||
@@ -17,7 +17,7 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
"X-Generator: Weblate 4.18.2\n"
|
||||
"X-Generator: Weblate 4.17\n"
|
||||
|
||||
#: pretix/_base_settings.py:78
|
||||
msgid "English"
|
||||
@@ -2435,8 +2435,6 @@ msgstr "Disponibilidad de cuotas"
|
||||
msgid ""
|
||||
"Download a spreadsheet of all quotas including their current availability."
|
||||
msgstr ""
|
||||
"Descargar un archivo Excel con todas las cuotas incluyendo su disponibilidad "
|
||||
"actual."
|
||||
|
||||
#: pretix/base/exporters/orderlist.py:1082
|
||||
#: pretix/control/templates/pretixcontrol/items/quotas.html:45
|
||||
@@ -2501,7 +2499,6 @@ msgstr "Tarjeta de regalo"
|
||||
#: pretix/base/exporters/orderlist.py:1132
|
||||
msgid "Download a spreadsheet of all gift card transactions."
|
||||
msgstr ""
|
||||
"Descargar una hoja de cálculo con todas las transacciones de tarjeta regalo."
|
||||
|
||||
#: pretix/base/exporters/orderlist.py:1160
|
||||
#: pretix/base/exporters/orderlist.py:1207
|
||||
@@ -2574,8 +2571,6 @@ msgstr "Redenciones de tarjetas de regalo"
|
||||
msgid ""
|
||||
"Download a spreadsheet of all payments or refunds that involve gift cards."
|
||||
msgstr ""
|
||||
"Descargar una hoja de cálculo con todos los pagos y devoluciones que "
|
||||
"contienen tarjetas regalo."
|
||||
|
||||
#: pretix/base/exporters/orderlist.py:1207
|
||||
#: pretix/control/templates/pretixcontrol/giftcards/payment.html:16
|
||||
@@ -2782,8 +2777,6 @@ msgid ""
|
||||
"Due to technical reasons you cannot set inputs, that need to be masked (e.g. "
|
||||
"passwords), to %(value)s."
|
||||
msgstr ""
|
||||
"Por razones técnicas, no puedes introducir datos que deben estar ocultos ("
|
||||
"ej. contraseñas) en el campo %(value)s."
|
||||
|
||||
#: pretix/base/forms/auth.py:57 pretix/base/forms/auth.py:168
|
||||
msgid "Keep me logged in"
|
||||
@@ -2855,8 +2848,6 @@ msgid ""
|
||||
"You uploaded an image in landscape orientation. Please upload an image in "
|
||||
"portrait orientation."
|
||||
msgstr ""
|
||||
"Has cargado una imagen con formato horizontal. Por favor sube una imagen en "
|
||||
"vertical."
|
||||
|
||||
#: pretix/base/forms/questions.py:471
|
||||
msgid "Please upload an image where the width is 3/4 of the height."
|
||||
@@ -2879,8 +2870,6 @@ msgid ""
|
||||
"If you keep this empty, the ticket will be valid starting at the time of "
|
||||
"purchase."
|
||||
msgstr ""
|
||||
"Si mantienes este campo vacío, la entrada será válida empezando en el "
|
||||
"momento de la compra."
|
||||
|
||||
#: pretix/base/forms/questions.py:664 pretix/base/forms/questions.py:992
|
||||
msgid "Street and Number"
|
||||
@@ -2896,8 +2885,6 @@ msgid ""
|
||||
"Optional, but depending on the country you reside in we might need to charge "
|
||||
"you additional taxes if you do not enter it."
|
||||
msgstr ""
|
||||
"Opcional, pero dependiendo de tu país de residencia, es posible que haya que "
|
||||
"aplicar cargos adicionales si no nos facilitas tu dirección."
|
||||
|
||||
#: pretix/base/forms/questions.py:1033 pretix/base/forms/questions.py:1039
|
||||
msgid "If you are registered in Switzerland, you can enter your UID instead."
|
||||
@@ -2908,8 +2895,6 @@ msgid ""
|
||||
"Optional, but it might be required for you to claim tax benefits on your "
|
||||
"invoice depending on your and the seller’s country of residence."
|
||||
msgstr ""
|
||||
"Opcional, pero puede que sea necesario si aplican beneficios fiscales en tu "
|
||||
"factura dependiendo del país de residencia del vendedor."
|
||||
|
||||
#: pretix/base/forms/questions.py:1129
|
||||
msgid "You need to provide a company name."
|
||||
@@ -2942,7 +2927,7 @@ msgstr "La contraseña actual que ingresó no es correcta."
|
||||
|
||||
#: pretix/base/forms/user.py:58
|
||||
msgid "Please choose a password different to your current one."
|
||||
msgstr "Elige una contraseña diferente a la actual."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/forms/user.py:63 pretix/presale/forms/customer.py:373
|
||||
#: pretix/presale/forms/customer.py:442
|
||||
@@ -3154,7 +3139,7 @@ msgstr "Monto"
|
||||
#, python-brace-format
|
||||
msgctxt "invoice"
|
||||
msgid "Single price: {net_price} net / {gross_price} gross"
|
||||
msgstr "Precio único: {net_price} neto / {gross_price} bruto"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/invoice.py:659
|
||||
#, fuzzy, python-brace-format
|
||||
@@ -3251,7 +3236,7 @@ msgstr "Por favor, seleccione una cuota."
|
||||
|
||||
#: pretix/base/media.py:61
|
||||
msgid "Barcode / QR-Code"
|
||||
msgstr "Código de barras / Código QR"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/media.py:77
|
||||
#: pretix/control/templates/pretixcontrol/organizers/edit.html:237
|
||||
@@ -3450,7 +3435,7 @@ msgstr "Tipo de ticket no está permitido"
|
||||
|
||||
#: pretix/base/models/checkin.py:351
|
||||
msgid "Ticket code is ambiguous on list"
|
||||
msgstr "El código de la entrada es ambiguo en la lista"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/models/checkin.py:352
|
||||
#, fuzzy
|
||||
@@ -3501,8 +3486,6 @@ msgid ""
|
||||
"The identifier may only contain letters, numbers, dots, dashes, and "
|
||||
"underscores. It must start and end with a letter or number."
|
||||
msgstr ""
|
||||
"El identificador solo puede contener letras, números, puntos, y barras "
|
||||
"bajas. Tiene que empezar y terminar con una letra o un número."
|
||||
|
||||
#: pretix/base/models/customers.py:299 pretix/base/models/orders.py:1392
|
||||
#: pretix/base/models/orders.py:2971 pretix/base/settings.py:1093
|
||||
@@ -3518,7 +3501,7 @@ msgstr "Seleccione país"
|
||||
#: pretix/base/models/customers.py:370
|
||||
msgctxt "openidconnect"
|
||||
msgid "Confidential"
|
||||
msgstr "Confidencial"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/models/customers.py:371
|
||||
#, fuzzy
|
||||
@@ -3537,7 +3520,7 @@ msgstr "Código de transacción"
|
||||
#: pretix/base/models/customers.py:378
|
||||
msgctxt "openidconnect"
|
||||
msgid "Implicit"
|
||||
msgstr "Implícito"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/models/customers.py:382
|
||||
msgid "OpenID Connect access (required)"
|
||||
@@ -3589,7 +3572,7 @@ msgstr "Este identificador ya se utiliza para una pregunta diferente."
|
||||
#: pretix/control/templates/pretixcontrol/organizers/gates.html:16
|
||||
#: pretix/plugins/checkinlists/exporters.py:671
|
||||
msgid "Gate"
|
||||
msgstr "Puerta"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/models/devices.py:132
|
||||
#: pretix/control/templates/pretixcontrol/organizers/devices.html:83
|
||||
@@ -3981,7 +3964,7 @@ msgstr "Parametrizaciones adicionales"
|
||||
#: pretix/base/models/exports.py:61 pretix/base/models/exports.py:66
|
||||
#: pretix/base/models/exports.py:71
|
||||
msgid "You can specify multiple recipients separated by commas."
|
||||
msgstr "Puedes especificar múltiples destinatarios separados por comas."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/models/exports.py:64
|
||||
#, fuzzy
|
||||
@@ -4023,7 +4006,6 @@ msgstr "Hora de inicio del evento"
|
||||
#: pretix/base/models/exports.py:86
|
||||
msgid "The actual start time might be delayed depending on system load."
|
||||
msgstr ""
|
||||
"La hora de inicio real puede atrasarse dependiendo de la carga del sistema."
|
||||
|
||||
#: pretix/base/models/fields.py:33
|
||||
msgid "No value can contain the delimiter character."
|
||||
@@ -4435,11 +4417,11 @@ msgstr "minutos"
|
||||
|
||||
#: pretix/base/models/items.py:626
|
||||
msgid "Hours"
|
||||
msgstr "Horas"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/models/items.py:630
|
||||
msgid "Days"
|
||||
msgstr "Días"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/models/items.py:634
|
||||
#, fuzzy
|
||||
@@ -4471,7 +4453,7 @@ msgstr "El elemento seleccionado no pertenece a este evento."
|
||||
|
||||
#: pretix/base/models/items.py:650
|
||||
msgid "Reusable media policy"
|
||||
msgstr "Condiciones de utilización de imágenes"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/models/items.py:652
|
||||
msgid ""
|
||||
@@ -5160,7 +5142,7 @@ msgstr "Tarjeta de crédito"
|
||||
|
||||
#: pretix/base/models/memberships.py:44
|
||||
msgid "Membership is transferable"
|
||||
msgstr "La suscripción es transferible"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/models/memberships.py:45
|
||||
msgid ""
|
||||
@@ -5170,7 +5152,7 @@ msgstr ""
|
||||
|
||||
#: pretix/base/models/memberships.py:50
|
||||
msgid "Parallel usage is allowed"
|
||||
msgstr "El uso paralelo está permitido"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/models/memberships.py:51
|
||||
msgid ""
|
||||
@@ -5253,7 +5235,7 @@ msgstr ""
|
||||
|
||||
#: pretix/base/models/orders.py:234
|
||||
msgid "We'll show you this order to be due for a follow-up on this day."
|
||||
msgstr "Te mostraremos esta compra en el seguimiento de ese día."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/models/orders.py:240
|
||||
msgid ""
|
||||
@@ -5432,7 +5414,7 @@ msgstr "Tarifa de cancelación"
|
||||
|
||||
#: pretix/base/models/orders.py:2132
|
||||
msgid "Insurance fee"
|
||||
msgstr "Prima de seguro"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/models/orders.py:2133
|
||||
msgid "Other fees"
|
||||
@@ -5633,7 +5615,7 @@ msgstr ""
|
||||
|
||||
#: pretix/base/models/tax.py:168
|
||||
msgid "Official name"
|
||||
msgstr "Nombre oficial"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/models/tax.py:169
|
||||
msgid "Should be short, e.g. \"VAT\""
|
||||
@@ -5716,7 +5698,7 @@ msgstr ""
|
||||
#: pretix/base/models/tax.py:372
|
||||
msgctxt "invoice"
|
||||
msgid "VAT liability rests with the service recipient."
|
||||
msgstr "La responsabilidad del IVA es del destinatario del servicio."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/models/vouchers.py:171
|
||||
msgid "No effect"
|
||||
@@ -6003,7 +5985,7 @@ msgstr "Debe elegir el producto \"{prod}\" para este asiento."
|
||||
#: pretix/base/models/vouchers.py:500
|
||||
#, python-brace-format
|
||||
msgid "The seat \"{id}\" is already sold or currently blocked."
|
||||
msgstr "El puesto\"{id}\" ya se ha vendido o está bloqueado."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/models/waitinglist.py:64
|
||||
msgid "On waiting list since"
|
||||
@@ -6525,7 +6507,7 @@ msgstr "Habilitar método de pago"
|
||||
|
||||
#: pretix/base/payment.py:441
|
||||
msgid "Share this link with customers who should use this payment method."
|
||||
msgstr "Comparte este link con clientes que deben usar este método de pago."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/payment.py:487
|
||||
msgctxt "invoice"
|
||||
@@ -6966,7 +6948,7 @@ msgstr "Dirección de facturación empresa"
|
||||
|
||||
#: pretix/base/pdf.py:339
|
||||
msgid "Sesame Street 42"
|
||||
msgstr "Calle Sésamo 42"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/pdf.py:344
|
||||
#, fuzzy
|
||||
@@ -7349,8 +7331,6 @@ msgid ""
|
||||
"All payments for this event need to be confirmed already, so no new orders "
|
||||
"can be created."
|
||||
msgstr ""
|
||||
"Todos los pagos de este evento tienen que estar ya confirmados, por lo que "
|
||||
"no se pueden crear nuevos pedidos."
|
||||
|
||||
#: pretix/base/services/cart.py:136
|
||||
msgid ""
|
||||
@@ -7599,12 +7579,12 @@ msgstr "Razón desconocida"
|
||||
#: pretix/base/services/checkin.py:246
|
||||
#, python-brace-format
|
||||
msgid "Only allowed before {datetime}"
|
||||
msgstr "Solo está permitido antes del {datetime}"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/services/checkin.py:248
|
||||
#, python-brace-format
|
||||
msgid "Only allowed after {datetime}"
|
||||
msgstr "Solo está permitido después de {datetime}"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/services/checkin.py:251
|
||||
msgid "Ticket type not allowed"
|
||||
@@ -7673,22 +7653,22 @@ msgstr "Domingo"
|
||||
#: pretix/base/services/checkin.py:307
|
||||
#, python-brace-format
|
||||
msgid "{variable} is not {value}"
|
||||
msgstr "{variable} no es {value}"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/services/checkin.py:309
|
||||
#, python-brace-format
|
||||
msgid "Maximum {variable} exceeded"
|
||||
msgstr "Máximo {variable} superado"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/services/checkin.py:311
|
||||
#, python-brace-format
|
||||
msgid "Minimum {variable} exceeded"
|
||||
msgstr "Mínimo {variable} superado"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/services/checkin.py:313
|
||||
#, python-brace-format
|
||||
msgid "{variable} is {value}"
|
||||
msgstr "{variable} es {value}"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/services/checkin.py:763
|
||||
msgid "This order position has been canceled."
|
||||
@@ -7851,7 +7831,7 @@ msgstr "Product de Ejemplo A"
|
||||
#: pretix/base/services/invoices.py:519
|
||||
#, python-brace-format
|
||||
msgid "New invoice: {number}"
|
||||
msgstr "Nueva factura: {number}"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/services/invoices.py:521
|
||||
#, python-brace-format
|
||||
@@ -7863,13 +7843,6 @@ msgid ""
|
||||
"We are sending this email because you configured us to do so in your event "
|
||||
"settings."
|
||||
msgstr ""
|
||||
"Hola,\n"
|
||||
"\n"
|
||||
"Una nueva factura para tu pedido {order} de {event} se ha creado, la puedes "
|
||||
"encontrar adjunta.\n"
|
||||
"\n"
|
||||
"Te estamos enviando este email porque lo has configurado así en la página de "
|
||||
"configuración del evento."
|
||||
|
||||
#: pretix/base/services/mail.py:266
|
||||
#, fuzzy, python-brace-format
|
||||
@@ -10078,7 +10051,17 @@ msgstr ""
|
||||
"su equipo {event}"
|
||||
|
||||
#: pretix/base/settings.py:2108
|
||||
#, python-brace-format
|
||||
#, fuzzy, python-brace-format
|
||||
#| msgid ""
|
||||
#| "Hello,\n"
|
||||
#| "\n"
|
||||
#| "your order {code} for {event} has been canceled.\n"
|
||||
#| "\n"
|
||||
#| "You can view the details of your order at\n"
|
||||
#| "{url}\n"
|
||||
#| "\n"
|
||||
#| "Best regards, \n"
|
||||
#| "Your {event} team"
|
||||
msgid ""
|
||||
"Hello {attendee_name},\n"
|
||||
"\n"
|
||||
@@ -10090,15 +10073,15 @@ msgid ""
|
||||
"Best regards, \n"
|
||||
"Your {event} team"
|
||||
msgstr ""
|
||||
"Hola, {attendee_name}: \n"
|
||||
"Hola, \n"
|
||||
"\n"
|
||||
"Te has registrado correctamente para {event}. \n"
|
||||
"su pedido {code} para {event} ha sido cancelado. \n"
|
||||
"\n"
|
||||
"Puedes ver el estado y los detalles de tu entrada aquí:\n"
|
||||
"Puede ver los detalles de su pedido en\n"
|
||||
"{url}. \n"
|
||||
"\n"
|
||||
"Saludos cordiales, \n"
|
||||
"El equipo {event}"
|
||||
"su equipo {event}"
|
||||
|
||||
#: pretix/base/settings.py:2128
|
||||
#, python-brace-format
|
||||
@@ -10638,7 +10621,19 @@ msgid "Order approved and confirmed: {code}"
|
||||
msgstr "Pedido aprobado y confirmado: {code}"
|
||||
|
||||
#: pretix/base/settings.py:2462
|
||||
#, python-brace-format
|
||||
#, fuzzy, python-brace-format
|
||||
#| msgid ""
|
||||
#| "Hello,\n"
|
||||
#| "\n"
|
||||
#| "your order for {event} was successful. As you only ordered free "
|
||||
#| "products,\n"
|
||||
#| "no payment is required.\n"
|
||||
#| "\n"
|
||||
#| "You can change your order details and view the status of your order at\n"
|
||||
#| "{url}\n"
|
||||
#| "\n"
|
||||
#| "Best regards, \n"
|
||||
#| "Your {event} team"
|
||||
msgid ""
|
||||
"Hello,\n"
|
||||
"\n"
|
||||
@@ -10653,15 +10648,15 @@ msgid ""
|
||||
msgstr ""
|
||||
"Hola, \n"
|
||||
"\n"
|
||||
"se ha aprobado tu pedido para {event} y te damos la bienvenida a nuestro "
|
||||
"evento. Como solo ha pedido productos gratuitos, no se requiere ningún pago. "
|
||||
"\n"
|
||||
"su pedido para {event} fue un exitoso. Como sólo ha pedido productos "
|
||||
"gratuitos , \n"
|
||||
"no se requiere ningún pago. \n"
|
||||
"\n"
|
||||
"Puede cambiar los detalles de su pedido y ver el estado del mismo en\n"
|
||||
"{url}\n"
|
||||
"\n"
|
||||
"Saludos cordiales, \n"
|
||||
"El equipo de {event}"
|
||||
"su equipo {event}"
|
||||
|
||||
#: pretix/base/settings.py:2495
|
||||
#, python-brace-format
|
||||
@@ -10722,7 +10717,17 @@ msgid "Your ticket is ready for download: {code}"
|
||||
msgstr "Su ticket está listo para descargar: {code}"
|
||||
|
||||
#: pretix/base/settings.py:2536
|
||||
#, python-brace-format
|
||||
#, fuzzy, python-brace-format
|
||||
#| msgid ""
|
||||
#| "Hello {attendee_name},\n"
|
||||
#| "\n"
|
||||
#| "you are registered for {event}.\n"
|
||||
#| "\n"
|
||||
#| "If you did not do so already, you can download your ticket here:\n"
|
||||
#| "{url}\n"
|
||||
#| "\n"
|
||||
#| "Best regards, \n"
|
||||
#| "Your {event} team"
|
||||
msgid ""
|
||||
"Hello {attendee_name},\n"
|
||||
"\n"
|
||||
@@ -10734,11 +10739,11 @@ msgid ""
|
||||
"Best regards, \n"
|
||||
"Your {event} team"
|
||||
msgstr ""
|
||||
"Hola, {attendee_name}:\n"
|
||||
"Hola {attendee_name},\n"
|
||||
"\n"
|
||||
"está registrado en {event}.\n"
|
||||
"\n"
|
||||
"Si aún no lo ha hecho, puede descargar su entrada aquí:\n"
|
||||
"Si aún no lo ha hecho, puede descargar su entrada aquí :\n"
|
||||
"{url} \n"
|
||||
"\n"
|
||||
"Saludos cordiales, \n"
|
||||
@@ -12448,8 +12453,10 @@ msgid "Ask for {fields}, display like {example}"
|
||||
msgstr "Pregunta por {fields}, despliega como {example}"
|
||||
|
||||
#: pretix/control/forms/event.py:634 pretix/control/forms/organizer.py:454
|
||||
#, fuzzy
|
||||
#| msgid "Free price input"
|
||||
msgid "Free text input"
|
||||
msgstr "Entrada de texto libre"
|
||||
msgstr "Entrada de precio gratuita"
|
||||
|
||||
#: pretix/control/forms/event.py:666
|
||||
#, fuzzy
|
||||
@@ -12726,8 +12733,10 @@ msgid "Subject for approved free order"
|
||||
msgstr "Pedido aprobado"
|
||||
|
||||
#: pretix/control/forms/event.py:1233
|
||||
#, fuzzy
|
||||
#| msgid "Approved order"
|
||||
msgid "Text for approved free order"
|
||||
msgstr "Texto aprobado"
|
||||
msgstr "Pedido aprobado"
|
||||
|
||||
#: pretix/control/forms/event.py:1236 pretix/control/forms/event.py:1254
|
||||
#, fuzzy
|
||||
@@ -14250,7 +14259,7 @@ msgstr "ticket secreto:"
|
||||
|
||||
#: pretix/control/forms/orders.py:458
|
||||
msgid "Validity start"
|
||||
msgstr "Incio de validez"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/orders.py:463
|
||||
#, fuzzy
|
||||
@@ -14401,8 +14410,10 @@ msgid "Keep a fixed cancellation fee per ticket"
|
||||
msgstr "Mantener una tarifa de cancelación fija"
|
||||
|
||||
#: pretix/control/forms/orders.py:828
|
||||
#, fuzzy
|
||||
#| msgid "Generate tickets for non-admission products"
|
||||
msgid "Free tickets and add-on products are not counted"
|
||||
msgstr "Las entradas gratuitas en productos complementarios no contabilizan"
|
||||
msgstr "Generar tickets para productos no admitidos"
|
||||
|
||||
#: pretix/control/forms/orders.py:838
|
||||
#, fuzzy
|
||||
@@ -14596,23 +14607,29 @@ msgid "Gift card value"
|
||||
msgstr "Tarjeta de regalo"
|
||||
|
||||
#: pretix/control/forms/organizer.py:700
|
||||
#, fuzzy
|
||||
#| msgid "This ticket has already been redeemed."
|
||||
msgid "An medium with this type and identifier is already registered."
|
||||
msgstr "Un medio con este tipo y este identificador ya ha sido registrado."
|
||||
msgstr "Este ticket ya ha sido canjeado."
|
||||
|
||||
#: pretix/control/forms/organizer.py:801
|
||||
#, fuzzy
|
||||
#| msgid "This ticket has already been redeemed."
|
||||
msgid "An account with this customer ID is already registered."
|
||||
msgstr "Una cuenta con este identificador de usuario ya está registrado."
|
||||
msgstr "Este ticket ya ha sido canjeado."
|
||||
|
||||
#: pretix/control/forms/organizer.py:802 pretix/presale/forms/customer.py:439
|
||||
#, fuzzy
|
||||
#| msgid "This ticket has already been redeemed."
|
||||
msgid "An account with this email address is already registered."
|
||||
msgstr "Una cuenta con esta dirección de correo ya está registrada."
|
||||
msgstr "Este ticket ya ha sido canjeado."
|
||||
|
||||
#: pretix/control/forms/organizer.py:818
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customer.html:60
|
||||
#: pretix/presale/forms/customer.py:156 pretix/presale/forms/customer.py:472
|
||||
#: pretix/presale/templates/pretixpresale/organizers/customer_profile.html:32
|
||||
msgid "Phone"
|
||||
msgstr "Teléfono"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/organizer.py:925
|
||||
#, fuzzy
|
||||
@@ -14638,7 +14655,7 @@ msgstr "Clave Secreta"
|
||||
#: pretix/control/forms/organizer.py:937
|
||||
msgctxt "sso_oidc"
|
||||
msgid "Scope"
|
||||
msgstr "Alcance"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/organizer.py:938
|
||||
msgctxt "sso_oidc"
|
||||
@@ -14648,7 +14665,7 @@ msgstr ""
|
||||
#: pretix/control/forms/organizer.py:942
|
||||
msgctxt "sso_oidc"
|
||||
msgid "User ID field"
|
||||
msgstr "Campo identificador del usuario"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/organizer.py:943
|
||||
msgctxt "sso_oidc"
|
||||
@@ -17047,8 +17064,6 @@ msgid ""
|
||||
"We've detected that you are using <strong>Microsoft Internet Explorer</"
|
||||
"strong>."
|
||||
msgstr ""
|
||||
"Hemos detectado que estás usando <strong> Microsoft Internet Explorer "
|
||||
"</strong>."
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/base.html:328
|
||||
msgid ""
|
||||
@@ -17126,8 +17141,6 @@ msgid ""
|
||||
"For security reasons, please change your password before you continue. "
|
||||
"Afterwards you will be redirected to your original destination."
|
||||
msgstr ""
|
||||
"Por motivos de seguridad, por favor cambia tu contraseña antes de continuar. "
|
||||
"Serás redirigido después a la página de origen."
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/base.html:446
|
||||
#, python-format
|
||||
@@ -17316,7 +17329,7 @@ msgstr "Resultado"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/boxoffice/payment.html:108
|
||||
msgid "Cash"
|
||||
msgstr "Efectivo"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/checkin/checkins.html:9
|
||||
#: pretix/control/templates/pretixcontrol/checkin/checkins.html:41
|
||||
@@ -20826,7 +20839,7 @@ msgstr "No hay solicitudes registradas todavía."
|
||||
#: pretix/control/templates/pretixcontrol/oauth/app_register.html:4
|
||||
#: pretix/control/templates/pretixcontrol/oauth/app_register.html:6
|
||||
msgid "Register a new application"
|
||||
msgstr "Hacer un nuevo registro"
|
||||
msgstr "Registrar una nueva aplicación"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/oauth/app_rollkeys.html:4
|
||||
#: pretix/control/templates/pretixcontrol/oauth/app_rollkeys.html:6
|
||||
@@ -22693,7 +22706,7 @@ msgstr "Crear varias fechas"
|
||||
#: pretix/control/templates/pretixcontrol/subevents/bulk_edit.html:13
|
||||
#, python-format
|
||||
msgid "%(number)s selected"
|
||||
msgstr "%(number)s selecionado"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/organizers/device_bulk_edit.html:36
|
||||
#: pretix/control/templates/pretixcontrol/organizers/device_edit.html:24
|
||||
@@ -26915,8 +26928,10 @@ msgid "The device has been removed."
|
||||
msgstr "El dispositivo ha sido retirado."
|
||||
|
||||
#: pretix/control/views/user.py:449
|
||||
#, fuzzy
|
||||
#| msgid "This ticket has already been redeemed."
|
||||
msgid "This security device is already registered."
|
||||
msgstr "Este dispositivo ya está registrado."
|
||||
msgstr "Este ticket ya ha sido canjeado."
|
||||
|
||||
#: pretix/control/views/user.py:471 pretix/control/views/user.py:532
|
||||
msgid "A new two-factor authentication device has been added to your account."
|
||||
@@ -28800,8 +28815,6 @@ msgid ""
|
||||
"After placing your order, you will be able to select your desired payment "
|
||||
"method, including PayPal."
|
||||
msgstr ""
|
||||
"Después de hacer el pedido, podrás elegir el método de pago preferido, "
|
||||
"incluyendo PayPal."
|
||||
|
||||
#: pretix/plugins/paypal2/templates/pretixplugins/paypal2/checkout_payment_form.html:5
|
||||
msgid ""
|
||||
@@ -29830,8 +29843,10 @@ msgid "Blocked Seats"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/plugins/statistics/templates/pretixplugins/statistics/index.html:86
|
||||
#, fuzzy
|
||||
#| msgid "Free order"
|
||||
msgid "Free Seats"
|
||||
msgstr "Asiento gratuito"
|
||||
msgstr "Pedido gratuito"
|
||||
|
||||
#: pretix/plugins/statistics/templates/pretixplugins/statistics/index.html:94
|
||||
#, fuzzy
|
||||
@@ -31051,8 +31066,6 @@ msgid ""
|
||||
"An account with this email address is already registered. Please try to log "
|
||||
"in or reset your password instead."
|
||||
msgstr ""
|
||||
"Una cuenta con esta dirección de correo ya está registrada. Puedes entrar o "
|
||||
"recuperar la contraseña."
|
||||
|
||||
#: pretix/presale/forms/customer.py:189
|
||||
#, python-brace-format
|
||||
@@ -31694,7 +31707,7 @@ msgstr "cantidad mínima a pedir: %(num)s"
|
||||
#: pretix/presale/templates/pretixpresale/event/voucher.html:354
|
||||
msgctxt "price"
|
||||
msgid "free"
|
||||
msgstr "gratis"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/presale/templates/pretixpresale/event/fragment_addon_choice.html:77
|
||||
#: pretix/presale/templates/pretixpresale/event/fragment_product_list.html:51
|
||||
@@ -32387,7 +32400,7 @@ msgstr ""
|
||||
#: pretix/presale/templates/pretixpresale/event/fragment_subevent_calendar.html:22
|
||||
#: pretix/presale/templates/pretixpresale/organizers/calendar.html:24
|
||||
msgid "Select month to show"
|
||||
msgstr "Seleccione un mes a mostrar"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/presale/templates/pretixpresale/event/fragment_subevent_calendar.html:32
|
||||
#: pretix/presale/templates/pretixpresale/event/fragment_subevent_calendar_week.html:36
|
||||
@@ -32410,7 +32423,7 @@ msgstr ""
|
||||
#: pretix/presale/templates/pretixpresale/event/fragment_subevent_calendar_week.html:22
|
||||
#: pretix/presale/templates/pretixpresale/organizers/calendar_week.html:26
|
||||
msgid "Select week to show"
|
||||
msgstr "Selecciona semana a mostrar"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/presale/templates/pretixpresale/event/fragment_subevent_calendar_week.html:43
|
||||
#, python-format
|
||||
@@ -32766,7 +32779,6 @@ msgstr "Cambiar detalles"
|
||||
msgid ""
|
||||
"You need to select a payment method above before you can request an invoice."
|
||||
msgstr ""
|
||||
"Es necesario seleccionar un método de pago antes de solicitar una factura."
|
||||
|
||||
#: pretix/presale/templates/pretixpresale/event/order.html:267
|
||||
#: pretix/presale/templates/pretixpresale/event/order.html:274
|
||||
@@ -33129,8 +33141,6 @@ msgid ""
|
||||
"Please select the desired changes to your ticket. Note that you can only "
|
||||
"perform changes that do not change the total price of the ticket."
|
||||
msgstr ""
|
||||
"Selecciona los cambios que quieres hacer en tu entrada. Ten en cuenta que "
|
||||
"solo puedes hacer cambios que no cambien el valor total de la entrada."
|
||||
|
||||
#: pretix/presale/templates/pretixpresale/event/position_change_confirm.html:19
|
||||
#, fuzzy
|
||||
@@ -33692,7 +33702,7 @@ msgstr "No se ha encontrado el organizador seleccionado."
|
||||
msgid ""
|
||||
"Your selected payment method can only be used for a payment of at least "
|
||||
"{amount}."
|
||||
msgstr "El método de pago solo se puede usar para un pago de mínimo {amount}."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/presale/views/cart.py:183
|
||||
msgid "Please enter positive numbers only."
|
||||
@@ -33971,8 +33981,6 @@ msgid ""
|
||||
"Thank you very much! We will assign your spot on the waiting list to someone "
|
||||
"else."
|
||||
msgstr ""
|
||||
"¡Muchas gracias! Le asignaremos tu puesto en la lista de espera a otra "
|
||||
"persona."
|
||||
|
||||
#: pretix/presale/views/widget.py:341
|
||||
#, fuzzy
|
||||
@@ -33993,7 +34001,7 @@ msgstr "de %(start_date)s"
|
||||
|
||||
#: pretix/settings.py:710
|
||||
msgid "User profile only"
|
||||
msgstr "Solo perfil de usuario"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/settings.py:711
|
||||
msgid "Read access"
|
||||
|
||||
@@ -4,7 +4,7 @@ msgstr ""
|
||||
"Project-Id-Version: 1\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2023-07-27 11:49+0000\n"
|
||||
"PO-Revision-Date: 2023-08-09 03:00+0000\n"
|
||||
"PO-Revision-Date: 2023-07-22 21:00+0000\n"
|
||||
"Last-Translator: Ronan LE MEILLAT <ronan.le_meillat@highcanfly.club>\n"
|
||||
"Language-Team: French <https://translate.pretix.eu/projects/pretix/pretix/fr/"
|
||||
">\n"
|
||||
@@ -13,7 +13,7 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n > 1;\n"
|
||||
"X-Generator: Weblate 4.18.2\n"
|
||||
"X-Generator: Weblate 4.17\n"
|
||||
|
||||
#: pretix/_base_settings.py:78
|
||||
msgid "English"
|
||||
@@ -1666,7 +1666,7 @@ msgstr "Nécessite une attention particulière"
|
||||
#: pretix/base/exporters/items.py:91 pretix/base/models/items.py:553
|
||||
#: pretix/base/models/items.py:1018
|
||||
msgid "Original price"
|
||||
msgstr "Prix d'origine"
|
||||
msgstr "Facture originale"
|
||||
|
||||
#: pretix/base/exporters/items.py:92 pretix/base/models/items.py:565
|
||||
msgid "This product is a gift card"
|
||||
@@ -6227,18 +6227,24 @@ msgid "Ambiguous option selected."
|
||||
msgstr "Option ambiguë sélectionnée."
|
||||
|
||||
#: pretix/base/orderimport.py:845
|
||||
#, fuzzy
|
||||
#| msgid "No matching seat was found."
|
||||
msgid "No matching customer was found."
|
||||
msgstr "Aucun client correspondant n’a été trouvé."
|
||||
msgstr "Aucun siège correspondant n’a été trouvé."
|
||||
|
||||
#: pretix/base/payment.py:86
|
||||
#, fuzzy
|
||||
#| msgid "Apply"
|
||||
msgctxt "payment"
|
||||
msgid "Apple Pay"
|
||||
msgstr "Apple Pay"
|
||||
msgstr "Appliquer"
|
||||
|
||||
#: pretix/base/payment.py:87
|
||||
#, fuzzy
|
||||
#| msgid "Android (Google Play)"
|
||||
msgctxt "payment"
|
||||
msgid "Google Pay"
|
||||
msgstr "Google Pay"
|
||||
msgstr "Android (Google Play)"
|
||||
|
||||
#: pretix/base/payment.py:256
|
||||
#: pretix/presale/templates/pretixpresale/event/order.html:115
|
||||
@@ -8223,14 +8229,16 @@ msgid "Gift card currency"
|
||||
msgstr "Devise de la carte-cadeau"
|
||||
|
||||
#: pretix/base/settings.py:277
|
||||
#, fuzzy
|
||||
#| msgid ""
|
||||
#| "Automatically create a new gift card if a previously unknown chip is seen"
|
||||
msgid "Automatically create a new gift card if a new chip is encoded"
|
||||
msgstr ""
|
||||
"Créer automatiquement une nouvelle carte-cadeau si une nouvelle puce est "
|
||||
"encodée"
|
||||
"Créer automatiquement une nouvelle carte-cadeau si une puce inconnue est vue"
|
||||
|
||||
#: pretix/base/settings.py:299
|
||||
msgid "Use UID protection feature of NFC chip"
|
||||
msgstr "Utiliser la fonction de protection UID de la puce NFC"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/settings.py:313
|
||||
msgid "Maximum number of items per order"
|
||||
@@ -8745,8 +8753,10 @@ msgstr ""
|
||||
"commandés par d'autres personnes."
|
||||
|
||||
#: pretix/base/settings.py:942
|
||||
#, fuzzy
|
||||
#| msgid "Expiration date"
|
||||
msgid "Expiration delay"
|
||||
msgstr "Délai d’expiration"
|
||||
msgstr "Date d'expiration"
|
||||
|
||||
#: pretix/base/settings.py:943
|
||||
msgid ""
|
||||
@@ -8756,11 +8766,6 @@ msgid ""
|
||||
"beyond the \"last date of payments\" configured above, which is always "
|
||||
"enforced."
|
||||
msgstr ""
|
||||
"La commande n’expirera réellement que ce nombre de jours après la date d’"
|
||||
"expiration communiquée au client. Si vous sélectionnez « Ne terminez les "
|
||||
"conditions de paiement que les jours de semaine » ci-dessus, cela sera "
|
||||
"également respecté. Cependant, cela ne retardera pas au-delà de la « "
|
||||
"dernière date de paiement » configurée ci-dessus, qui est toujours appliquée."
|
||||
|
||||
#: pretix/base/settings.py:964
|
||||
msgid "Hide \"payment pending\" state on customer-facing pages"
|
||||
@@ -10181,12 +10186,25 @@ msgstr ""
|
||||
"Votre équipe {event}"
|
||||
|
||||
#: pretix/base/settings.py:2349
|
||||
#, python-brace-format
|
||||
#, fuzzy, python-brace-format
|
||||
#| msgid "Payment received for your order: {code}"
|
||||
msgid "Payment failed for your order: {code}"
|
||||
msgstr "Paiement échoué pour votre commande : {code}"
|
||||
msgstr "Paiement reçu pour votre commande : {code}"
|
||||
|
||||
#: pretix/base/settings.py:2353
|
||||
#, python-brace-format
|
||||
#, fuzzy, python-brace-format
|
||||
#| msgid ""
|
||||
#| "Hello,\n"
|
||||
#| "\n"
|
||||
#| "we did not yet receive a full payment for your order for {event}.\n"
|
||||
#| "Please keep in mind that we only guarantee your order if we receive\n"
|
||||
#| "your payment before {expire_date}.\n"
|
||||
#| "\n"
|
||||
#| "You can view the payment information and the status of your order at\n"
|
||||
#| "{url}\n"
|
||||
#| "\n"
|
||||
#| "Best regards, \n"
|
||||
#| "Your {event} team"
|
||||
msgid ""
|
||||
"Hello,\n"
|
||||
"\n"
|
||||
@@ -10204,18 +10222,18 @@ msgid ""
|
||||
msgstr ""
|
||||
"Bonjour\n"
|
||||
"\n"
|
||||
"Votre tentative de paiement pour votre commande pour {event} a échoué.\n"
|
||||
"Nous n’avons pas encore reçu le paiement intégral de votre commande de "
|
||||
"{event}.\n"
|
||||
"Veuillez garder à l’esprit que nous ne garantissons votre commande que si "
|
||||
"nous recevons\n"
|
||||
"votre paiement avant {expire_date}.\n"
|
||||
"\n"
|
||||
"Votre commande est toujours valide et vous pouvez essayer de payer à nouveau "
|
||||
"en utilisant le même mode de paiement ou un mode de paiement différent. "
|
||||
"Veuillez effectuer votre paiement avant {expire_date}.\n"
|
||||
"\n"
|
||||
"Vous pouvez réessayer le paiement et consulter l’état de votre commande à l’"
|
||||
"adresse\n"
|
||||
"Vous pouvez consulter les informations de paiement et l’état de votre "
|
||||
"commande à l’adresse\n"
|
||||
"{url}\n"
|
||||
"\n"
|
||||
"Sinceres salutations \n"
|
||||
"Votre équipe {event}"
|
||||
"Votre {event} équipe"
|
||||
|
||||
#: pretix/base/settings.py:2367
|
||||
#, python-brace-format
|
||||
@@ -11177,7 +11195,7 @@ msgstr ""
|
||||
|
||||
#: pretix/base/settings.py:3720
|
||||
msgid "This needs to be disabled if other NFC-based types are active."
|
||||
msgstr "Cela doit être désactivé si d’autres types NFC sont actifs."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/shredder.py:74 pretix/base/shredder.py:77
|
||||
msgid "Your event needs to be over to use this feature."
|
||||
@@ -14902,8 +14920,10 @@ msgid "The medium has been connected to a new ticket."
|
||||
msgstr "Le média a été connecté à un nouveau ticket."
|
||||
|
||||
#: pretix/control/logdisplay.py:371
|
||||
#, fuzzy
|
||||
#| msgid "The medium has been connected to a new ticket."
|
||||
msgid "The medium has been connected to a new gift card."
|
||||
msgstr "Le média a été connecté à une nouvelle carte cadeau."
|
||||
msgstr "Le média a été connecté à un nouveau ticket."
|
||||
|
||||
#: pretix/control/logdisplay.py:372 pretix/control/logdisplay.py:413
|
||||
msgid "Sending of an email has failed."
|
||||
@@ -15173,9 +15193,12 @@ msgstr ""
|
||||
"l'utilisateur."
|
||||
|
||||
#: pretix/control/logdisplay.py:436
|
||||
#, fuzzy
|
||||
#| msgid ""
|
||||
#| "An email has been sent to notify the user that payment has been received."
|
||||
msgid "An email has been sent to notify the user that the payment failed."
|
||||
msgstr ""
|
||||
"Un mail a été envoyé pour informer l'utilisateur que le paiement a échoué."
|
||||
"Un mail a été envoyé pour informer l'utilisateur que le paiement a été reçu."
|
||||
|
||||
#: pretix/control/logdisplay.py:437
|
||||
#, python-brace-format
|
||||
@@ -18000,7 +18023,7 @@ msgstr "Contenu de l' e-mail"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/mail.html:90
|
||||
msgid "Placed order"
|
||||
msgstr "Commande placée"
|
||||
msgstr "Ordre placé"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/mail.html:93
|
||||
msgid "Paid order"
|
||||
@@ -18021,8 +18044,10 @@ msgid "Payment reminder"
|
||||
msgstr "Rappel de paiement"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/mail.html:108
|
||||
#, fuzzy
|
||||
#| msgid "Payment fee"
|
||||
msgid "Payment failed"
|
||||
msgstr "Paiement échoué"
|
||||
msgstr "Frais de paiement"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/mail.html:111
|
||||
msgid "Waiting list notification"
|
||||
@@ -18077,6 +18102,8 @@ msgid "Deadlines"
|
||||
msgstr "Échéances"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/payment.html:68
|
||||
#, fuzzy
|
||||
#| msgid "days"
|
||||
msgctxt "unit"
|
||||
msgid "days"
|
||||
msgstr "jours"
|
||||
@@ -22149,10 +22176,6 @@ msgid ""
|
||||
"made by NXP. This provides a higher level of security than other approaches, "
|
||||
"but requires all chips to be encoded prior to use."
|
||||
msgstr ""
|
||||
"Ce type de support ne fonctionne qu’avec des puces NFC du type Mifare "
|
||||
"Ultralight AES fabriquées par NXP. Cela fournit un niveau de sécurité plus "
|
||||
"élevé que les autres approches, mais nécessite que toutes les puces soient "
|
||||
"encodées avant utilisation."
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/organizers/export.html:64
|
||||
msgid "Run export now and download result"
|
||||
@@ -24232,15 +24255,19 @@ msgid ""
|
||||
"For safety reasons, the waiting list does not run if the quota is set to "
|
||||
"unlimited."
|
||||
msgstr ""
|
||||
"Pour des raisons de sécurité, la liste d’attente ne fonctionne pas si le "
|
||||
"quota est fixé sur illimité."
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/waitinglist/index.html:219
|
||||
#, fuzzy
|
||||
#| msgid "Quota name"
|
||||
msgid "Quota unlimited"
|
||||
msgstr "Quota illimité"
|
||||
msgstr "Nom du quota"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/waitinglist/index.html:225
|
||||
#, python-format
|
||||
#, fuzzy, python-format
|
||||
#| msgid ""
|
||||
#| "\n"
|
||||
#| " Waiting, product %(num)sx available\n"
|
||||
#| " "
|
||||
msgid ""
|
||||
"\n"
|
||||
" Waiting, product %(num)sx "
|
||||
@@ -24248,9 +24275,8 @@ msgid ""
|
||||
" "
|
||||
msgstr ""
|
||||
"\n"
|
||||
" En attente, produit %(num)sx "
|
||||
"disponible\n"
|
||||
" "
|
||||
" En attente, produit %(num)sx disponible\n"
|
||||
" "
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/waitinglist/index.html:231
|
||||
msgid "Waiting, product unavailable"
|
||||
@@ -25021,6 +25047,13 @@ msgid "The selected product has been deactivated."
|
||||
msgstr "Le produit sélectionné a été désactivé."
|
||||
|
||||
#: pretix/control/views/mailsetup.py:195
|
||||
#, fuzzy
|
||||
#| msgid ""
|
||||
#| "We could not find an SPF record set for the domain you are trying to use. "
|
||||
#| "You can still proceed, but it will increase the chance of emails going to "
|
||||
#| "spam or being rejected. We strongly recommend setting an SPF record on "
|
||||
#| "the domain. You can do so through the DNS settings at the provider you "
|
||||
#| "registered your domain with."
|
||||
msgid ""
|
||||
"We could not find an SPF record set for the domain you are trying to use. "
|
||||
"This means that there is a very high change most of the emails will be "
|
||||
@@ -25029,11 +25062,11 @@ msgid ""
|
||||
"registered your domain with."
|
||||
msgstr ""
|
||||
"Nous n’avons pas pu trouver de jeu d’enregistrements SPF pour le domaine que "
|
||||
"vous essayez d’utiliser. Cela signifie qu’il y a un changement très élevé, "
|
||||
"la plupart des e-mails seront rejetés ou marqués comme spam. Nous vous "
|
||||
"recommandons vivement de définir un enregistrement SPF sur le domaine. Vous "
|
||||
"pouvez le faire via les paramètres DNS du fournisseur auprès duquel vous "
|
||||
"avez enregistré votre domaine."
|
||||
"vous essayez d’utiliser. Vous pouvez toujours continuer, mais cela "
|
||||
"augmentera les chances que les e-mails soient envoyés au spam ou rejetés. "
|
||||
"Nous vous recommandons vivement de définir un enregistrement SPF sur le "
|
||||
"domaine. Vous pouvez le faire via les paramètres DNS du fournisseur auprès "
|
||||
"duquel vous avez enregistré votre domaine."
|
||||
|
||||
#: pretix/control/views/mailsetup.py:202
|
||||
msgid ""
|
||||
@@ -28127,6 +28160,9 @@ msgid "Restrict to event dates starting before"
|
||||
msgstr "Limiter aux dates d’événements commençant avant"
|
||||
|
||||
#: pretix/plugins/sendmail/forms.py:170
|
||||
#, fuzzy
|
||||
#| msgctxt "sendmail_from"
|
||||
#| msgid "Send to"
|
||||
msgctxt "sendmail_form"
|
||||
msgid "Send to"
|
||||
msgstr "Envoyer à"
|
||||
@@ -28141,6 +28177,9 @@ msgid "Filter check-in status"
|
||||
msgstr "Filtrer le statut d'enregistrement"
|
||||
|
||||
#: pretix/plugins/sendmail/forms.py:189
|
||||
#, fuzzy
|
||||
#| msgctxt "sendmail_from"
|
||||
#| msgid "Restrict to recipients without check-in"
|
||||
msgctxt "sendmail_form"
|
||||
msgid "Restrict to recipients without check-in"
|
||||
msgstr "Restreindre aux destinataires sans enregistrement"
|
||||
@@ -28194,11 +28233,17 @@ msgid "pending with payment overdue"
|
||||
msgstr "en attente avec retard"
|
||||
|
||||
#: pretix/plugins/sendmail/forms.py:258
|
||||
#, fuzzy
|
||||
#| msgctxt "sendmail_from"
|
||||
#| msgid "Restrict to orders with status"
|
||||
msgctxt "sendmail_form"
|
||||
msgid "Restrict to orders with status"
|
||||
msgstr "Restreindre aux commandes avec statut"
|
||||
|
||||
#: pretix/plugins/sendmail/forms.py:283 pretix/plugins/sendmail/forms.py:287
|
||||
#, fuzzy
|
||||
#| msgctxt "sendmail_from"
|
||||
#| msgid "Restrict to recipients with check-in on list"
|
||||
msgctxt "sendmail_form"
|
||||
msgid "Restrict to recipients with check-in on list"
|
||||
msgstr "Restreindre aux destinataires avec enregistrement sur la liste"
|
||||
@@ -28269,6 +28314,9 @@ msgid "Limit products"
|
||||
msgstr "Limiter les produits"
|
||||
|
||||
#: pretix/plugins/sendmail/models.py:218
|
||||
#, fuzzy
|
||||
#| msgctxt "sendmail_from"
|
||||
#| msgid "Restrict to orders with status"
|
||||
msgid "Restrict to orders with status"
|
||||
msgstr "Restreindre aux commandes avec statut"
|
||||
|
||||
@@ -28832,7 +28880,7 @@ msgstr ""
|
||||
|
||||
#: pretix/plugins/stripe/payment.py:296
|
||||
msgid "Check for Apple Pay/Google Pay"
|
||||
msgstr "Vérifier Apple Pay/Google Pay"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/plugins/stripe/payment.py:300
|
||||
msgid ""
|
||||
@@ -28842,11 +28890,6 @@ msgid ""
|
||||
"take into consideration if Google Pay/Apple Pay has been disabled in the "
|
||||
"Stripe Dashboard."
|
||||
msgstr ""
|
||||
"pretix tentera de vérifier si le navigateur Web du client prend en charge "
|
||||
"les méthodes de paiement basées sur le portefeuille comme Apple Pay ou "
|
||||
"Google Pay et les affichera bien en évidence avec le mode de paiement par "
|
||||
"carte de crédit. Cette détection ne prend pas en compte si Google Pay/Apple "
|
||||
"Pay a été désactivé dans le tableau de bord Stripe."
|
||||
|
||||
#: pretix/plugins/stripe/payment.py:309
|
||||
msgid "Statement descriptor postfix"
|
||||
@@ -28896,32 +28939,38 @@ msgid "Bancontact"
|
||||
msgstr "Bancontact"
|
||||
|
||||
#: pretix/plugins/stripe/payment.py:357
|
||||
#, fuzzy
|
||||
#| msgid "Disable SEPA Direct Debit"
|
||||
msgid "SEPA Direct Debit"
|
||||
msgstr "Prélèvement SEPA"
|
||||
msgstr "Désactiver le prélèvement SEPA"
|
||||
|
||||
#: pretix/plugins/stripe/payment.py:362
|
||||
#, fuzzy
|
||||
#| msgid ""
|
||||
#| "Despite the name, Sofort payments via Stripe are <strong>not</strong> "
|
||||
#| "processed instantly but might take up to <strong>14 days</strong> to be "
|
||||
#| "confirmed in some cases. Please only activate this payment method if your "
|
||||
#| "payment term allows for this lag."
|
||||
msgid ""
|
||||
"SEPA Direct Debit payments via Stripe are <strong>not</strong> processed "
|
||||
"instantly but might take up to <strong>14 days</strong> to be confirmed in "
|
||||
"some cases. Please only activate this payment method if your payment term "
|
||||
"allows for this lag."
|
||||
msgstr ""
|
||||
"Les paiements par prélèvement SEPA via Stripe ne sont <strong>pas</strong> "
|
||||
"traités instantanément, mais peuvent prendre jusqu’à <strong>14 jours</"
|
||||
"strong> pour être confirmés dans certains cas. Veuillez n’activer ce mode de "
|
||||
"paiement que si votre délai de paiement le permet."
|
||||
"Malgré leur nom, les paiements Sofort via Stripe <strong>ne sont pas</"
|
||||
"strong> traités instantanément, mais peuvent prendre jusqu’à <strong>14 "
|
||||
"jours</strong> pour être confirmés dans certains cas. Veuillez n’activer ce "
|
||||
"mode de paiement que si votre délai de paiement le permet."
|
||||
|
||||
#: pretix/plugins/stripe/payment.py:370
|
||||
msgid "SEPA Creditor Mandate Name"
|
||||
msgstr "Nom du mandat du créancier SEPA"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/plugins/stripe/payment.py:372
|
||||
msgid ""
|
||||
"Please provide your SEPA Creditor Mandate Name, that will be displayed to "
|
||||
"the user."
|
||||
msgstr ""
|
||||
"Veuillez fournir votre nom de mandat de créancier SEPA, qui sera affiché à "
|
||||
"l’utilisateur."
|
||||
|
||||
#: pretix/plugins/stripe/payment.py:383
|
||||
msgid "SOFORT"
|
||||
@@ -29032,32 +29081,44 @@ msgid "Credit card"
|
||||
msgstr "Carte de crédit"
|
||||
|
||||
#: pretix/plugins/stripe/payment.py:1157
|
||||
#, fuzzy
|
||||
#| msgid "EPS via Stripe"
|
||||
msgid "SEPA Debit via Stripe"
|
||||
msgstr "Prélèvement SEPA via Stripe"
|
||||
msgstr "EPS via Stripe"
|
||||
|
||||
#: pretix/plugins/stripe/payment.py:1158
|
||||
msgid "SEPA Debit"
|
||||
msgstr "Débit SEPA"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/plugins/stripe/payment.py:1197
|
||||
#, fuzzy
|
||||
#| msgid "Account holder"
|
||||
msgid "Account Holder Name"
|
||||
msgstr "Titulaire du compte"
|
||||
|
||||
#: pretix/plugins/stripe/payment.py:1202
|
||||
#, fuzzy
|
||||
#| msgid "Account holder"
|
||||
msgid "Account Holder Street"
|
||||
msgstr "Rue du titulaire du compte"
|
||||
msgstr "Titulaire du compte"
|
||||
|
||||
#: pretix/plugins/stripe/payment.py:1214
|
||||
#, fuzzy
|
||||
#| msgid "Account holder"
|
||||
msgid "Account Holder Postal Code"
|
||||
msgstr "Code postal du titulaire du compte"
|
||||
msgstr "Titulaire du compte"
|
||||
|
||||
#: pretix/plugins/stripe/payment.py:1226
|
||||
#, fuzzy
|
||||
#| msgid "Account holder"
|
||||
msgid "Account Holder City"
|
||||
msgstr "Ville du titulaire du compte"
|
||||
msgstr "Titulaire du compte"
|
||||
|
||||
#: pretix/plugins/stripe/payment.py:1238
|
||||
#, fuzzy
|
||||
#| msgid "Account holder"
|
||||
msgid "Account Holder Country"
|
||||
msgstr "Pays du titulaire du compte"
|
||||
msgstr "Titulaire du compte"
|
||||
|
||||
#: pretix/plugins/stripe/payment.py:1282
|
||||
msgid "giropay via Stripe"
|
||||
@@ -29228,18 +29289,22 @@ msgid "Card type"
|
||||
msgstr "Type de carte"
|
||||
|
||||
#: pretix/plugins/stripe/templates/pretixplugins/stripe/checkout_payment_confirm.html:14
|
||||
#, fuzzy
|
||||
#| msgid "The total amount will be withdrawn from your credit card."
|
||||
msgid "The total amount will be withdrawn from your bank account."
|
||||
msgstr "Le montant total sera prélevé sur votre compte bancaire."
|
||||
msgstr "Le montant total sera prélevé sur votre carte de crédit."
|
||||
|
||||
#: pretix/plugins/stripe/templates/pretixplugins/stripe/checkout_payment_confirm.html:18
|
||||
#: pretix/plugins/stripe/templates/pretixplugins/stripe/checkout_payment_form_sepadirectdebit.html:20
|
||||
msgid "Banking Institution"
|
||||
msgstr "Établissement bancaire"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/plugins/stripe/templates/pretixplugins/stripe/checkout_payment_confirm.html:20
|
||||
#: pretix/plugins/stripe/templates/pretixplugins/stripe/checkout_payment_form_sepadirectdebit.html:22
|
||||
#, fuzzy
|
||||
#| msgid "Account holder"
|
||||
msgid "Account number"
|
||||
msgstr "Numéro de compte"
|
||||
msgstr "Titulaire du compte"
|
||||
|
||||
#: pretix/plugins/stripe/templates/pretixplugins/stripe/checkout_payment_confirm.html:24
|
||||
#: pretix/plugins/stripe/templates/pretixplugins/stripe/checkout_payment_form_simple.html:4
|
||||
@@ -29288,20 +29353,28 @@ msgstr ""
|
||||
"serveurs."
|
||||
|
||||
#: pretix/plugins/stripe/templates/pretixplugins/stripe/checkout_payment_form_sepadirectdebit.html:10
|
||||
#, fuzzy
|
||||
#| msgid "For a credit card payment, please turn on JavaScript."
|
||||
msgid "For a SEPA Debit payment, please turn on JavaScript."
|
||||
msgstr "Pour un paiement par prélèvement SEPA, veuillez activer JavaScript."
|
||||
msgstr "Pour un paiement par carte de crédit, veuillez activer JavaScript."
|
||||
|
||||
#: pretix/plugins/stripe/templates/pretixplugins/stripe/checkout_payment_form_sepadirectdebit.html:16
|
||||
#, fuzzy
|
||||
#| msgid ""
|
||||
#| "You already entered a card number that we will use to charge the payment "
|
||||
#| "amount."
|
||||
msgid ""
|
||||
"You already entered a bank account that we will use to charge the payment "
|
||||
"amount."
|
||||
msgstr ""
|
||||
"Vous avez déjà saisi un compte bancaire que nous utiliserons pour débiter le "
|
||||
"Vous avez déjà entré un numéro de carte que nous utiliserons pour débiter le "
|
||||
"montant du paiement."
|
||||
|
||||
#: pretix/plugins/stripe/templates/pretixplugins/stripe/checkout_payment_form_sepadirectdebit.html:27
|
||||
#, fuzzy
|
||||
#| msgid "Use a different card"
|
||||
msgid "Use a different account"
|
||||
msgstr "Utiliser un autre compte"
|
||||
msgstr "Utiliser une autre carte"
|
||||
|
||||
#: pretix/plugins/stripe/templates/pretixplugins/stripe/checkout_payment_form_sepadirectdebit.html:51
|
||||
#, python-format
|
||||
@@ -29317,18 +29390,6 @@ msgid ""
|
||||
"statement that you can obtain from your bank. You agree to receive "
|
||||
"notifications for future debits up to 2 days before they occur."
|
||||
msgstr ""
|
||||
"En fournissant vos informations de paiement et en confirmant ce paiement, "
|
||||
"vous autorisez (A) %(sepa_creditor_name)s et Stripe, notre prestataire de "
|
||||
"services de paiement et/ou PPRO, son prestataire de services local, à "
|
||||
"envoyer des instructions à votre banque pour débiter votre compte et (B) "
|
||||
"votre banque à débiter votre compte conformément à ces instructions. Dans le "
|
||||
"cadre de vos droits, vous avez droit à un remboursement de votre banque "
|
||||
"selon les termes et conditions de votre accord avec votre banque. Un "
|
||||
"remboursement doit être demandé dans un délai de 8 semaines à compter de la "
|
||||
"date à laquelle votre compte a été débité. Vos droits sont expliqués dans "
|
||||
"une déclaration que vous pouvez obtenir auprès de votre banque. Vous "
|
||||
"acceptez de recevoir des notifications pour les débits futurs jusqu’à 2 "
|
||||
"jours avant qu’ils ne se produisent."
|
||||
|
||||
#: pretix/plugins/stripe/templates/pretixplugins/stripe/control.html:6
|
||||
msgid "Charge ID"
|
||||
|
||||
@@ -7,7 +7,7 @@ msgstr ""
|
||||
"Project-Id-Version: French\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2023-07-21 11:46+0000\n"
|
||||
"PO-Revision-Date: 2023-08-02 02:00+0000\n"
|
||||
"PO-Revision-Date: 2023-07-19 17:00+0000\n"
|
||||
"Last-Translator: Ronan LE MEILLAT <ronan.le_meillat@highcanfly.club>\n"
|
||||
"Language-Team: French <https://translate.pretix.eu/projects/pretix/pretix-js/"
|
||||
"fr/>\n"
|
||||
@@ -16,7 +16,7 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n > 1;\n"
|
||||
"X-Generator: Weblate 4.18.2\n"
|
||||
"X-Generator: Weblate 4.17\n"
|
||||
|
||||
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:56
|
||||
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:62
|
||||
@@ -63,7 +63,7 @@ msgstr "iDEAL"
|
||||
|
||||
#: pretix/plugins/paypal2/static/pretixplugins/paypal2/pretix-paypal.js:42
|
||||
msgid "SEPA Direct Debit"
|
||||
msgstr "Prélèvement SEPA"
|
||||
msgstr "Débit direct SEPA"
|
||||
|
||||
#: pretix/plugins/paypal2/static/pretixplugins/paypal2/pretix-paypal.js:43
|
||||
msgid "Bancontact"
|
||||
@@ -679,8 +679,10 @@ msgid "Your local time:"
|
||||
msgstr "Votre heure locale :"
|
||||
|
||||
#: pretix/static/pretixpresale/js/walletdetection.js:39
|
||||
#, fuzzy
|
||||
#| msgid "Apple Pay"
|
||||
msgid "Google Pay"
|
||||
msgstr "Google Pay"
|
||||
msgstr "Apple Pay"
|
||||
|
||||
#: pretix/static/pretixpresale/js/widget/widget.js:17
|
||||
msgctxt "widget"
|
||||
|
||||
@@ -77,8 +77,6 @@ def get_event_domain(event, fallback=False, return_info=False):
|
||||
|
||||
def get_organizer_domain(organizer):
|
||||
assert isinstance(organizer, Organizer)
|
||||
if not organizer.pk:
|
||||
return None
|
||||
domain = getattr(organizer, '_cached_domain', None) or organizer.cache.get('domain')
|
||||
if domain is None:
|
||||
domains = organizer.domains.filter(event__isnull=True)
|
||||
@@ -128,7 +126,7 @@ def eventreverse(obj, name, kwargs=None):
|
||||
:param kwargs: A dictionary of additional keyword arguments that should be used. You do not
|
||||
need to provide the organizer or event slug here, it will be added automatically as
|
||||
needed.
|
||||
:returns: An absolute or relative URL as a string
|
||||
:returns: An absolute URL (including scheme and host) as a string
|
||||
"""
|
||||
from pretix.multidomain import (
|
||||
event_domain_urlconf, maindomain_urlconf, organizer_domain_urlconf,
|
||||
@@ -177,17 +175,6 @@ def eventreverse(obj, name, kwargs=None):
|
||||
|
||||
|
||||
def build_absolute_uri(obj, urlname, kwargs=None):
|
||||
"""
|
||||
Works similar to ``eventreverse`` but always returns an absolute URL.
|
||||
|
||||
:param obj: An ``Event`` or ``Organizer`` object
|
||||
:param name: The name of the URL route
|
||||
:type name: str
|
||||
:param kwargs: A dictionary of additional keyword arguments that should be used. You do not
|
||||
need to provide the organizer or event slug here, it will be added automatically as
|
||||
needed.
|
||||
:returns: An absolute URL (including scheme and host) as a string
|
||||
"""
|
||||
reversedurl = eventreverse(obj, urlname, kwargs)
|
||||
if '://' in reversedurl:
|
||||
return reversedurl
|
||||
|
||||
@@ -535,11 +535,9 @@ class BankTransfer(BasePaymentProvider):
|
||||
'eu_barcodes': self.event.currency == 'EUR',
|
||||
'pending_description': self.settings.get('pending_description', as_type=LazyI18nString),
|
||||
'details': self.settings.get('bank_details', as_type=LazyI18nString),
|
||||
'has_invoices': payment.order.invoices.exists(),
|
||||
'invoice_email_enabled': self.settings.get('invoice_email', as_type=bool),
|
||||
}
|
||||
ctx['any_barcodes'] = ctx['swiss_qrbill'] or ctx['eu_barcodes']
|
||||
return template.render(ctx, request=request)
|
||||
return template.render(ctx)
|
||||
|
||||
def payment_control_render(self, request: HttpRequest, payment: OrderPayment) -> str:
|
||||
warning = None
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
{% load money %}
|
||||
{% load unidecode %}
|
||||
{% load rich_text %}
|
||||
{% load eventurl %}
|
||||
|
||||
{% if pending_description %}
|
||||
{{ pending_description|rich_text }}
|
||||
@@ -104,28 +103,3 @@ SCT
|
||||
{% if swiss_qrbill %}
|
||||
<link rel="stylesheet" href="{% static "pretixplugins/banktransfer/swisscross.css" %}">
|
||||
{% endif %}
|
||||
|
||||
{% if invoice_email_enabled and has_invoices %}
|
||||
<form method="post" action="{% eventurl event "plugins:banktransfer:mail_invoice" order=order.code secret=order.secret %}">
|
||||
{% csrf_token %}
|
||||
<p>
|
||||
{% blocktrans trimmed %}
|
||||
To send the invoice directly to your accounting department, please enter their email address:
|
||||
{% endblocktrans %}
|
||||
</p>
|
||||
<div class="row">
|
||||
<div class="col-md-9 col-xs-12">
|
||||
<label for="mail_invoice_email" class="sr-only">{% trans "Invoice recipient email" %}:</label>
|
||||
<input type="email" name="email" id="mail_invoice_email" class="form-control" value="" required
|
||||
placeholder="{% trans "Email address" %}" />
|
||||
</div>
|
||||
<div class="col-md-3 col-xs-12">
|
||||
<button class="btn btn-default btn-block">
|
||||
<span class="fa fa-envelope-o" aria-hidden="true"></span>
|
||||
{% trans "Send invoice via email" %}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<hr>
|
||||
{% endif %}
|
||||
@@ -19,19 +19,13 @@
|
||||
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
|
||||
# <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
from django.urls import include, re_path
|
||||
from django.urls import re_path
|
||||
|
||||
from pretix.api.urls import orga_router
|
||||
from pretix.plugins.banktransfer.api import BankImportJobViewSet
|
||||
|
||||
from . import views
|
||||
|
||||
event_patterns = [
|
||||
re_path(r'^banktransfer/', include([
|
||||
re_path(r'^(?P<order>[^/][^w]+)/(?P<secret>[A-Za-z0-9]+)/mail-invoice/$', views.SendInvoiceMailView.as_view(), name='mail_invoice'),
|
||||
])),
|
||||
]
|
||||
|
||||
urlpatterns = [
|
||||
re_path(r'^control/organizer/(?P<organizer>[^/]+)/banktransfer/import/',
|
||||
views.OrganizerImportView.as_view(),
|
||||
|
||||
@@ -44,18 +44,14 @@ from typing import Set
|
||||
|
||||
from django import forms
|
||||
from django.contrib import messages
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.core.validators import validate_email
|
||||
from django.db import transaction
|
||||
from django.db.models import Count, Q, QuerySet
|
||||
from django.http import FileResponse, Http404, JsonResponse
|
||||
from django.http import FileResponse, JsonResponse
|
||||
from django.shortcuts import get_object_or_404, redirect, render
|
||||
from django.urls import reverse
|
||||
from django.utils.decorators import method_decorator
|
||||
from django.utils.functional import cached_property
|
||||
from django.utils.timezone import now
|
||||
from django.utils.translation import gettext as _
|
||||
from django.views.decorators.clickjacking import xframe_options_exempt
|
||||
from django.views.generic import DetailView, FormView, ListView, View
|
||||
from django.views.generic.detail import SingleObjectMixin
|
||||
from localflavor.generic.forms import BICFormField, IBANFormField
|
||||
@@ -79,8 +75,6 @@ from pretix.plugins.banktransfer.refund_export import (
|
||||
build_sepa_xml, get_refund_export_csv,
|
||||
)
|
||||
from pretix.plugins.banktransfer.tasks import process_banktransfers
|
||||
from pretix.presale.views import EventViewMixin
|
||||
from pretix.presale.views.order import OrderDetailMixin
|
||||
|
||||
logger = logging.getLogger('pretix.plugins.banktransfer')
|
||||
|
||||
@@ -892,36 +886,3 @@ class OrganizerSepaXMLExportView(OrganizerPermissionRequiredMixin, OrganizerDeta
|
||||
organizer=self.request.organizer,
|
||||
pk=self.kwargs.get('id')
|
||||
)
|
||||
|
||||
|
||||
@method_decorator(xframe_options_exempt, 'dispatch')
|
||||
class SendInvoiceMailView(EventViewMixin, OrderDetailMixin, View):
|
||||
def post(self, request, *args, **kwargs):
|
||||
if not self.order:
|
||||
raise Http404(_('Unknown order code or not authorized to access this order.'))
|
||||
try:
|
||||
validate_email(request.POST['email'])
|
||||
except ValidationError:
|
||||
messages.error(request, _('Please enter a valid email address.'))
|
||||
return redirect(self.get_order_url())
|
||||
|
||||
last_payment = self.order.payments.last()
|
||||
if (not last_payment
|
||||
or last_payment.provider != BankTransfer.identifier
|
||||
or last_payment.state != OrderPayment.PAYMENT_STATE_CREATED):
|
||||
messages.error(request, _('No pending bank transfer payment found. Maybe the order has been paid already?'))
|
||||
return redirect(self.get_order_url())
|
||||
if not last_payment.payment_provider.settings.get('invoice_email', as_type=bool):
|
||||
messages.error(request, _('Sending invoices via email is disabled by the event organizer.'))
|
||||
return redirect(self.get_order_url())
|
||||
|
||||
last_invoice = self.order.invoices.last()
|
||||
if not last_invoice:
|
||||
messages.error(request, _('No invoice found, please request an invoice first.'))
|
||||
return redirect(self.get_order_url())
|
||||
|
||||
provider = last_payment.payment_provider
|
||||
provider.send_invoice_to_alternate_email(self.order, last_invoice, request.POST['email'])
|
||||
|
||||
messages.success(request, _('Sending the latest invoice via e-mail to {email}.').format(email=request.POST['email']))
|
||||
return redirect(self.get_order_url())
|
||||
|
||||
@@ -76,11 +76,7 @@ class BaseMailForm(FormPlaceholderMixin, forms.Form):
|
||||
attachment = CachedFileField(
|
||||
label=_("Attachment"),
|
||||
required=False,
|
||||
ext_whitelist=(
|
||||
".png", ".jpg", ".gif", ".jpeg", ".pdf", ".txt", ".docx", ".gif", ".svg",
|
||||
".pptx", ".ppt", ".doc", ".xlsx", ".xls", ".jfif", ".heic", ".heif", ".pages",
|
||||
".bmp", ".tif", ".tiff"
|
||||
),
|
||||
ext_whitelist=settings.FILE_UPLOAD_EXTENSIONS_EMAIL_ATTACHMENT,
|
||||
help_text=_('Sending an attachment increases the chance of your email not arriving or being sorted into spam folders. We recommend only using PDFs '
|
||||
'of no more than 2 MB in size.'),
|
||||
max_size=settings.FILE_UPLOAD_MAX_SIZE_EMAIL_ATTACHMENT
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
{% load i18n %}
|
||||
{% load eventurl %}
|
||||
{% if ev.location and show_location %}
|
||||
<div class="info-row">
|
||||
<span class="fa fa-map-marker fa-fw" aria-hidden="true" title="{% trans "Where does the event happen?" %}"></span>
|
||||
<p><span class="sr-only">{% trans "Where does the event happen?" %}</span>
|
||||
{{ ev.location|linebreaksbr }}
|
||||
</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if ev.settings.show_dates_on_frontpage %}
|
||||
<div class="info-row">
|
||||
<span class="fa fa-clock-o fa-fw" aria-hidden="true" title="{% trans "When does the event happen?" %}"></span>
|
||||
<p><span class="sr-only">{% trans "When does the event happen?" %}</span>
|
||||
{{ ev.get_date_range_display_as_html }}
|
||||
{% if event.settings.show_times %}
|
||||
<br>
|
||||
<span data-time="{{ ev.date_from.isoformat }}" data-timezone="{{ request.event.timezone }}">
|
||||
{% with time_human=ev.date_from|date:"TIME_FORMAT" time_24=ev.date_from|time:"H:i" %}
|
||||
{% blocktrans trimmed with time='<time datetime="'|add:time_24|add:'">'|add:time_human|add:"</time>"|safe %}
|
||||
Begin: {{ time }}
|
||||
{% endblocktrans %}
|
||||
{% endwith %}
|
||||
</span>
|
||||
{% if event.settings.show_date_to and ev.date_to %}
|
||||
<br>
|
||||
<span data-time="{{ ev.date_to.isoformat }}" data-timezone="{{ request.event.timezone }}">
|
||||
{% with time_human=ev.date_to|date:"TIME_FORMAT" time_24=ev.date_to|time:"H:i" %}
|
||||
{% blocktrans trimmed with time='<time datetime="'|add:time_24|add:'">'|add:time_human|add:"</time>"|safe %}
|
||||
End: {{ time }}
|
||||
{% endblocktrans %}
|
||||
{% endwith %}
|
||||
</span>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if ev.date_admission %}
|
||||
<br>
|
||||
{% if ev.date_admission|date:"SHORT_DATE_FORMAT" == ev.date_from|date:"SHORT_DATE_FORMAT" %}
|
||||
<span data-time="{{ ev.date_admission.isoformat }}" data-timezone="{{ request.event.timezone }}">
|
||||
{% with time_human=ev.date_admission|date:"TIME_FORMAT" time_24=ev.date_admission|time:"H:i" %}
|
||||
{% blocktrans trimmed with time='<time datetime="'|add:time_24|add:'">'|add:time_human|add:"</time>"|safe %}
|
||||
Admission: {{ time }}
|
||||
{% endblocktrans %}
|
||||
{% endwith %}
|
||||
</span>
|
||||
{% else %}
|
||||
<span data-time="{{ ev.date_admission.isoformat }}" data-timezone="{{ request.event.timezone }}">
|
||||
{% with datetime_human=ev.date_admission|date:"SHORT_DATETIME_FORMAT" datetime_iso=ev.date_admission|time:"Y-m-d H:i" %}
|
||||
{% blocktrans trimmed with datetime='<time datetime="'|add:datetime_iso|add:'">'|add:datetime_human|add:"</time>"|safe %}
|
||||
Admission: {{ datetime }}
|
||||
{% endblocktrans %}
|
||||
{% endwith %}
|
||||
</span>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
<br>
|
||||
{% if subevent %}
|
||||
<a href="{% eventurl event "presale:event.ical.download" subevent=subevent.pk %}">
|
||||
{% else %}
|
||||
<a href="{% eventurl event "presale:event.ical.download" %}">
|
||||
{% endif %}
|
||||
{% trans "Add to Calendar" %}
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
@@ -162,8 +162,73 @@
|
||||
{% endif %}
|
||||
{% if not cart_namespace or subevent %}
|
||||
<div>
|
||||
{% include "pretixpresale/event/fragment_event_info.html" with event=request.event subevent=subevent ev=ev show_location=True %}
|
||||
{% if ev.location %}
|
||||
<div class="info-row">
|
||||
<span class="fa fa-map-marker fa-fw" aria-hidden="true" title="{% trans "Where does the event happen?" %}"></span>
|
||||
<p><span class="sr-only">{% trans "Where does the event happen?" %}</span>
|
||||
{{ ev.location|linebreaksbr }}
|
||||
</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if ev.settings.show_dates_on_frontpage %}
|
||||
<div class="info-row">
|
||||
<span class="fa fa-clock-o fa-fw" aria-hidden="true" title="{% trans "When does the event happen?" %}"></span>
|
||||
<p><span class="sr-only">{% trans "When does the event happen?" %}</span>
|
||||
{{ ev.get_date_range_display_as_html }}
|
||||
{% if event.settings.show_times %}
|
||||
<br>
|
||||
<span data-time="{{ ev.date_from.isoformat }}" data-timezone="{{ request.event.timezone }}">
|
||||
{% with time_human=ev.date_from|date:"TIME_FORMAT" time_24=ev.date_from|time:"H:i" %}
|
||||
{% blocktrans trimmed with time='<time datetime="'|add:time_24|add:'">'|add:time_human|add:"</time>"|safe %}
|
||||
Begin: {{ time }}
|
||||
{% endblocktrans %}
|
||||
{% endwith %}
|
||||
</span>
|
||||
{% if event.settings.show_date_to and ev.date_to %}
|
||||
<br>
|
||||
<span data-time="{{ ev.date_to.isoformat }}" data-timezone="{{ request.event.timezone }}">
|
||||
{% with time_human=ev.date_to|date:"TIME_FORMAT" time_24=ev.date_to|time:"H:i" %}
|
||||
{% blocktrans trimmed with time='<time datetime="'|add:time_24|add:'">'|add:time_human|add:"</time>"|safe %}
|
||||
End: {{ time }}
|
||||
{% endblocktrans %}
|
||||
{% endwith %}
|
||||
</span>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if ev.date_admission %}
|
||||
<br>
|
||||
{% if ev.date_admission|date:"SHORT_DATE_FORMAT" == ev.date_from|date:"SHORT_DATE_FORMAT" %}
|
||||
<span data-time="{{ ev.date_admission.isoformat }}" data-timezone="{{ request.event.timezone }}">
|
||||
{% with time_human=ev.date_admission|date:"TIME_FORMAT" time_24=ev.date_admission|time:"H:i" %}
|
||||
{% blocktrans trimmed with time='<time datetime="'|add:time_24|add:'">'|add:time_human|add:"</time>"|safe %}
|
||||
Admission: {{ time }}
|
||||
{% endblocktrans %}
|
||||
{% endwith %}
|
||||
</span>
|
||||
{% else %}
|
||||
<span data-time="{{ ev.date_admission.isoformat }}" data-timezone="{{ request.event.timezone }}">
|
||||
{% with datetime_human=ev.date_admission|date:"SHORT_DATETIME_FORMAT" datetime_iso=ev.date_admission|time:"Y-m-d H:i" %}
|
||||
{% blocktrans trimmed with datetime='<time datetime="'|add:datetime_iso|add:'">'|add:datetime_human|add:"</time>"|safe %}
|
||||
Admission: {{ datetime }}
|
||||
{% endblocktrans %}
|
||||
{% endwith %}
|
||||
</span>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
<br>
|
||||
{% if subevent %}
|
||||
<a href="{% eventurl event "presale:event.ical.download" subevent=subevent.pk %}">
|
||||
{% else %}
|
||||
<a href="{% eventurl event "presale:event.ical.download" %}">
|
||||
{% endif %}
|
||||
{% trans "Add to Calendar" %}
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
||||
{% eventsignal event "pretix.presale.signals.front_page_top" request=request subevent=subevent %}
|
||||
{% endif %}
|
||||
|
||||
|
||||
@@ -13,28 +13,63 @@
|
||||
{% include "pretixpresale/event/fragment_cart_box.html" with open=request.GET.show_cart %}
|
||||
{% endif %}
|
||||
|
||||
<h2>{% trans "Voucher redemption" %}</h2>
|
||||
|
||||
{% if subevent %}
|
||||
<h2>{% trans "Voucher redemption" %}</h2>
|
||||
{% if request.GET.subevent and subevent.pk|stringformat:"i" != request.GET.subevent %}
|
||||
<div class="alert alert-warning">
|
||||
{% trans "This voucher is valid only for the following specific date and time." %}
|
||||
</div>
|
||||
{% endif %}
|
||||
<h3>{{ subevent.name }}</h3>
|
||||
{% include "pretixpresale/event/fragment_event_info.html" with event=request.event subevent=subevent ev=subevent show_location=True %}
|
||||
{% else %}
|
||||
{% if event_logo and event_logo_show_title %}
|
||||
<h2 class="content-header">
|
||||
{{ event.name }}
|
||||
{% if request.event.settings.show_dates_on_frontpage %}
|
||||
<small>{{ event.get_date_range_display_as_html }}</small>
|
||||
{% endif %}
|
||||
</h2>
|
||||
{% include "pretixpresale/event/fragment_event_info.html" with event=request.event subevent=None ev=request.event show_location=True %}
|
||||
<h3>{% trans "Voucher redemption" %}</h3>
|
||||
{% else %}
|
||||
<h2>{% trans "Voucher redemption" %}</h2>
|
||||
{% endif %}
|
||||
{% with ev=subevent %}
|
||||
<div class="info-row">
|
||||
<span class="fa fa-clock-o fa-fw" aria-hidden="true"></span>
|
||||
<p>
|
||||
{{ ev.get_date_range_display_as_html }}
|
||||
{% if event.settings.show_times %}
|
||||
<br>
|
||||
{% with time_human=ev.date_from|date:"TIME_FORMAT" time_24=ev.date_from|time:"H:i" %}
|
||||
{% blocktrans trimmed with time='<time datetime="'|add:time_24|add:'">'|add:time_human|add:"</time>"|safe %}
|
||||
Begin: {{ time }}
|
||||
{% endblocktrans %}
|
||||
{% endwith %}
|
||||
{% if event.settings.show_date_to and ev.date_to %}
|
||||
<br>
|
||||
{% with time_human=ev.date_to|date:"TIME_FORMAT" time_24=ev.date_to|time:"H:i" %}
|
||||
{% blocktrans trimmed with time='<time datetime="'|add:time_24|add:'">'|add:time_human|add:"</time>"|safe %}
|
||||
End: {{ time }}
|
||||
{% endblocktrans %}
|
||||
{% endwith %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if ev.date_admission %}
|
||||
<br>
|
||||
{% if ev.date_admission|date:"SHORT_DATE_FORMAT" == ev.date_from|date:"SHORT_DATE_FORMAT" %}
|
||||
{% with time_human=ev.date_admission|date:"TIME_FORMAT" time_24=ev.date_admission|time:"H:i" %}
|
||||
{% blocktrans trimmed with time='<time datetime="'|add:time_24|add:'">'|add:time_human|add:"</time>"|safe %}
|
||||
Admission: {{ time }}
|
||||
{% endblocktrans %}
|
||||
{% endwith %}
|
||||
{% else %}
|
||||
{% with datetime_human=ev.date_admission|date:"SHORT_DATETIME_FORMAT" datetime_iso=ev.date_admission|time:"Y-m-d H:i" %}
|
||||
{% blocktrans trimmed with datetime='<time datetime="'|add:datetime_iso|add:'">'|add:datetime_human|add:"</time>"|safe %}
|
||||
Admission: {{ datetime }}
|
||||
{% endblocktrans %}
|
||||
{% endwith %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
<br>
|
||||
{% if subevent %}
|
||||
<a href="{% eventurl event "presale:event.ical.download" subevent=subevent.pk %}">
|
||||
{% else %}
|
||||
<a href="{% eventurl event "presale:event.ical.download" %}">
|
||||
{% endif %}
|
||||
{% trans "Add to Calendar" %}
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
{% endwith %}
|
||||
{% endif %}
|
||||
|
||||
<p>
|
||||
|
||||
@@ -188,13 +188,13 @@ if SITE_URL.endswith('/'):
|
||||
|
||||
CSRF_TRUSTED_ORIGINS = [urlparse(SITE_URL).scheme + '://' + urlparse(SITE_URL).hostname]
|
||||
|
||||
TRUST_X_FORWARDED_FOR = config.get('pretix', 'trust_x_forwarded_for', fallback=False)
|
||||
USE_X_FORWARDED_HOST = config.get('pretix', 'trust_x_forwarded_host', fallback=False)
|
||||
TRUST_X_FORWARDED_FOR = config.getboolean('pretix', 'trust_x_forwarded_for', fallback=False)
|
||||
USE_X_FORWARDED_HOST = config.getboolean('pretix', 'trust_x_forwarded_host', fallback=False)
|
||||
|
||||
|
||||
REQUEST_ID_HEADER = config.get('pretix', 'request_id_header', fallback=False)
|
||||
|
||||
if config.get('pretix', 'trust_x_forwarded_proto', fallback=False):
|
||||
if config.getboolean('pretix', 'trust_x_forwarded_proto', fallback=False):
|
||||
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
|
||||
|
||||
PRETIX_PLUGINS_DEFAULT = config.get('pretix', 'plugins_default',
|
||||
@@ -733,4 +733,5 @@ FILE_UPLOAD_MAX_SIZE_EMAIL_ATTACHMENT = 1024 * 1024 * config.getint("pretix_file
|
||||
FILE_UPLOAD_MAX_SIZE_EMAIL_AUTO_ATTACHMENT = 1024 * 1024 * config.getint("pretix_file_upload", "max_size_email_auto_attachment", fallback=1)
|
||||
FILE_UPLOAD_MAX_SIZE_OTHER = 1024 * 1024 * config.getint("pretix_file_upload", "max_size_other", fallback=10)
|
||||
|
||||
|
||||
DEFAULT_AUTO_FIELD = 'django.db.models.AutoField' # sadly. we would prefer BigInt, and should use it for all new models but the migration will be hard
|
||||
|
||||
@@ -80,15 +80,7 @@
|
||||
"DATE_INPUT_FORMATS": [
|
||||
"%Y-%m-%d",
|
||||
"%m/%d/%Y",
|
||||
"%m/%d/%y",
|
||||
"%b %d %Y",
|
||||
"%b %d, %Y",
|
||||
"%d %b %Y",
|
||||
"%d %b, %Y",
|
||||
"%B %d %Y",
|
||||
"%B %d, %Y",
|
||||
"%d %B %Y",
|
||||
"%d %B, %Y"
|
||||
"%m/%d/%y"
|
||||
],
|
||||
"DECIMAL_SEPARATOR": ".",
|
||||
"FIRST_DAY_OF_WEEK": 0,
|
||||
|
||||
135
src/pretix/static/npm_dir/package-lock.json
generated
135
src/pretix/static/npm_dir/package-lock.json
generated
@@ -8,7 +8,7 @@
|
||||
"name": "pretix",
|
||||
"version": "0.0.0",
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.22.9",
|
||||
"@babel/core": "^7.22.5",
|
||||
"@babel/preset-env": "^7.22.9",
|
||||
"@rollup/plugin-babel": "^6.0.3",
|
||||
"@rollup/plugin-node-resolve": "^15.1.0",
|
||||
@@ -50,25 +50,25 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/core": {
|
||||
"version": "7.22.9",
|
||||
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.9.tgz",
|
||||
"integrity": "sha512-G2EgeufBcYw27U4hhoIwFcgc1XU7TlXJ3mv04oOv1WCuo900U/anZSPzEqNjwdjgffkk2Gs0AN0dW1CKVLcG7w==",
|
||||
"version": "7.22.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.5.tgz",
|
||||
"integrity": "sha512-SBuTAjg91A3eKOvD+bPEz3LlhHZRNu1nFOVts9lzDJTXshHTjII0BAtDS3Y2DAkdZdDKWVZGVwkDfc4Clxn1dg==",
|
||||
"dependencies": {
|
||||
"@ampproject/remapping": "^2.2.0",
|
||||
"@babel/code-frame": "^7.22.5",
|
||||
"@babel/generator": "^7.22.9",
|
||||
"@babel/helper-compilation-targets": "^7.22.9",
|
||||
"@babel/helper-module-transforms": "^7.22.9",
|
||||
"@babel/helpers": "^7.22.6",
|
||||
"@babel/parser": "^7.22.7",
|
||||
"@babel/generator": "^7.22.5",
|
||||
"@babel/helper-compilation-targets": "^7.22.5",
|
||||
"@babel/helper-module-transforms": "^7.22.5",
|
||||
"@babel/helpers": "^7.22.5",
|
||||
"@babel/parser": "^7.22.5",
|
||||
"@babel/template": "^7.22.5",
|
||||
"@babel/traverse": "^7.22.8",
|
||||
"@babel/traverse": "^7.22.5",
|
||||
"@babel/types": "^7.22.5",
|
||||
"convert-source-map": "^1.7.0",
|
||||
"debug": "^4.1.0",
|
||||
"gensync": "^1.0.0-beta.2",
|
||||
"json5": "^2.2.2",
|
||||
"semver": "^6.3.1"
|
||||
"semver": "^6.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -98,9 +98,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/generator": {
|
||||
"version": "7.22.9",
|
||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.9.tgz",
|
||||
"integrity": "sha512-KtLMbmicyuK2Ak/FTCJVbDnkN1SlT8/kceFTiuDiiRUUSMnHMidxSCdG4ndkTOHHpoomWe/4xkvHkEOncwjYIw==",
|
||||
"version": "7.22.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.5.tgz",
|
||||
"integrity": "sha512-+lcUbnTRhd0jOewtFSedLyiPsD5tswKkbgcezOqqWFUVNEwoUTlpPOBmvhG7OXWLR4jMdv0czPGH5XbflnD1EA==",
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.22.5",
|
||||
"@jridgewell/gen-mapping": "^0.3.2",
|
||||
@@ -308,21 +308,21 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-module-transforms": {
|
||||
"version": "7.22.9",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.22.9.tgz",
|
||||
"integrity": "sha512-t+WA2Xn5K+rTeGtC8jCsdAH52bjggG5TKRuRrAGNM/mjIbO4GxvlLMFOEz9wXY5I2XQ60PMFsAG2WIcG82dQMQ==",
|
||||
"version": "7.22.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.22.5.tgz",
|
||||
"integrity": "sha512-+hGKDt/Ze8GFExiVHno/2dvG5IdstpzCq0y4Qc9OJ25D4q3pKfiIP/4Vp3/JvhDkLKsDK2api3q3fpIgiIF5bw==",
|
||||
"dependencies": {
|
||||
"@babel/helper-environment-visitor": "^7.22.5",
|
||||
"@babel/helper-module-imports": "^7.22.5",
|
||||
"@babel/helper-simple-access": "^7.22.5",
|
||||
"@babel/helper-split-export-declaration": "^7.22.6",
|
||||
"@babel/helper-validator-identifier": "^7.22.5"
|
||||
"@babel/helper-split-export-declaration": "^7.22.5",
|
||||
"@babel/helper-validator-identifier": "^7.22.5",
|
||||
"@babel/template": "^7.22.5",
|
||||
"@babel/traverse": "^7.22.5",
|
||||
"@babel/types": "^7.22.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@babel/core": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-optimise-call-expression": {
|
||||
@@ -447,12 +447,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helpers": {
|
||||
"version": "7.22.6",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.6.tgz",
|
||||
"integrity": "sha512-YjDs6y/fVOYFV8hAf1rxd1QvR9wJe1pDBZ2AREKq/SDayfPzgk0PBnVuTCE5X1acEpMMNOVUqoe+OwiZGJ+OaA==",
|
||||
"version": "7.22.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.5.tgz",
|
||||
"integrity": "sha512-pSXRmfE1vzcUIDFQcSGA5Mr+GxBV9oiRKDuDxXvWQQBCh8HoIjs/2DlDB7H8smac1IVrB9/xdXj2N3Wol9Cr+Q==",
|
||||
"dependencies": {
|
||||
"@babel/template": "^7.22.5",
|
||||
"@babel/traverse": "^7.22.6",
|
||||
"@babel/traverse": "^7.22.5",
|
||||
"@babel/types": "^7.22.5"
|
||||
},
|
||||
"engines": {
|
||||
@@ -473,9 +473,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/parser": {
|
||||
"version": "7.22.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.7.tgz",
|
||||
"integrity": "sha512-7NF8pOkHP5o2vpmGgNGcfAeCvOYhGLyA3Z4eBQkT1RJlWu47n63bCs93QfJ2hIAFCil7L5P2IWhs1oToVgrL0Q==",
|
||||
"version": "7.22.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.5.tgz",
|
||||
"integrity": "sha512-DFZMC9LJUG9PLOclRC32G63UXwzqS2koQC8dkx+PLdmt1xSePYpbT/NbsrJy8Q/muXz7o/h/d4A7Fuyixm559Q==",
|
||||
"bin": {
|
||||
"parser": "bin/babel-parser.js"
|
||||
},
|
||||
@@ -1631,17 +1631,17 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/traverse": {
|
||||
"version": "7.22.8",
|
||||
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.8.tgz",
|
||||
"integrity": "sha512-y6LPR+wpM2I3qJrsheCTwhIinzkETbplIgPBbwvqPKc+uljeA5gP+3nP8irdYt1mjQaDnlIcG+dw8OjAco4GXw==",
|
||||
"version": "7.22.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.5.tgz",
|
||||
"integrity": "sha512-7DuIjPgERaNo6r+PZwItpjCZEa5vyw4eJGufeLxrPdBXBoLcCJCIasvK6pK/9DVNrLZTLFhUGqaC6X/PA007TQ==",
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.22.5",
|
||||
"@babel/generator": "^7.22.7",
|
||||
"@babel/generator": "^7.22.5",
|
||||
"@babel/helper-environment-visitor": "^7.22.5",
|
||||
"@babel/helper-function-name": "^7.22.5",
|
||||
"@babel/helper-hoist-variables": "^7.22.5",
|
||||
"@babel/helper-split-export-declaration": "^7.22.6",
|
||||
"@babel/parser": "^7.22.7",
|
||||
"@babel/helper-split-export-declaration": "^7.22.5",
|
||||
"@babel/parser": "^7.22.5",
|
||||
"@babel/types": "^7.22.5",
|
||||
"debug": "^4.1.0",
|
||||
"globals": "^11.1.0"
|
||||
@@ -4160,25 +4160,25 @@
|
||||
"integrity": "sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ=="
|
||||
},
|
||||
"@babel/core": {
|
||||
"version": "7.22.9",
|
||||
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.9.tgz",
|
||||
"integrity": "sha512-G2EgeufBcYw27U4hhoIwFcgc1XU7TlXJ3mv04oOv1WCuo900U/anZSPzEqNjwdjgffkk2Gs0AN0dW1CKVLcG7w==",
|
||||
"version": "7.22.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.5.tgz",
|
||||
"integrity": "sha512-SBuTAjg91A3eKOvD+bPEz3LlhHZRNu1nFOVts9lzDJTXshHTjII0BAtDS3Y2DAkdZdDKWVZGVwkDfc4Clxn1dg==",
|
||||
"requires": {
|
||||
"@ampproject/remapping": "^2.2.0",
|
||||
"@babel/code-frame": "^7.22.5",
|
||||
"@babel/generator": "^7.22.9",
|
||||
"@babel/helper-compilation-targets": "^7.22.9",
|
||||
"@babel/helper-module-transforms": "^7.22.9",
|
||||
"@babel/helpers": "^7.22.6",
|
||||
"@babel/parser": "^7.22.7",
|
||||
"@babel/generator": "^7.22.5",
|
||||
"@babel/helper-compilation-targets": "^7.22.5",
|
||||
"@babel/helper-module-transforms": "^7.22.5",
|
||||
"@babel/helpers": "^7.22.5",
|
||||
"@babel/parser": "^7.22.5",
|
||||
"@babel/template": "^7.22.5",
|
||||
"@babel/traverse": "^7.22.8",
|
||||
"@babel/traverse": "^7.22.5",
|
||||
"@babel/types": "^7.22.5",
|
||||
"convert-source-map": "^1.7.0",
|
||||
"debug": "^4.1.0",
|
||||
"gensync": "^1.0.0-beta.2",
|
||||
"json5": "^2.2.2",
|
||||
"semver": "^6.3.1"
|
||||
"semver": "^6.3.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"json5": {
|
||||
@@ -4194,9 +4194,9 @@
|
||||
}
|
||||
},
|
||||
"@babel/generator": {
|
||||
"version": "7.22.9",
|
||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.9.tgz",
|
||||
"integrity": "sha512-KtLMbmicyuK2Ak/FTCJVbDnkN1SlT8/kceFTiuDiiRUUSMnHMidxSCdG4ndkTOHHpoomWe/4xkvHkEOncwjYIw==",
|
||||
"version": "7.22.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.5.tgz",
|
||||
"integrity": "sha512-+lcUbnTRhd0jOewtFSedLyiPsD5tswKkbgcezOqqWFUVNEwoUTlpPOBmvhG7OXWLR4jMdv0czPGH5XbflnD1EA==",
|
||||
"requires": {
|
||||
"@babel/types": "^7.22.5",
|
||||
"@jridgewell/gen-mapping": "^0.3.2",
|
||||
@@ -4355,15 +4355,18 @@
|
||||
}
|
||||
},
|
||||
"@babel/helper-module-transforms": {
|
||||
"version": "7.22.9",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.22.9.tgz",
|
||||
"integrity": "sha512-t+WA2Xn5K+rTeGtC8jCsdAH52bjggG5TKRuRrAGNM/mjIbO4GxvlLMFOEz9wXY5I2XQ60PMFsAG2WIcG82dQMQ==",
|
||||
"version": "7.22.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.22.5.tgz",
|
||||
"integrity": "sha512-+hGKDt/Ze8GFExiVHno/2dvG5IdstpzCq0y4Qc9OJ25D4q3pKfiIP/4Vp3/JvhDkLKsDK2api3q3fpIgiIF5bw==",
|
||||
"requires": {
|
||||
"@babel/helper-environment-visitor": "^7.22.5",
|
||||
"@babel/helper-module-imports": "^7.22.5",
|
||||
"@babel/helper-simple-access": "^7.22.5",
|
||||
"@babel/helper-split-export-declaration": "^7.22.6",
|
||||
"@babel/helper-validator-identifier": "^7.22.5"
|
||||
"@babel/helper-split-export-declaration": "^7.22.5",
|
||||
"@babel/helper-validator-identifier": "^7.22.5",
|
||||
"@babel/template": "^7.22.5",
|
||||
"@babel/traverse": "^7.22.5",
|
||||
"@babel/types": "^7.22.5"
|
||||
}
|
||||
},
|
||||
"@babel/helper-optimise-call-expression": {
|
||||
@@ -4449,12 +4452,12 @@
|
||||
}
|
||||
},
|
||||
"@babel/helpers": {
|
||||
"version": "7.22.6",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.6.tgz",
|
||||
"integrity": "sha512-YjDs6y/fVOYFV8hAf1rxd1QvR9wJe1pDBZ2AREKq/SDayfPzgk0PBnVuTCE5X1acEpMMNOVUqoe+OwiZGJ+OaA==",
|
||||
"version": "7.22.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.5.tgz",
|
||||
"integrity": "sha512-pSXRmfE1vzcUIDFQcSGA5Mr+GxBV9oiRKDuDxXvWQQBCh8HoIjs/2DlDB7H8smac1IVrB9/xdXj2N3Wol9Cr+Q==",
|
||||
"requires": {
|
||||
"@babel/template": "^7.22.5",
|
||||
"@babel/traverse": "^7.22.6",
|
||||
"@babel/traverse": "^7.22.5",
|
||||
"@babel/types": "^7.22.5"
|
||||
}
|
||||
},
|
||||
@@ -4469,9 +4472,9 @@
|
||||
}
|
||||
},
|
||||
"@babel/parser": {
|
||||
"version": "7.22.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.7.tgz",
|
||||
"integrity": "sha512-7NF8pOkHP5o2vpmGgNGcfAeCvOYhGLyA3Z4eBQkT1RJlWu47n63bCs93QfJ2hIAFCil7L5P2IWhs1oToVgrL0Q=="
|
||||
"version": "7.22.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.5.tgz",
|
||||
"integrity": "sha512-DFZMC9LJUG9PLOclRC32G63UXwzqS2koQC8dkx+PLdmt1xSePYpbT/NbsrJy8Q/muXz7o/h/d4A7Fuyixm559Q=="
|
||||
},
|
||||
"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": {
|
||||
"version": "7.22.5",
|
||||
@@ -5224,17 +5227,17 @@
|
||||
}
|
||||
},
|
||||
"@babel/traverse": {
|
||||
"version": "7.22.8",
|
||||
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.8.tgz",
|
||||
"integrity": "sha512-y6LPR+wpM2I3qJrsheCTwhIinzkETbplIgPBbwvqPKc+uljeA5gP+3nP8irdYt1mjQaDnlIcG+dw8OjAco4GXw==",
|
||||
"version": "7.22.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.5.tgz",
|
||||
"integrity": "sha512-7DuIjPgERaNo6r+PZwItpjCZEa5vyw4eJGufeLxrPdBXBoLcCJCIasvK6pK/9DVNrLZTLFhUGqaC6X/PA007TQ==",
|
||||
"requires": {
|
||||
"@babel/code-frame": "^7.22.5",
|
||||
"@babel/generator": "^7.22.7",
|
||||
"@babel/generator": "^7.22.5",
|
||||
"@babel/helper-environment-visitor": "^7.22.5",
|
||||
"@babel/helper-function-name": "^7.22.5",
|
||||
"@babel/helper-hoist-variables": "^7.22.5",
|
||||
"@babel/helper-split-export-declaration": "^7.22.6",
|
||||
"@babel/parser": "^7.22.7",
|
||||
"@babel/helper-split-export-declaration": "^7.22.5",
|
||||
"@babel/parser": "^7.22.5",
|
||||
"@babel/types": "^7.22.5",
|
||||
"debug": "^4.1.0",
|
||||
"globals": "^11.1.0"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"private": true,
|
||||
"scripts": {},
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.22.9",
|
||||
"@babel/core": "^7.22.5",
|
||||
"@babel/preset-env": "^7.22.9",
|
||||
"@rollup/plugin-babel": "^6.0.3",
|
||||
"@rollup/plugin-node-resolve": "^15.1.0",
|
||||
|
||||
@@ -4,20 +4,9 @@ setup_collapsible_details = function (el) {
|
||||
|
||||
el.find('details.sneak-peek:not([open])').each(function() {
|
||||
this.open = true;
|
||||
var $elements = $("> :not(summary)", this).show().filter(':not(.sneak-peek-trigger)');
|
||||
var $elements = $("> :not(summary)", this).show().filter(':not(.sneak-peek-trigger)').attr('aria-hidden', 'true');
|
||||
|
||||
var container = this;
|
||||
|
||||
if (Array.prototype.reduce.call($elements, function (h, e) {
|
||||
return h + $(e).outerHeight();
|
||||
}, 0) < 200) {
|
||||
$(".sneak-peek-trigger", this).remove();
|
||||
$(container).removeClass('sneak-peek');
|
||||
container.style.removeProperty('height');
|
||||
return;
|
||||
}
|
||||
|
||||
$elements.attr('aria-hidden', 'true');
|
||||
|
||||
var trigger = $('summary, .sneak-peek-trigger button', container);
|
||||
function onclick(e) {
|
||||
e.preventDefault();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*global $,u2f */
|
||||
$(function () {
|
||||
$('.sidebar .dropdown, ul.navbar-nav .dropdown, .navbar-events-collapse').on('shown.bs.collapse shown.bs.dropdown', function () {
|
||||
$(this).parent().find("input").val("").trigger('forceRunQuery').focus();
|
||||
$(this).parent().find("input").val("").change().focus();
|
||||
});
|
||||
$('.dropdown-menu .form-box input').click(function (e) {
|
||||
e.stopPropagation();
|
||||
@@ -11,22 +11,11 @@ $(function () {
|
||||
var $container = $(this);
|
||||
var $query = $(this).find('[data-typeahead-query]').length ? $(this).find('[data-typeahead-query]') : $($(this).attr("data-typeahead-field"));
|
||||
$container.find("li:not(.query-holder)").remove();
|
||||
var lastQuery = null;
|
||||
var lastQuery = "";
|
||||
var runQueryTimeout = null;
|
||||
var loadIndicatorTimeout = null;
|
||||
function showLoadIndicator() {
|
||||
$container.find("li:not(.query-holder)").remove();
|
||||
$container.append("<li class='loading'><span class='fa fa-4x fa-cog fa-spin'></span></li>");
|
||||
$container.toggleClass('focused', $query.is(":focus") && $container.children().length > 0);
|
||||
}
|
||||
function runQuery() {
|
||||
var thisQuery = $query.val();
|
||||
if (thisQuery === lastQuery) return;
|
||||
lastQuery = $query.val();
|
||||
|
||||
window.clearTimeout(loadIndicatorTimeout)
|
||||
loadIndicatorTimeout = window.setTimeout(showLoadIndicator, 80)
|
||||
|
||||
var thisQuery = $query.val();
|
||||
$.getJSON(
|
||||
$container.attr("data-source") + "?query=" + encodeURIComponent($query.val()) + (typeof $container.attr("data-organizer") !== "undefined" ? "&organizer=" + $container.attr("data-organizer") : ""),
|
||||
function (data) {
|
||||
@@ -34,74 +23,107 @@ $(function () {
|
||||
// Lost race condition
|
||||
return;
|
||||
}
|
||||
window.clearTimeout(loadIndicatorTimeout);
|
||||
$container.find("li:not(.query-holder)").remove();
|
||||
$.each(data.results, function (i, res) {
|
||||
let $linkContent = $("<div>");
|
||||
if (res.type === "organizer") {
|
||||
$linkContent.append(
|
||||
$("<span>").addClass("event-name-full").append(
|
||||
$("<span>").addClass("fa fa-users fa-fw")
|
||||
).append(" ").append($("<div>").text(res.name).html())
|
||||
)
|
||||
$container.append(
|
||||
$("<li>").append(
|
||||
$("<a>").attr("href", res.url).append(
|
||||
$("<div>").append(
|
||||
$("<span>").addClass("event-name-full").append(
|
||||
$("<span>").addClass("fa fa-users fa-fw")
|
||||
).append(" ").append($("<div>").text(res.name).html())
|
||||
)
|
||||
).on("mousedown", function (event) {
|
||||
if ($(this).length) {
|
||||
location.href = $(this).attr("href");
|
||||
}
|
||||
$(this).parent().addClass("active");
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
})
|
||||
)
|
||||
);
|
||||
} else if (res.type === "order" || res.type === "voucher") {
|
||||
$linkContent.append(
|
||||
$("<span>").addClass("event-name-full").append($("<div>").text(res.title).html())
|
||||
).append(
|
||||
$("<span>").addClass("event-organizer").append(
|
||||
$("<span>").addClass("fa fa-calendar fa-fw")
|
||||
).append(" ").append($("<div>").text(res.event).html())
|
||||
)
|
||||
$container.append(
|
||||
$("<li>").append(
|
||||
$("<a>").attr("href", res.url).append(
|
||||
$("<div>").append(
|
||||
$("<span>").addClass("event-name-full").append($("<div>").text(res.title).html())
|
||||
).append(
|
||||
$("<span>").addClass("event-organizer").append(
|
||||
$("<span>").addClass("fa fa-calendar fa-fw")
|
||||
).append(" ").append($("<div>").text(res.event).html())
|
||||
)
|
||||
).on("mousedown", function (event) {
|
||||
if ($(this).length) {
|
||||
location.href = $(this).attr("href");
|
||||
}
|
||||
$(this).parent().addClass("active");
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
})
|
||||
)
|
||||
);
|
||||
} else if (res.type === "user") {
|
||||
$linkContent.append(
|
||||
$("<span>").addClass("event-name-full").append(
|
||||
$("<span>").addClass("fa fa-user fa-fw")
|
||||
).append(" ").append($("<div>").text(res.name).html())
|
||||
)
|
||||
$container.append(
|
||||
$("<li>").append(
|
||||
$("<a>").attr("href", res.url).append(
|
||||
$("<div>").append(
|
||||
$("<span>").addClass("event-name-full").append(
|
||||
$("<span>").addClass("fa fa-user fa-fw")
|
||||
).append(" ").append($("<div>").text(res.name).html())
|
||||
)
|
||||
).on("mousedown", function (event) {
|
||||
if ($(this).length) {
|
||||
location.href = $(this).attr("href");
|
||||
}
|
||||
$(this).parent().addClass("active");
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
})
|
||||
)
|
||||
);
|
||||
} else {
|
||||
$linkContent.append(
|
||||
$("<span>").addClass("event-name-full").append($("<div>").text(res.name).html())
|
||||
).append(
|
||||
$("<span>").addClass("event-organizer").append(
|
||||
$("<span>").addClass("fa fa-users fa-fw")
|
||||
).append(" ").append($("<div>").text(res.organizer).html())
|
||||
).append(
|
||||
$("<span>").addClass("event-daterange").append(
|
||||
$("<span>").addClass("fa fa-calendar fa-fw")
|
||||
).append(" ").append(res.date_range)
|
||||
)
|
||||
$container.append(
|
||||
$("<li>").append(
|
||||
$("<a>").attr("href", res.url).append(
|
||||
$("<div>").append(
|
||||
$("<span>").addClass("event-name-full").append($("<div>").text(res.name).html())
|
||||
).append(
|
||||
$("<span>").addClass("event-organizer").append(
|
||||
$("<span>").addClass("fa fa-users fa-fw")
|
||||
).append(" ").append($("<div>").text(res.organizer).html())
|
||||
).append(
|
||||
$("<span>").addClass("event-daterange").append(
|
||||
$("<span>").addClass("fa fa-calendar fa-fw")
|
||||
).append(" ").append(res.date_range)
|
||||
)
|
||||
).on("mousedown", function (event) {
|
||||
if ($(this).length) {
|
||||
location.href = $(this).attr("href");
|
||||
}
|
||||
$(this).parent().addClass("active");
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$container.append(
|
||||
$("<li>").append(
|
||||
$("<a>").attr("href", res.url).append(
|
||||
$linkContent
|
||||
).on("mousedown", function (event) {
|
||||
if ($(this).length) {
|
||||
location.href = $(this).attr("href");
|
||||
}
|
||||
$(this).parent().addClass("active");
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
})
|
||||
)
|
||||
);
|
||||
});
|
||||
$container.toggleClass('focused', $query.is(":focus") && $container.children().length > 0);
|
||||
}
|
||||
);
|
||||
}
|
||||
$query.on("forceRunQuery", function () {
|
||||
runQuery();
|
||||
});
|
||||
$query.on("input", function () {
|
||||
$query.on("change", function () {
|
||||
if ($container.attr("data-typeahead-field") && $query.val() === "") {
|
||||
$container.removeClass('focused');
|
||||
$container.find("li:not(.query-holder)").remove();
|
||||
lastQuery = null;
|
||||
return;
|
||||
}
|
||||
window.clearTimeout(runQueryTimeout)
|
||||
if (runQueryTimeout != null) {
|
||||
window.clearTimeout(runQueryTimeout)
|
||||
}
|
||||
runQueryTimeout = window.setTimeout(runQuery, 250)
|
||||
});
|
||||
$query.on("keydown", function (event) {
|
||||
@@ -155,6 +177,8 @@ $(function () {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
return true;
|
||||
} else {
|
||||
$(this).change();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -243,7 +243,7 @@ div.mail-preview {
|
||||
}
|
||||
}
|
||||
.input-group-btn .btn {
|
||||
padding-bottom: 8px;
|
||||
padding-bottom: 7px;
|
||||
}
|
||||
.reldatetime {
|
||||
input[type=text], select {
|
||||
|
||||
@@ -412,11 +412,6 @@ body.loading #wrapper {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
.loading {
|
||||
padding: 10px;
|
||||
text-align: center;
|
||||
color: lightgrey;
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar-content {
|
||||
|
||||
@@ -54,10 +54,10 @@ $(function () {
|
||||
|
||||
wallets.forEach(function(wallet) {
|
||||
const labels = $('[data-wallets*='+wallet+'] + label strong, [data-wallets*='+wallet+'] + strong')
|
||||
.append('<span class="wallet wallet-loading" data-wallet="'+wallet+'"> <i aria-hidden="true" class="fa fa-cog fa-spin"></i></span>')
|
||||
.append('<span class="wallet wallet-loading"> <i aria-hidden="true" class="fa fa-cog fa-spin"></i></span>')
|
||||
walletdetection[wallet]()
|
||||
.then(function(result) {
|
||||
const spans = labels.find(".wallet-loading[data-wallet=" + wallet + "]");
|
||||
const spans = labels.find(".wallet-loading:nth-of-type(1)");
|
||||
if (result) {
|
||||
spans.removeClass('wallet-loading').hide().text(', ' + walletdetection.name_map[wallet]).fadeIn(300);
|
||||
} else {
|
||||
@@ -65,7 +65,7 @@ $(function () {
|
||||
}
|
||||
})
|
||||
.catch(function(result) {
|
||||
labels.find(".wallet-loading[data-wallet=" + wallet + "]").remove();
|
||||
labels.find(".wallet-loading:nth-of-type(1)").remove();
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
@@ -42,7 +42,7 @@ EMAIL_BACKEND = EMAIL_CUSTOM_SMTP_BACKEND = 'django.core.mail.backends.locmem.Em
|
||||
|
||||
COMPRESS_ENABLED = COMPRESS_OFFLINE = False
|
||||
COMPRESS_CACHE_BACKEND = 'testcache'
|
||||
STORAGES["staticfiles"]["BACKEND"] = 'django.contrib.staticfiles.storage.StaticFilesStorage'
|
||||
STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.StaticFilesStorage'
|
||||
PRETIX_INSTANCE_NAME = 'pretix.eu'
|
||||
|
||||
COMPRESS_PRECOMPILERS_ORIGINAL = COMPRESS_PRECOMPILERS
|
||||
|
||||
@@ -21,8 +21,6 @@ addopts = --reruns 3 -rw
|
||||
filterwarnings =
|
||||
error
|
||||
ignore:The 'warn' method is deprecated:DeprecationWarning
|
||||
ignore::django.utils.deprecation.RemovedInDjango51Warning:django.core.files.storage
|
||||
ignore:.*index_together.*:django.utils.deprecation.RemovedInDjango51Warning:
|
||||
ignore::DeprecationWarning:mt940
|
||||
ignore::DeprecationWarning:cbor2
|
||||
ignore::DeprecationWarning:markdown
|
||||
|
||||
@@ -1794,8 +1794,6 @@ def test_pdf_data(token_client, organizer, event, order, django_assert_max_num_q
|
||||
))
|
||||
assert resp.status_code == 200
|
||||
assert resp.data['positions'][0].get('pdf_data')
|
||||
assert resp.data['positions'][0]['pdf_data']['positionid'] == '1'
|
||||
assert resp.data['positions'][0]['pdf_data']['order'] == order.code
|
||||
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/{}/'.format(
|
||||
organizer.slug, event.slug, order.code
|
||||
))
|
||||
@@ -1809,8 +1807,6 @@ def test_pdf_data(token_client, organizer, event, order, django_assert_max_num_q
|
||||
))
|
||||
assert resp.status_code == 200
|
||||
assert resp.data['results'][0]['positions'][0].get('pdf_data')
|
||||
assert resp.data['results'][0]['positions'][0]['pdf_data']['positionid'] == '1'
|
||||
assert resp.data['results'][0]['positions'][0]['pdf_data']['order'] == order.code
|
||||
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/'.format(
|
||||
organizer.slug, event.slug
|
||||
))
|
||||
@@ -1824,8 +1820,6 @@ def test_pdf_data(token_client, organizer, event, order, django_assert_max_num_q
|
||||
))
|
||||
assert resp.status_code == 200
|
||||
assert resp.data['results'][0].get('pdf_data')
|
||||
assert resp.data['results'][0]['pdf_data']['positionid'] == '1'
|
||||
assert resp.data['results'][0]['pdf_data']['order'] == order.code
|
||||
resp = token_client.get('/api/v1/organizers/{}/events/{}/orderpositions/'.format(
|
||||
organizer.slug, event.slug
|
||||
))
|
||||
@@ -1840,8 +1834,6 @@ def test_pdf_data(token_client, organizer, event, order, django_assert_max_num_q
|
||||
))
|
||||
assert resp.status_code == 200
|
||||
assert resp.data.get('pdf_data')
|
||||
assert resp.data['pdf_data']['positionid'] == '1'
|
||||
assert resp.data['pdf_data']['order'] == order.code
|
||||
resp = token_client.get('/api/v1/organizers/{}/events/{}/orderpositions/{}/'.format(
|
||||
organizer.slug, event.slug, posid
|
||||
))
|
||||
|
||||
@@ -940,8 +940,8 @@ def test_rules_reasoning_prefer_number_over_date(event, position, clist):
|
||||
|
||||
|
||||
@pytest.mark.django_db(transaction=True)
|
||||
def test_position_queries(django_assert_max_num_queries, position, clist):
|
||||
with django_assert_max_num_queries(13) as captured:
|
||||
def test_position_queries(django_assert_num_queries, position, clist):
|
||||
with django_assert_num_queries(12 if 'sqlite' in settings.DATABASES['default']['ENGINE'] else 11) as captured:
|
||||
perform_checkin(position, clist, {})
|
||||
if 'sqlite' not in settings.DATABASES['default']['ENGINE']:
|
||||
assert any('FOR UPDATE' in s['sql'] for s in captured)
|
||||
|
||||
@@ -38,10 +38,10 @@ class I18nStringTest(TestCase):
|
||||
'en': 'Hello'
|
||||
}
|
||||
s = LazyI18nString(data)
|
||||
with translation.override('en'):
|
||||
self.assertEqual(str(s), 'Hello')
|
||||
with translation.override('de'):
|
||||
self.assertEqual(str(s), 'Hallo')
|
||||
translation.activate('en')
|
||||
self.assertEqual(str(s), 'Hello')
|
||||
translation.activate('de')
|
||||
self.assertEqual(str(s), 'Hallo')
|
||||
|
||||
def test_similar_translations(self):
|
||||
data = {
|
||||
@@ -50,57 +50,57 @@ class I18nStringTest(TestCase):
|
||||
'de-informal': 'Du'
|
||||
}
|
||||
s = LazyI18nString(data)
|
||||
with translation.override('de'):
|
||||
self.assertEqual(str(s), 'Sie')
|
||||
with translation.override('de-informal'):
|
||||
self.assertEqual(str(s), 'Du')
|
||||
translation.activate('de')
|
||||
self.assertEqual(str(s), 'Sie')
|
||||
translation.activate('de-informal')
|
||||
self.assertEqual(str(s), 'Du')
|
||||
|
||||
data = {
|
||||
'en': 'You',
|
||||
'de-informal': 'Du'
|
||||
}
|
||||
s = LazyI18nString(data)
|
||||
with translation.override('de'):
|
||||
self.assertEqual(str(s), 'Du')
|
||||
with translation.override('de-informal'):
|
||||
self.assertEqual(str(s), 'Du')
|
||||
translation.activate('de')
|
||||
self.assertEqual(str(s), 'Du')
|
||||
translation.activate('de-informal')
|
||||
self.assertEqual(str(s), 'Du')
|
||||
|
||||
data = {
|
||||
'en': 'You',
|
||||
'de': 'Sie'
|
||||
}
|
||||
s = LazyI18nString(data)
|
||||
with translation.override('de'):
|
||||
self.assertEqual(str(s), 'Sie')
|
||||
with translation.override('de-informal'):
|
||||
self.assertEqual(str(s), 'Sie')
|
||||
translation.activate('de')
|
||||
self.assertEqual(str(s), 'Sie')
|
||||
translation.activate('de-informal')
|
||||
self.assertEqual(str(s), 'Sie')
|
||||
|
||||
def test_missing_default_translation(self):
|
||||
data = {
|
||||
'de': 'Hallo',
|
||||
}
|
||||
s = LazyI18nString(data)
|
||||
with translation.override('en'):
|
||||
self.assertEqual(str(s), 'Hallo')
|
||||
with translation.override('de'):
|
||||
self.assertEqual(str(s), 'Hallo')
|
||||
translation.activate('en')
|
||||
self.assertEqual(str(s), 'Hallo')
|
||||
translation.activate('de')
|
||||
self.assertEqual(str(s), 'Hallo')
|
||||
|
||||
def test_missing_translation(self):
|
||||
data = {
|
||||
'en': 'Hello',
|
||||
}
|
||||
s = LazyI18nString(data)
|
||||
with translation.override('en'):
|
||||
self.assertEqual(str(s), 'Hello')
|
||||
with translation.override('de'):
|
||||
self.assertEqual(str(s), 'Hello')
|
||||
translation.activate('en')
|
||||
self.assertEqual(str(s), 'Hello')
|
||||
translation.activate('de')
|
||||
self.assertEqual(str(s), 'Hello')
|
||||
|
||||
def test_legacy_string(self):
|
||||
s = LazyI18nString("Hello")
|
||||
with translation.override('en'):
|
||||
self.assertEqual(str(s), 'Hello')
|
||||
with translation.override('de'):
|
||||
self.assertEqual(str(s), 'Hello')
|
||||
translation.activate('en')
|
||||
self.assertEqual(str(s), 'Hello')
|
||||
translation.activate('de')
|
||||
self.assertEqual(str(s), 'Hello')
|
||||
|
||||
def test_none(self):
|
||||
s = LazyI18nString(None)
|
||||
@@ -124,10 +124,10 @@ class I18nFieldTest(TestCase):
|
||||
obj = ItemCategory.objects.create(event=self.event, name="Hello")
|
||||
obj = ItemCategory.objects.get(id=obj.id)
|
||||
self.assertIsInstance(obj.name, LazyI18nString)
|
||||
with translation.override('en'):
|
||||
self.assertEqual(str(obj.name), "Hello")
|
||||
with translation.override('de'):
|
||||
self.assertEqual(str(obj.name), "Hello")
|
||||
translation.activate('en')
|
||||
self.assertEqual(str(obj.name), "Hello")
|
||||
translation.activate('de')
|
||||
self.assertEqual(str(obj.name), "Hello")
|
||||
|
||||
def test_save_load_cycle_i18n_string(self):
|
||||
obj = ItemCategory.objects.create(event=self.event,
|
||||
@@ -139,7 +139,7 @@ class I18nFieldTest(TestCase):
|
||||
))
|
||||
obj = ItemCategory.objects.get(id=obj.id)
|
||||
self.assertIsInstance(obj.name, LazyI18nString)
|
||||
with translation.override('en'):
|
||||
self.assertEqual(str(obj.name), "Hello")
|
||||
with translation.override('de'):
|
||||
self.assertEqual(str(obj.name), "Hallo")
|
||||
translation.activate('en')
|
||||
self.assertEqual(str(obj.name), "Hello")
|
||||
translation.activate('de')
|
||||
self.assertEqual(str(obj.name), "Hallo")
|
||||
|
||||
@@ -71,7 +71,6 @@ def inputfile_factory():
|
||||
'I': 'Foo',
|
||||
'J': '2021-06-28 11:00:00',
|
||||
'K': '06221/32177-50',
|
||||
'L': 'True'
|
||||
},
|
||||
{
|
||||
'A': 'Daniel',
|
||||
@@ -85,7 +84,6 @@ def inputfile_factory():
|
||||
'I': 'Bar',
|
||||
'J': '2021-06-28 11:00:00',
|
||||
'K': '+4962213217750',
|
||||
'L': 'False',
|
||||
},
|
||||
{},
|
||||
{
|
||||
@@ -100,11 +98,10 @@ def inputfile_factory():
|
||||
'I': 'Foo,Bar',
|
||||
'J': '2021-06-28 11:00:00',
|
||||
'K': '',
|
||||
'L': '',
|
||||
},
|
||||
]
|
||||
f = StringIO()
|
||||
w = csv.DictWriter(f, ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L'], dialect=csv.excel)
|
||||
w = csv.DictWriter(f, ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K'], dialect=csv.excel)
|
||||
w.writeheader()
|
||||
w.writerows(d)
|
||||
f.seek(0)
|
||||
@@ -798,37 +795,22 @@ def test_import_question_validate(user, event, item):
|
||||
@scopes_disabled()
|
||||
def test_import_question_valid(user, event, item):
|
||||
settings = dict(DEFAULT_SETTINGS)
|
||||
q1 = event.questions.create(question='Foo', type=Question.TYPE_CHOICE_MULTIPLE)
|
||||
o1 = q1.options.create(answer='Foo', identifier='Foo')
|
||||
o2 = q1.options.create(answer='Bar', identifier='Bar')
|
||||
q2 = event.questions.create(question='Boolean', type=Question.TYPE_BOOLEAN)
|
||||
q = event.questions.create(question='Foo', type=Question.TYPE_CHOICE_MULTIPLE)
|
||||
o1 = q.options.create(answer='Foo', identifier='Foo')
|
||||
o2 = q.options.create(answer='Bar', identifier='Bar')
|
||||
settings['item'] = 'static:{}'.format(item.pk)
|
||||
settings['attendee_email'] = 'csv:C'
|
||||
settings['question_{}'.format(q1.pk)] = 'csv:I'
|
||||
settings['question_{}'.format(q2.pk)] = 'csv:L'
|
||||
settings['question_{}'.format(q.pk)] = 'csv:I'
|
||||
|
||||
import_orders.apply(
|
||||
args=(event.pk, inputfile_factory().id, settings, 'en', user.pk)
|
||||
).get()
|
||||
assert QuestionAnswer.objects.filter(question=q1).count() == 3
|
||||
assert QuestionAnswer.objects.filter(question=q).count() == 3
|
||||
a1 = OrderPosition.objects.get(attendee_email='schneider@example.org').answers.first()
|
||||
assert a1.question == q1
|
||||
assert a1.question == q
|
||||
assert list(a1.options.all()) == [o1]
|
||||
a3 = OrderPosition.objects.get(attendee_email__isnull=True).answers.first()
|
||||
assert a3.question == q1
|
||||
assert a3.question == q
|
||||
assert set(a3.options.all()) == {o1, o2}
|
||||
|
||||
# Boolean question: One True, One False, one empty == 2 Question answers
|
||||
assert QuestionAnswer.objects.filter(question=q2).count() == 2
|
||||
a4 = OrderPosition.objects.get(attendee_email='schneider@example.org').answers.last()
|
||||
assert a4.question == q2
|
||||
assert a4.answer == 'True'
|
||||
a5 = OrderPosition.objects.get(attendee_email='daniel@example.org').answers.last()
|
||||
assert a5.question == q2
|
||||
assert a5.answer == 'False'
|
||||
a6 = OrderPosition.objects.get(attendee_email__isnull=True).answers
|
||||
assert a6.count() == 1
|
||||
assert a6.first().question == q1
|
||||
assert a6.last().question == q1
|
||||
|
||||
# TODO: validate question
|
||||
|
||||
@@ -2228,7 +2228,6 @@ class OrderChangeManagerTests(TestCase):
|
||||
@classscope(attr='o')
|
||||
def test_split_and_change_higher(self):
|
||||
self.order.status = Order.STATUS_PAID
|
||||
self.order.expires = now() - timedelta(days=1)
|
||||
self.order.save()
|
||||
self.order.payments.create(
|
||||
provider='manual',
|
||||
@@ -2248,7 +2247,6 @@ class OrderChangeManagerTests(TestCase):
|
||||
assert not self.order.fees.exists()
|
||||
assert self.order.status == Order.STATUS_PAID
|
||||
assert self.order.pending_sum == Decimal('0.00')
|
||||
assert self.order.expires < now()
|
||||
r = self.order.refunds.last()
|
||||
assert r.provider == 'offsetting'
|
||||
assert r.amount == Decimal('23.00')
|
||||
@@ -2257,7 +2255,6 @@ class OrderChangeManagerTests(TestCase):
|
||||
# New order
|
||||
assert self.op2.order != self.order
|
||||
o2 = self.op2.order
|
||||
assert o2.expires > now()
|
||||
assert o2.total == Decimal('42.00')
|
||||
assert o2.status == Order.STATUS_PENDING
|
||||
assert o2.positions.count() == 1
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
import inspect
|
||||
|
||||
import pytest
|
||||
from django.utils import translation
|
||||
from django_scopes import scopes_disabled
|
||||
from xdist.dsession import DSession
|
||||
|
||||
@@ -69,8 +68,3 @@ def pytest_fixture_setup(fixturedef, request):
|
||||
else:
|
||||
with scopes_disabled():
|
||||
yield
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def reset_locale():
|
||||
translation.activate("en")
|
||||
|
||||
@@ -20,19 +20,19 @@
|
||||
# <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
from django import urls
|
||||
from django.test import override_settings
|
||||
from django.conf import settings
|
||||
|
||||
from pretix.helpers.urls import build_absolute_uri
|
||||
|
||||
|
||||
def test_site_url_domain():
|
||||
with override_settings(SITE_URL='https://example.com'):
|
||||
assert build_absolute_uri('control:auth.login') == 'https://example.com/control/login'
|
||||
settings.SITE_URL = 'https://example.com'
|
||||
assert build_absolute_uri('control:auth.login') == 'https://example.com/control/login'
|
||||
|
||||
|
||||
def test_site_url_subpath():
|
||||
with override_settings(SITE_URL='https://example.com/presale'):
|
||||
old_prefix = urls.get_script_prefix()
|
||||
urls.set_script_prefix('/presale/')
|
||||
assert build_absolute_uri('control:auth.login') == 'https://example.com/presale/control/login'
|
||||
urls.set_script_prefix(old_prefix)
|
||||
settings.SITE_URL = 'https://example.com/presale'
|
||||
old_prefix = urls.get_script_prefix()
|
||||
urls.set_script_prefix('/presale/')
|
||||
assert build_absolute_uri('control:auth.login') == 'https://example.com/presale/control/login'
|
||||
urls.set_script_prefix(old_prefix)
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
# <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
import pytest
|
||||
from django.conf import settings
|
||||
from django.test.utils import override_settings
|
||||
from django.utils.timezone import now
|
||||
|
||||
@@ -35,6 +36,7 @@ def env():
|
||||
date_from=now(), live=True
|
||||
)
|
||||
event.get_cache().clear()
|
||||
settings.SITE_URL = 'http://example.com'
|
||||
return o, event
|
||||
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
# <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
import pytest
|
||||
from django.conf import settings
|
||||
from django.utils.timezone import now
|
||||
|
||||
from pretix.base.models import Event, Organizer
|
||||
@@ -32,6 +33,7 @@ def event():
|
||||
organizer=o, name='MRMCD2015', slug='2015',
|
||||
date_from=now(),
|
||||
)
|
||||
settings.SITE_URL = 'http://example.com'
|
||||
return event
|
||||
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
# <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
import pytest
|
||||
from django.conf import settings
|
||||
from django.template import Context, Template, TemplateSyntaxError
|
||||
from django.urls import NoReverseMatch
|
||||
from django.utils.timezone import now
|
||||
@@ -35,6 +36,7 @@ def env():
|
||||
organizer=o, name='MRMCD2015', slug='2015',
|
||||
date_from=now()
|
||||
)
|
||||
settings.SITE_URL = 'http://example.com'
|
||||
event.get_cache().clear()
|
||||
return o, event
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
# <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
import pytest
|
||||
from django.conf import settings
|
||||
from django.test import override_settings
|
||||
from django.utils.timezone import now
|
||||
from django_scopes import scopes_disabled
|
||||
@@ -37,6 +38,7 @@ def env():
|
||||
organizer=o, name='MRMCD2015', slug='2015',
|
||||
date_from=now()
|
||||
)
|
||||
settings.SITE_URL = 'http://example.com'
|
||||
event.get_cache().clear()
|
||||
return o, event
|
||||
|
||||
@@ -97,6 +99,7 @@ def test_event_org_domain_keep_port(env):
|
||||
@pytest.mark.django_db
|
||||
def test_event_org_domain_keep_scheme(env):
|
||||
with override_settings(SITE_URL='https://example.com'):
|
||||
settings.SITE_URL = 'https://example.com'
|
||||
KnownDomain.objects.create(domainname='foobar', organizer=env[0])
|
||||
assert eventreverse(env[1], 'presale:event.index') == 'https://foobar/2015/'
|
||||
|
||||
|
||||
@@ -1,91 +0,0 @@
|
||||
#
|
||||
# This file is part of pretix (Community Edition).
|
||||
#
|
||||
# Copyright (C) 2014-2020 Raphael Michel and contributors
|
||||
# Copyright (C) 2020-2021 rami.io GmbH and contributors
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
|
||||
# Public License as published by the Free Software Foundation in version 3 of the License.
|
||||
#
|
||||
# ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are
|
||||
# applicable granting you additional permissions and placing additional restrictions on your usage of this software.
|
||||
# Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive
|
||||
# this file, see <https://pretix.eu/about/en/license>.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
|
||||
# <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
# This file is based on an earlier version of pretix which was released under the Apache License 2.0. The full text of
|
||||
# the Apache License 2.0 can be obtained at <http://www.apache.org/licenses/LICENSE-2.0>.
|
||||
#
|
||||
# This file may have since been changed and any changes are released under the terms of AGPLv3 as described above. A
|
||||
# full history of changes and contributors is available at <https://github.com/pretix/pretix>.
|
||||
#
|
||||
# This file contains Apache-licensed contributions copyrighted by: Flavia Bastos
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software distributed under the Apache License 2.0 is
|
||||
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations under the License.
|
||||
|
||||
from django.core import mail as djmail
|
||||
from django_countries.fields import Country
|
||||
from django_scopes import scopes_disabled
|
||||
from tests.presale.test_orders import BaseOrdersTest
|
||||
|
||||
from pretix.base.models import InvoiceAddress, OrderPayment
|
||||
from pretix.base.services.invoices import generate_invoice
|
||||
|
||||
|
||||
class BanktransferOrdersTest(BaseOrdersTest):
|
||||
def test_unknown_order(self):
|
||||
response = self.client.post(
|
||||
'/%s/%s/banktransfer/ABCDE/123/mail-invoice/' % (self.orga.slug, self.event.slug)
|
||||
)
|
||||
assert response.status_code == 404
|
||||
response = self.client.post(
|
||||
'/%s/%s/banktransfer/%s/123/mail-invoice/' % (self.orga.slug, self.event.slug, self.not_my_order.code)
|
||||
)
|
||||
assert response.status_code == 404
|
||||
|
||||
def test_order_with_no_invoice(self):
|
||||
djmail.outbox = []
|
||||
response = self.client.post(
|
||||
'/%s/%s/banktransfer/%s/%s/mail-invoice/' % (
|
||||
self.orga.slug, self.event.slug, self.order.code, self.order.secret),
|
||||
{'email': 'test@example.org'}
|
||||
)
|
||||
assert response.status_code == 302
|
||||
|
||||
from django.contrib.messages import get_messages
|
||||
messages = list(get_messages(response.wsgi_request))
|
||||
assert len(messages) == 1
|
||||
assert str(messages[0]) == 'No pending bank transfer payment found. Maybe the order has been paid already?'
|
||||
assert len(djmail.outbox) == 0
|
||||
|
||||
def test_valid_order(self):
|
||||
with scopes_disabled():
|
||||
self.event.settings.set('payment_banktransfer_invoice_email', True)
|
||||
self.order.payments.create(provider='banktransfer', state=OrderPayment.PAYMENT_STATE_CREATED,
|
||||
amount=self.order.total)
|
||||
InvoiceAddress.objects.create(order=self.order, company="Sample company", country=Country('NZ'))
|
||||
generate_invoice(self.order)
|
||||
|
||||
djmail.outbox = []
|
||||
response = self.client.post(
|
||||
'/%s/%s/banktransfer/%s/%s/mail-invoice/' % (
|
||||
self.orga.slug, self.event.slug, self.order.code, self.order.secret),
|
||||
{'email': 'test@example.org'}
|
||||
)
|
||||
assert response.status_code == 302
|
||||
|
||||
from django.contrib.messages import get_messages
|
||||
messages = list(get_messages(response.wsgi_request))
|
||||
assert len(messages) == 1
|
||||
assert str(messages[0]) == 'Sending the latest invoice via e-mail to test@example.org.'
|
||||
|
||||
assert len(djmail.outbox) == 1
|
||||
@@ -582,6 +582,7 @@ class WidgetCartTest(CartTestMixin, TestCase):
|
||||
|
||||
response = self.client.get('/%s/%s/widget/product_list' % (self.orga.slug, self.event.slug))
|
||||
data = json.loads(response.content.decode())
|
||||
settings.SITE_URL = 'http://example.com'
|
||||
assert data == {
|
||||
'list_type': 'list',
|
||||
'name': '30C3',
|
||||
@@ -609,6 +610,7 @@ class WidgetCartTest(CartTestMixin, TestCase):
|
||||
self.event.subevents.create(name="Hidden", active=True, is_public=False, date_from=now() + datetime.timedelta(days=3))
|
||||
|
||||
response = self.client.get('/%s/%s/widget/product_list?style=calendar' % (self.orga.slug, self.event.slug))
|
||||
settings.SITE_URL = 'http://example.com'
|
||||
data = json.loads(response.content.decode())
|
||||
assert data == {
|
||||
'list_type': 'calendar',
|
||||
@@ -684,6 +686,7 @@ class WidgetCartTest(CartTestMixin, TestCase):
|
||||
self.event.subevents.create(name="Hidden", active=True, is_public=False, date_from=now() + datetime.timedelta(days=3))
|
||||
|
||||
response = self.client.get('/%s/%s/widget/product_list?style=week' % (self.orga.slug, self.event.slug))
|
||||
settings.SITE_URL = 'http://example.com'
|
||||
data = json.loads(response.content.decode())
|
||||
assert data == {
|
||||
'list_type': 'week',
|
||||
@@ -727,6 +730,7 @@ class WidgetCartTest(CartTestMixin, TestCase):
|
||||
self.event.subevents.create(name="Disabled", active=False, date_from=now() + datetime.timedelta(days=3))
|
||||
self.event.subevents.create(name="Hidden", active=True, is_public=False, date_from=now() + datetime.timedelta(days=3))
|
||||
|
||||
settings.SITE_URL = 'http://example.com'
|
||||
response = self.client.get('/%s/widget/product_list' % (self.orga.slug,))
|
||||
data = json.loads(response.content.decode())
|
||||
assert data == {
|
||||
@@ -769,6 +773,7 @@ class WidgetCartTest(CartTestMixin, TestCase):
|
||||
self.event.subevents.create(name="Hidden", active=True, is_public=False, date_from=now() + datetime.timedelta(days=3))
|
||||
|
||||
response = self.client.get('/%s/widget/product_list?style=calendar' % (self.orga.slug,))
|
||||
settings.SITE_URL = 'http://example.com'
|
||||
data = json.loads(response.content.decode())
|
||||
assert data == {
|
||||
'date': '2019-01-01',
|
||||
|
||||
Reference in New Issue
Block a user