mirror of
https://github.com/pretix/pretix.git
synced 2026-07-14 06:41:54 +00:00
Compare commits
17 Commits
hotfix
..
db-conn-tz
| Author | SHA1 | Date | |
|---|---|---|---|
| b00b063e6d | |||
| 0b8432b2c5 | |||
| 9be6ad4124 | |||
| fdc77f6bd8 | |||
| e3d0a18bee | |||
| 81c271ee2a | |||
| e981f00dc7 | |||
| 2daf35c39e | |||
| c9530c56af | |||
| f3e31287f4 | |||
| c9aaa343e6 | |||
| 87a196c4df | |||
| a220f1678b | |||
| c8fa0852b2 | |||
| fe3433106c | |||
| f8086daf34 | |||
| 66f75a5614 |
+20
-2
@@ -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.
|
||||
|
||||
@@ -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
|
||||
-----
|
||||
|
||||
|
||||
@@ -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
|
||||
--------------------
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -17,4 +17,5 @@ If you want to **create** a plugin, please go to the
|
||||
campaigns
|
||||
certificates
|
||||
digital
|
||||
imported_secrets
|
||||
webinar
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
.. _secret_generators:
|
||||
|
||||
Ticket secret generators
|
||||
========================
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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, '')
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
})
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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>')
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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
|
||||
@@ -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 }}
|
||||
<{{ default_sender_address }}>
|
||||
</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 %}
|
||||
|
||||
<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 }}
|
||||
|
||||
<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 %}
|
||||
|
||||
<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 }}
|
||||
|
||||
<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 %}
|
||||
|
||||
@@ -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'),
|
||||
|
||||
@@ -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'
|
||||
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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!"
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
+774
-575
File diff suppressed because it is too large
Load Diff
@@ -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-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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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: 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
@@ -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
@@ -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 ""
|
||||
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user