mirror of
https://github.com/pretix/pretix.git
synced 2025-12-12 04:42:28 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a362f4ad3b |
@@ -220,30 +220,12 @@ Example::
|
|||||||
``user``, ``password``
|
``user``, ``password``
|
||||||
The SMTP user data to use for the connection. Empty by default.
|
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``
|
``from``
|
||||||
The email address to set as ``From`` header in outgoing emails by the system.
|
The email address to set as ``From`` header in outgoing emails by the system.
|
||||||
Default: ``pretix@localhost``
|
Default: ``pretix@localhost``
|
||||||
|
|
||||||
``from_notifications``
|
``tls``, ``ssl``
|
||||||
The email address to set as ``From`` header in admin notification emails by the system.
|
Use STARTTLS or SSL for the SMTP connection. Off by default.
|
||||||
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``
|
``admins``
|
||||||
Comma-separated list of email addresses that should receive a report about every error code 500 thrown by pretix.
|
Comma-separated list of email addresses that should receive a report about every error code 500 thrown by pretix.
|
||||||
|
|||||||
@@ -713,6 +713,7 @@ class EventSettingsSerializer(SettingsSerializer):
|
|||||||
'ticket_download_require_validated_email',
|
'ticket_download_require_validated_email',
|
||||||
'ticket_secret_length',
|
'ticket_secret_length',
|
||||||
'mail_prefix',
|
'mail_prefix',
|
||||||
|
'mail_from',
|
||||||
'mail_from_name',
|
'mail_from_name',
|
||||||
'mail_attach_ical',
|
'mail_attach_ical',
|
||||||
'mail_attach_tickets',
|
'mail_attach_tickets',
|
||||||
|
|||||||
@@ -665,13 +665,13 @@ class Event(EventMixin, LoggedModel):
|
|||||||
|
|
||||||
return locking.LockManager(self)
|
return locking.LockManager(self)
|
||||||
|
|
||||||
def get_mail_backend(self, timeout=None):
|
def get_mail_backend(self, timeout=None, force_custom=False):
|
||||||
"""
|
"""
|
||||||
Returns an email server connection, either by using the system-wide connection
|
Returns an email server connection, either by using the system-wide connection
|
||||||
or by returning a custom one based on the event's settings.
|
or by returning a custom one based on the event's settings.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if self.settings.smtp_use_custom:
|
if self.settings.smtp_use_custom or force_custom:
|
||||||
return get_connection(backend=settings.EMAIL_CUSTOM_SMTP_BACKEND,
|
return get_connection(backend=settings.EMAIL_CUSTOM_SMTP_BACKEND,
|
||||||
host=self.settings.smtp_host,
|
host=self.settings.smtp_host,
|
||||||
port=self.settings.smtp_port,
|
port=self.settings.smtp_port,
|
||||||
|
|||||||
@@ -191,12 +191,12 @@ class Organizer(LoggedModel):
|
|||||||
e.delete()
|
e.delete()
|
||||||
self.teams.all().delete()
|
self.teams.all().delete()
|
||||||
|
|
||||||
def get_mail_backend(self, timeout=None):
|
def get_mail_backend(self, timeout=None, force_custom=False):
|
||||||
"""
|
"""
|
||||||
Returns an email server connection, either by using the system-wide connection
|
Returns an email server connection, either by using the system-wide connection
|
||||||
or by returning a custom one based on the organizer's settings.
|
or by returning a custom one based on the organizer's settings.
|
||||||
"""
|
"""
|
||||||
if self.settings.smtp_use_custom:
|
if self.settings.smtp_use_custom or force_custom:
|
||||||
return get_connection(backend=settings.EMAIL_CUSTOM_SMTP_BACKEND,
|
return get_connection(backend=settings.EMAIL_CUSTOM_SMTP_BACKEND,
|
||||||
host=self.settings.smtp_host,
|
host=self.settings.smtp_host,
|
||||||
port=self.settings.smtp_port,
|
port=self.settings.smtp_port,
|
||||||
|
|||||||
@@ -217,8 +217,7 @@ def mail(email: Union[str, Sequence[str]], subject: str, template: Union[str, La
|
|||||||
for bcc_mail in settings_holder.settings.mail_bcc.split(','):
|
for bcc_mail in settings_holder.settings.mail_bcc.split(','):
|
||||||
bcc.append(bcc_mail.strip())
|
bcc.append(bcc_mail.strip())
|
||||||
|
|
||||||
if settings_holder.settings.mail_from not in (settings.DEFAULT_FROM_EMAIL, settings.MAIL_FROM_ORGANIZERS) \
|
if settings_holder.settings.mail_from == settings.DEFAULT_FROM_EMAIL and settings_holder.settings.contact_mail and not headers.get('Reply-To'):
|
||||||
and settings_holder.settings.contact_mail and not headers.get('Reply-To'):
|
|
||||||
headers['Reply-To'] = settings_holder.settings.contact_mail
|
headers['Reply-To'] = settings_holder.settings.contact_mail
|
||||||
|
|
||||||
prefix = settings_holder.settings.get('mail_prefix')
|
prefix = settings_holder.settings.get('mail_prefix')
|
||||||
|
|||||||
@@ -148,7 +148,7 @@ def send_notification_mail(notification: Notification, user: User):
|
|||||||
),
|
),
|
||||||
'body': body_plain,
|
'body': body_plain,
|
||||||
'html': body_html,
|
'html': body_html,
|
||||||
'sender': settings.MAIL_FROM_NOTIFICATIONS,
|
'sender': settings.MAIL_FROM,
|
||||||
'headers': {},
|
'headers': {},
|
||||||
'user': user.pk
|
'user': user.pk
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1589,7 +1589,7 @@ DEFAULTS = {
|
|||||||
'type': str
|
'type': str
|
||||||
},
|
},
|
||||||
'mail_from': {
|
'mail_from': {
|
||||||
'default': settings.MAIL_FROM_ORGANIZERS,
|
'default': settings.MAIL_FROM,
|
||||||
'type': str,
|
'type': str,
|
||||||
'form_class': forms.EmailField,
|
'form_class': forms.EmailField,
|
||||||
'serializer_class': serializers.EmailField,
|
'serializer_class': serializers.EmailField,
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ from django.utils.timezone import now
|
|||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from django_scopes.forms import SafeModelMultipleChoiceField
|
from django_scopes.forms import SafeModelMultipleChoiceField
|
||||||
|
|
||||||
from ...base.forms import I18nModelForm
|
from ...base.forms import I18nModelForm, SecretKeySettingsField
|
||||||
|
|
||||||
# Import for backwards compatibility with okd import paths
|
# Import for backwards compatibility with okd import paths
|
||||||
from ...base.forms.widgets import ( # noqa
|
from ...base.forms.widgets import ( # noqa
|
||||||
@@ -373,6 +373,49 @@ class FontSelect(forms.RadioSelect):
|
|||||||
option_template_name = 'pretixcontrol/font_option.html'
|
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):
|
class ItemMultipleChoiceField(SafeModelMultipleChoiceField):
|
||||||
def label_from_instance(self, obj):
|
def label_from_instance(self, obj):
|
||||||
return str(obj) if obj.active else mark_safe(f'<strike class="text-muted">{escape(obj)}</strike>')
|
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,
|
PERSON_NAME_SCHEMES, PERSON_NAME_TITLE_GROUPS, validate_event_settings,
|
||||||
)
|
)
|
||||||
from pretix.control.forms import (
|
from pretix.control.forms import (
|
||||||
MultipleLanguagesWidget, SlugWidget, SplitDateTimeField,
|
MultipleLanguagesWidget, SlugWidget, SMTPSettingsMixin, SplitDateTimeField,
|
||||||
SplitDateTimePickerWidget,
|
SplitDateTimePickerWidget,
|
||||||
)
|
)
|
||||||
from pretix.control.forms.widgets import Select2
|
from pretix.control.forms.widgets import Select2
|
||||||
@@ -865,9 +865,10 @@ def contains_web_channel_validate(val):
|
|||||||
raise ValidationError(_("The online shop must be selected to receive these emails."))
|
raise ValidationError(_("The online shop must be selected to receive these emails."))
|
||||||
|
|
||||||
|
|
||||||
class MailSettingsForm(SettingsForm):
|
class MailSettingsForm(SMTPSettingsMixin, SettingsForm):
|
||||||
auto_fields = [
|
auto_fields = [
|
||||||
'mail_prefix',
|
'mail_prefix',
|
||||||
|
'mail_from',
|
||||||
'mail_from_name',
|
'mail_from_name',
|
||||||
'mail_attach_ical',
|
'mail_attach_ical',
|
||||||
'mail_attach_tickets',
|
'mail_attach_tickets',
|
||||||
|
|||||||
@@ -1,129 +0,0 @@
|
|||||||
#
|
|
||||||
# This file is part of pretix (Community Edition).
|
|
||||||
#
|
|
||||||
# Copyright (C) 2014-2020 Raphael Michel and contributors
|
|
||||||
# Copyright (C) 2020-2021 rami.io GmbH and contributors
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
|
|
||||||
# Public License as published by the Free Software Foundation in version 3 of the License.
|
|
||||||
#
|
|
||||||
# ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are
|
|
||||||
# applicable granting you additional permissions and placing additional restrictions on your usage of this software.
|
|
||||||
# Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive
|
|
||||||
# this file, see <https://pretix.eu/about/en/license>.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
|
||||||
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
|
||||||
# details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
|
|
||||||
# <https://www.gnu.org/licenses/>.
|
|
||||||
#
|
|
||||||
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,7 +60,9 @@ from pretix.base.models import (
|
|||||||
MembershipType, Organizer, Team,
|
MembershipType, Organizer, Team,
|
||||||
)
|
)
|
||||||
from pretix.base.settings import PERSON_NAME_SCHEMES, PERSON_NAME_TITLE_GROUPS
|
from pretix.base.settings import PERSON_NAME_SCHEMES, PERSON_NAME_TITLE_GROUPS
|
||||||
from pretix.control.forms import ExtFileField, SplitDateTimeField
|
from pretix.control.forms import (
|
||||||
|
ExtFileField, SMTPSettingsMixin, SplitDateTimeField,
|
||||||
|
)
|
||||||
from pretix.control.forms.event import (
|
from pretix.control.forms.event import (
|
||||||
SafeEventMultipleChoiceField, multimail_validate,
|
SafeEventMultipleChoiceField, multimail_validate,
|
||||||
)
|
)
|
||||||
@@ -356,8 +358,9 @@ class OrganizerSettingsForm(SettingsForm):
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class MailSettingsForm(SettingsForm):
|
class MailSettingsForm(SMTPSettingsMixin, SettingsForm):
|
||||||
auto_fields = [
|
auto_fields = [
|
||||||
|
'mail_from',
|
||||||
'mail_from_name',
|
'mail_from_name',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
{% 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 %}
|
|
||||||
@@ -1,127 +0,0 @@
|
|||||||
{% 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 %}
|
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
{% 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 %}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
{% 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,49 +12,16 @@
|
|||||||
<div class="tabbed-form">
|
<div class="tabbed-form">
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>{% trans "General" %}</legend>
|
<legend>{% trans "General" %}</legend>
|
||||||
{% bootstrap_field form.mail_prefix layout="control" %}
|
|
||||||
{% bootstrap_field form.mail_attach_tickets layout="control" %}
|
|
||||||
{% bootstrap_field form.mail_attach_ical layout="control" %}
|
|
||||||
{% url "control:organizer.settings.mail" organizer=request.organizer.slug as org_url %}
|
{% url "control:organizer.settings.mail" organizer=request.organizer.slug as org_url %}
|
||||||
{% propagated request.event org_url "mail_from" "smtp_use_custom" "smtp_host" "smtp_port" "smtp_username" "smtp_password" "smtp_use_tls" "smtp_use_ssl" %}
|
{% propagated request.event org_url "mail_from" "mail_from_name" "mail_text_signature" "mail_bcc" %}
|
||||||
<div class="form-group">
|
{% bootstrap_field form.mail_from layout="control" %}
|
||||||
<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_from_name layout="control" %}
|
||||||
{% bootstrap_field form.mail_text_signature layout="control" %}
|
{% bootstrap_field form.mail_text_signature layout="control" %}
|
||||||
{% bootstrap_field form.mail_bcc layout="control" %}
|
{% bootstrap_field form.mail_bcc layout="control" %}
|
||||||
{% endpropagated %}
|
{% 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" %}
|
{% bootstrap_field form.mail_sales_channel_placed_paid layout="control" %}
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
@@ -118,11 +85,26 @@
|
|||||||
<h4>{% trans "Attachments" %}</h4>
|
<h4>{% trans "Attachments" %}</h4>
|
||||||
{% bootstrap_field form.mail_attachment_new_order layout="control" %}
|
{% bootstrap_field form.mail_attachment_new_order layout="control" %}
|
||||||
</fieldset>
|
</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>
|
||||||
<div class="form-group submit-group">
|
<div class="form-group submit-group">
|
||||||
<button type="submit" class="btn btn-primary btn-save">
|
<button type="submit" class="btn btn-primary btn-save">
|
||||||
{% trans "Save" %}
|
{% trans "Save" %}
|
||||||
</button>
|
</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>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -11,45 +11,13 @@
|
|||||||
<h1>{% trans "E-mail settings" %}</h1>
|
<h1>{% trans "E-mail settings" %}</h1>
|
||||||
|
|
||||||
<form action="" method="post" class="form-horizontal" enctype="multipart/form-data"
|
<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 %}
|
{% csrf_token %}
|
||||||
{% bootstrap_form_errors form %}
|
{% bootstrap_form_errors form %}
|
||||||
<div class="tabbed-form">
|
<div class="tabbed-form">
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>{% trans "General" %}</legend>
|
<legend>{% trans "General" %}</legend>
|
||||||
<div class="form-group">
|
{% bootstrap_field form.mail_from layout="control" %}
|
||||||
<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_from_name layout="control" %}
|
||||||
{% bootstrap_field form.mail_text_signature layout="control" %}
|
{% bootstrap_field form.mail_text_signature layout="control" %}
|
||||||
{% bootstrap_field form.mail_bcc layout="control" %}
|
{% bootstrap_field form.mail_bcc layout="control" %}
|
||||||
@@ -67,11 +35,24 @@
|
|||||||
{% include "pretixcontrol/event/mail_settings_fragment.html" with pid="reset" title=title_reset items="mail_text_customer_reset" %}
|
{% include "pretixcontrol/event/mail_settings_fragment.html" with pid="reset" title=title_reset items="mail_text_customer_reset" %}
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</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>
|
||||||
<div class="form-group submit-group">
|
<div class="form-group submit-group">
|
||||||
<button type="submit" class="btn btn-primary btn-save">
|
<button type="submit" class="btn btn-primary btn-save">
|
||||||
{% trans "Save" %}
|
{% trans "Save" %}
|
||||||
</button>
|
</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>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -112,8 +112,6 @@ urlpatterns = [
|
|||||||
re_path(r'^organizer/(?P<organizer>[^/]+)/edit$', organizer.OrganizerUpdate.as_view(), name='organizer.edit'),
|
re_path(r'^organizer/(?P<organizer>[^/]+)/edit$', organizer.OrganizerUpdate.as_view(), name='organizer.edit'),
|
||||||
re_path(r'^organizer/(?P<organizer>[^/]+)/settings/email$',
|
re_path(r'^organizer/(?P<organizer>[^/]+)/settings/email$',
|
||||||
organizer.OrganizerMailSettings.as_view(), name='organizer.settings.mail'),
|
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$',
|
re_path(r'^organizer/(?P<organizer>[^/]+)/settings/email/preview$',
|
||||||
organizer.MailSettingsPreview.as_view(), name='organizer.settings.mail.preview'),
|
organizer.MailSettingsPreview.as_view(), name='organizer.settings.mail.preview'),
|
||||||
re_path(r'^organizer/(?P<organizer>[^/]+)/delete$', organizer.OrganizerDelete.as_view(), name='organizer.delete'),
|
re_path(r'^organizer/(?P<organizer>[^/]+)/delete$', organizer.OrganizerDelete.as_view(), name='organizer.delete'),
|
||||||
@@ -216,7 +214,6 @@ urlpatterns = [
|
|||||||
re_path(r'^settings/tickets/preview/(?P<output>[^/]+)$', event.TicketSettingsPreview.as_view(),
|
re_path(r'^settings/tickets/preview/(?P<output>[^/]+)$', event.TicketSettingsPreview.as_view(),
|
||||||
name='event.settings.tickets.preview'),
|
name='event.settings.tickets.preview'),
|
||||||
re_path(r'^settings/email$', event.MailSettings.as_view(), name='event.settings.mail'),
|
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/preview$', event.MailSettingsPreview.as_view(), name='event.settings.mail.preview'),
|
||||||
re_path(r'^settings/email/layoutpreview$', event.MailSettingsRendererPreview.as_view(),
|
re_path(r'^settings/email/layoutpreview$', event.MailSettingsRendererPreview.as_view(),
|
||||||
name='event.settings.mail.preview.layout'),
|
name='event.settings.mail.preview.layout'),
|
||||||
|
|||||||
@@ -65,7 +65,9 @@ from i18nfield.utils import I18nJSONEncoder
|
|||||||
from pytz import timezone
|
from pytz import timezone
|
||||||
|
|
||||||
from pretix.base.channels import get_all_sales_channels
|
from pretix.base.channels import get_all_sales_channels
|
||||||
from pretix.base.email import get_available_placeholders
|
from pretix.base.email import (
|
||||||
|
get_available_placeholders, test_custom_smtp_backend,
|
||||||
|
)
|
||||||
from pretix.base.models import Event, LogEntry, Order, TaxRule, Voucher
|
from pretix.base.models import Event, LogEntry, Order, TaxRule, Voucher
|
||||||
from pretix.base.models.event import EventMetaValue
|
from pretix.base.models.event import EventMetaValue
|
||||||
from pretix.base.services import tickets
|
from pretix.base.services import tickets
|
||||||
@@ -81,7 +83,6 @@ from pretix.control.forms.event import (
|
|||||||
TicketSettingsForm, WidgetCodeForm,
|
TicketSettingsForm, WidgetCodeForm,
|
||||||
)
|
)
|
||||||
from pretix.control.permissions import EventPermissionRequiredMixin
|
from pretix.control.permissions import EventPermissionRequiredMixin
|
||||||
from pretix.control.views.mailsetup import MailSettingsSetupView
|
|
||||||
from pretix.control.views.user import RecentAuthenticationRequiredMixin
|
from pretix.control.views.user import RecentAuthenticationRequiredMixin
|
||||||
from pretix.helpers.database import rolledback_transaction
|
from pretix.helpers.database import rolledback_transaction
|
||||||
from pretix.multidomain.urlreverse import get_event_domain
|
from pretix.multidomain.urlreverse import get_event_domain
|
||||||
@@ -638,29 +639,29 @@ class MailSettings(EventSettingsViewMixin, EventSettingsFormView):
|
|||||||
k: form.cleaned_data.get(k) for k in form.changed_data
|
k: form.cleaned_data.get(k) for k in form.changed_data
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
messages.success(self.request, _('Your changes have been saved.'))
|
|
||||||
|
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.'))
|
||||||
return redirect(self.get_success_url())
|
return redirect(self.get_success_url())
|
||||||
else:
|
else:
|
||||||
messages.error(self.request, _('We could not save your changes. See below for details.'))
|
messages.error(self.request, _('We could not save your changes. See below for details.'))
|
||||||
return self.get(request)
|
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):
|
class MailSettingsPreview(EventPermissionRequiredMixin, View):
|
||||||
permission = 'can_change_event_settings'
|
permission = 'can_change_event_settings'
|
||||||
|
|
||||||
|
|||||||
@@ -1,278 +0,0 @@
|
|||||||
#
|
|
||||||
# This file is part of pretix (Community Edition).
|
|
||||||
#
|
|
||||||
# Copyright (C) 2014-2020 Raphael Michel and contributors
|
|
||||||
# Copyright (C) 2020-2021 rami.io GmbH and contributors
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
|
|
||||||
# Public License as published by the Free Software Foundation in version 3 of the License.
|
|
||||||
#
|
|
||||||
# ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are
|
|
||||||
# applicable granting you additional permissions and placing additional restrictions on your usage of this software.
|
|
||||||
# Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive
|
|
||||||
# this file, see <https://pretix.eu/about/en/license>.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
|
||||||
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
|
||||||
# details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
|
|
||||||
# <https://www.gnu.org/licenses/>.
|
|
||||||
#
|
|
||||||
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:
|
|
||||||
for resp in dns.resolver.resolve(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,6 +64,7 @@ from django.views.generic import (
|
|||||||
from pretix.api.models import WebHook
|
from pretix.api.models import WebHook
|
||||||
from pretix.base.auth import get_auth_backends
|
from pretix.base.auth import get_auth_backends
|
||||||
from pretix.base.channels import get_all_sales_channels
|
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.i18n import language
|
||||||
from pretix.base.models import (
|
from pretix.base.models import (
|
||||||
CachedFile, Customer, Device, Gate, GiftCard, Invoice, LogEntry,
|
CachedFile, Customer, Device, Gate, GiftCard, Invoice, LogEntry,
|
||||||
@@ -101,7 +102,6 @@ from pretix.control.permissions import (
|
|||||||
)
|
)
|
||||||
from pretix.control.signals import nav_organizer
|
from pretix.control.signals import nav_organizer
|
||||||
from pretix.control.views import PaginationMixin
|
from pretix.control.views import PaginationMixin
|
||||||
from pretix.control.views.mailsetup import MailSettingsSetupView
|
|
||||||
from pretix.helpers.dicts import merge_dicts
|
from pretix.helpers.dicts import merge_dicts
|
||||||
from pretix.helpers.urls import build_absolute_uri as build_global_uri
|
from pretix.helpers.urls import build_absolute_uri as build_global_uri
|
||||||
from pretix.multidomain.urlreverse import build_absolute_uri
|
from pretix.multidomain.urlreverse import build_absolute_uri
|
||||||
@@ -262,6 +262,22 @@ class OrganizerMailSettings(OrganizerSettingsFormView):
|
|||||||
k: form.cleaned_data.get(k) for k in form.changed_data
|
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.'))
|
messages.success(self.request, _('Your changes have been saved.'))
|
||||||
return redirect(self.get_success_url())
|
return redirect(self.get_success_url())
|
||||||
else:
|
else:
|
||||||
@@ -269,21 +285,6 @@ class OrganizerMailSettings(OrganizerSettingsFormView):
|
|||||||
return self.get(request)
|
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):
|
class MailSettingsPreview(OrganizerPermissionRequiredMixin, View):
|
||||||
permission = 'can_change_organizer_settings'
|
permission = 'can_change_organizer_settings'
|
||||||
|
|
||||||
|
|||||||
@@ -213,12 +213,8 @@ ALLOWED_HOSTS = ['*']
|
|||||||
LANGUAGE_CODE = config.get('locale', 'default', fallback='en')
|
LANGUAGE_CODE = config.get('locale', 'default', fallback='en')
|
||||||
TIME_ZONE = config.get('locale', 'timezone', fallback='UTC')
|
TIME_ZONE = config.get('locale', 'timezone', fallback='UTC')
|
||||||
|
|
||||||
MAIL_FROM = SERVER_EMAIL = DEFAULT_FROM_EMAIL = config.get('mail', 'from', fallback='pretix@localhost')
|
MAIL_FROM = SERVER_EMAIL = DEFAULT_FROM_EMAIL = config.get(
|
||||||
MAIL_FROM_NOTIFICATIONS = config.get('mail', 'from_notifications', fallback=MAIL_FROM)
|
'mail', 'from', fallback='pretix@localhost')
|
||||||
MAIL_FROM_ORGANIZERS = config.get('mail', 'from_organizers', fallback=MAIL_FROM)
|
|
||||||
MAIL_CUSTOM_SENDER_VERIFICATION_REQUIRED = config.getboolean('mail', 'custom_sender_verification_required', fallback=True)
|
|
||||||
MAIL_CUSTOM_SENDER_SPF_STRING = config.get('mail', 'custom_sender_spf_string', fallback='')
|
|
||||||
MAIL_CUSTOM_SMTP_ALLOW_PRIVATE_NETWORKS = config.getboolean('mail', 'custom_smtp_allow_private_networks', fallback=False)
|
|
||||||
EMAIL_HOST = config.get('mail', 'host', fallback='localhost')
|
EMAIL_HOST = config.get('mail', 'host', fallback='localhost')
|
||||||
EMAIL_PORT = config.getint('mail', 'port', fallback=25)
|
EMAIL_PORT = config.getint('mail', 'port', fallback=25)
|
||||||
EMAIL_HOST_USER = config.get('mail', 'user', fallback='')
|
EMAIL_HOST_USER = config.get('mail', 'user', fallback='')
|
||||||
|
|||||||
@@ -21,9 +21,6 @@ td > .form-group > .checkbox {
|
|||||||
.static-form-row {
|
.static-form-row {
|
||||||
padding-top: 7px;
|
padding-top: 7px;
|
||||||
}
|
}
|
||||||
.static-form-row-with-btn {
|
|
||||||
padding-top: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-inline .form-control {
|
.form-inline .form-control {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
@@ -343,7 +340,6 @@ input[type=number].short {
|
|||||||
.propagated-settings-box.locked {
|
.propagated-settings-box.locked {
|
||||||
.propagated-settings-form {
|
.propagated-settings-form {
|
||||||
opacity: 0.7;
|
opacity: 0.7;
|
||||||
pointer-events: none;
|
|
||||||
}
|
}
|
||||||
.panel-body.help-text {
|
.panel-body.help-text {
|
||||||
border-bottom: 1px solid $panel-default-heading-bg;
|
border-bottom: 1px solid $panel-default-heading-bg;
|
||||||
|
|||||||
@@ -190,7 +190,6 @@ setup(
|
|||||||
'django-scopes==1.2.*',
|
'django-scopes==1.2.*',
|
||||||
'django-statici18n==2.1.*',
|
'django-statici18n==2.1.*',
|
||||||
'djangorestframework==3.12.*',
|
'djangorestframework==3.12.*',
|
||||||
'dnspython==2.2.*',
|
|
||||||
'drf_ujson2==1.6.*',
|
'drf_ujson2==1.6.*',
|
||||||
'isoweek',
|
'isoweek',
|
||||||
'jsonschema',
|
'jsonschema',
|
||||||
|
|||||||
@@ -36,11 +36,8 @@
|
|||||||
import datetime
|
import datetime
|
||||||
import time
|
import time
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
from smtplib import SMTPResponseException
|
|
||||||
|
|
||||||
import pytest
|
|
||||||
import pytz
|
import pytz
|
||||||
from django.test.utils import override_settings
|
|
||||||
from django.utils.timezone import now
|
from django.utils.timezone import now
|
||||||
from django_scopes import scopes_disabled
|
from django_scopes import scopes_disabled
|
||||||
from i18nfield.strings import LazyI18nString
|
from i18nfield.strings import LazyI18nString
|
||||||
@@ -51,12 +48,6 @@ from pretix.base.models import Event, LogEntry, Order, Organizer, Team, User
|
|||||||
from pretix.testutils.mock import mocker_context
|
from pretix.testutils.mock import mocker_context
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def class_monkeypatch(request, monkeypatch):
|
|
||||||
request.cls.monkeypatch = monkeypatch
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.usefixtures("class_monkeypatch")
|
|
||||||
class EventsTest(SoupTest):
|
class EventsTest(SoupTest):
|
||||||
@scopes_disabled()
|
@scopes_disabled()
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
@@ -515,204 +506,25 @@ class EventsTest(SoupTest):
|
|||||||
assert self.event1.settings.primary_color == self.orga1.settings.primary_color
|
assert self.event1.settings.primary_color == self.orga1.settings.primary_color
|
||||||
|
|
||||||
def test_email_settings(self):
|
def test_email_settings(self):
|
||||||
doc = self.get_doc('/control/event/%s/%s/settings/email' % (self.orga1.slug, self.event1.slug))
|
with mocker_context() as mocker:
|
||||||
data = extract_form_fields(doc.select("form")[0])
|
mocked = mocker.patch('pretix.control.views.event.test_custom_smtp_backend')
|
||||||
data['mail_from_name'] = 'test'
|
doc = self.get_doc('/control/event/%s/%s/settings/email' % (self.orga1.slug, self.event1.slug))
|
||||||
doc = self.post_doc('/control/event/%s/%s/settings/email' % (self.orga1.slug, self.event1.slug),
|
data = extract_form_fields(doc.select("form")[0])
|
||||||
data, follow=True)
|
data['test'] = '1'
|
||||||
assert doc.select('.alert-success')
|
doc = self.post_doc('/control/event/%s/%s/settings/email' % (self.orga1.slug, self.event1.slug),
|
||||||
self.event1.settings.flush()
|
data, follow=True)
|
||||||
assert self.event1.settings.mail_from_name == "test"
|
print(doc)
|
||||||
|
assert doc.select('.alert-success')
|
||||||
def test_email_setup_system(self):
|
self.event1.settings.flush()
|
||||||
doc = self.post_doc(
|
assert mocked.called
|
||||||
'/control/event/%s/%s/settings/email/setup' % (self.orga1.slug, self.event1.slug),
|
|
||||||
{
|
|
||||||
'mode': 'system'
|
|
||||||
},
|
|
||||||
follow=True
|
|
||||||
)
|
|
||||||
assert doc.select('.alert-success')
|
|
||||||
self.event1.settings.flush()
|
|
||||||
assert "mail_from" not in self.orga1.settings._cache()
|
|
||||||
assert not self.event1.settings.smtp_use_custom
|
|
||||||
|
|
||||||
@override_settings(MAIL_CUSTOM_SENDER_VERIFICATION_REQUIRED=True, MAIL_CUSTOM_SENDER_SPF_STRING=False)
|
|
||||||
def test_email_setup_simple_with_verification(self):
|
|
||||||
doc = self.post_doc(
|
|
||||||
'/control/event/%s/%s/settings/email/setup' % (self.orga1.slug, self.event1.slug),
|
|
||||||
{
|
|
||||||
'mode': 'simple',
|
|
||||||
'simple-mail_from': 'test@test.pretix.dev',
|
|
||||||
},
|
|
||||||
follow=True
|
|
||||||
)
|
|
||||||
self.event1.settings.flush()
|
|
||||||
assert "mail_from" not in self.event1.settings._cache()
|
|
||||||
data = extract_form_fields(doc.select("form")[0])
|
|
||||||
data['verification'] = self.client.session[
|
|
||||||
f'sender_mail_verification_code_/control/event/{self.orga1.slug}/{self.event1.slug}/settings/email/setup_test@test.pretix.dev'
|
|
||||||
]
|
|
||||||
doc = self.post_doc(
|
|
||||||
'/control/event/%s/%s/settings/email/setup' % (self.orga1.slug, self.event1.slug),
|
|
||||||
data,
|
|
||||||
follow=True
|
|
||||||
)
|
|
||||||
assert doc.select('.alert-success')
|
|
||||||
self.event1.settings.flush()
|
|
||||||
assert self.event1.settings.mail_from == 'test@test.pretix.dev'
|
|
||||||
|
|
||||||
@override_settings(MAIL_CUSTOM_SENDER_VERIFICATION_REQUIRED=True, MAIL_CUSTOM_SENDER_SPF_STRING=False)
|
|
||||||
def test_email_setup_simple_with_verification_wrong_code(self):
|
|
||||||
doc = self.post_doc(
|
|
||||||
'/control/event/%s/%s/settings/email/setup' % (self.orga1.slug, self.event1.slug),
|
|
||||||
{
|
|
||||||
'mode': 'simple',
|
|
||||||
'simple-mail_from': 'test@test.pretix.dev',
|
|
||||||
},
|
|
||||||
follow=True
|
|
||||||
)
|
|
||||||
self.event1.settings.flush()
|
|
||||||
assert "mail_from" not in self.event1.settings._cache()
|
|
||||||
data = extract_form_fields(doc.select("form")[0])
|
|
||||||
data['verification'] = 'AAAA'
|
|
||||||
doc = self.post_doc(
|
|
||||||
'/control/event/%s/%s/settings/email/setup' % (self.orga1.slug, self.event1.slug),
|
|
||||||
data,
|
|
||||||
follow=True
|
|
||||||
)
|
|
||||||
assert doc.select('.alert-danger')
|
|
||||||
self.event1.settings.flush()
|
|
||||||
assert "mail_from" not in self.event1.settings._cache()
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _fake_spf_record(hostname):
|
|
||||||
return {
|
|
||||||
'test.pretix.dev': 'v=spf1 a mx include:level2.pretix.dev ~all',
|
|
||||||
'level2.pretix.dev': 'v=spf1 a mx +include:level3.pretix.dev include:spftest.pretix.dev '
|
|
||||||
'-include:level4.pretix.dev ~all',
|
|
||||||
'level3.pretix.dev': 'v=spf1 a mx include:test2.pretix.dev ~all',
|
|
||||||
'level4.pretix.dev': 'v=spf1 a mx include:test3.pretix.dev ~all',
|
|
||||||
'test2.pretix.dev': None,
|
|
||||||
'test3.pretix.dev': None,
|
|
||||||
'spftest.pretix.dev': None,
|
|
||||||
}[hostname]
|
|
||||||
|
|
||||||
@override_settings(MAIL_CUSTOM_SENDER_VERIFICATION_REQUIRED=False, MAIL_CUSTOM_SENDER_SPF_STRING="include:spftest.pretix.dev include:test2.pretix.dev")
|
|
||||||
def test_email_setup_no_verification_spf_success(self):
|
|
||||||
self.monkeypatch.setattr("pretix.control.views.mailsetup.get_spf_record", EventsTest._fake_spf_record)
|
|
||||||
doc = self.post_doc(
|
|
||||||
'/control/event/%s/%s/settings/email/setup' % (self.orga1.slug, self.event1.slug),
|
|
||||||
{
|
|
||||||
'mode': 'simple',
|
|
||||||
'simple-mail_from': 'test@test.pretix.dev',
|
|
||||||
},
|
|
||||||
follow=True
|
|
||||||
)
|
|
||||||
assert doc.select('.alert-success')
|
|
||||||
self.event1.settings.flush()
|
|
||||||
# not yet saved
|
|
||||||
assert "mail_from" not in self.event1.settings._cache()
|
|
||||||
data = extract_form_fields(doc.select("form")[0])
|
|
||||||
doc = self.post_doc(
|
|
||||||
'/control/event/%s/%s/settings/email/setup' % (self.orga1.slug, self.event1.slug),
|
|
||||||
data,
|
|
||||||
follow=True
|
|
||||||
)
|
|
||||||
assert doc.select('.alert-success')
|
|
||||||
self.event1.settings.flush()
|
|
||||||
assert self.event1.settings.mail_from == 'test@test.pretix.dev'
|
|
||||||
|
|
||||||
@override_settings(MAIL_CUSTOM_SENDER_VERIFICATION_REQUIRED=False, MAIL_CUSTOM_SENDER_SPF_STRING="include:spftest.pretix.dev include:test3.pretix.dev")
|
|
||||||
def test_email_setup_no_verification_spf_warning(self):
|
|
||||||
self.monkeypatch.setattr("pretix.control.views.mailsetup.get_spf_record", EventsTest._fake_spf_record)
|
|
||||||
doc = self.post_doc(
|
|
||||||
'/control/event/%s/%s/settings/email/setup' % (self.orga1.slug, self.event1.slug),
|
|
||||||
{
|
|
||||||
'mode': 'simple',
|
|
||||||
'simple-mail_from': 'test@test.pretix.dev',
|
|
||||||
},
|
|
||||||
follow=True
|
|
||||||
)
|
|
||||||
assert doc.select('.alert-warning')
|
|
||||||
self.event1.settings.flush()
|
|
||||||
# not yet saved
|
|
||||||
assert "mail_from" not in self.event1.settings._cache()
|
|
||||||
|
|
||||||
def test_email_setup_smtp(self):
|
|
||||||
self.monkeypatch.setattr("pretix.base.email.test_custom_smtp_backend", lambda b, a: None)
|
|
||||||
self.monkeypatch.setattr("socket.gethostbyname", lambda h: "8.8.8.8")
|
|
||||||
doc = self.post_doc(
|
|
||||||
'/control/event/%s/%s/settings/email/setup' % (self.orga1.slug, self.event1.slug),
|
|
||||||
{
|
|
||||||
'mode': 'smtp',
|
|
||||||
'smtp-mail_from': 'test@test.pretix.dev',
|
|
||||||
'smtp-smtp_host': 'test.pretix.dev',
|
|
||||||
'smtp-smtp_port': '587',
|
|
||||||
},
|
|
||||||
follow=True
|
|
||||||
)
|
|
||||||
assert doc.select('.alert-success')
|
|
||||||
# not yet saved
|
|
||||||
self.event1.settings.flush()
|
|
||||||
assert "smtp_use_custom" not in self.event1.settings._cache()
|
|
||||||
data = extract_form_fields(doc.select("form")[0])
|
|
||||||
doc = self.post_doc(
|
|
||||||
'/control/event/%s/%s/settings/email/setup' % (self.orga1.slug, self.event1.slug),
|
|
||||||
data,
|
|
||||||
follow=True
|
|
||||||
)
|
|
||||||
assert doc.select('.alert-success')
|
|
||||||
self.event1.settings.flush()
|
|
||||||
assert self.event1.settings.mail_from == 'test@test.pretix.dev'
|
|
||||||
assert self.event1.settings.smtp_host == 'test.pretix.dev'
|
|
||||||
assert self.event1.settings.smtp_port == 587
|
|
||||||
assert self.event1.settings.smtp_use_custom
|
|
||||||
|
|
||||||
def test_email_setup_smtp_failure(self):
|
|
||||||
def fail(a, b):
|
|
||||||
raise SMTPResponseException(400, 'Auth denied')
|
|
||||||
self.monkeypatch.setattr("pretix.base.email.test_custom_smtp_backend", fail)
|
|
||||||
self.monkeypatch.setattr("socket.gethostbyname", lambda h: "8.8.8.8")
|
|
||||||
doc = self.post_doc(
|
|
||||||
'/control/event/%s/%s/settings/email/setup' % (self.orga1.slug, self.event1.slug),
|
|
||||||
{
|
|
||||||
'mode': 'smtp',
|
|
||||||
'smtp-mail_from': 'test@test.pretix.dev',
|
|
||||||
'smtp-smtp_host': 'test.pretix.dev',
|
|
||||||
'smtp-smtp_port': '587',
|
|
||||||
},
|
|
||||||
follow=True
|
|
||||||
)
|
|
||||||
assert 'Auth denied' in doc.select('.alert-danger')[0].text
|
|
||||||
# not yet saved
|
|
||||||
self.event1.settings.flush()
|
|
||||||
assert "smtp_use_custom" not in self.event1.settings._cache()
|
|
||||||
assert "mail_from" not in self.event1.settings._cache()
|
|
||||||
|
|
||||||
def test_email_setup_do_not_allow_private_ip_by_default(self):
|
|
||||||
doc = self.post_doc(
|
|
||||||
'/control/event/%s/%s/settings/email/setup' % (self.orga1.slug, self.event1.slug),
|
|
||||||
{
|
|
||||||
'mode': 'simple',
|
|
||||||
'smtp-mail_from': 'test@test.pretix.dev',
|
|
||||||
'smtp-smtp_host': '10.0.1.1',
|
|
||||||
'smtp-smtp_port': '587',
|
|
||||||
},
|
|
||||||
follow=True
|
|
||||||
)
|
|
||||||
assert doc.select('.has-error')
|
|
||||||
# not yet saved
|
|
||||||
self.event1.settings.flush()
|
|
||||||
assert "smtp_use_custom" not in self.event1.settings._cache()
|
|
||||||
assert "mail_from" not in self.event1.settings._cache()
|
|
||||||
|
|
||||||
def test_ticket_settings(self):
|
def test_ticket_settings(self):
|
||||||
doc = self.get_doc('/control/event/%s/%s/settings/tickets' % (self.orga1.slug, self.event1.slug))
|
doc = self.get_doc('/control/event/%s/%s/settings/tickets' % (self.orga1.slug, self.event1.slug))
|
||||||
data = extract_form_fields(doc.select("form")[0])
|
data = extract_form_fields(doc.select("form")[0])
|
||||||
data['ticket_download'] = 'on'
|
data['ticket_download'] = 'on'
|
||||||
data['ticketoutput_testdummy__enabled'] = 'on'
|
data['ticketoutput_testdummy__enabled'] = 'on'
|
||||||
self.post_doc('/control/event/%s/%s/settings/tickets' % (self.orga1.slug, self.event1.slug), data, follow=True)
|
doc = self.post_doc('/control/event/%s/%s/settings/tickets' % (self.orga1.slug, self.event1.slug),
|
||||||
|
data, follow=True)
|
||||||
self.event1.settings.flush()
|
self.event1.settings.flush()
|
||||||
assert self.event1.settings.get('ticket_download', as_type=bool)
|
assert self.event1.settings.get('ticket_download', as_type=bool)
|
||||||
|
|
||||||
|
|||||||
@@ -20,15 +20,14 @@
|
|||||||
# <https://www.gnu.org/licenses/>.
|
# <https://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
import datetime
|
import datetime
|
||||||
from smtplib import SMTPResponseException
|
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
from django.test.utils import override_settings
|
|
||||||
from django_scopes import scopes_disabled
|
from django_scopes import scopes_disabled
|
||||||
from tests.base import SoupTest, extract_form_fields
|
from tests.base import SoupTest, extract_form_fields
|
||||||
|
|
||||||
from pretix.base.models import Event, Organizer, Team, User
|
from pretix.base.models import Event, Organizer, Team, User
|
||||||
|
from pretix.testutils.mock import mocker_context
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
@@ -101,194 +100,13 @@ class OrganizerTest(SoupTest):
|
|||||||
assert called
|
assert called
|
||||||
|
|
||||||
def test_email_settings(self):
|
def test_email_settings(self):
|
||||||
doc = self.get_doc('/control/organizer/%s/settings/email' % self.orga1.slug)
|
with mocker_context() as mocker:
|
||||||
data = extract_form_fields(doc.select("form")[0])
|
mocked = mocker.patch('pretix.control.views.organizer.test_custom_smtp_backend')
|
||||||
data['mail_from_name'] = 'test'
|
doc = self.get_doc('/control/organizer/%s/settings/email' % self.orga1.slug)
|
||||||
doc = self.post_doc('/control/organizer/%s/settings/email' % self.orga1.slug,
|
data = extract_form_fields(doc.select("form")[0])
|
||||||
data, follow=True)
|
data['test'] = '1'
|
||||||
assert doc.select('.alert-success')
|
doc = self.post_doc('/control/organizer/%s/settings/email' % self.orga1.slug,
|
||||||
self.orga1.settings.flush()
|
data, follow=True)
|
||||||
assert self.orga1.settings.mail_from_name == "test"
|
assert doc.select('.alert-success')
|
||||||
|
self.event1.settings.flush()
|
||||||
def test_email_setup_system(self):
|
assert mocked.called
|
||||||
doc = self.post_doc(
|
|
||||||
'/control/organizer/%s/settings/email/setup' % self.orga1.slug,
|
|
||||||
{
|
|
||||||
'mode': 'system'
|
|
||||||
},
|
|
||||||
follow=True
|
|
||||||
)
|
|
||||||
assert doc.select('.alert-success')
|
|
||||||
self.orga1.settings.flush()
|
|
||||||
assert "mail_from" not in self.orga1.settings._cache()
|
|
||||||
assert not self.orga1.settings.smtp_use_custom
|
|
||||||
|
|
||||||
@override_settings(MAIL_CUSTOM_SENDER_VERIFICATION_REQUIRED=True, MAIL_CUSTOM_SENDER_SPF_STRING=False)
|
|
||||||
def test_email_setup_simple_with_verification(self):
|
|
||||||
doc = self.post_doc(
|
|
||||||
'/control/organizer/%s/settings/email/setup' % self.orga1.slug,
|
|
||||||
{
|
|
||||||
'mode': 'simple',
|
|
||||||
'simple-mail_from': 'test@test.pretix.dev',
|
|
||||||
},
|
|
||||||
follow=True
|
|
||||||
)
|
|
||||||
self.orga1.settings.flush()
|
|
||||||
assert "mail_from" not in self.orga1.settings._cache()
|
|
||||||
data = extract_form_fields(doc.select("form")[0])
|
|
||||||
data['verification'] = self.client.session[
|
|
||||||
f'sender_mail_verification_code_/control/organizer/{self.orga1.slug}/settings/email/setup_test@test.pretix.dev'
|
|
||||||
]
|
|
||||||
doc = self.post_doc(
|
|
||||||
'/control/organizer/%s/settings/email/setup' % self.orga1.slug,
|
|
||||||
data,
|
|
||||||
follow=True
|
|
||||||
)
|
|
||||||
assert doc.select('.alert-success')
|
|
||||||
self.orga1.settings.flush()
|
|
||||||
assert self.orga1.settings.mail_from == 'test@test.pretix.dev'
|
|
||||||
|
|
||||||
@override_settings(MAIL_CUSTOM_SENDER_VERIFICATION_REQUIRED=True, MAIL_CUSTOM_SENDER_SPF_STRING=False)
|
|
||||||
def test_email_setup_simple_with_verification_wrong_code(self):
|
|
||||||
doc = self.post_doc(
|
|
||||||
'/control/organizer/%s/settings/email/setup' % self.orga1.slug,
|
|
||||||
{
|
|
||||||
'mode': 'simple',
|
|
||||||
'simple-mail_from': 'test@test.pretix.dev',
|
|
||||||
},
|
|
||||||
follow=True
|
|
||||||
)
|
|
||||||
self.orga1.settings.flush()
|
|
||||||
assert "mail_from" not in self.orga1.settings._cache()
|
|
||||||
data = extract_form_fields(doc.select("form")[0])
|
|
||||||
data['verification'] = 'AAAA'
|
|
||||||
doc = self.post_doc(
|
|
||||||
'/control/organizer/%s/settings/email/setup' % self.orga1.slug,
|
|
||||||
data,
|
|
||||||
follow=True
|
|
||||||
)
|
|
||||||
assert doc.select('.alert-danger')
|
|
||||||
self.orga1.settings.flush()
|
|
||||||
assert "mail_from" not in self.orga1.settings._cache()
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _fake_spf_record(hostname):
|
|
||||||
return {
|
|
||||||
'test.pretix.dev': 'v=spf1 a mx include:level2.pretix.dev ~all',
|
|
||||||
'level2.pretix.dev': 'v=spf1 a mx +include:level3.pretix.dev include:spftest.pretix.dev '
|
|
||||||
'-include:level4.pretix.dev ~all',
|
|
||||||
'level3.pretix.dev': 'v=spf1 a mx include:test2.pretix.dev ~all',
|
|
||||||
'level4.pretix.dev': 'v=spf1 a mx include:test3.pretix.dev ~all',
|
|
||||||
'test2.pretix.dev': None,
|
|
||||||
'test3.pretix.dev': None,
|
|
||||||
'spftest.pretix.dev': None,
|
|
||||||
}[hostname]
|
|
||||||
|
|
||||||
@override_settings(MAIL_CUSTOM_SENDER_VERIFICATION_REQUIRED=False, MAIL_CUSTOM_SENDER_SPF_STRING="include:spftest.pretix.dev include:test2.pretix.dev")
|
|
||||||
def test_email_setup_no_verification_spf_success(self):
|
|
||||||
self.monkeypatch.setattr("pretix.control.views.mailsetup.get_spf_record", OrganizerTest._fake_spf_record)
|
|
||||||
doc = self.post_doc(
|
|
||||||
'/control/organizer/%s/settings/email/setup' % self.orga1.slug,
|
|
||||||
{
|
|
||||||
'mode': 'simple',
|
|
||||||
'simple-mail_from': 'test@test.pretix.dev',
|
|
||||||
},
|
|
||||||
follow=True
|
|
||||||
)
|
|
||||||
assert doc.select('.alert-success')
|
|
||||||
self.orga1.settings.flush()
|
|
||||||
# not yet saved
|
|
||||||
assert "mail_from" not in self.orga1.settings._cache()
|
|
||||||
data = extract_form_fields(doc.select("form")[0])
|
|
||||||
doc = self.post_doc(
|
|
||||||
'/control/organizer/%s/settings/email/setup' % self.orga1.slug,
|
|
||||||
data,
|
|
||||||
follow=True
|
|
||||||
)
|
|
||||||
assert doc.select('.alert-success')
|
|
||||||
self.orga1.settings.flush()
|
|
||||||
assert self.orga1.settings.mail_from == 'test@test.pretix.dev'
|
|
||||||
|
|
||||||
@override_settings(MAIL_CUSTOM_SENDER_VERIFICATION_REQUIRED=False, MAIL_CUSTOM_SENDER_SPF_STRING="include:spftest.pretix.dev include:test3.pretix.dev")
|
|
||||||
def test_email_setup_no_verification_spf_warning(self):
|
|
||||||
self.monkeypatch.setattr("pretix.control.views.mailsetup.get_spf_record", OrganizerTest._fake_spf_record)
|
|
||||||
doc = self.post_doc(
|
|
||||||
'/control/organizer/%s/settings/email/setup' % self.orga1.slug,
|
|
||||||
{
|
|
||||||
'mode': 'simple',
|
|
||||||
'simple-mail_from': 'test@test.pretix.dev',
|
|
||||||
},
|
|
||||||
follow=True
|
|
||||||
)
|
|
||||||
assert doc.select('.alert-warning')
|
|
||||||
self.orga1.settings.flush()
|
|
||||||
# not yet saved
|
|
||||||
assert "mail_from" not in self.orga1.settings._cache()
|
|
||||||
|
|
||||||
def test_email_setup_smtp(self):
|
|
||||||
self.monkeypatch.setattr("pretix.base.email.test_custom_smtp_backend", lambda b, a: None)
|
|
||||||
self.monkeypatch.setattr("socket.gethostbyname", lambda h: "8.8.8.8")
|
|
||||||
doc = self.post_doc(
|
|
||||||
'/control/organizer/%s/settings/email/setup' % self.orga1.slug,
|
|
||||||
{
|
|
||||||
'mode': 'smtp',
|
|
||||||
'smtp-mail_from': 'test@test.pretix.dev',
|
|
||||||
'smtp-smtp_host': 'test.pretix.dev',
|
|
||||||
'smtp-smtp_port': '587',
|
|
||||||
},
|
|
||||||
follow=True
|
|
||||||
)
|
|
||||||
assert doc.select('.alert-success')
|
|
||||||
# not yet saved
|
|
||||||
self.orga1.settings.flush()
|
|
||||||
assert "smtp_use_custom" not in self.orga1.settings._cache()
|
|
||||||
data = extract_form_fields(doc.select("form")[0])
|
|
||||||
doc = self.post_doc(
|
|
||||||
'/control/organizer/%s/settings/email/setup' % self.orga1.slug,
|
|
||||||
data,
|
|
||||||
follow=True
|
|
||||||
)
|
|
||||||
assert doc.select('.alert-success')
|
|
||||||
self.orga1.settings.flush()
|
|
||||||
assert self.orga1.settings.mail_from == 'test@test.pretix.dev'
|
|
||||||
assert self.orga1.settings.smtp_host == 'test.pretix.dev'
|
|
||||||
assert self.orga1.settings.smtp_port == 587
|
|
||||||
assert self.orga1.settings.smtp_use_custom
|
|
||||||
|
|
||||||
def test_email_setup_smtp_failure(self):
|
|
||||||
def fail(a, b):
|
|
||||||
raise SMTPResponseException(400, 'Auth denied')
|
|
||||||
self.monkeypatch.setattr("pretix.base.email.test_custom_smtp_backend", fail)
|
|
||||||
self.monkeypatch.setattr("socket.gethostbyname", lambda h: "8.8.8.8")
|
|
||||||
doc = self.post_doc(
|
|
||||||
'/control/organizer/%s/settings/email/setup' % self.orga1.slug,
|
|
||||||
{
|
|
||||||
'mode': 'smtp',
|
|
||||||
'smtp-mail_from': 'test@test.pretix.dev',
|
|
||||||
'smtp-smtp_host': 'test.pretix.dev',
|
|
||||||
'smtp-smtp_port': '587',
|
|
||||||
},
|
|
||||||
follow=True
|
|
||||||
)
|
|
||||||
assert 'Auth denied' in doc.select('.alert-danger')[0].text
|
|
||||||
# not yet saved
|
|
||||||
self.orga1.settings.flush()
|
|
||||||
assert "smtp_use_custom" not in self.orga1.settings._cache()
|
|
||||||
assert "mail_from" not in self.orga1.settings._cache()
|
|
||||||
|
|
||||||
def test_email_setup_do_not_allow_private_ip_by_default(self):
|
|
||||||
doc = self.post_doc(
|
|
||||||
'/control/organizer/%s/settings/email/setup' % self.orga1.slug,
|
|
||||||
{
|
|
||||||
'mode': 'simple',
|
|
||||||
'smtp-mail_from': 'test@test.pretix.dev',
|
|
||||||
'smtp-smtp_host': '10.0.1.1',
|
|
||||||
'smtp-smtp_port': '587',
|
|
||||||
},
|
|
||||||
follow=True
|
|
||||||
)
|
|
||||||
assert doc.select('.has-error')
|
|
||||||
# not yet saved
|
|
||||||
self.orga1.settings.flush()
|
|
||||||
assert "smtp_use_custom" not in self.orga1.settings._cache()
|
|
||||||
assert "mail_from" not in self.orga1.settings._cache()
|
|
||||||
|
|||||||
@@ -92,7 +92,6 @@ event_urls = [
|
|||||||
"settings/payment",
|
"settings/payment",
|
||||||
"settings/tickets",
|
"settings/tickets",
|
||||||
"settings/email",
|
"settings/email",
|
||||||
"settings/email/setup",
|
|
||||||
"settings/cancel",
|
"settings/cancel",
|
||||||
"settings/invoice",
|
"settings/invoice",
|
||||||
"settings/invoice/preview",
|
"settings/invoice/preview",
|
||||||
@@ -172,8 +171,6 @@ event_urls = [
|
|||||||
organizer_urls = [
|
organizer_urls = [
|
||||||
'organizer/abc/edit',
|
'organizer/abc/edit',
|
||||||
'organizer/abc/',
|
'organizer/abc/',
|
||||||
'organizer/abc/settings/email',
|
|
||||||
'organizer/abc/settings/email/setup',
|
|
||||||
'organizer/abc/teams',
|
'organizer/abc/teams',
|
||||||
'organizer/abc/team/1/',
|
'organizer/abc/team/1/',
|
||||||
'organizer/abc/team/1/edit',
|
'organizer/abc/team/1/edit',
|
||||||
@@ -288,7 +285,6 @@ event_permission_urls = [
|
|||||||
("can_change_event_settings", "settings/payment", 200, HTTP_GET),
|
("can_change_event_settings", "settings/payment", 200, HTTP_GET),
|
||||||
("can_change_event_settings", "settings/tickets", 200, HTTP_GET),
|
("can_change_event_settings", "settings/tickets", 200, HTTP_GET),
|
||||||
("can_change_event_settings", "settings/email", 200, HTTP_GET),
|
("can_change_event_settings", "settings/email", 200, HTTP_GET),
|
||||||
("can_change_event_settings", "settings/email/setup", 200, HTTP_GET),
|
|
||||||
("can_change_event_settings", "settings/cancel", 200, HTTP_GET),
|
("can_change_event_settings", "settings/cancel", 200, HTTP_GET),
|
||||||
("can_change_event_settings", "settings/invoice", 200, HTTP_GET),
|
("can_change_event_settings", "settings/invoice", 200, HTTP_GET),
|
||||||
("can_change_event_settings", "settings/widget", 200, HTTP_GET),
|
("can_change_event_settings", "settings/widget", 200, HTTP_GET),
|
||||||
@@ -485,8 +481,6 @@ organizer_permission_urls = [
|
|||||||
("can_change_teams", "organizer/dummy/team/1/edit", 200),
|
("can_change_teams", "organizer/dummy/team/1/edit", 200),
|
||||||
("can_change_teams", "organizer/dummy/team/1/delete", 200),
|
("can_change_teams", "organizer/dummy/team/1/delete", 200),
|
||||||
("can_change_organizer_settings", "organizer/dummy/edit", 200),
|
("can_change_organizer_settings", "organizer/dummy/edit", 200),
|
||||||
("can_change_organizer_settings", "organizer/dummy/settings/email", 200),
|
|
||||||
("can_change_organizer_settings", "organizer/dummy/settings/email/setup", 200),
|
|
||||||
("can_change_organizer_settings", "organizer/dummy/devices", 200),
|
("can_change_organizer_settings", "organizer/dummy/devices", 200),
|
||||||
("can_change_organizer_settings", "organizer/dummy/device/add", 200),
|
("can_change_organizer_settings", "organizer/dummy/device/add", 200),
|
||||||
("can_change_organizer_settings", "organizer/dummy/device/1/edit", 404),
|
("can_change_organizer_settings", "organizer/dummy/device/1/edit", 404),
|
||||||
|
|||||||
Reference in New Issue
Block a user