Compare commits

...

1 Commits

Author SHA1 Message Date
Raphael Michel
ece1b21298 First steps 2017-10-02 15:42:55 +02:00
9 changed files with 138 additions and 106 deletions

View File

@@ -2,12 +2,15 @@ import logging
from smtplib import SMTPRecipientsRefused, SMTPSenderRefused
from django.core.mail.backends.smtp import EmailBackend
from django.utils.translation import ugettext_lazy as _
from i18nfield.forms import I18nFormField, I18nTextarea
from pretix.base.validators import PlaceholderValidator
logger = logging.getLogger('pretix.base.email')
class CustomSMTPBackend(EmailBackend):
def test(self, from_addr):
try:
self.open()
@@ -24,3 +27,72 @@ class CustomSMTPBackend(EmailBackend):
raise SMTPRecipientsRefused(senderrs)
finally:
self.close()
class MailTemplateRenderer:
def __init__(self, placeholders: list):
self.placeholders = placeholders
def formfield(self, **kwargs):
defaults = {
'required': False,
'widget': I18nTextarea,
'validators': [],
'help_text': ''
}
defaults.update(kwargs)
if defaults['help_text']:
defaults['help_text'] += ' '
defaults['help_text'] += _('Available placeholders: {list}').format(
list=', '.join(['{' + v + '}' for v in self.placeholders])
)
defaults['validators'].append(PlaceholderValidator(['{' + v + '}' for v in self.placeholders]))
return I18nFormField(**defaults)
def preview(self, text, **kwargs):
return text.format(**kwargs)
def render(self, text, values):
set_placeholders = set(values.keys())
expected_palceholders = set(self.placeholders)
if set_placeholders != expected_palceholders:
raise ValueError('Invalid placeholder set. Unknown placeholders: {}. Missing placeholders: {}'.format(
set_placeholders - expected_palceholders, expected_palceholders - set_placeholders
))
return text.format_map(values)
mail_text_order_placed = MailTemplateRenderer(
['event', 'total', 'currency', 'date', 'payment_info', 'url', 'invoice_name', 'invoice_company']
)
mail_text_order_paid = MailTemplateRenderer(
['event', 'url', 'invoice_name', 'invoice_company', 'payment_info']
)
mail_text_order_free = MailTemplateRenderer(
['event', 'url', 'invoice_name', 'invoice_company']
)
mail_text_order_changed = MailTemplateRenderer(
['event', 'url', 'invoice_name', 'invoice_company']
)
mail_text_resend_link = MailTemplateRenderer(
['event', 'url', 'invoice_name', 'invoice_company']
)
mail_text_resend_all_links = MailTemplateRenderer(
['event', 'orders']
)
mail_text_order_expire_warning = MailTemplateRenderer(
['event', 'url', 'expire_date', 'invoice_name', 'invoice_company']
)
mail_text_waiting_list = MailTemplateRenderer(
['event', 'url', 'product', 'hours', 'code']
)
mail_text_order_canceled = MailTemplateRenderer(
['event', 'url', 'code']
)
mail_text_order_custom_mail = MailTemplateRenderer(
['expire_date', 'event', 'code', 'date', 'url', 'invoice_name', 'invoice_company']
)
mail_text_download_reminder = MailTemplateRenderer(
['event', 'url']
)

View File

@@ -9,8 +9,6 @@ from hierarkey.forms import HierarkeyForm
from pretix.base.models import Event
from pretix.base.reldate import RelativeDateField, RelativeDateTimeField
from .validators import PlaceholderValidator # NOQA
logger = logging.getLogger('pretix.plugins.ticketoutputpdf')

View File

@@ -1,38 +0,0 @@
import re
from django.core.exceptions import ValidationError
from django.core.validators import BaseValidator
from django.utils.translation import ugettext_lazy as _
from i18nfield.strings import LazyI18nString
class PlaceholderValidator(BaseValidator):
"""
Takes list of allowed placeholders,
validates form field by checking for placeholders,
which are not presented in taken list.
"""
def __init__(self, limit_value):
super().__init__(limit_value)
self.limit_value = limit_value
def __call__(self, value):
if isinstance(value, LazyI18nString):
for l, v in value.data.items():
self.__call__(v)
return
data_placeholders = list(re.findall(r'({[\w\s]*})', value, re.X))
invalid_placeholders = []
for placeholder in data_placeholders:
if placeholder not in self.limit_value:
invalid_placeholders.append(placeholder)
if invalid_placeholders:
raise ValidationError(
_('Invalid placeholder(s): %(value)s'),
code='invalid',
params={'value': ", ".join(invalid_placeholders,)})
def clean(self, x):
return x

View File

@@ -1,6 +1,42 @@
import re
from django.core.exceptions import ValidationError
from django.core.validators import BaseValidator
from django.utils.deconstruct import deconstructible
from django.utils.translation import ugettext_lazy as _
from i18nfield.strings import LazyI18nString
class PlaceholderValidator(BaseValidator):
"""
Takes list of allowed placeholders,
validates form field by checking for placeholders,
which are not presented in taken list.
"""
def __init__(self, limit_value):
super().__init__(limit_value)
self.limit_value = limit_value
def __call__(self, value):
if isinstance(value, LazyI18nString):
for l, v in value.data.items():
self.__call__(v)
return
data_placeholders = list(re.findall(r'({[\w\s]*})', value, re.X))
invalid_placeholders = []
for placeholder in data_placeholders:
if placeholder not in self.limit_value:
invalid_placeholders.append(placeholder)
if invalid_placeholders:
raise ValidationError(
_('Invalid placeholder(s): %(value)s'),
code='invalid',
params={'value': ", ".join(invalid_placeholders,)})
def clean(self, x):
return x
class BlacklistValidator:

View File

@@ -8,13 +8,15 @@ from django.utils.translation import ugettext_lazy as _
from i18nfield.forms import I18nFormField, I18nTextarea
from pytz import common_timezones, timezone
from pretix.base.forms import I18nModelForm, PlaceholderValidator, SettingsForm
from pretix.base.forms import I18nModelForm, SettingsForm
from pretix.base.models import Event, Organizer, TaxRule
from pretix.base.models.event import EventMetaValue
from pretix.base.reldate import RelativeDateField, RelativeDateTimeField
from pretix.base.validators import PlaceholderValidator
from pretix.control.forms import ExtFileField, SlugWidget
from pretix.multidomain.urlreverse import build_absolute_uri
from pretix.presale.style import get_fonts
from pretix.base import email
class EventWizardFoundationForm(forms.Form):
@@ -580,7 +582,6 @@ class MailSettingsForm(SettingsForm):
label=_("Sender address"),
help_text=_("Sender address for outgoing emails")
)
mail_text_signature = I18nFormField(
label=_("Signature"),
required=False,
@@ -588,50 +589,29 @@ class MailSettingsForm(SettingsForm):
help_text=_("This will be attached to every email. Available placeholders: {event}"),
validators=[PlaceholderValidator(['{event}'])]
)
mail_text_order_placed = I18nFormField(
mail_text_order_placed = email.mail_text_order_placed.formfield(
label=_("Text"),
required=False,
widget=I18nTextarea,
help_text=_("Available placeholders: {event}, {total}, {currency}, {date}, {payment_info}, {url}, "
"{invoice_name}, {invoice_company}"),
validators=[PlaceholderValidator(['{event}', '{total}', '{currency}', '{date}', '{payment_info}',
'{url}', '{invoice_name}', '{invoice_company}'])]
)
mail_text_order_paid = I18nFormField(
mail_text_order_paid = email.mail_text_order_paid.formfield(
label=_("Text"),
required=False,
widget=I18nTextarea,
help_text=_("Available placeholders: {event}, {url}, {invoice_name}, {invoice_company}, {payment_info}"),
validators=[PlaceholderValidator(['{event}', '{url}', '{invoice_name}', '{invoice_company}', '{payment_info}'])]
)
mail_text_order_free = I18nFormField(
mail_text_order_free = email.mail_text_order_free.formfield(
label=_("Text"),
required=False,
widget=I18nTextarea,
help_text=_("Available placeholders: {event}, {url}, {invoice_name}, {invoice_company}"),
validators=[PlaceholderValidator(['{event}', '{url}', '{invoice_name}', '{invoice_company}'])]
)
mail_text_order_changed = I18nFormField(
mail_text_order_changed = email.mail_text_order_changed.formfield(
label=_("Text"),
required=False,
widget=I18nTextarea,
help_text=_("Available placeholders: {event}, {url}, {invoice_name}, {invoice_company}"),
validators=[PlaceholderValidator(['{event}', '{url}', '{invoice_name}', '{invoice_company}'])]
)
mail_text_resend_link = I18nFormField(
mail_text_resend_link = email.mail_text_resend_link.formfield(
label=_("Text (sent by admin)"),
required=False,
widget=I18nTextarea,
help_text=_("Available placeholders: {event}, {url}, {invoice_name}, {invoice_company}"),
validators=[PlaceholderValidator(['{event}', '{url}', '{invoice_name}', '{invoice_company}'])]
)
mail_text_resend_all_links = I18nFormField(
mail_text_resend_all_links = email.mail_text_resend_all_links.formfield(
label=_("Text (requested by user)"),
required=False,
widget=I18nTextarea,
help_text=_("Available placeholders: {event}, {orders}"),
validators=[PlaceholderValidator(['{event}', '{orders}'])]
)
mail_days_order_expire_warning = forms.IntegerField(
label=_("Number of days"),
@@ -640,42 +620,25 @@ class MailSettingsForm(SettingsForm):
help_text=_("This email will be sent out this many days before the order expires. If the "
"value is 0, the mail will never be sent.")
)
mail_text_order_expire_warning = I18nFormField(
mail_text_order_expire_warning = email.mail_text_order_expire_warning.formfield(
label=_("Text"),
required=False,
widget=I18nTextarea,
help_text=_("Available placeholders: {event}, {url}, {expire_date}, {invoice_name}, {invoice_company}"),
validators=[PlaceholderValidator(['{event}', '{url}', '{expire_date}', '{invoice_name}', '{invoice_company}'])]
)
mail_text_waiting_list = I18nFormField(
mail_text_waiting_list = email.mail_text_waiting_list.formfield(
label=_("Text"),
required=False,
widget=I18nTextarea,
help_text=_("Available placeholders: {event}, {url}, {product}, {hours}, {code}"),
validators=[PlaceholderValidator(['{event}', '{url}', '{product}', '{hours}', '{code}'])]
)
mail_text_order_canceled = I18nFormField(
mail_text_order_canceled = email.mail_text_order_canceled.formfield(
label=_("Text"),
required=False,
widget=I18nTextarea,
help_text=_("Available placeholders: {event}, {code}, {url}"),
validators=[PlaceholderValidator(['{event}', '{code}', '{url}'])]
)
mail_text_order_custom_mail = I18nFormField(
mail_text_order_custom_mail = email.mail_text_order_custom_mail.formfield(
label=_("Text"),
required=False,
widget=I18nTextarea,
help_text=_("Available placeholders: {expire_date}, {event}, {code}, {date}, {url}, "
"{invoice_name}, {invoice_company}"),
validators=[PlaceholderValidator(['{expire_date}', '{event}', '{code}', '{date}', '{url}',
'{invoice_name}', '{invoice_company}'])]
)
mail_text_download_reminder = I18nFormField(
mail_text_download_reminder = email.mail_text_download_reminder.formfield(
label=_("Text"),
required=False,
widget=I18nTextarea,
help_text=_("Available placeholders: {event}, {url}"),
validators=[PlaceholderValidator(['{event}', '{url}'])]
)
mail_days_download_reminder = forms.IntegerField(
label=_("Number of days"),

View File

@@ -6,12 +6,14 @@ from django.utils.formats import localize
from django.utils.timezone import now
from django.utils.translation import pgettext_lazy, ugettext_lazy as _
from pretix.base.forms import I18nModelForm, PlaceholderValidator
from pretix.base.email import mail_text_order_custom_mail
from pretix.base.forms import I18nModelForm
from pretix.base.models import (
InvoiceAddress, Item, ItemAddOn, Order, OrderPosition,
)
from pretix.base.models.event import SubEvent
from pretix.base.services.pricing import get_price
from pretix.base.validators import PlaceholderValidator
class ExtendForm(I18nModelForm):
@@ -269,13 +271,9 @@ class OrderMailForm(forms.Form):
initial=order.email
)
self.fields['sendto'].widget.attrs['readonly'] = 'readonly'
self.fields['message'] = forms.CharField(
self.fields['message'] = mail_text_order_custom_mail.formfield(
label=_("Message"),
required=True,
widget=forms.Textarea,
initial=order.event.settings.mail_text_order_custom_mail.localize(order.locale),
help_text=_("Available placeholders: {expire_date}, {event}, {code}, {date}, {url}, "
"{invoice_name}, {invoice_company}"),
validators=[PlaceholderValidator(['{expire_date}', '{event}', '{code}', '{date}', '{url}',
'{invoice_name}', '{invoice_company}'])]
)

View File

@@ -0,0 +1,6 @@
from pretix.base.email import MailTemplateRenderer
mail_text_sendmail = MailTemplateRenderer(
['expire_date', 'event', 'code', 'date', 'url', 'invoice_name', 'invoice_company']
)

View File

@@ -2,9 +2,9 @@ from django import forms
from django.utils.translation import pgettext_lazy, ugettext_lazy as _
from i18nfield.forms import I18nFormField, I18nTextarea, I18nTextInput
from pretix.base.forms import PlaceholderValidator
from pretix.base.models import Order
from pretix.base.models.event import SubEvent
from pretix.plugins.sendmail.email import mail_text_sendmail
class MailForm(forms.Form):
@@ -25,13 +25,9 @@ class MailForm(forms.Form):
widget=I18nTextInput, required=True,
locales=event.settings.get('locales')
)
self.fields['message'] = I18nFormField(
self.fields['message'] = mail_text_sendmail.formfield(
widget=I18nTextarea, required=True,
locales=event.settings.get('locales'),
help_text=_("Available placeholders: {expire_date}, {event}, {code}, {date}, {url}, "
"{invoice_name}, {invoice_company}"),
validators=[PlaceholderValidator(['{expire_date}', '{event}', '{code}', '{date}', '{url}',
'{invoice_name}', '{invoice_company}'])]
)
choices = list(Order.STATUS_CHOICE)
if not event.settings.get('payment_term_expire_automatically', as_type=bool):

View File

@@ -17,6 +17,7 @@ from pretix.base.models.event import SubEvent
from pretix.base.services.mail import SendMailException, mail
from pretix.control.permissions import EventPermissionRequiredMixin
from pretix.multidomain.urlreverse import build_absolute_uri
from pretix.plugins.sendmail.email import mail_text_sendmail
from . import forms
@@ -82,8 +83,8 @@ class SenderView(EventPermissionRequiredMixin, FormView):
self.output[l] = []
self.output[l].append(
_('Subject: {subject}').format(subject=form.cleaned_data['subject'].localize(l)))
message = form.cleaned_data['message'].localize(l)
preview_text = message.format(
preview_text = mail_text_sendmail.preview(
text=form.cleaned_data['message'].localize(l),
code='ORDER1234',
event=self.request.event.name,
date=date_format(now(), 'SHORT_DATE_FORMAT'),