mirror of
https://github.com/pretix/pretix.git
synced 2026-05-03 14:54:04 +00:00
Log all other order-specified emails and include them into email history.
This commit is contained in:
@@ -4,7 +4,7 @@ import os
|
||||
import string
|
||||
from datetime import datetime, time
|
||||
from decimal import Decimal
|
||||
from typing import List, Union
|
||||
from typing import Any, Dict, List, Union
|
||||
|
||||
import pytz
|
||||
from django.conf import settings
|
||||
@@ -20,7 +20,10 @@ from django.utils.safestring import mark_safe
|
||||
from django.utils.timezone import make_aware, now
|
||||
from django.utils.translation import pgettext_lazy, ugettext_lazy as _
|
||||
from django_countries.fields import CountryField
|
||||
from i18nfield.strings import LazyI18nString
|
||||
|
||||
from pretix.base.i18n import language
|
||||
from pretix.base.models import User
|
||||
from pretix.base.reldate import RelativeDateWrapper
|
||||
|
||||
from ..decimal import round_decimal
|
||||
@@ -388,6 +391,32 @@ class Order(LoggedModel):
|
||||
return str(e)
|
||||
return True
|
||||
|
||||
def send_mail(self, subject: str, template: Union[str, LazyI18nString],
|
||||
context: Dict[str, Any]=None, log_entry_type: str='pretix.event.order.email.sent',
|
||||
user: User=None, headers: dict=None, sender: str=None):
|
||||
from pretix.base.services.mail import SendMailException, mail, render_mail
|
||||
|
||||
recipient = self.email
|
||||
email_content = render_mail(template, context)[0]
|
||||
try:
|
||||
with language(self.locale):
|
||||
mail(
|
||||
recipient, subject, template, context,
|
||||
self.event, self.locale, self, headers, sender
|
||||
)
|
||||
except SendMailException:
|
||||
raise
|
||||
else:
|
||||
self.log_action(
|
||||
log_entry_type,
|
||||
user=user,
|
||||
data={
|
||||
'subject': subject,
|
||||
'message': email_content,
|
||||
'recipient': recipient
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def answerfile_name(instance, filename: str) -> str:
|
||||
secret = get_random_string(length=32, allowed_chars=string.ascii_letters + string.digits)
|
||||
|
||||
@@ -81,18 +81,7 @@ def mail(email: str, subject: str, template: Union[str, LazyI18nString],
|
||||
'invoice_name': '',
|
||||
'invoice_company': ''
|
||||
})
|
||||
if isinstance(template, LazyI18nString):
|
||||
body = str(template)
|
||||
if context:
|
||||
body = body.format_map(TolerantDict(context))
|
||||
body_md = bleach.linkify(bleach.clean(markdown.markdown(body), tags=bleach.ALLOWED_TAGS + [
|
||||
'p',
|
||||
]))
|
||||
else:
|
||||
tpl = get_template(template)
|
||||
body = tpl.render(context)
|
||||
body_md = bleach.linkify(markdown.markdown(body))
|
||||
|
||||
body, body_md = render_mail(template, context)
|
||||
sender = sender or (event.settings.get('mail_from') if event else settings.MAIL_FROM)
|
||||
|
||||
subject = str(subject)
|
||||
@@ -170,3 +159,18 @@ def mail_send_task(to: List[str], subject: str, body: str, html: str, sender: st
|
||||
|
||||
def mail_send(*args, **kwargs):
|
||||
mail_send_task.apply_async(args=args, kwargs=kwargs)
|
||||
|
||||
|
||||
def render_mail(template, context):
|
||||
if isinstance(template, LazyI18nString):
|
||||
body = str(template)
|
||||
if context:
|
||||
body = body.format_map(TolerantDict(context))
|
||||
body_md = bleach.linkify(bleach.clean(markdown.markdown(body), tags=bleach.ALLOWED_TAGS + [
|
||||
'p',
|
||||
]))
|
||||
else:
|
||||
tpl = get_template(template)
|
||||
body = tpl.render(context)
|
||||
body_md = bleach.linkify(markdown.markdown(body))
|
||||
return body, body_md
|
||||
|
||||
@@ -31,7 +31,7 @@ from pretix.base.services.invoices import (
|
||||
generate_cancellation, generate_invoice, invoice_qualified,
|
||||
)
|
||||
from pretix.base.services.locking import LockTimeoutException
|
||||
from pretix.base.services.mail import SendMailException, mail
|
||||
from pretix.base.services.mail import SendMailException
|
||||
from pretix.base.services.pricing import get_price
|
||||
from pretix.base.signals import order_paid, order_placed, periodic_task
|
||||
from pretix.celery_app import app
|
||||
@@ -129,22 +129,27 @@ def mark_order_paid(order: Order, provider: str=None, info: str=None, date: date
|
||||
except InvoiceAddress.DoesNotExist:
|
||||
invoice_name = ""
|
||||
invoice_company = ""
|
||||
mail(
|
||||
order.email, _('Payment received for your order: %(code)s') % {'code': order.code},
|
||||
order.event.settings.mail_text_order_paid,
|
||||
{
|
||||
'event': order.event.name,
|
||||
'url': build_absolute_uri(order.event, 'presale:event.order', kwargs={
|
||||
'order': order.code,
|
||||
'secret': order.secret
|
||||
}),
|
||||
'downloads': order.event.settings.get('ticket_download', as_type=bool),
|
||||
'invoice_name': invoice_name,
|
||||
'invoice_company': invoice_company,
|
||||
'payment_info': mail_text
|
||||
},
|
||||
order.event, locale=order.locale
|
||||
)
|
||||
email_template = order.event.settings.mail_text_order_paid
|
||||
email_context = {
|
||||
'event': order.event.name,
|
||||
'url': build_absolute_uri(order.event, 'presale:event.order', kwargs={
|
||||
'order': order.code,
|
||||
'secret': order.secret
|
||||
}),
|
||||
'downloads': order.event.settings.get('ticket_download', as_type=bool),
|
||||
'invoice_name': invoice_name,
|
||||
'invoice_company': invoice_company,
|
||||
'payment_info': mail_text
|
||||
}
|
||||
email_subject = _('Payment received for your order: %(code)s') % {'code': order.code}
|
||||
try:
|
||||
order.send_mail(
|
||||
email_subject, email_template, email_context,
|
||||
'pretix.event.order.email.order_paid', user
|
||||
)
|
||||
except SendMailException:
|
||||
logger.exception('Order paid email could not be sent')
|
||||
|
||||
return order
|
||||
|
||||
|
||||
@@ -198,20 +203,25 @@ def _cancel_order(order, user=None, send_mail: bool=True):
|
||||
Voucher.objects.filter(pk=position.voucher.pk).update(redeemed=F('redeemed') - 1)
|
||||
|
||||
if send_mail:
|
||||
email_template = order.event.settings.mail_text_order_canceled
|
||||
email_context = {
|
||||
'event': order.event.name,
|
||||
'code': order.code,
|
||||
'url': build_absolute_uri(order.event, 'presale:event.order', kwargs={
|
||||
'order': order.code,
|
||||
'secret': order.secret
|
||||
})
|
||||
}
|
||||
email_subject = _('Order canceled: %(code)s') % {'code': order.code}
|
||||
with language(order.locale):
|
||||
mail(
|
||||
order.email, _('Order canceled: %(code)s') % {'code': order.code},
|
||||
order.event.settings.mail_text_order_canceled,
|
||||
{
|
||||
'event': order.event.name,
|
||||
'code': order.code,
|
||||
'url': build_absolute_uri(order.event, 'presale:event.order', kwargs={
|
||||
'order': order.code,
|
||||
'secret': order.secret
|
||||
})
|
||||
},
|
||||
order.event, locale=order.locale
|
||||
)
|
||||
try:
|
||||
order.send_mail(
|
||||
email_subject, email_template, email_context,
|
||||
'pretix.event.order.email.order_canceled', user
|
||||
)
|
||||
except SendMailException:
|
||||
logger.exception('Order canceled email could not be sent')
|
||||
|
||||
return order.pk
|
||||
|
||||
|
||||
@@ -423,9 +433,11 @@ def _perform_order(event: str, payment_provider: str, position_ids: List[str],
|
||||
generate_invoice(order)
|
||||
|
||||
if order.total == Decimal('0.00'):
|
||||
mailtext = event.settings.mail_text_order_free
|
||||
email_template = event.settings.mail_text_order_free
|
||||
log_entry = 'pretix.event.order.email.order_free'
|
||||
else:
|
||||
mailtext = event.settings.mail_text_order_placed
|
||||
email_template = event.settings.mail_text_order_placed
|
||||
log_entry = 'pretix.event.order.email.order_placed'
|
||||
|
||||
try:
|
||||
invoice_name = order.invoice_address.name
|
||||
@@ -433,25 +445,27 @@ def _perform_order(event: str, payment_provider: str, position_ids: List[str],
|
||||
except InvoiceAddress.DoesNotExist:
|
||||
invoice_name = ""
|
||||
invoice_company = ""
|
||||
|
||||
mail(
|
||||
order.email, _('Your order: %(code)s') % {'code': order.code},
|
||||
mailtext,
|
||||
{
|
||||
'total': LazyNumber(order.total),
|
||||
'currency': event.currency,
|
||||
'date': LazyDate(order.expires),
|
||||
'event': event.name,
|
||||
'url': build_absolute_uri(event, 'presale:event.order', kwargs={
|
||||
'order': order.code,
|
||||
'secret': order.secret
|
||||
}),
|
||||
'payment_info': str(pprov.order_pending_mail_render(order)),
|
||||
'invoice_name': invoice_name,
|
||||
'invoice_company': invoice_company,
|
||||
},
|
||||
event, locale=order.locale
|
||||
)
|
||||
email_context = {
|
||||
'total': LazyNumber(order.total),
|
||||
'currency': event.currency,
|
||||
'date': LazyDate(order.expires),
|
||||
'event': event.name,
|
||||
'url': build_absolute_uri(event, 'presale:event.order', kwargs={
|
||||
'order': order.code,
|
||||
'secret': order.secret
|
||||
}),
|
||||
'payment_info': str(pprov.order_pending_mail_render(order)),
|
||||
'invoice_name': invoice_name,
|
||||
'invoice_company': invoice_company,
|
||||
}
|
||||
email_subject = _('Your order: %(code)s') % {'code': order.code}
|
||||
try:
|
||||
order.send_mail(
|
||||
email_subject, email_template, email_context,
|
||||
log_entry
|
||||
)
|
||||
except SendMailException:
|
||||
logger.exception('Order received email could not be sent')
|
||||
|
||||
return order.id
|
||||
|
||||
@@ -493,27 +507,25 @@ def send_expiry_warnings(sender, **kwargs):
|
||||
except InvoiceAddress.DoesNotExist:
|
||||
invoice_name = ""
|
||||
invoice_company = ""
|
||||
email_template = eventsettings.mail_text_order_expire_warning
|
||||
email_context = {
|
||||
'event': o.event.name,
|
||||
'url': build_absolute_uri(o.event, 'presale:event.order', kwargs={
|
||||
'order': o.code,
|
||||
'secret': o.secret
|
||||
}),
|
||||
'expire_date': date_format(o.expires.astimezone(tz), 'SHORT_DATE_FORMAT'),
|
||||
'invoice_name': invoice_name,
|
||||
'invoice_company': invoice_company,
|
||||
}
|
||||
email_subject = _('Your order is about to expire: %(code)s') % {'code': o.code}
|
||||
try:
|
||||
with language(o.locale):
|
||||
mail(
|
||||
o.email, _('Your order is about to expire: %(code)s') % {'code': o.code},
|
||||
eventsettings.mail_text_order_expire_warning,
|
||||
{
|
||||
'event': o.event.name,
|
||||
'url': build_absolute_uri(o.event, 'presale:event.order', kwargs={
|
||||
'order': o.code,
|
||||
'secret': o.secret
|
||||
}),
|
||||
'expire_date': date_format(o.expires.astimezone(tz), 'SHORT_DATE_FORMAT'),
|
||||
'invoice_name': invoice_name,
|
||||
'invoice_company': invoice_company,
|
||||
},
|
||||
o.event, locale=o.locale
|
||||
)
|
||||
o.send_mail(
|
||||
email_subject, email_template, email_context,
|
||||
'pretix.event.order.email.expire_warning_sent'
|
||||
)
|
||||
except SendMailException:
|
||||
logger.exception('Reminder email could not be sent')
|
||||
else:
|
||||
o.log_action('pretix.event.order.expire_warning_sent')
|
||||
|
||||
|
||||
class OrderChangeManager:
|
||||
@@ -764,20 +776,24 @@ class OrderChangeManager:
|
||||
except InvoiceAddress.DoesNotExist:
|
||||
invoice_name = ""
|
||||
invoice_company = ""
|
||||
mail(
|
||||
self.order.email, _('Your order has been changed: %(code)s') % {'code': self.order.code},
|
||||
self.order.event.settings.mail_text_order_changed,
|
||||
{
|
||||
'event': self.order.event.name,
|
||||
'url': build_absolute_uri(self.order.event, 'presale:event.order', kwargs={
|
||||
'order': self.order.code,
|
||||
'secret': self.order.secret
|
||||
}),
|
||||
'invoice_name': invoice_name,
|
||||
'invoice_company': invoice_company,
|
||||
},
|
||||
self.order.event, locale=self.order.locale
|
||||
)
|
||||
email_template = self.order.event.settings.mail_text_order_changed
|
||||
email_context = {
|
||||
'event': self.order.event.name,
|
||||
'url': build_absolute_uri(self.order.event, 'presale:event.order', kwargs={
|
||||
'order': self.order.code,
|
||||
'secret': self.order.secret
|
||||
}),
|
||||
'invoice_name': invoice_name,
|
||||
'invoice_company': invoice_company,
|
||||
}
|
||||
email_subject = _('Your order has been changed: %(code)s') % {'code': self.order.code}
|
||||
try:
|
||||
self.order.send_mail(
|
||||
email_subject, email_template, email_context,
|
||||
'pretix.event.order.email.order_changed', self.user
|
||||
)
|
||||
except SendMailException:
|
||||
logger.exception('Order changed email could not be sent')
|
||||
|
||||
def commit(self):
|
||||
if not self._operations:
|
||||
|
||||
@@ -90,7 +90,6 @@ def pretixcontrol_logentry_display(sender: Event, logentry: LogEntry, **kwargs):
|
||||
'pretix.event.comment': _('The event\'s internal comment has been updated.'),
|
||||
'pretix.event.order.modified': _('The order details have been modified.'),
|
||||
'pretix.event.order.unpaid': _('The order has been marked as unpaid.'),
|
||||
'pretix.event.order.resend': _('The link to the order detail page has been resent to the user.'),
|
||||
'pretix.event.order.secret.changed': _('The order\'s secret has been changed.'),
|
||||
'pretix.event.order.expirychanged': _('The order\'s expiry date has been changed.'),
|
||||
'pretix.event.order.expired': _('The order has been marked as expired.'),
|
||||
@@ -105,9 +104,16 @@ def pretixcontrol_logentry_display(sender: Event, logentry: LogEntry, **kwargs):
|
||||
'pretix.event.order.invoice.reissued': _('The invoice has been reissued.'),
|
||||
'pretix.event.order.comment': _('The order\'s internal comment has been updated.'),
|
||||
'pretix.event.order.payment.changed': _('The payment method has been changed.'),
|
||||
'pretix.event.order.expire_warning_sent': _('An email has been sent with a warning that the order is about '
|
||||
'to expire.'),
|
||||
'pretix.event.order.mail_sent': _('A custom email has been sent.'),
|
||||
'pretix.event.order.email.sent': _('An unindentified type email has been sent.'),
|
||||
'pretix.event.order.email.custom_sent': _('A custom email has been sent.'),
|
||||
'pretix.event.order.email.expire_warning_sent': _('An email has been sent with a warning that the order is about '
|
||||
'to expire.'),
|
||||
'pretix.event.order.email.order_canceled': _('An email has been sent to notify user order has been canceled.'),
|
||||
'pretix.event.order.email.order_changed': _('An email has been sent to notify user order has been changed.'),
|
||||
'pretix.event.order.email.order_free': _('An email has been sent to notify user order has been received.'),
|
||||
'pretix.event.order.email.order_paid': _('An email has been sent to notify user payment has been received.'),
|
||||
'pretix.event.order.email.order_placed': _('An email has been sent to notify user order has been received and require payment.'),
|
||||
'pretix.event.order.email.resend': _('An email has been sent with link to the order detail page has been resent to the user.'),
|
||||
'pretix.user.settings.2fa.enabled': _('Two-factor authentication has been enabled.'),
|
||||
'pretix.user.settings.2fa.disabled': _('Two-factor authentication has been disabled.'),
|
||||
'pretix.user.settings.2fa.regenemergency': _('Your two-factor emergency codes have been regenerated.'),
|
||||
|
||||
@@ -12,9 +12,6 @@
|
||||
{% endblocktrans %}
|
||||
</a>
|
||||
</h1>
|
||||
<div class="alert alert-info">
|
||||
{% trans "Includes sent custom and mass emails history only." %}
|
||||
</div>
|
||||
<div>
|
||||
<ul class="list-group">
|
||||
{% for log in logs %}
|
||||
|
||||
@@ -4,7 +4,7 @@ import pytz
|
||||
from django.conf import settings
|
||||
from django.contrib import messages
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.db.models import Count, Q
|
||||
from django.db.models import Count
|
||||
from django.http import FileResponse, Http404, HttpResponseNotAllowed
|
||||
from django.shortcuts import redirect, render
|
||||
from django.utils.formats import date_format
|
||||
@@ -28,7 +28,7 @@ from pretix.base.services.invoices import (
|
||||
regenerate_invoice,
|
||||
)
|
||||
from pretix.base.services.locking import LockTimeoutException
|
||||
from pretix.base.services.mail import SendMailException, mail
|
||||
from pretix.base.services.mail import SendMailException, render_mail
|
||||
from pretix.base.services.orders import (
|
||||
OrderChangeManager, OrderError, cancel_order, mark_order_paid,
|
||||
)
|
||||
@@ -332,26 +332,26 @@ class OrderResendLink(OrderView):
|
||||
except InvoiceAddress.DoesNotExist:
|
||||
invoice_name = ""
|
||||
invoice_company = ""
|
||||
mail(
|
||||
self.order.email, _('Your order: %(code)s') % {'code': self.order.code},
|
||||
self.order.event.settings.mail_text_resend_link,
|
||||
{
|
||||
'event': self.order.event.name,
|
||||
'url': build_absolute_uri(self.order.event, 'presale:event.order', kwargs={
|
||||
'order': self.order.code,
|
||||
'secret': self.order.secret
|
||||
}),
|
||||
'invoice_name': invoice_name,
|
||||
'invoice_company': invoice_company,
|
||||
},
|
||||
self.order.event, locale=self.order.locale
|
||||
email_template = self.order.event.settings.mail_text_resend_link
|
||||
email_context = {
|
||||
'event': self.order.event.name,
|
||||
'url': build_absolute_uri(self.order.event, 'presale:event.order', kwargs={
|
||||
'order': self.order.code,
|
||||
'secret': self.order.secret
|
||||
}),
|
||||
'invoice_name': invoice_name,
|
||||
'invoice_company': invoice_company,
|
||||
}
|
||||
email_subject = _('Your order: %(code)s') % {'code': self.order.code}
|
||||
self.order.send_mail(
|
||||
email_subject, email_template, email_context,
|
||||
'pretix.event.order.email.resend', user=self.request.user
|
||||
)
|
||||
except SendMailException:
|
||||
messages.error(self.request, _('There was an error sending the mail. Please try again later.'))
|
||||
return redirect(self.get_order_url())
|
||||
|
||||
messages.success(self.request, _('The email has been queued to be sent.'))
|
||||
self.order.log_action('pretix.event.order.resend', user=self.request.user)
|
||||
return redirect(self.get_order_url())
|
||||
|
||||
def get(self, *args, **kwargs):
|
||||
@@ -684,8 +684,8 @@ class OrderSendMail(EventPermissionRequiredMixin, OrderViewMixin, FormView):
|
||||
'invoice_name': invoice_name,
|
||||
'invoice_company': invoice_company,
|
||||
}
|
||||
|
||||
email_content = form.cleaned_data['message'].format_map(email_context)
|
||||
email_template = LazyI18nString(form.cleaned_data['message'])
|
||||
email_content = render_mail(email_template, email_context)[0]
|
||||
if self.request.POST.get('action') == 'preview':
|
||||
self.preview_output = []
|
||||
self.preview_output.append(
|
||||
@@ -694,22 +694,10 @@ class OrderSendMail(EventPermissionRequiredMixin, OrderViewMixin, FormView):
|
||||
return self.get(self.request, *self.args, **self.kwargs)
|
||||
else:
|
||||
try:
|
||||
with language(order.locale):
|
||||
email_template = LazyI18nString(form.cleaned_data['message'])
|
||||
mail(
|
||||
order.email, form.cleaned_data['subject'],
|
||||
email_template, email_context,
|
||||
self.request.event, locale=order.locale,
|
||||
order=order
|
||||
)
|
||||
order.log_action(
|
||||
'pretix.event.order.mail_sent',
|
||||
user=self.request.user,
|
||||
data={
|
||||
'subject': form.cleaned_data['subject'],
|
||||
'message': email_content,
|
||||
'recipient': form.cleaned_data['sendto'],
|
||||
}
|
||||
order.send_mail(
|
||||
form.cleaned_data['subject'], email_template,
|
||||
email_context, 'pretix.event.order.email.custom_sent',
|
||||
self.request.user
|
||||
)
|
||||
messages.success(self.request, _('Your message has been queued and will be sent to {}.'.format(order.email)))
|
||||
except SendMailException:
|
||||
@@ -746,8 +734,7 @@ class OrderEmailHistory(EventPermissionRequiredMixin, OrderViewMixin, ListView):
|
||||
).first()
|
||||
qs = order.all_logentries()
|
||||
qs = qs.filter(
|
||||
Q(action_type="pretix.plugins.sendmail.order.email.sent")
|
||||
| Q(action_type="pretix.event.order.mail_sent")
|
||||
action_type__contains="order.email"
|
||||
)
|
||||
return qs
|
||||
|
||||
|
||||
Reference in New Issue
Block a user