Compare commits

..

17 Commits

Author SHA1 Message Date
Raphael Michel b00b063e6d Explicitly set SQL connection timezone 2022-02-01 18:09:56 +01:00
Raphael Michel 0b8432b2c5 Docs: Add node on MySQL's SQL mode 2022-01-31 15:44:26 +01:00
Raphael Michel 9be6ad4124 Add documentation on secrets import plugin 2022-01-31 10:20:23 +01:00
Raphael Michel fdc77f6bd8 Quota deletion: Show internal names of products 2022-01-31 09:56:55 +01:00
Raphael Michel e3d0a18bee Show internal category names in product list 2022-01-31 09:34:13 +01:00
Raphael Michel 81c271ee2a Fix ordering of add-on products in email info block 2022-01-28 17:05:46 +01:00
Raphael Michel e981f00dc7 Fix typo 2022-01-27 17:52:37 +01:00
Raphael Michel 2daf35c39e Allow to customize description of calendar files (#2415)
Co-authored-by: Martin Gross <gross@rami.io>
2022-01-27 14:58:16 +01:00
Raphael Michel c9530c56af Fix isort issue 2022-01-27 14:42:19 +01:00
Raphael Michel f3e31287f4 Bump to 4.7.0.dev0 2022-01-27 13:44:53 +01:00
Raphael Michel c9aaa343e6 Bump to 4.6.0 2022-01-27 13:44:39 +01:00
Raphael Michel 87a196c4df Translations: Update German
Currently translated at 100.0% (4613 of 4613 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/de/

powered by weblate
2022-01-27 12:27:58 +01:00
Raphael Michel a220f1678b Translations: Update German (informal) (de_Informal)
Currently translated at 100.0% (4613 of 4613 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/de_Informal/

powered by weblate
2022-01-27 12:27:58 +01:00
Raphael Michel c8fa0852b2 Add DNS to English word list 2022-01-27 12:15:31 +01:00
Raphael Michel fe3433106c Extend spelling wordlists 2022-01-27 12:11:34 +01:00
Raphael Michel f8086daf34 Update po files
[CI skip]

Signed-off-by: Raphael Michel <michel@rami.io>
2022-01-27 11:02:14 +01:00
Raphael Michel 66f75a5614 Revert dnspython to 1.x 2022-01-26 16:15:12 +01:00
111 changed files with 28455 additions and 19525 deletions
+20 -2
View File
@@ -220,12 +220,30 @@ Example::
``user``, ``password``
The SMTP user data to use for the connection. Empty by default.
``tls``, ``ssl``
Use STARTTLS or SSL for the SMTP connection. Off by default.
``from``
The email address to set as ``From`` header in outgoing emails by the system.
Default: ``pretix@localhost``
``tls``, ``ssl``
Use STARTTLS or SSL for the SMTP connection. Off by default.
``from_notifications``
The email address to set as ``From`` header in admin notification emails by the system.
Defaults to the value of ``from``.
``from_organizers``
The email address to set as ``From`` header in outgoing emails by the system sent on behalf of organizers.
Defaults to the value of ``from``.
``custom_sender_verification_required``
If this is on (the default), organizers need to verify email addresses they want to use as senders in their event.
``custom_sender_spf_string``
If this is set to a valid SPF string, pretix will show a warning if organizers use a sender address from a domain
that does not include this value.
``custom_smtp_allow_private_networks``
If this is off (the default), custom SMTP servers cannot be private network addresses.
``admins``
Comma-separated list of email addresses that should receive a report about every error code 500 thrown by pretix.
+5 -3
View File
@@ -36,9 +36,6 @@ Linux and firewalls, we recommend that you start with `ufw`_.
SSL certificates can be obtained for free these days. We also *do not* provide support for HTTP-only
installations except for evaluation purposes.
.. warning:: We recommend **PostgreSQL**. If you go for MySQL, make sure you run **MySQL 5.7 or newer** or
**MariaDB 10.2.7 or newer**.
.. warning:: By default, using `ufw` in conjunction will not have any effect. Please make sure to either bind the exposed
ports of your docker container explicitly to 127.0.0.1 or configure docker to respect any set up firewall
rules.
@@ -61,6 +58,9 @@ directory writable to the user that runs pretix inside the docker container::
Database
--------
.. warning:: **Please use PostgreSQL for all new installations**. If you need to go for MySQL, make sure you run
**MySQL 5.7 or newer** or **MariaDB 10.2.7 or newer**.
Next, we need a database and a database user. We can create these with any kind of database managing tool or directly on
our database's shell. Please make sure that UTF8 is used as encoding for the best compatibility. You can check this with
the following command::
@@ -91,6 +91,8 @@ When using MySQL, make sure you set the character set of the database to ``utf8m
mysql > CREATE DATABASE pretix DEFAULT CHARACTER SET utf8mb4 DEFAULT COLLATE utf8mb4_unicode_ci;
You will also need to make sure that ``sql_mode`` in your ``my.cnf`` file does **not** include ``ONLY_FULL_GROUP_BY``.
Redis
-----
+5 -3
View File
@@ -34,9 +34,6 @@ Linux and firewalls, we recommend that you start with `ufw`_.
SSL certificates can be obtained for free these days. We also *do not* provide support for HTTP-only
installations except for evaluation purposes.
.. warning:: We recommend **PostgreSQL**. If you go for MySQL, make sure you run **MySQL 5.7 or newer** or
**MariaDB 10.2.7 or newer**.
Unix user
---------
@@ -50,6 +47,9 @@ In this guide, all code lines prepended with a ``#`` symbol are commands that yo
Database
--------
.. warning:: **Please use PostgreSQL for all new installations**. If you need to go for MySQL, make sure you run
**MySQL 5.7 or newer** or **MariaDB 10.2.7 or newer**.
Having the database server installed, we still need a database and a database user. We can create these with any kind
of database managing tool or directly on our database's shell. Please make sure that UTF8 is used as encoding for the
best compatibility. You can check this with the following command::
@@ -65,6 +65,8 @@ When using MySQL, make sure you set the character set of the database to ``utf8m
mysql > CREATE DATABASE pretix DEFAULT CHARACTER SET utf8mb4 DEFAULT COLLATE utf8mb4_unicode_ci;
You will also need to make sure that ``sql_mode`` in your ``my.cnf`` file does **not** include ``ONLY_FULL_GROUP_BY``.
Package dependencies
--------------------
+301
View File
@@ -0,0 +1,301 @@
Secrets Import
==============
Usually, pretix generates ticket secrets (i.e. the QR code used for scanning) itself. You can read more about this
process at :ref:`secret_generators`.
With the "Secrets Import" plugin, you can upload your own list of secrets to be used instead. This is useful for
integrating with third-party check-in systems.
API Resource description
-------------------------
The secrets import plugin provides a HTTP API that allows you to create new secrets.
The imported secret resource contains the following public fields:
.. rst-class:: rest-resource-table
===================================== ========================== =======================================================
Field Type Description
===================================== ========================== =======================================================
id integer Internal ID of the secret
secret string Actual string content of the secret (QR code content)
used boolean Whether the secret was already used for a ticket. If ``true``,
the secret can no longer be deleted. Secrets are never used
twice, even if an order is canceled or deleted.
item integer Internal ID of a product, or ``null``. If set, the secret
will only be used for tickets of this product.
variation integer Internal ID of a product variation, or ``null``. If set, the secret
will only be used for tickets of this product variation.
subevent integer Internal ID of an event series date, or ``null``. If set, the secret
will only be used for tickets of this event series date.
===================================== ========================== =======================================================
API Endpoints
-------------
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/imported_secrets/
Returns a list of all secrets imported for an event.
**Example request**:
.. sourcecode:: http
GET /api/v1/organizers/bigevents/events/sampleconf/imported_secrets/ HTTP/1.1
Host: pretix.eu
Accept: application/json, text/javascript
**Example response**:
.. sourcecode:: http
HTTP/1.1 200 OK
Vary: Accept
Content-Type: application/json
{
"count": 1,
"next": null,
"previous": null,
"results": [
{
"id": 1,
"secret": "foobar",
"used": false,
"item": null,
"variation": null,
"subevent": null
}
]
}
:query page: The page number in case of a multi-page result set, default is 1
:param organizer: The ``slug`` field of a valid organizer
:param event: The ``slug`` field of the event to fetch
:statuscode 200: no error
:statuscode 401: Authentication failure
:statuscode 403: The requested organizer or event does not exist **or** you have no permission to view it.
.. http:get:: /api/v1/organizers/(organizer)/events/(event)/imported_secrets/(id)/
Returns information on one secret, identified by its ID.
**Example request**:
.. sourcecode:: http
GET /api/v1/organizers/bigevents/events/sampleconf/imported_secrets/1/ HTTP/1.1
Host: pretix.eu
Accept: application/json, text/javascript
**Example response**:
.. sourcecode:: http
HTTP/1.1 200 OK
Vary: Accept
Content-Type: application/json
{
"id": 1,
"secret": "foobar",
"used": false,
"item": null,
"variation": null,
"subevent": null
}
:param organizer: The ``slug`` field of the organizer to fetch
:param event: The ``slug`` field of the event to fetch
:param id: The ``id`` field of the secret to fetch
:statuscode 200: no error
:statuscode 401: Authentication failure
:statuscode 403: The requested organizer/event/secret does not exist **or** you have no permission to view it.
.. http:post:: /api/v1/organizers/(organizer)/events/(event)/imported_secrets/
Create a new secret.
**Example request**:
.. sourcecode:: http
POST /api/v1/organizers/bigevents/events/sampleconf/imported_secrets/ HTTP/1.1
Host: pretix.eu
Accept: application/json, text/javascript
Content-Type: application/json
Content-Length: 166
{
"secret": "foobar",
"used": false,
"item": null,
"variation": null,
"subevent": null
}
**Example response**:
.. sourcecode:: http
HTTP/1.1 201 Created
Vary: Accept
Content-Type: application/json
{
"id": 1,
"secret": "foobar",
"used": false,
"item": null,
"variation": null,
"subevent": null
}
:param organizer: The ``slug`` field of the organizer to a create new secret for
:param event: The ``slug`` field of the event to create a new secret for
:statuscode 201: no error
:statuscode 400: The secret could not be created due to invalid submitted data.
:statuscode 401: Authentication failure
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to create secrets.
.. http:post:: /api/v1/organizers/(organizer)/events/(event)/imported_secrets/bulk_create/
Create new secrets in bulk (up to 500 per request). The request either succeeds or fails entirely.
**Example request**:
.. sourcecode:: http
POST /api/v1/organizers/bigevents/events/sampleconf/imported_secrets/bulk_create/ HTTP/1.1
Host: pretix.eu
Accept: application/json, text/javascript
Content-Type: application/json
Content-Length: 166
[
{
"secret": "foobar",
"used": false,
"item": null,
"variation": null,
"subevent": null
},
{
"secret": "baz",
"used": false,
"item": null,
"variation": null,
"subevent": null
}
]
**Example response**:
.. sourcecode:: http
HTTP/1.1 200 OK
Vary: Accept
Content-Type: application/json
[
{
"id": 1,
"secret": "foobar",
"used": false,
"item": null,
"variation": null,
"subevent": null
},
{
"id": 2,
"secret": "baz",
"used": false,
"item": null,
"variation": null,
"subevent": null
}
]
:param organizer: The ``slug`` field of the organizer to create new secrets for
:param event: The ``slug`` field of the event to create new secrets for
:statuscode 201: no error
:statuscode 400: The secrets could not be created due to invalid submitted data.
:statuscode 401: Authentication failure
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to create secrets.
.. http:patch:: /api/v1/organizers/(organizer)/events/(event)/imported_secrets/(id)/
Update a secret. You can also use ``PUT`` instead of ``PATCH``. With ``PUT``, you have to provide all fields of
the resource, other fields will be reset to default. With ``PATCH``, you only need to provide the fields that you
want to change.
**Example request**:
.. sourcecode:: http
PATCH /api/v1/organizers/bigevents/events/sampleconf/imported_secrets/1/ HTTP/1.1
Host: pretix.eu
Accept: application/json, text/javascript
Content-Type: application/json
Content-Length: 34
{
"item": 2
}
**Example response**:
.. sourcecode:: http
HTTP/1.1 200 OK
Vary: Accept
Content-Type: text/javascript
{
"id": 1,
"secret": "foobar",
"used": false,
"item": 2,
"variation": null,
"subevent": null
}
:param organizer: The ``slug`` field of the organizer to modify
:param event: The ``slug`` field of the event to modify
:param id: The ``id`` field of the secret to modify
:statuscode 200: no error
:statuscode 400: The secret could not be modified due to invalid submitted data.
:statuscode 401: Authentication failure
:statuscode 403: The requested organizer/event/secret does not exist **or** you have no permission to change it.
.. http:delete:: /api/v1/organizers/(organizer)/events/(event)/imported_secrets/(id)/
Delete a secret. You can only delete secrets that have not yet been used.
**Example request**:
.. sourcecode:: http
DELETE /api/v1/organizers/bigevents/events/sampleconf/imported_secrets/1/ HTTP/1.1
Host: pretix.eu
Accept: application/json, text/javascript
**Example response**:
.. sourcecode:: http
HTTP/1.1 204 No Content
Vary: Accept
:param organizer: The ``slug`` field of the organizer to modify
:param event: The ``slug`` field of the event to modify
:param id: The ``id`` field of the secret to delete
:statuscode 204: no error
:statuscode 401: Authentication failure
:statuscode 403: The requested organizer/event/secret does not exist **or** you have no permission to change it **or** the secret has already been used
+1
View File
@@ -17,4 +17,5 @@ If you want to **create** a plugin, please go to the
campaigns
certificates
digital
imported_secrets
webinar
+2
View File
@@ -1,3 +1,5 @@
.. _secret_generators:
Ticket secret generators
========================
+1 -1
View File
@@ -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__ = "4.6.0.dev0"
__version__ = "4.7.0.dev0"
-1
View File
@@ -713,7 +713,6 @@ class EventSettingsSerializer(SettingsSerializer):
'ticket_download_require_validated_email',
'ticket_secret_length',
'mail_prefix',
'mail_from',
'mail_from_name',
'mail_attach_ical',
'mail_attach_tickets',
+3 -2
View File
@@ -659,12 +659,13 @@ class OrderViewSet(viewsets.ModelViewSet):
_order_placed_email(
request.event, order, payment.payment_provider if payment else None, email_template,
log_entry, invoice, payment
log_entry, invoice, payment, is_free=free_flow
)
if email_attendees:
for p in order.positions.all():
if p.addon_to_id is None and p.attendee_email and p.attendee_email != order.email:
_order_placed_email_attendee(request.event, order, p, email_attendees_template, log_entry)
_order_placed_email_attendee(request.event, order, p, email_attendees_template, log_entry,
is_free=free_flow)
if not free_flow and order.status == Order.STATUS_PAID and payment:
payment._send_paid_mail(invoice, None, '')
+28 -3
View File
@@ -33,6 +33,7 @@ from django.core.mail.backends.smtp import EmailBackend
from django.db.models import Count
from django.dispatch import receiver
from django.template.loader import get_template
from django.utils.formats import date_format
from django.utils.timezone import now
from django.utils.translation import (
get_language, gettext_lazy as _, pgettext_lazy,
@@ -164,9 +165,20 @@ class TemplateBasedMailRenderer(BaseHTMLMailRenderer):
has_addons=Count('addons')
))
htmlctx['cart'] = [(k, list(v)) for k, v in groupby(
positions, key=lambda op: (
op.item, op.variation, op.subevent, op.attendee_name,
(op.pk if op.addon_to_id else None), (op.pk if op.has_addons else None)
sorted(
positions,
key=lambda op: (
(op.addon_to.positionid if op.addon_to_id else op.positionid),
op.positionid
)
),
key=lambda op: (
op.item,
op.variation,
op.subevent,
op.attendee_name,
(op.pk if op.addon_to_id else None),
(op.pk if op.has_addons else None)
)
)]
@@ -453,6 +465,15 @@ def base_placeholders(sender, **kwargs):
}
),
),
SimpleFunctionalMailTextPlaceholder(
'event_location', ['event_or_subevent'], lambda event_or_subevent: str(event_or_subevent.location or ''),
lambda event: str(event.location or ''),
),
SimpleFunctionalMailTextPlaceholder(
'event_admission_time', ['event_or_subevent'],
lambda event_or_subevent: date_format(event_or_subevent.date_admission, 'TIME_FORMAT') if event_or_subevent.date_admission else '',
lambda event: date_format(event.date_admission, 'TIME_FORMAT') if event.date_admission else '',
),
SimpleFunctionalMailTextPlaceholder(
'subevent', ['waiting_list_entry', 'event'],
lambda waiting_list_entry, event: str(waiting_list_entry.subevent or event),
@@ -622,6 +643,10 @@ def base_placeholders(sender, **kwargs):
'meta_%s' % k, ['event'], lambda event, k=k: event.meta_data[k],
v
))
ph.append(SimpleFunctionalMailTextPlaceholder(
'meta_%s' % k, ['event_or_subevent'], lambda event_or_subevent, k=k: event_or_subevent.meta_data[k],
v
))
return ph
+2 -2
View File
@@ -665,13 +665,13 @@ class Event(EventMixin, LoggedModel):
return locking.LockManager(self)
def get_mail_backend(self, timeout=None, force_custom=False):
def get_mail_backend(self, timeout=None):
"""
Returns an email server connection, either by using the system-wide connection
or by returning a custom one based on the event's settings.
"""
if self.settings.smtp_use_custom or force_custom:
if self.settings.smtp_use_custom:
return get_connection(backend=settings.EMAIL_CUSTOM_SMTP_BACKEND,
host=self.settings.smtp_host,
port=self.settings.smtp_port,
+2 -2
View File
@@ -191,12 +191,12 @@ class Organizer(LoggedModel):
e.delete()
self.teams.all().delete()
def get_mail_backend(self, timeout=None, force_custom=False):
def get_mail_backend(self, timeout=None):
"""
Returns an email server connection, either by using the system-wide connection
or by returning a custom one based on the organizer's settings.
"""
if self.settings.smtp_use_custom or force_custom:
if self.settings.smtp_use_custom:
return get_connection(backend=settings.EMAIL_CUSTOM_SMTP_BACKEND,
host=self.settings.smtp_host,
port=self.settings.smtp_port,
+4 -14
View File
@@ -77,7 +77,7 @@ from pretix.base.signals import email_filter, global_email_filter
from pretix.celery_app import app
from pretix.helpers.hierarkey import clean_filename
from pretix.multidomain.urlreverse import build_absolute_uri
from pretix.presale.ical import get_ical
from pretix.presale.ical import get_private_icals
logger = logging.getLogger('pretix.base.mail')
INVALID_ADDRESS = 'invalid-pretix-mail-address'
@@ -217,7 +217,8 @@ def mail(email: Union[str, Sequence[str]], subject: str, template: Union[str, La
for bcc_mail in settings_holder.settings.mail_bcc.split(','):
bcc.append(bcc_mail.strip())
if settings_holder.settings.mail_from == settings.DEFAULT_FROM_EMAIL and settings_holder.settings.contact_mail and not headers.get('Reply-To'):
if settings_holder.settings.mail_from not in (settings.DEFAULT_FROM_EMAIL, settings.MAIL_FROM_ORGANIZERS) \
and settings_holder.settings.contact_mail and not headers.get('Reply-To'):
headers['Reply-To'] = settings_holder.settings.contact_mail
prefix = settings_holder.settings.get('mail_prefix')
@@ -429,18 +430,7 @@ def mail_send_task(self, *args, to: List[str], subject: str, body: str, html: st
}
)
if attach_ical:
ical_events = set()
if event.has_subevents:
if position:
ical_events.add(position.subevent)
else:
for p in order.positions.all():
ical_events.add(p.subevent)
else:
ical_events.add(order.event)
for i, e in enumerate(ical_events):
cal = get_ical([e])
for i, cal in enumerate(get_private_icals(event, [position] if position else order.positions.all())):
email.attach('event-{}.ics'.format(i), cal.serialize(), 'text/calendar')
email = email_filter.send_chained(event, 'message', message=email, order=order, user=user)
+1 -1
View File
@@ -148,7 +148,7 @@ def send_notification_mail(notification: Notification, user: User):
),
'body': body_plain,
'html': body_html,
'sender': settings.MAIL_FROM,
'sender': settings.MAIL_FROM_NOTIFICATIONS,
'headers': {},
'user': user.pk
})
+8 -6
View File
@@ -932,7 +932,7 @@ def _create_order(event: Event, email: str, positions: List[CartPosition], now_d
def _order_placed_email(event: Event, order: Order, pprov: BasePaymentProvider, email_template, log_entry: str,
invoice, payment: OrderPayment):
invoice, payment: OrderPayment, is_free=False):
email_context = get_email_context(event=event, order=order, payment=payment if pprov else None)
email_subject = _('Your order: %(code)s') % {'code': order.code}
try:
@@ -941,7 +941,7 @@ def _order_placed_email(event: Event, order: Order, pprov: BasePaymentProvider,
log_entry,
invoices=[invoice] if invoice and event.settings.invoice_email_attachment else [],
attach_tickets=True,
attach_ical=event.settings.mail_attach_ical,
attach_ical=event.settings.mail_attach_ical and (not event.settings.mail_attach_ical_paid_only or is_free),
attach_other_files=[a for a in [
event.settings.get('mail_attachment_new_order', as_type=str, default='')[len('file://'):]
] if a],
@@ -950,7 +950,7 @@ def _order_placed_email(event: Event, order: Order, pprov: BasePaymentProvider,
logger.exception('Order received email could not be sent')
def _order_placed_email_attendee(event: Event, order: Order, position: OrderPosition, email_template, log_entry: str):
def _order_placed_email_attendee(event: Event, order: Order, position: OrderPosition, email_template, log_entry: str, is_free=False):
email_context = get_email_context(event=event, order=order, position=position)
email_subject = _('Your event registration: %(code)s') % {'code': order.code}
@@ -961,7 +961,7 @@ def _order_placed_email_attendee(event: Event, order: Order, position: OrderPosi
invoices=[],
attach_tickets=True,
position=position,
attach_ical=event.settings.mail_attach_ical,
attach_ical=event.settings.mail_attach_ical and (not event.settings.mail_attach_ical_paid_only or is_free),
attach_other_files=[a for a in [
event.settings.get('mail_attachment_new_order', as_type=str, default='')[len('file://'):]
] if a],
@@ -1070,11 +1070,13 @@ def _perform_order(event: Event, payment_provider: str, position_ids: List[str],
email_attendees_template = event.settings.mail_text_order_placed_attendee
if sales_channel in event.settings.mail_sales_channel_placed_paid:
_order_placed_email(event, order, pprov, email_template, log_entry, invoice, payment)
_order_placed_email(event, order, pprov, email_template, log_entry, invoice, payment,
is_free=free_order_flow)
if email_attendees:
for p in order.positions.all():
if p.addon_to_id is None and p.attendee_email and p.attendee_email != order.email:
_order_placed_email_attendee(event, order, p, email_attendees_template, log_entry)
_order_placed_email_attendee(event, order, p, email_attendees_template, log_entry,
is_free=free_order_flow)
return order.id
+27 -1
View File
@@ -1573,6 +1573,32 @@ DEFAULTS = {
help_text=_("If enabled, we will attach an .ics calendar file to order confirmation emails."),
)
},
'mail_attach_ical_paid_only': {
'default': 'False',
'type': bool,
'form_class': forms.BooleanField,
'serializer_class': serializers.BooleanField,
'form_kwargs': dict(
label=_("Attach calendar files only after order has been paid"),
help_text=_("Use this if you e.g. put a private access link into the calendar file to make sure people only "
"receive it after their payment was confirmed."),
)
},
'mail_attach_ical_description': {
'default': '',
'type': LazyI18nString,
'form_class': I18nFormField,
'form_kwargs': dict(
label=_("Event description"),
widget=I18nTextarea,
help_text=_(
"You can use this to share information with your attendees, such as travel information or the link to a digital event. "
"If you keep it empty, we will put a link to the event shop, the admission time, and your organizer name in there. "
"We do not allow using placeholders with sensitive person-specific data as calendar entries are often shared with an "
"unspecified number of people."
),
)
},
'mail_prefix': {
'default': None,
'type': str,
@@ -1589,7 +1615,7 @@ DEFAULTS = {
'type': str
},
'mail_from': {
'default': settings.MAIL_FROM,
'default': settings.MAIL_FROM_ORGANIZERS,
'type': str,
'form_class': forms.EmailField,
'serializer_class': serializers.EmailField,
+1 -1
View File
@@ -23,8 +23,8 @@ import urllib.parse
from django.core import signing
from django.http import HttpResponseBadRequest, HttpResponseRedirect
from django.urls import reverse
from django.shortcuts import render
from django.urls import reverse
def _is_samesite_referer(request):
+1 -44
View File
@@ -48,7 +48,7 @@ from django.utils.timezone import now
from django.utils.translation import gettext_lazy as _
from django_scopes.forms import SafeModelMultipleChoiceField
from ...base.forms import I18nModelForm, SecretKeySettingsField
from ...base.forms import I18nModelForm
# Import for backwards compatibility with okd import paths
from ...base.forms.widgets import ( # noqa
@@ -373,49 +373,6 @@ class FontSelect(forms.RadioSelect):
option_template_name = 'pretixcontrol/font_option.html'
class SMTPSettingsMixin(forms.Form):
smtp_use_custom = forms.BooleanField(
label=_("Use custom SMTP server"),
help_text=_("All mail related to your event will be sent over the smtp server specified by you."),
required=False
)
smtp_host = forms.CharField(
label=_("Hostname"),
required=False,
widget=forms.TextInput(attrs={'placeholder': 'mail.example.org'})
)
smtp_port = forms.IntegerField(
label=_("Port"),
required=False,
widget=forms.TextInput(attrs={'placeholder': 'e.g. 587, 465, 25, ...'})
)
smtp_username = forms.CharField(
label=_("Username"),
widget=forms.TextInput(attrs={'placeholder': 'myuser@example.org'}),
required=False
)
smtp_password = SecretKeySettingsField(
label=_("Password"),
required=False,
)
smtp_use_tls = forms.BooleanField(
label=_("Use STARTTLS"),
help_text=_("Commonly enabled on port 587."),
required=False
)
smtp_use_ssl = forms.BooleanField(
label=_("Use SSL"),
help_text=_("Commonly enabled on port 465."),
required=False
)
def clean(self):
data = super().clean()
if data.get('smtp_use_tls') and data.get('smtp_use_ssl'):
raise ValidationError(_('You can activate either SSL or STARTTLS security, but not both at the same time.'))
return data
class ItemMultipleChoiceField(SafeModelMultipleChoiceField):
def label_from_instance(self, obj):
return str(obj) if obj.active else mark_safe(f'<strike class="text-muted">{escape(obj)}</strike>')
+6 -4
View File
@@ -64,7 +64,7 @@ from pretix.base.settings import (
PERSON_NAME_SCHEMES, PERSON_NAME_TITLE_GROUPS, validate_event_settings,
)
from pretix.control.forms import (
MultipleLanguagesWidget, SlugWidget, SMTPSettingsMixin, SplitDateTimeField,
MultipleLanguagesWidget, SlugWidget, SplitDateTimeField,
SplitDateTimePickerWidget,
)
from pretix.control.forms.widgets import Select2
@@ -865,14 +865,15 @@ def contains_web_channel_validate(val):
raise ValidationError(_("The online shop must be selected to receive these emails."))
class MailSettingsForm(SMTPSettingsMixin, SettingsForm):
class MailSettingsForm(SettingsForm):
auto_fields = [
'mail_prefix',
'mail_from',
'mail_from_name',
'mail_attach_ical',
'mail_attach_tickets',
'mail_attachment_new_order',
'mail_attach_ical_paid_only',
'mail_attach_ical_description',
]
mail_sales_channel_placed_paid = forms.MultipleChoiceField(
@@ -1080,7 +1081,8 @@ class MailSettingsForm(SMTPSettingsMixin, SettingsForm):
'mail_text_download_reminder_attendee': ['event', 'order', 'position'],
'mail_text_resend_link': ['event', 'order'],
'mail_text_waiting_list': ['event', 'waiting_list_entry'],
'mail_text_resend_all_links': ['event', 'orders']
'mail_text_resend_all_links': ['event', 'orders'],
'mail_attach_ical_description': ['event', 'event_or_subevent'],
}
def _set_field_placeholders(self, fn, base_parameters):
+129
View File
@@ -0,0 +1,129 @@
#
# 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/>.
#
import ipaddress
import socket
from django import forms
from django.conf import settings
from django.core.exceptions import ValidationError
from django.utils.translation import gettext_lazy as _
from pretix.base.forms import SecretKeySettingsField, SettingsForm
class SMTPMailForm(SettingsForm):
mail_from = forms.EmailField(
label=_("Sender address"),
help_text=_("Sender address for outgoing emails"),
required=True,
)
smtp_host = forms.CharField(
label=_("Hostname"),
required=True,
widget=forms.TextInput(attrs={'placeholder': 'mail.example.org'})
)
smtp_port = forms.IntegerField(
label=_("Port"),
required=True,
widget=forms.TextInput(attrs={'placeholder': 'e.g. 587, 465, 25, ...'})
)
smtp_username = forms.CharField(
label=_("Username"),
widget=forms.TextInput(attrs={'placeholder': 'myuser@example.org'}),
required=False
)
smtp_password = SecretKeySettingsField(
label=_("Password"),
required=False,
)
smtp_use_tls = forms.BooleanField(
label=_("Use STARTTLS"),
help_text=_("Commonly enabled on port 587."),
required=False
)
smtp_use_ssl = forms.BooleanField(
label=_("Use SSL"),
help_text=_("Commonly enabled on port 465."),
required=False
)
def clean(self):
data = super().clean()
if data.get('smtp_use_tls') and data.get('smtp_use_ssl'):
raise ValidationError(_('You can activate either SSL or STARTTLS security, but not both at the same time.'))
for k, v in self.fields.items():
val = data.get(k)
if v._required and not val:
self.add_error(k, _('This field is required.'))
return data
def clean_smtp_host(self):
v = self.cleaned_data['smtp_host']
if not settings.MAIL_CUSTOM_SMTP_ALLOW_PRIVATE_NETWORKS:
try:
if ipaddress.ip_address(v).is_private:
raise ValidationError(_('You are not allowed to use this mail server, please choose one with a '
'public IP address instead.'))
except ValueError:
try:
if ipaddress.ip_address(socket.gethostbyname(v)).is_private:
raise ValidationError(_('You are not allowed to use this mail server, please choose one with a '
'public IP address instead.'))
except OSError:
raise ValidationError(_('We were unable to resolve this hostname.'))
return v
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if self.obj.settings.mail_from in (settings.MAIL_FROM, settings.MAIL_FROM_ORGANIZERS):
self.initial.pop('mail_from')
for k, v in self.fields.items():
v._required = v.required
v.required = False
v.widget.is_required = False
class SimpleMailForm(SettingsForm):
mail_from = forms.EmailField(
label=_("Sender address"),
help_text=_("Sender address for outgoing emails"),
required=True,
)
def clean(self):
cleaned_data = super().clean()
for k, v in self.fields.items():
val = cleaned_data.get(k)
if v._required and not val:
self.add_error(k, _('This field is required.'))
return cleaned_data
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if self.obj.settings.mail_from in (settings.MAIL_FROM, settings.MAIL_FROM_ORGANIZERS):
self.initial.pop('mail_from')
for k, v in self.fields.items():
v._required = v.required
v.required = False
v.widget.is_required = False
+2 -5
View File
@@ -60,9 +60,7 @@ from pretix.base.models import (
MembershipType, Organizer, Team,
)
from pretix.base.settings import PERSON_NAME_SCHEMES, PERSON_NAME_TITLE_GROUPS
from pretix.control.forms import (
ExtFileField, SMTPSettingsMixin, SplitDateTimeField,
)
from pretix.control.forms import ExtFileField, SplitDateTimeField
from pretix.control.forms.event import (
SafeEventMultipleChoiceField, multimail_validate,
)
@@ -358,9 +356,8 @@ class OrganizerSettingsForm(SettingsForm):
]
class MailSettingsForm(SMTPSettingsMixin, SettingsForm):
class MailSettingsForm(SettingsForm):
auto_fields = [
'mail_from',
'mail_from_name',
]
@@ -0,0 +1,14 @@
{% load i18n %}{% blocktrans with code=code instance=instance %}Hello,
someone requested to use {{ address }} as a sender address on {{ instance }}.
This will allow them to send emails that are shown to originate from this email address.
If that was you, please enter the following confirmation code:
{{ code }}
If this was not requested by you, you can safely ignore this email.
Best regards,
Your {{ instance }} team
{% endblocktrans %}
@@ -0,0 +1,127 @@
{% extends basetpl %}
{% load i18n %}
{% load bootstrap3 %}
{% load hierarkey_form %}
{% load static %}
{% block title %}{% trans "Organizer" %}{% endblock %}
{% block content %}
<h1>{% trans "E-mail sending" %}</h1>
<form action="" method="post" class="form-horizontal">
{% csrf_token %}
<div class="panel-group" id="email">
<div class="panel panel-default">
<div class="accordion-radio">
<div class="panel-heading">
<p class="panel-title">
<input type="radio" name="mode" value="system"
data-parent="#email"
{% if mode == "system" %}checked="checked"{% endif %}
id="input_mode_system"
data-toggle="radiocollapse" data-target="#mode_system"/>
<label for="input_mode_system"><strong>{% trans "Use system default" %}</strong></label>
</p>
</div>
</div>
<div id="mode_system"
class="panel-collapse collapsed {% if mode == "system" %}in{% endif %}">
<div class="panel-body form-horizontal">
<p>
{% blocktrans trimmed %}
E-mails will be sent through the system's default server. They will show the following
sender information:
{% endblocktrans %}
</p>
<dl class="dl-horizontal">
<dt>{% trans "From" context "mail_header" %}</dt>
<dd>{{ object.settings.mail_from_name|default_if_none:object.name }}
&lt;{{ default_sender_address }}&gt;
</dd>
{% if object.settings.contact_mail %}
<dt>{% trans "Reply-To" context "mail_header" %}</dt>
<dd>{{ object.settings.contact_mail }}</dd>
{% endif %}
</dl>
</div>
</div>
</div>
<div class="panel panel-default">
<div class="accordion-radio">
<div class="panel-heading">
<p class="panel-title">
<input type="radio" name="mode" value="simple"
data-parent="#email"
{% if mode == "simple" %}checked="checked"{% endif %}
id="input_mode_simple"
data-toggle="radiocollapse" data-target="#mode_simple"/>
<label for="input_mode_simple"><strong>{% trans "Use system email server with a custom sender address" %}</strong></label>
</p>
</div>
</div>
<div id="mode_simple"
class="panel-collapse collapsed {% if mode == "simple" %}in{% endif %}">
<div class="panel-body form-horizontal">
<p>
{% blocktrans trimmed %}
E-mails will be sent through the system's default server but with your own sender
address.
This will make your emails look more personalized and coming directly from you, but it
also might require some extra steps to ensure good deliverability.
{% endblocktrans %}
</p>
{% bootstrap_form simple_form layout="control" %}
</div>
</div>
</div>
<div class="panel panel-default">
<div class="accordion-radio">
<div class="panel-heading">
<p class="panel-title">
<input type="radio" name="mode" value="smtp"
data-parent="#email"
{% if mode == "smtp" %}checked="checked"{% endif %}
id="input_mode_smtp"
data-toggle="radiocollapse" data-target="#mode_smtp"/>
<label for="input_mode_smtp"><strong>{% trans "Use a custom SMTP server" %}</strong></label>
</p>
</div>
</div>
<div id="mode_smtp"
class="panel-collapse collapsed {% if mode == "smtp" %}in{% endif %}">
<div class="panel-body form-horizontal">
<p>
{% blocktrans trimmed %}
For full customization, you can configure your own SMTP server that will be used for
email sending.
{% endblocktrans %}
</p>
{% bootstrap_form smtp_form layout="control" %}
</div>
</div>
</div>
{% if request.event %}
<div class="panel panel-default">
<div class="accordion-radio">
<div class="panel-heading">
<p class="panel-title">
<input type="radio" name="mode" value="reset"
data-parent="#reset"
id="input_mode_reset"
data-toggle="radiocollapse" data-target="#mode_reset"/>
<label for="input_mode_reset"><strong>{% trans "Reset to organizer settings" %}</strong></label>
</p>
</div>
</div>
<div id="mode_reset"
class="panel-collapse collapsed {% if mode == "reset" %}in{% endif %}">
</div>
</div>
{% endif %}
</div>
<div class="form-group submit-group">
<button type="submit" class="btn btn-primary btn-save">
{% trans "Continue" %}
</button>
</div>
</form>
{% endblock %}
@@ -0,0 +1,79 @@
{% extends basetpl %}
{% load i18n %}
{% load bootstrap3 %}
{% load hierarkey_form %}
{% load static %}
{% block title %}{% trans "Organizer" %}{% endblock %}
{% block content %}
<h1>{% trans "E-mail sending" %}</h1>
<form action="" method="post" class="form-horizontal">
{% csrf_token %}
{% for k, v in request.POST.items %}
<input type="hidden" name="{{ k }}" value="{{ v }}">
{% endfor %}
<input type="hidden" name="state" value="save">
<div class="panel panel-default">
<div class="panel-heading">
<p class="panel-title">
<strong>{% trans "Use system email server with a custom sender address" %}</strong>
</p>
</div>
<div class="panel-body form-horizontal">
{% if spf_warning %}
<div class="alert alert-warning">
<p>
{{ spf_warning }}
</p>
{% if spf_record %}
<p>
{% trans "This is the SPF record we found on your domain:" %}
</p>
<pre><code>{{ spf_record }}</code></pre>
<p>
{% trans "To fix this, include the following part before the last word:" %}
</p>
<pre><code>{{ spf_key }}</code></pre>
{% else %}
<p>
{% trans "Your new SPF record could look like this:" %}
</p>
<pre><code>v=spf1 a mx {{ spf_key }} ~all</code></pre>
{% endif %}
<p>
{% trans "Please keep in mind that updates to DNS might require multiple hours to take effect." %}
</p>
</div>
{% elif spf_key %}
<div class="alert alert-success">
{% blocktrans trimmed %}
We found an SPF record on your domain that includes this system. Great!
{% endblocktrans %}
</div>
{% endif %}
{% if verification %}
<h3>{% trans "Verification" %}</h3>
<p>
{% blocktrans trimmed with recp=recp %}
We've sent an email to {{ recp }} with a confirmation code to verify that this email address
is owned by you. Please enter the verification code below:
{% endblocktrans %}
</p>
<div class="form-group">
<label class="col-md-3 control-label" for="id_verification">
{% trans "Verification code" %}
</label>
<div class="col-md-9">
<input type="text" name="verification" class="form-control">
</div>
</div>
{% endif %}
</div>
</div>
<div class="form-group submit-group">
<button type="submit" class="btn btn-primary btn-save">
{% trans "Save" %}
</button>
</div>
</form>
{% endblock %}
@@ -0,0 +1,42 @@
{% extends basetpl %}
{% load i18n %}
{% load bootstrap3 %}
{% load hierarkey_form %}
{% load static %}
{% block title %}{% trans "Organizer" %}{% endblock %}
{% block content %}
<h1>{% trans "E-mail sending" %}</h1>
<form action="" method="post" class="form-horizontal">
{% csrf_token %}
{% for k, v in request.POST.items %}
<input type="hidden" name="{{ k }}" value="{{ v }}">
{% endfor %}
<input type="hidden" name="state" value="save">
<div class="panel panel-default">
<div class="panel-heading">
<p class="panel-title">
<strong>{% trans "Use a custom SMTP server" %}</strong>
</p>
</div>
<div class="panel-body form-horizontal">
<div class="alert alert-success">
{% blocktrans trimmed %}
A test connection to your SMTP server was successful. You can now save your new settings
to put them in use.
{% endblocktrans %}
</div>
{% if known_host_problem %}
<div class="alert alert-warning">
{{ known_host_problem }}
</div>
{% endif %}
</div>
</div>
<div class="form-group submit-group">
<button type="submit" class="btn btn-primary btn-save">
{% trans "Save" %}
</button>
</div>
</form>
{% endblock %}
@@ -12,18 +12,56 @@
<div class="tabbed-form">
<fieldset>
<legend>{% trans "General" %}</legend>
{% bootstrap_field form.mail_prefix layout="control" %}
{% bootstrap_field form.mail_attach_tickets layout="control" %}
{% url "control:organizer.settings.mail" organizer=request.organizer.slug as org_url %}
{% propagated request.event org_url "mail_from" "mail_from_name" "mail_text_signature" "mail_bcc" %}
{% bootstrap_field form.mail_from layout="control" %}
{% propagated request.event org_url "mail_from" "smtp_use_custom" "smtp_host" "smtp_port" "smtp_username" "smtp_password" "smtp_use_tls" "smtp_use_ssl" %}
<div class="form-group">
<label class="col-md-3 control-label">
{% trans "Sending method" %}
</label>
<div class="col-md-9 static-form-row-with-btn">
{% if request.event.settings.smtp_use_custom %}
{% trans "Custom SMTP server" %}: {{ request.event.settings.smtp_host }}
{% else %}
{% trans "System-provided email server" %}
{% endif %}
&nbsp;&nbsp;
<a href="{% url "control:event.settings.mail.setup" organizer=request.organizer.slug event=request.event.slug %}"
class="btn btn-default">
<span class="fa fa-edit"></span>
{% trans "Edit" %}
</a>
</div>
</div>
<div class="form-group">
<label class="col-md-3 control-label">
{% trans "Sender address" %}
</label>
<div class="col-md-9 static-form-row-with-btn">
{{ request.event.settings.mail_from }}
&nbsp;&nbsp;
<a href="{% url "control:event.settings.mail.setup" organizer=request.organizer.slug event=request.event.slug %}"
class="btn btn-default">
<span class="fa fa-edit"></span>
{% trans "Edit" %}
</a>
</div>
</div>
{% endpropagated %}
{% propagated request.event org_url "mail_from_name" "mail_text_signature" "mail_bcc" %}
{% bootstrap_field form.mail_from_name layout="control" %}
{% bootstrap_field form.mail_text_signature layout="control" %}
{% bootstrap_field form.mail_bcc layout="control" %}
{% endpropagated %}
{% bootstrap_field form.mail_prefix layout="control" %}
{% bootstrap_field form.mail_attach_tickets layout="control" %}
{% bootstrap_field form.mail_attach_ical layout="control" %}
{% bootstrap_field form.mail_sales_channel_placed_paid layout="control" %}
</fieldset>
<fieldset>
<legend>{% trans "Calendar invites" %}</legend>
{% bootstrap_field form.mail_attach_ical layout="control" %}
{% bootstrap_field form.mail_attach_ical_paid_only layout="control" %}
{% bootstrap_field form.mail_attach_ical_description layout="control" %}
</fieldset>
<fieldset>
<legend>{% trans "E-mail design" %}</legend>
<div class="row">
@@ -85,26 +123,11 @@
<h4>{% trans "Attachments" %}</h4>
{% bootstrap_field form.mail_attachment_new_order layout="control" %}
</fieldset>
<fieldset>
<legend>{% trans "SMTP settings" %}</legend>
{% propagated request.event org_url "smtp_use_custom" "smtp_host" "smtp_port" "smtp_username" "smtp_password" "smtp_use_tls" "smtp_use_ssl" %}
{% bootstrap_field form.smtp_use_custom layout="control" %}
{% bootstrap_field form.smtp_host layout="control" %}
{% bootstrap_field form.smtp_port layout="control" %}
{% bootstrap_field form.smtp_username layout="control" %}
{% bootstrap_field form.smtp_password layout="control" %}
{% bootstrap_field form.smtp_use_tls layout="control" %}
{% bootstrap_field form.smtp_use_ssl layout="control" %}
{% endpropagated %}
</fieldset>
</div>
<div class="form-group submit-group">
<button type="submit" class="btn btn-primary btn-save">
{% trans "Save" %}
</button>
<button type="submit" class="btn btn-default btn-save pull-left" name="test" value="1">
{% trans "Save and test custom SMTP connection" %}
</button>
</div>
</form>
{% endblock %}
@@ -46,7 +46,7 @@
{% for c in cat_list %}
<tbody data-dnd-url="{% url "control:event.items.reorder" organizer=request.event.organizer.slug event=request.event.slug %}">
{% for i in c.list %}
{% if forloop.counter0 == 0 and i.category %}<tr class="sortable-disabled"><th colspan="8" scope="colgroup" class="text-muted">{{ i.category.name }}</th></tr>{% endif %}
{% if forloop.counter0 == 0 and i.category %}<tr class="sortable-disabled"><th colspan="8" scope="colgroup" class="text-muted">{{ i.category }}</th></tr>{% endif %}
<tr data-dnd-id="{{ i.id }}" {% if not i.active %}class="row-muted"{% endif %}>
<td><strong>
{% if not i.active %}<strike>{% endif %}
@@ -13,7 +13,7 @@
<ul>
{% for item in dependent %}
<li>
<a href="{% url "control:event.item" organizer=request.event.organizer.slug event=request.event.slug item=item.pk %}">{{ item.name }}</a>
<a href="{% url "control:event.item" organizer=request.event.organizer.slug event=request.event.slug item=item.pk %}">{{ item }}</a>
</li>
{% endfor %}
</ul>
@@ -11,13 +11,45 @@
<h1>{% trans "E-mail settings" %}</h1>
<form action="" method="post" class="form-horizontal" enctype="multipart/form-data"
mail-preview-url="{% url "control:organizer.settings.mail.preview" organizer=request.organizer.slug %}">
mail-preview-url="{% url "control:organizer.settings.mail.preview" organizer=request.organizer.slug %}">
{% csrf_token %}
{% bootstrap_form_errors form %}
<div class="tabbed-form">
<fieldset>
<legend>{% trans "General" %}</legend>
{% bootstrap_field form.mail_from layout="control" %}
<div class="form-group">
<label class="col-md-3 control-label">
{% trans "Sending method" %}
</label>
<div class="col-md-9 static-form-row-with-btn">
{% if request.organizer.settings.smtp_use_custom %}
{% trans "Custom SMTP server" %}: {{ request.organizer.settings.smtp_host }}
{% else %}
{% trans "System-provided email server" %}
{% endif %}
&nbsp;&nbsp;
<a href="{% url "control:organizer.settings.mail.setup" organizer=request.organizer.slug %}"
class="btn btn-default">
<span class="fa fa-edit"></span>
{% trans "Edit" %}
</a>
</div>
</div>
<div class="form-group">
<label class="col-md-3 control-label">
{% trans "Sender address" %}
</label>
<div class="col-md-9 static-form-row-with-btn">
{{ request.organizer.settings.mail_from }}
&nbsp;&nbsp;
<a href="{% url "control:organizer.settings.mail.setup" organizer=request.organizer.slug %}"
class="btn btn-default">
<span class="fa fa-edit"></span>
{% trans "Edit" %}
</a>
</div>
</div>
{% bootstrap_field form.mail_from_name layout="control" %}
{% bootstrap_field form.mail_text_signature layout="control" %}
{% bootstrap_field form.mail_bcc layout="control" %}
@@ -35,24 +67,11 @@
{% include "pretixcontrol/event/mail_settings_fragment.html" with pid="reset" title=title_reset items="mail_text_customer_reset" %}
</div>
</fieldset>
<fieldset>
<legend>{% trans "SMTP settings" %}</legend>
{% bootstrap_field form.smtp_use_custom layout="control" %}
{% bootstrap_field form.smtp_host layout="control" %}
{% bootstrap_field form.smtp_port layout="control" %}
{% bootstrap_field form.smtp_username layout="control" %}
{% bootstrap_field form.smtp_password layout="control" %}
{% bootstrap_field form.smtp_use_tls layout="control" %}
{% bootstrap_field form.smtp_use_ssl layout="control" %}
</fieldset>
</div>
<div class="form-group submit-group">
<button type="submit" class="btn btn-primary btn-save">
{% trans "Save" %}
</button>
<button type="submit" class="btn btn-default btn-save pull-left" name="test" value="1">
{% trans "Save and test custom SMTP connection" %}
</button>
</div>
</form>
{% endblock %}
+3
View File
@@ -112,6 +112,8 @@ urlpatterns = [
re_path(r'^organizer/(?P<organizer>[^/]+)/edit$', organizer.OrganizerUpdate.as_view(), name='organizer.edit'),
re_path(r'^organizer/(?P<organizer>[^/]+)/settings/email$',
organizer.OrganizerMailSettings.as_view(), name='organizer.settings.mail'),
re_path(r'^organizer/(?P<organizer>[^/]+)/settings/email/setup$',
organizer.MailSettingsSetup.as_view(), name='organizer.settings.mail.setup'),
re_path(r'^organizer/(?P<organizer>[^/]+)/settings/email/preview$',
organizer.MailSettingsPreview.as_view(), name='organizer.settings.mail.preview'),
re_path(r'^organizer/(?P<organizer>[^/]+)/delete$', organizer.OrganizerDelete.as_view(), name='organizer.delete'),
@@ -214,6 +216,7 @@ urlpatterns = [
re_path(r'^settings/tickets/preview/(?P<output>[^/]+)$', event.TicketSettingsPreview.as_view(),
name='event.settings.tickets.preview'),
re_path(r'^settings/email$', event.MailSettings.as_view(), name='event.settings.mail'),
re_path(r'^settings/email/setup$', event.MailSettingsSetup.as_view(), name='event.settings.mail.setup'),
re_path(r'^settings/email/preview$', event.MailSettingsPreview.as_view(), name='event.settings.mail.preview'),
re_path(r'^settings/email/layoutpreview$', event.MailSettingsRendererPreview.as_view(),
name='event.settings.mail.preview.layout'),
+19 -20
View File
@@ -65,9 +65,7 @@ from i18nfield.utils import I18nJSONEncoder
from pytz import timezone
from pretix.base.channels import get_all_sales_channels
from pretix.base.email import (
get_available_placeholders, test_custom_smtp_backend,
)
from pretix.base.email import get_available_placeholders
from pretix.base.models import Event, LogEntry, Order, TaxRule, Voucher
from pretix.base.models.event import EventMetaValue
from pretix.base.services import tickets
@@ -83,6 +81,7 @@ from pretix.control.forms.event import (
TicketSettingsForm, WidgetCodeForm,
)
from pretix.control.permissions import EventPermissionRequiredMixin
from pretix.control.views.mailsetup import MailSettingsSetupView
from pretix.control.views.user import RecentAuthenticationRequiredMixin
from pretix.helpers.database import rolledback_transaction
from pretix.multidomain.urlreverse import get_event_domain
@@ -639,29 +638,29 @@ class MailSettings(EventSettingsViewMixin, EventSettingsFormView):
k: form.cleaned_data.get(k) for k in form.changed_data
}
)
if request.POST.get('test', '0').strip() == '1':
backend = self.request.event.get_mail_backend(force_custom=True, timeout=10)
try:
test_custom_smtp_backend(backend, self.request.event.settings.mail_from)
except Exception as e:
messages.warning(self.request, _('An error occurred while contacting the SMTP server: %s') % str(e))
else:
if form.cleaned_data.get('smtp_use_custom'):
messages.success(self.request, _('Your changes have been saved and the connection attempt to '
'your SMTP server was successful.'))
else:
messages.success(self.request, _('We\'ve been able to contact the SMTP server you configured. '
'Remember to check the "use custom SMTP server" checkbox, '
'otherwise your SMTP server will not be used.'))
else:
messages.success(self.request, _('Your changes have been saved.'))
messages.success(self.request, _('Your changes have been saved.'))
return redirect(self.get_success_url())
else:
messages.error(self.request, _('We could not save your changes. See below for details.'))
return self.get(request)
class MailSettingsSetup(EventPermissionRequiredMixin, MailSettingsSetupView):
permission = 'can_change_event_settings'
basetpl = 'pretixcontrol/event/base.html'
def get_success_url(self) -> str:
return reverse('control:event.settings.mail', kwargs={
'organizer': self.request.event.organizer.slug,
'event': self.request.event.slug
})
def log_action(self, data):
self.request.event.log_action(
'pretix.event.settings', user=self.request.user, data=data
)
class MailSettingsPreview(EventPermissionRequiredMixin, View):
permission = 'can_change_event_settings'
+279
View File
@@ -0,0 +1,279 @@
#
# 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/>.
#
import logging
import dns.resolver
from django.conf import settings
from django.contrib import messages
from django.core.mail import get_connection
from django.shortcuts import redirect
from django.utils.crypto import get_random_string
from django.utils.functional import cached_property
from django.utils.translation import gettext_lazy as _
from django.views.generic import TemplateView
from pretix.base import email
from pretix.base.models import Event
from pretix.base.services.mail import mail
from pretix.control.forms.filter import OrganizerFilterForm
from pretix.control.forms.mailsetup import SimpleMailForm, SMTPMailForm
logger = logging.getLogger(__name__)
def get_spf_record(hostname):
try:
r = dns.resolver.Resolver()
for resp in r.query(hostname, 'TXT'):
data = b''.join(resp.strings).decode()
if data.lower().strip().startswith('v=spf1 '): # RFC7208, section 4.5
return data
except:
logger.exception("Could not fetch SPF record")
def _check_spf_record(not_found_lookup_parts, spf_record, depth):
if depth > 10: # prevent infinite loops
return
parts = spf_record.lower().split(" ") # RFC 7208, section 4.6.1
for p in parts:
try:
not_found_lookup_parts.remove(p)
except KeyError:
pass
if not not_found_lookup_parts: # save some DNS requests if we already found everything
return
for p in parts:
if p.startswith('include:') or p.startswith('+include:'):
_, hostname = p.split(':')
rec_record = get_spf_record(hostname)
if rec_record:
_check_spf_record(not_found_lookup_parts, rec_record, depth + 1)
def check_spf_record(lookup, spf_record):
"""
Check that all parts of lookup appear somewhere in the given SPF record, resolving
include: directives recursively
"""
not_found_lookup_parts = set(lookup.split(" "))
_check_spf_record(not_found_lookup_parts, spf_record, 0)
return not not_found_lookup_parts
class MailSettingsSetupView(TemplateView):
template_name = 'pretixcontrol/email_setup.html'
basetpl = None
@cached_property
def object(self):
return getattr(self.request, 'event', self.request.organizer)
@cached_property
def smtp_form(self):
return SMTPMailForm(
obj=self.object,
prefix='smtp',
data=self.request.POST if (self.request.method == "POST" and self.request.POST.get("mode") == "smtp") else None,
)
@cached_property
def simple_form(self):
return SimpleMailForm(
obj=self.object,
prefix='simple',
data=self.request.POST if (self.request.method == "POST" and self.request.POST.get("mode") == "simple") else None,
)
def get_context_data(self, **kwargs):
ctx = super().get_context_data(**kwargs)
ctx['basetpl'] = self.basetpl
ctx['object'] = self.object
ctx['smtp_form'] = self.smtp_form
ctx['simple_form'] = self.simple_form
ctx['default_sender_address'] = settings.MAIL_FROM_ORGANIZERS
if 'mode' in self.request.POST:
ctx['mode'] = self.request.POST.get('mode')
elif self.object.settings.smtp_use_custom:
ctx['mode'] = 'smtp'
elif self.object.settings.mail_from not in (settings.MAIL_FROM_ORGANIZERS, settings.MAIL_FROM):
ctx['mode'] = 'simple'
else:
ctx['mode'] = 'system'
return ctx
@cached_property
def filter_form(self):
return OrganizerFilterForm(data=self.request.GET, request=self.request)
def post(self, request, *args, **kwargs):
if request.POST.get('mode') == 'system':
if isinstance(self.object, Event) and 'mail_from' in self.object.organizer.settings._cache():
self.object.settings.mail_from = settings.MAIL_FROM_ORGANIZERS
else:
del self.object.settings.mail_from
self.object.settings.smtp_use_custom = False
del self.object.settings.smtp_host
del self.object.settings.smtp_port
del self.object.settings.smtp_username
del self.object.settings.smtp_password
del self.object.settings.smtp_use_tls
del self.object.settings.smtp_use_ssl
messages.success(request, _('Your changes have been saved.'))
return redirect(self.get_success_url())
elif request.POST.get('mode') == 'reset':
del self.object.settings.mail_from
del self.object.settings.smtp_use_custom
del self.object.settings.smtp_host
del self.object.settings.smtp_port
del self.object.settings.smtp_username
del self.object.settings.smtp_password
del self.object.settings.smtp_use_tls
del self.object.settings.smtp_use_ssl
messages.success(request, _('Your changes have been saved.'))
return redirect(self.get_success_url())
elif request.POST.get('mode') == 'simple':
if not self.simple_form.is_valid():
return super().get(request, *args, **kwargs)
session_key = f'sender_mail_verification_code_{self.request.path}_{self.simple_form.cleaned_data.get("mail_from")}'
allow_save = (
(not settings.MAIL_CUSTOM_SENDER_VERIFICATION_REQUIRED or
('verification' in self.request.POST and self.request.POST.get('verification', '') == self.request.session.get(session_key, None))) and
(not settings.MAIL_CUSTOM_SENDER_SPF_STRING or self.request.POST.get('state') == 'save')
)
if allow_save:
for k, v in self.simple_form.cleaned_data.items():
self.object.settings.set(k, v)
self.log_action(self.simple_form.cleaned_data)
if session_key in request.session:
del request.session[session_key]
messages.success(request, _('Your changes have been saved.'))
return redirect(self.get_success_url())
spf_warning = None
spf_record = None
if settings.MAIL_CUSTOM_SENDER_SPF_STRING:
hostname = self.simple_form.cleaned_data['mail_from'].split('@')[-1]
spf_record = get_spf_record(hostname)
if not spf_record:
spf_warning = _(
'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.'
)
elif not check_spf_record(settings.MAIL_CUSTOM_SENDER_SPF_STRING, spf_record):
spf_warning = _(
'We found an SPF record set for the domain you are trying to use, but it does not include this '
'system\'s email server. This means that there is a very high chance most of the emails will be '
'rejected or marked as spam. You should update the DNS settings of your domain to include '
'this system in the SPF record.'
)
if settings.MAIL_CUSTOM_SENDER_VERIFICATION_REQUIRED:
if 'verification' in self.request.POST:
messages.error(request, _('The verification code was incorrect, please try again.'))
else:
self.request.session[session_key] = get_random_string(length=6, allowed_chars='1234567890')
mail(
self.simple_form.cleaned_data.get('mail_from'),
_('Sender address verification'),
'pretixcontrol/email/email_setup.txt',
{
'code': self.request.session[session_key],
'address': self.simple_form.cleaned_data.get('mail_from'),
'instance': settings.PRETIX_INSTANCE_NAME,
},
None,
locale=self.request.LANGUAGE_CODE,
user=self.request.user
)
return self.response_class(
request=self.request,
template='pretixcontrol/email_setup_simple.html',
context={
'basetpl': self.basetpl,
'object': self.object,
'verification': settings.MAIL_CUSTOM_SENDER_VERIFICATION_REQUIRED,
'spf_warning': spf_warning,
'spf_record': spf_record,
'spf_key': settings.MAIL_CUSTOM_SENDER_SPF_STRING,
'recp': self.simple_form.cleaned_data.get('mail_from')
},
using=self.template_engine,
)
elif request.POST.get('mode') == 'smtp':
if not self.smtp_form.is_valid():
return super().get(request, *args, **kwargs)
if request.POST.get('state') == 'save':
for k, v in self.smtp_form.cleaned_data.items():
self.object.settings.set(k, v)
self.object.settings.smtp_use_custom = True
self.log_action({**self.smtp_form.cleaned_data, 'smtp_use_custom': True})
messages.success(request, _('Your changes have been saved.'))
return redirect(self.get_success_url())
else:
backend = get_connection(
backend=settings.EMAIL_CUSTOM_SMTP_BACKEND,
host=self.smtp_form.cleaned_data['smtp_host'],
port=self.smtp_form.cleaned_data['smtp_port'],
username=self.smtp_form.cleaned_data.get('smtp_username', ''),
password=self.smtp_form.cleaned_data.get('smtp_password', ''),
use_tls=self.smtp_form.cleaned_data.get('smtp_use_tls', False),
use_ssl=self.smtp_form.cleaned_data.get('smtp_use_ssl', False),
fail_silently=False,
timeout=10,
)
try:
email.test_custom_smtp_backend(backend, self.smtp_form.cleaned_data.get('mail_from'))
except Exception as e:
messages.error(self.request, _('An error occurred while contacting the SMTP server: %s') % str(e))
return self.get(request, *args, **kwargs)
return self.response_class(
request=self.request,
template='pretixcontrol/email_setup_smtp.html',
context={
'basetpl': self.basetpl,
'object': self.object,
'known_host_problem': {
'smtp.gmail.com': _(
'We recommend not using Google Mail for transactional emails. If you try sending many '
'emails in a short amount of time, e.g. when sending information to all your ticket '
'buyers, there is a high chance Google will not deliver all of your emails since they '
'impose a maximum number of emails per time period.'
),
}.get(self.smtp_form.cleaned_data['smtp_host']),
},
using=self.template_engine,
)
+16 -17
View File
@@ -64,7 +64,6 @@ from django.views.generic import (
from pretix.api.models import WebHook
from pretix.base.auth import get_auth_backends
from pretix.base.channels import get_all_sales_channels
from pretix.base.email import test_custom_smtp_backend
from pretix.base.i18n import language
from pretix.base.models import (
CachedFile, Customer, Device, Gate, GiftCard, Invoice, LogEntry,
@@ -102,6 +101,7 @@ from pretix.control.permissions import (
)
from pretix.control.signals import nav_organizer
from pretix.control.views import PaginationMixin
from pretix.control.views.mailsetup import MailSettingsSetupView
from pretix.helpers.dicts import merge_dicts
from pretix.helpers.urls import build_absolute_uri as build_global_uri
from pretix.multidomain.urlreverse import build_absolute_uri
@@ -262,22 +262,6 @@ class OrganizerMailSettings(OrganizerSettingsFormView):
k: form.cleaned_data.get(k) for k in form.changed_data
}
)
if request.POST.get('test', '0').strip() == '1':
backend = self.request.organizer.get_mail_backend(force_custom=True, timeout=10)
try:
test_custom_smtp_backend(backend, self.request.organizer.settings.mail_from)
except Exception as e:
messages.warning(self.request, _('An error occurred while contacting the SMTP server: %s') % str(e))
else:
if form.cleaned_data.get('smtp_use_custom'):
messages.success(self.request, _('Your changes have been saved and the connection attempt to '
'your SMTP server was successful.'))
else:
messages.success(self.request, _('We\'ve been able to contact the SMTP server you configured. '
'Remember to check the "use custom SMTP server" checkbox, '
'otherwise your SMTP server will not be used.'))
else:
messages.success(self.request, _('Your changes have been saved.'))
return redirect(self.get_success_url())
else:
@@ -285,6 +269,21 @@ class OrganizerMailSettings(OrganizerSettingsFormView):
return self.get(request)
class MailSettingsSetup(OrganizerPermissionRequiredMixin, MailSettingsSetupView):
permission = 'can_change_organizer_settings'
basetpl = 'pretixcontrol/base.html'
def get_success_url(self):
return reverse('control:organizer.settings.mail', kwargs={
'organizer': self.request.organizer.slug,
})
def log_action(self, data):
self.request.organizer.log_action(
'pretix.organizer.settings', user=self.request.user, data=data
)
class MailSettingsPreview(OrganizerPermissionRequiredMixin, View):
permission = 'can_change_organizer_settings'
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-01-14 14:33+0000\n"
"POT-Creation-Date: 2022-01-27 10:02+0000\n"
"PO-Revision-Date: 2021-09-15 11:22+0000\n"
"Last-Translator: Mohamed Tawfiq <mtawfiq@wafyapp.com>\n"
"Language-Team: Arabic <https://translate.pretix.eu/projects/pretix/pretix-js/"
@@ -453,15 +453,15 @@ msgstr "البحث في الاستفسارات"
msgid "Selected only"
msgstr "المختارة فقط"
#: pretix/static/pretixcontrol/js/ui/main.js:834
#: pretix/static/pretixcontrol/js/ui/main.js:848
msgid "Use a different name internally"
msgstr "قم باستخدم اسم مختلف داخليا"
#: pretix/static/pretixcontrol/js/ui/main.js:870
#: pretix/static/pretixcontrol/js/ui/main.js:884
msgid "Click to close"
msgstr "اضغط لاغلاق الصفحة"
#: pretix/static/pretixcontrol/js/ui/main.js:911
#: pretix/static/pretixcontrol/js/ui/main.js:925
msgid "You have unsaved changes!"
msgstr "لم تقم بحفظ التعديلات!"
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-01-14 14:33+0000\n"
"POT-Creation-Date: 2022-01-27 10:02+0000\n"
"PO-Revision-Date: 2020-12-19 07:00+0000\n"
"Last-Translator: albert <albert.serra.monner@gmail.com>\n"
"Language-Team: Catalan <https://translate.pretix.eu/projects/pretix/pretix-"
@@ -438,15 +438,15 @@ msgstr ""
msgid "Selected only"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:834
#: pretix/static/pretixcontrol/js/ui/main.js:848
msgid "Use a different name internally"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:870
#: pretix/static/pretixcontrol/js/ui/main.js:884
msgid "Click to close"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:911
#: pretix/static/pretixcontrol/js/ui/main.js:925
msgid "You have unsaved changes!"
msgstr ""
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-01-14 14:33+0000\n"
"POT-Creation-Date: 2022-01-27 10:02+0000\n"
"PO-Revision-Date: 2021-12-06 23:00+0000\n"
"Last-Translator: Ondřej Sokol <osokol@treesoft.cz>\n"
"Language-Team: Czech <https://translate.pretix.eu/projects/pretix/pretix-js/"
@@ -453,15 +453,15 @@ msgstr "Hledaný výraz"
msgid "Selected only"
msgstr "Pouze vybrané"
#: pretix/static/pretixcontrol/js/ui/main.js:834
#: pretix/static/pretixcontrol/js/ui/main.js:848
msgid "Use a different name internally"
msgstr "Interně používat jiný název"
#: pretix/static/pretixcontrol/js/ui/main.js:870
#: pretix/static/pretixcontrol/js/ui/main.js:884
msgid "Click to close"
msgstr "Kliknutím zavřete"
#: pretix/static/pretixcontrol/js/ui/main.js:911
#: pretix/static/pretixcontrol/js/ui/main.js:925
msgid "You have unsaved changes!"
msgstr "Máte neuložené změny!"
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -6,7 +6,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-01-14 14:33+0000\n"
"POT-Creation-Date: 2022-01-27 10:02+0000\n"
"PO-Revision-Date: 2021-09-13 09:48+0000\n"
"Last-Translator: Mie Frydensbjerg <mif@aarhus.dk>\n"
"Language-Team: Danish <https://translate.pretix.eu/projects/pretix/pretix-js/"
@@ -481,15 +481,15 @@ msgstr ""
msgid "Selected only"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:834
#: pretix/static/pretixcontrol/js/ui/main.js:848
msgid "Use a different name internally"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:870
#: pretix/static/pretixcontrol/js/ui/main.js:884
msgid "Click to close"
msgstr "Klik for at lukke"
#: pretix/static/pretixcontrol/js/ui/main.js:911
#: pretix/static/pretixcontrol/js/ui/main.js:925
msgid "You have unsaved changes!"
msgstr "Du har ændringer, der ikke er gemt!"
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-01-14 14:33+0000\n"
"POT-Creation-Date: 2022-01-27 10:02+0000\n"
"PO-Revision-Date: 2021-10-25 15:40+0000\n"
"Last-Translator: Raphael Michel <michel@rami.io>\n"
"Language-Team: German <https://translate.pretix.eu/projects/pretix/pretix-js/"
@@ -459,15 +459,15 @@ msgstr "Suchbegriff"
msgid "Selected only"
msgstr "Nur ausgewählte"
#: pretix/static/pretixcontrol/js/ui/main.js:834
#: pretix/static/pretixcontrol/js/ui/main.js:848
msgid "Use a different name internally"
msgstr "Intern einen anderen Namen verwenden"
#: pretix/static/pretixcontrol/js/ui/main.js:870
#: pretix/static/pretixcontrol/js/ui/main.js:884
msgid "Click to close"
msgstr "Klicken zum Schließen"
#: pretix/static/pretixcontrol/js/ui/main.js:911
#: pretix/static/pretixcontrol/js/ui/main.js:925
msgid "You have unsaved changes!"
msgstr "Sie haben ungespeicherte Änderungen!"
+4
View File
@@ -1,6 +1,7 @@
2FA
ABN
Absenderadresse
Absenderinformation
Absendername
Admin
Adminbereich
@@ -62,6 +63,7 @@ csv
Customer
Debug
deliverability
DNS
Di
Do
Doe
@@ -228,6 +230,7 @@ Sofort
SOFORT
Sorry
Source
SPF
SSL
STARTTLS
Steuerschuldnerschaft
@@ -255,6 +258,7 @@ TODO
TOTP
Trace
Tracking
transaktionale
Turnover
txt
überbuchen
File diff suppressed because it is too large Load Diff
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-01-14 14:33+0000\n"
"POT-Creation-Date: 2022-01-27 10:02+0000\n"
"PO-Revision-Date: 2021-10-25 15:40+0000\n"
"Last-Translator: Raphael Michel <michel@rami.io>\n"
"Language-Team: German (informal) <https://translate.pretix.eu/projects/"
@@ -458,15 +458,15 @@ msgstr "Suchbegriff"
msgid "Selected only"
msgstr "Nur ausgewählte"
#: pretix/static/pretixcontrol/js/ui/main.js:834
#: pretix/static/pretixcontrol/js/ui/main.js:848
msgid "Use a different name internally"
msgstr "Intern einen anderen Namen verwenden"
#: pretix/static/pretixcontrol/js/ui/main.js:870
#: pretix/static/pretixcontrol/js/ui/main.js:884
msgid "Click to close"
msgstr "Klicken zum Schließen"
#: pretix/static/pretixcontrol/js/ui/main.js:911
#: pretix/static/pretixcontrol/js/ui/main.js:925
msgid "You have unsaved changes!"
msgstr "Du hast ungespeicherte Änderungen!"
@@ -1,6 +1,7 @@
2FA
ABN
Absenderadresse
Absenderinformation
Absendername
Admin
Adminbereich
@@ -62,6 +63,7 @@ csv
Customer
Debug
deliverability
DNS
Di
Do
Doe
@@ -228,6 +230,7 @@ Sofort
SOFORT
Sorry
Source
SPF
SSL
STARTTLS
Steuerschuldnerschaft
@@ -255,6 +258,7 @@ TODO
TOTP
Trace
Tracking
transaktionale
Turnover
txt
überbuchen
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-01-14 14:33+0000\n"
"POT-Creation-Date: 2022-01-27 10:02+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -437,15 +437,15 @@ msgstr ""
msgid "Selected only"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:834
#: pretix/static/pretixcontrol/js/ui/main.js:848
msgid "Use a different name internally"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:870
#: pretix/static/pretixcontrol/js/ui/main.js:884
msgid "Click to close"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:911
#: pretix/static/pretixcontrol/js/ui/main.js:925
msgid "You have unsaved changes!"
msgstr ""
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-01-14 14:33+0000\n"
"POT-Creation-Date: 2022-01-27 10:02+0000\n"
"PO-Revision-Date: 2019-10-03 19:00+0000\n"
"Last-Translator: Chris Spy <chrispiropoulou@hotmail.com>\n"
"Language-Team: Greek <https://translate.pretix.eu/projects/pretix/pretix-js/"
@@ -495,15 +495,15 @@ msgstr ""
msgid "Selected only"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:834
#: pretix/static/pretixcontrol/js/ui/main.js:848
msgid "Use a different name internally"
msgstr "Χρησιμοποιήστε διαφορετικό όνομα εσωτερικά"
#: pretix/static/pretixcontrol/js/ui/main.js:870
#: pretix/static/pretixcontrol/js/ui/main.js:884
msgid "Click to close"
msgstr "Κάντε κλικ για να κλείσετε"
#: pretix/static/pretixcontrol/js/ui/main.js:911
#: pretix/static/pretixcontrol/js/ui/main.js:925
msgid "You have unsaved changes!"
msgstr ""
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-01-14 14:33+0000\n"
"POT-Creation-Date: 2022-01-27 10:02+0000\n"
"PO-Revision-Date: 2021-11-25 21:00+0000\n"
"Last-Translator: Ismael Menéndez Fernández <ismael.menendez@balidea.com>\n"
"Language-Team: Spanish <https://translate.pretix.eu/projects/pretix/pretix-"
@@ -457,15 +457,15 @@ msgstr "Consultar búsqueda"
msgid "Selected only"
msgstr "Solamente seleccionados"
#: pretix/static/pretixcontrol/js/ui/main.js:834
#: pretix/static/pretixcontrol/js/ui/main.js:848
msgid "Use a different name internally"
msgstr "Usar un nombre diferente internamente"
#: pretix/static/pretixcontrol/js/ui/main.js:870
#: pretix/static/pretixcontrol/js/ui/main.js:884
msgid "Click to close"
msgstr "Click para cerrar"
#: pretix/static/pretixcontrol/js/ui/main.js:911
#: pretix/static/pretixcontrol/js/ui/main.js:925
msgid "You have unsaved changes!"
msgstr "¡Tienes cambios sin guardar!"
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-01-14 14:33+0000\n"
"POT-Creation-Date: 2022-01-27 10:02+0000\n"
"PO-Revision-Date: 2021-11-10 05:00+0000\n"
"Last-Translator: Jaakko Rinta-Filppula <jaakko@r-f.fi>\n"
"Language-Team: Finnish <https://translate.pretix.eu/projects/pretix/pretix-"
@@ -456,15 +456,15 @@ msgstr ""
msgid "Selected only"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:834
#: pretix/static/pretixcontrol/js/ui/main.js:848
msgid "Use a different name internally"
msgstr "Käytä toista nimeä sisäisesti"
#: pretix/static/pretixcontrol/js/ui/main.js:870
#: pretix/static/pretixcontrol/js/ui/main.js:884
msgid "Click to close"
msgstr "Sulje klikkaamalla"
#: pretix/static/pretixcontrol/js/ui/main.js:911
#: pretix/static/pretixcontrol/js/ui/main.js:925
msgid "You have unsaved changes!"
msgstr "Sinulla on tallentamattomia muutoksia!"
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -6,7 +6,7 @@ msgid ""
msgstr ""
"Project-Id-Version: French\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-01-14 14:33+0000\n"
"POT-Creation-Date: 2022-01-27 10:02+0000\n"
"PO-Revision-Date: 2021-12-04 01:00+0000\n"
"Last-Translator: Eva-Maria Obermann <obermann@rami.io>\n"
"Language-Team: French <https://translate.pretix.eu/projects/pretix/pretix-js/"
@@ -487,15 +487,15 @@ msgstr ""
msgid "Selected only"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:834
#: pretix/static/pretixcontrol/js/ui/main.js:848
msgid "Use a different name internally"
msgstr "Utiliser un nom différent en interne"
#: pretix/static/pretixcontrol/js/ui/main.js:870
#: pretix/static/pretixcontrol/js/ui/main.js:884
msgid "Click to close"
msgstr "Cliquez pour fermer"
#: pretix/static/pretixcontrol/js/ui/main.js:911
#: pretix/static/pretixcontrol/js/ui/main.js:925
msgid "You have unsaved changes!"
msgstr "Vous avez des modifications non sauvegardées !"
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-01-14 14:33+0000\n"
"POT-Creation-Date: 2022-01-27 10:02+0000\n"
"PO-Revision-Date: 2021-11-25 21:00+0000\n"
"Last-Translator: Ismael Menéndez Fernández <ismael.menendez@balidea.com>\n"
"Language-Team: Galician <https://translate.pretix.eu/projects/pretix/pretix-"
@@ -455,15 +455,15 @@ msgstr "Consultar unha procura"
msgid "Selected only"
msgstr "Soamente seleccionados"
#: pretix/static/pretixcontrol/js/ui/main.js:834
#: pretix/static/pretixcontrol/js/ui/main.js:848
msgid "Use a different name internally"
msgstr "Usar un nome diferente internamente"
#: pretix/static/pretixcontrol/js/ui/main.js:870
#: pretix/static/pretixcontrol/js/ui/main.js:884
msgid "Click to close"
msgstr "Click para cerrar"
#: pretix/static/pretixcontrol/js/ui/main.js:911
#: pretix/static/pretixcontrol/js/ui/main.js:925
msgid "You have unsaved changes!"
msgstr "Tes cambios sen gardar!"
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-01-14 14:33+0000\n"
"POT-Creation-Date: 2022-01-27 10:02+0000\n"
"PO-Revision-Date: 2021-09-24 13:54+0000\n"
"Last-Translator: ofirtro <ofir.tro@gmail.com>\n"
"Language-Team: Hebrew <https://translate.pretix.eu/projects/pretix/pretix-js/"
@@ -441,15 +441,15 @@ msgstr ""
msgid "Selected only"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:834
#: pretix/static/pretixcontrol/js/ui/main.js:848
msgid "Use a different name internally"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:870
#: pretix/static/pretixcontrol/js/ui/main.js:884
msgid "Click to close"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:911
#: pretix/static/pretixcontrol/js/ui/main.js:925
msgid "You have unsaved changes!"
msgstr ""
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-01-14 14:33+0000\n"
"POT-Creation-Date: 2022-01-27 10:02+0000\n"
"PO-Revision-Date: 2020-01-24 08:00+0000\n"
"Last-Translator: Prokaj Miklós <mixolid0@gmail.com>\n"
"Language-Team: Hungarian <https://translate.pretix.eu/projects/pretix/pretix-"
@@ -483,15 +483,15 @@ msgstr ""
msgid "Selected only"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:834
#: pretix/static/pretixcontrol/js/ui/main.js:848
msgid "Use a different name internally"
msgstr "Használj másik nevet"
#: pretix/static/pretixcontrol/js/ui/main.js:870
#: pretix/static/pretixcontrol/js/ui/main.js:884
msgid "Click to close"
msgstr "Bezárásért kattints"
#: pretix/static/pretixcontrol/js/ui/main.js:911
#: pretix/static/pretixcontrol/js/ui/main.js:925
msgid "You have unsaved changes!"
msgstr "Mentetlen változtatások!"
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-01-14 14:33+0000\n"
"POT-Creation-Date: 2022-01-27 10:02+0000\n"
"PO-Revision-Date: 2021-11-20 03:00+0000\n"
"Last-Translator: Marco Giacopuzzi <marco.giaco2000@gmail.com>\n"
"Language-Team: Italian <https://translate.pretix.eu/projects/pretix/pretix-"
@@ -452,15 +452,15 @@ msgstr "Chiave di ricerca"
msgid "Selected only"
msgstr "Solo i selezionati"
#: pretix/static/pretixcontrol/js/ui/main.js:834
#: pretix/static/pretixcontrol/js/ui/main.js:848
msgid "Use a different name internally"
msgstr "Utilizza un nome diverso internamente"
#: pretix/static/pretixcontrol/js/ui/main.js:870
#: pretix/static/pretixcontrol/js/ui/main.js:884
msgid "Click to close"
msgstr "Clicca per chiudere"
#: pretix/static/pretixcontrol/js/ui/main.js:911
#: pretix/static/pretixcontrol/js/ui/main.js:925
msgid "You have unsaved changes!"
msgstr "Hai cambiamenti non salvati!"
File diff suppressed because it is too large Load Diff
+15 -9
View File
@@ -7,11 +7,11 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-01-14 14:33+0000\n"
"POT-Creation-Date: 2022-01-27 10:02+0000\n"
"PO-Revision-Date: 2022-01-19 21:00+0000\n"
"Last-Translator: Yuriko Matsunami <y.matsunami@enobyte.com>\n"
"Language-Team: Japanese <https://translate.pretix.eu/projects/pretix/"
"pretix-js/ja/>\n"
"Language-Team: Japanese <https://translate.pretix.eu/projects/pretix/pretix-"
"js/ja/>\n"
"Language: ja\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -431,7 +431,9 @@ msgstr "色彩のコントラストは読むのに十分です!"
msgid ""
"Your color has bad contrast for text on white background, please choose a "
"darker shade."
msgstr "このテキストカラーは白い背景とのコントラストがよくありません。暗い色に選び直してください。"
msgstr ""
"このテキストカラーは白い背景とのコントラストがよくありません。暗い色に選び直"
"してください。"
#: pretix/static/pretixcontrol/js/ui/main.js:417
msgid "All"
@@ -449,15 +451,15 @@ msgstr "検索ワード"
msgid "Selected only"
msgstr "選択したもののみ"
#: pretix/static/pretixcontrol/js/ui/main.js:834
#: pretix/static/pretixcontrol/js/ui/main.js:848
msgid "Use a different name internally"
msgstr "内部で別の名前を使用してください"
#: pretix/static/pretixcontrol/js/ui/main.js:870
#: pretix/static/pretixcontrol/js/ui/main.js:884
msgid "Click to close"
msgstr "クリックして閉じる"
#: pretix/static/pretixcontrol/js/ui/main.js:911
#: pretix/static/pretixcontrol/js/ui/main.js:925
msgid "You have unsaved changes!"
msgstr "保存されていない変更があります!"
@@ -637,7 +639,9 @@ msgctxt "widget"
msgid ""
"We could not create your cart, since there are currently too many users in "
"this ticket shop. Please click \"Continue\" to retry in a new tab."
msgstr "現在チケットショップが混雑しているため、お客様のカートを作ることができませんでした。新しいタブを開き「次へ」をクリックしてください。"
msgstr ""
"現在チケットショップが混雑しているため、お客様のカートを作ることができません"
"でした。新しいタブを開き「次へ」をクリックしてください。"
#: pretix/static/pretixpresale/js/widget/widget.js:38
msgctxt "widget"
@@ -649,7 +653,9 @@ msgctxt "widget"
msgid ""
"You currently have an active cart for this event. If you select more "
"products, they will be added to your existing cart."
msgstr "お客様のカートはイベントの申し込みに有効です。商品を選択し、カートへ追加してください。"
msgstr ""
"お客様のカートはイベントの申し込みに有効です。商品を選択し、カートへ追加して"
"ください。"
#: pretix/static/pretixpresale/js/widget/widget.js:41
msgctxt "widget"
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-01-14 14:33+0000\n"
"POT-Creation-Date: 2022-01-27 10:02+0000\n"
"PO-Revision-Date: 2021-12-09 15:49+0000\n"
"Last-Translator: Ilona Zilgalve <i.zilgalve@riga-jurmala.com>\n"
"Language-Team: Latvian <https://translate.pretix.eu/projects/pretix/pretix-"
@@ -458,15 +458,15 @@ msgstr "Meklēšanas pieprasījums"
msgid "Selected only"
msgstr "Tikai atzīmētos"
#: pretix/static/pretixcontrol/js/ui/main.js:834
#: pretix/static/pretixcontrol/js/ui/main.js:848
msgid "Use a different name internally"
msgstr "Izmantojiet citu nosaukumu iekšēji"
#: pretix/static/pretixcontrol/js/ui/main.js:870
#: pretix/static/pretixcontrol/js/ui/main.js:884
msgid "Click to close"
msgstr "Noklikšķiniet, lai aizvērtu"
#: pretix/static/pretixcontrol/js/ui/main.js:911
#: pretix/static/pretixcontrol/js/ui/main.js:925
msgid "You have unsaved changes!"
msgstr "Jums ir nesaglabātas izmaiņas!"
File diff suppressed because it is too large Load Diff
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-01-14 14:33+0000\n"
"POT-Creation-Date: 2022-01-27 10:02+0000\n"
"PO-Revision-Date: 2021-05-31 11:26+0000\n"
"Last-Translator: zackern <zacker@zacker.no>\n"
"Language-Team: Norwegian Bokmål <https://translate.pretix.eu/projects/pretix/"
@@ -449,15 +449,15 @@ msgstr ""
msgid "Selected only"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:834
#: pretix/static/pretixcontrol/js/ui/main.js:848
msgid "Use a different name internally"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:870
#: pretix/static/pretixcontrol/js/ui/main.js:884
msgid "Click to close"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:911
#: pretix/static/pretixcontrol/js/ui/main.js:925
msgid "You have unsaved changes!"
msgstr ""
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -6,7 +6,7 @@ msgid ""
msgstr ""
"Project-Id-Version: 1\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-01-14 14:33+0000\n"
"POT-Creation-Date: 2022-01-27 10:02+0000\n"
"PO-Revision-Date: 2021-10-29 02:00+0000\n"
"Last-Translator: Maarten van den Berg <maartenberg1@gmail.com>\n"
"Language-Team: Dutch <https://translate.pretix.eu/projects/pretix/pretix-js/"
@@ -451,15 +451,15 @@ msgstr "Zoekopdracht"
msgid "Selected only"
msgstr "Alleen geselecteerde"
#: pretix/static/pretixcontrol/js/ui/main.js:834
#: pretix/static/pretixcontrol/js/ui/main.js:848
msgid "Use a different name internally"
msgstr "Gebruik intern een andere naam"
#: pretix/static/pretixcontrol/js/ui/main.js:870
#: pretix/static/pretixcontrol/js/ui/main.js:884
msgid "Click to close"
msgstr "Klik om te sluiten"
#: pretix/static/pretixcontrol/js/ui/main.js:911
#: pretix/static/pretixcontrol/js/ui/main.js:925
msgid "You have unsaved changes!"
msgstr "U heeft nog niet opgeslagen wijzigingen!"
File diff suppressed because it is too large Load Diff
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-01-14 14:33+0000\n"
"POT-Creation-Date: 2022-01-27 10:02+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: Automatically generated\n"
"Language-Team: none\n"
@@ -436,15 +436,15 @@ msgstr ""
msgid "Selected only"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:834
#: pretix/static/pretixcontrol/js/ui/main.js:848
msgid "Use a different name internally"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:870
#: pretix/static/pretixcontrol/js/ui/main.js:884
msgid "Click to close"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:911
#: pretix/static/pretixcontrol/js/ui/main.js:925
msgid "You have unsaved changes!"
msgstr ""
File diff suppressed because it is too large Load Diff
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-01-14 14:33+0000\n"
"POT-Creation-Date: 2022-01-27 10:02+0000\n"
"PO-Revision-Date: 2021-08-05 04:00+0000\n"
"Last-Translator: Maarten van den Berg <maartenberg1@gmail.com>\n"
"Language-Team: Dutch (informal) <https://translate.pretix.eu/projects/pretix/"
@@ -456,15 +456,15 @@ msgstr "Zoekopdracht"
msgid "Selected only"
msgstr "Alleen geselecteerde"
#: pretix/static/pretixcontrol/js/ui/main.js:834
#: pretix/static/pretixcontrol/js/ui/main.js:848
msgid "Use a different name internally"
msgstr "Gebruik intern een andere naam"
#: pretix/static/pretixcontrol/js/ui/main.js:870
#: pretix/static/pretixcontrol/js/ui/main.js:884
msgid "Click to close"
msgstr "Klik om te sluiten"
#: pretix/static/pretixcontrol/js/ui/main.js:911
#: pretix/static/pretixcontrol/js/ui/main.js:925
msgid "You have unsaved changes!"
msgstr "Je hebt nog niet opgeslagen wijzigingen!"
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-01-14 14:33+0000\n"
"POT-Creation-Date: 2022-01-27 10:02+0000\n"
"PO-Revision-Date: 2019-09-24 19:00+0000\n"
"Last-Translator: Serge Bazanski <q3k@hackerspace.pl>\n"
"Language-Team: Polish <https://translate.pretix.eu/projects/pretix/pretix-js/"
@@ -488,15 +488,15 @@ msgstr ""
msgid "Selected only"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:834
#: pretix/static/pretixcontrol/js/ui/main.js:848
msgid "Use a different name internally"
msgstr "Użyj innej nazwy wewnętrznie"
#: pretix/static/pretixcontrol/js/ui/main.js:870
#: pretix/static/pretixcontrol/js/ui/main.js:884
msgid "Click to close"
msgstr "Zamknij"
#: pretix/static/pretixcontrol/js/ui/main.js:911
#: pretix/static/pretixcontrol/js/ui/main.js:925
msgid "You have unsaved changes!"
msgstr ""
File diff suppressed because it is too large Load Diff
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-01-14 14:33+0000\n"
"POT-Creation-Date: 2022-01-27 10:02+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: Automatically generated\n"
"Language-Team: none\n"
@@ -437,15 +437,15 @@ msgstr ""
msgid "Selected only"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:834
#: pretix/static/pretixcontrol/js/ui/main.js:848
msgid "Use a different name internally"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:870
#: pretix/static/pretixcontrol/js/ui/main.js:884
msgid "Click to close"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:911
#: pretix/static/pretixcontrol/js/ui/main.js:925
msgid "You have unsaved changes!"
msgstr ""
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-01-14 14:33+0000\n"
"POT-Creation-Date: 2022-01-27 10:02+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -437,15 +437,15 @@ msgstr ""
msgid "Selected only"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:834
#: pretix/static/pretixcontrol/js/ui/main.js:848
msgid "Use a different name internally"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:870
#: pretix/static/pretixcontrol/js/ui/main.js:884
msgid "Click to close"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:911
#: pretix/static/pretixcontrol/js/ui/main.js:925
msgid "You have unsaved changes!"
msgstr ""
File diff suppressed because it is too large Load Diff
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-01-14 14:33+0000\n"
"POT-Creation-Date: 2022-01-27 10:02+0000\n"
"PO-Revision-Date: 2019-03-19 09:00+0000\n"
"Last-Translator: Vitor Reis <vitor.reis7@gmail.com>\n"
"Language-Team: Portuguese (Brazil) <https://translate.pretix.eu/projects/"
@@ -494,15 +494,15 @@ msgstr ""
msgid "Selected only"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:834
#: pretix/static/pretixcontrol/js/ui/main.js:848
msgid "Use a different name internally"
msgstr "Use um nome diferente internamente"
#: pretix/static/pretixcontrol/js/ui/main.js:870
#: pretix/static/pretixcontrol/js/ui/main.js:884
msgid "Click to close"
msgstr "Clique para fechar"
#: pretix/static/pretixcontrol/js/ui/main.js:911
#: pretix/static/pretixcontrol/js/ui/main.js:925
msgid "You have unsaved changes!"
msgstr ""
File diff suppressed because it is too large Load Diff
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-01-14 14:33+0000\n"
"POT-Creation-Date: 2022-01-27 10:02+0000\n"
"PO-Revision-Date: 2020-10-27 06:00+0000\n"
"Last-Translator: David Vaz <davidmgvaz@gmail.com>\n"
"Language-Team: Portuguese (Portugal) <https://translate.pretix.eu/projects/"
@@ -473,15 +473,15 @@ msgstr ""
msgid "Selected only"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:834
#: pretix/static/pretixcontrol/js/ui/main.js:848
msgid "Use a different name internally"
msgstr "Use um nome interno diferente"
#: pretix/static/pretixcontrol/js/ui/main.js:870
#: pretix/static/pretixcontrol/js/ui/main.js:884
msgid "Click to close"
msgstr "Clique para fechar"
#: pretix/static/pretixcontrol/js/ui/main.js:911
#: pretix/static/pretixcontrol/js/ui/main.js:925
msgid "You have unsaved changes!"
msgstr "Tem alterações por guardar!"
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-01-14 14:33+0000\n"
"POT-Creation-Date: 2022-01-27 10:02+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: Automatically generated\n"
"Language-Team: none\n"
@@ -437,15 +437,15 @@ msgstr ""
msgid "Selected only"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:834
#: pretix/static/pretixcontrol/js/ui/main.js:848
msgid "Use a different name internally"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:870
#: pretix/static/pretixcontrol/js/ui/main.js:884
msgid "Click to close"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:911
#: pretix/static/pretixcontrol/js/ui/main.js:925
msgid "You have unsaved changes!"
msgstr ""
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-01-14 14:33+0000\n"
"POT-Creation-Date: 2022-01-27 10:02+0000\n"
"PO-Revision-Date: 2021-08-09 13:10+0000\n"
"Last-Translator: Svyatoslav <slava@digitalarthouse.eu>\n"
"Language-Team: Russian <https://translate.pretix.eu/projects/pretix/pretix-"
@@ -487,15 +487,15 @@ msgstr ""
msgid "Selected only"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:834
#: pretix/static/pretixcontrol/js/ui/main.js:848
msgid "Use a different name internally"
msgstr "Используйте другое внутреннее имя"
#: pretix/static/pretixcontrol/js/ui/main.js:870
#: pretix/static/pretixcontrol/js/ui/main.js:884
msgid "Click to close"
msgstr "Нажмите, чтобы закрыть"
#: pretix/static/pretixcontrol/js/ui/main.js:911
#: pretix/static/pretixcontrol/js/ui/main.js:925
msgid "You have unsaved changes!"
msgstr ""
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-01-14 14:33+0000\n"
"POT-Creation-Date: 2022-01-27 10:02+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: Automatically generated\n"
"Language-Team: none\n"
@@ -436,15 +436,15 @@ msgstr ""
msgid "Selected only"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:834
#: pretix/static/pretixcontrol/js/ui/main.js:848
msgid "Use a different name internally"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:870
#: pretix/static/pretixcontrol/js/ui/main.js:884
msgid "Click to close"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:911
#: pretix/static/pretixcontrol/js/ui/main.js:925
msgid "You have unsaved changes!"
msgstr ""
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-01-14 14:33+0000\n"
"POT-Creation-Date: 2022-01-27 10:02+0000\n"
"PO-Revision-Date: 2019-08-27 08:00+0000\n"
"Last-Translator: Bostjan Marusic <bostjan@brokenbones.si>\n"
"Language-Team: Slovenian <https://translate.pretix.eu/projects/pretix/pretix-"
@@ -484,15 +484,15 @@ msgstr ""
msgid "Selected only"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:834
#: pretix/static/pretixcontrol/js/ui/main.js:848
msgid "Use a different name internally"
msgstr "Uporabite drugo interno ime"
#: pretix/static/pretixcontrol/js/ui/main.js:870
#: pretix/static/pretixcontrol/js/ui/main.js:884
msgid "Click to close"
msgstr "Kliknite za zapiranje"
#: pretix/static/pretixcontrol/js/ui/main.js:911
#: pretix/static/pretixcontrol/js/ui/main.js:925
msgid "You have unsaved changes!"
msgstr ""
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-01-14 14:33+0000\n"
"POT-Creation-Date: 2022-01-27 10:02+0000\n"
"PO-Revision-Date: 2020-09-18 14:26+0000\n"
"Last-Translator: Tobias Sundgren <syrgas@gmail.com>\n"
"Language-Team: Swedish <https://translate.pretix.eu/projects/pretix/pretix-"
@@ -470,15 +470,15 @@ msgstr ""
msgid "Selected only"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:834
#: pretix/static/pretixcontrol/js/ui/main.js:848
msgid "Use a different name internally"
msgstr "Använd ett annat namn internt"
#: pretix/static/pretixcontrol/js/ui/main.js:870
#: pretix/static/pretixcontrol/js/ui/main.js:884
msgid "Click to close"
msgstr "Klicka för att stänga"
#: pretix/static/pretixcontrol/js/ui/main.js:911
#: pretix/static/pretixcontrol/js/ui/main.js:925
msgid "You have unsaved changes!"
msgstr "Du har osparade ändringar!"
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-01-14 14:33+0000\n"
"POT-Creation-Date: 2022-01-27 10:02+0000\n"
"PO-Revision-Date: 2018-09-03 06:36+0000\n"
"Last-Translator: Yunus Fırat Pişkin <firat.piskin@idvlabs.com>\n"
"Language-Team: Turkish <https://translate.pretix.eu/projects/pretix/pretix-"
@@ -490,15 +490,15 @@ msgstr ""
msgid "Selected only"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:834
#: pretix/static/pretixcontrol/js/ui/main.js:848
msgid "Use a different name internally"
msgstr "Dahili olarak farklı bir ad kullan"
#: pretix/static/pretixcontrol/js/ui/main.js:870
#: pretix/static/pretixcontrol/js/ui/main.js:884
msgid "Click to close"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/main.js:911
#: pretix/static/pretixcontrol/js/ui/main.js:925
msgid "You have unsaved changes!"
msgstr ""
+2
View File
@@ -29,6 +29,7 @@ Customizations
datetime
deliverability
DSS
DNS
EPC
EPS
favicon
@@ -106,6 +107,7 @@ timesaver
timezones
TODO
TOTP
transactional
trustable
txt
UID

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