mirror of
https://github.com/pretix/pretix.git
synced 2026-05-05 15:14:04 +00:00
* Data model * little crud * SubEventItemForm etc * Drop SubEventItem.active, quota editor * Fix failing tests * First frontend stuff * Addons form stuff * Quota calculation * net price display on EventIndex * Add tests, solve some bugs * Correct quota selection in more places, consolidate pricing logic * Fix failing quota tests * Fix TypeError * Add tests for checkout * Fixed a bug in QuotaForm * Prevent immutable cart if a quota was removed from an item * Add tests for pricing * Handle waiting list * Filter in check-in list * Fixed import lost in rebase * Fix waiting list widget * Voucher management * Voucher redemption * Fix broken tests * Add subevents to OrderChangeManager * Create a subevent during event creation * Fix bulk voucher creation * Introduce subevent.active * Copy from for subevents * Show active in list * ICal download for subevents * Check start and end of presale * Failing tests / show cart logic * Test * Rebase migrations * REST API integration of sub-events * Integrate quota calculation into the traditional quota form * Make subevent argument to add_position optional * Log-display foo * pretixdroid and subevents * Filter by subevent * Add more tests * Some mor tests * Rebase fixes * More tests * Relative dates * Restrict selection in relative datetime widgets * Filter subevent list * Re-label has_subevents * Rebase fixes, subevents in calendar view * Performance and caching issues * Refactor calendar templates * Permission tests * Calendar fixes and month selection * subevent selection * Rename subevents to dates * Add tests for calendar views
195 lines
8.1 KiB
Python
195 lines
8.1 KiB
Python
import logging
|
|
from datetime import timedelta
|
|
|
|
import pytz
|
|
from django.contrib import messages
|
|
from django.db.models import Q
|
|
from django.http import Http404
|
|
from django.shortcuts import redirect
|
|
from django.utils.formats import date_format
|
|
from django.utils.timezone import now
|
|
from django.utils.translation import ugettext_lazy as _
|
|
from django.views.generic import FormView, ListView
|
|
|
|
from pretix.base.i18n import LazyI18nString, language
|
|
from pretix.base.models import InvoiceAddress, LogEntry, Order
|
|
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 . import forms
|
|
|
|
logger = logging.getLogger('pretix.plugins.sendmail')
|
|
|
|
|
|
class SenderView(EventPermissionRequiredMixin, FormView):
|
|
template_name = 'pretixplugins/sendmail/send_form.html'
|
|
permission = 'can_change_orders'
|
|
form_class = forms.MailForm
|
|
|
|
def get_form_kwargs(self):
|
|
kwargs = super().get_form_kwargs()
|
|
kwargs['event'] = self.request.event
|
|
if 'from_log' in self.request.GET:
|
|
try:
|
|
from_log_id = self.request.GET.get('from_log')
|
|
logentry = LogEntry.objects.get(
|
|
id=from_log_id,
|
|
event=self.request.event,
|
|
action_type='pretix.plugins.sendmail.sent'
|
|
)
|
|
kwargs['initial'] = {
|
|
'message': LazyI18nString(logentry.parsed_data['message']),
|
|
'subject': LazyI18nString(logentry.parsed_data['subject']),
|
|
'sendto': logentry.parsed_data['sendto'],
|
|
}
|
|
if logentry.parsed_data.get('subevent'):
|
|
try:
|
|
kwargs['initial']['subevent'] = self.request.event.subevents.get(
|
|
pk=logentry.parsed_data['subevent']['id']
|
|
)
|
|
except SubEvent.DoesNotExist:
|
|
pass
|
|
except LogEntry.DoesNotExist:
|
|
raise Http404(_('You supplied an invalid log entry ID'))
|
|
return kwargs
|
|
|
|
def form_invalid(self, form):
|
|
messages.error(self.request, _('We could not send the email. See below for details.'))
|
|
return super().form_invalid(form)
|
|
|
|
def form_valid(self, form):
|
|
qs = Order.objects.filter(event=self.request.event)
|
|
statusq = Q(status__in=form.cleaned_data['sendto'])
|
|
if 'overdue' in form.cleaned_data['sendto']:
|
|
statusq |= Q(status=Order.STATUS_PENDING, expires__lt=now())
|
|
orders = qs.filter(statusq)
|
|
if form.cleaned_data.get('subevent'):
|
|
orders = orders.filter(positions__subevent__in=(form.cleaned_data.get('subevent'),)).distinct()
|
|
|
|
tz = pytz.timezone(self.request.event.settings.timezone)
|
|
|
|
failures = []
|
|
self.output = {}
|
|
if not orders:
|
|
messages.error(self.request, _('There are no orders matching this selection.'))
|
|
return self.get(self.request, *self.args, **self.kwargs)
|
|
|
|
if self.request.POST.get("action") == "preview":
|
|
for l in self.request.event.settings.locales:
|
|
with language(l):
|
|
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(
|
|
order='ORDER1234',
|
|
event=self.request.event.name,
|
|
order_date=date_format(now(), 'SHORT_DATE_FORMAT'),
|
|
due_date=date_format(now() + timedelta(days=7), 'SHORT_DATE_FORMAT'),
|
|
order_url=build_absolute_uri(self.request.event, 'presale:event.order', kwargs={
|
|
'order': 'ORDER1234',
|
|
'secret': 'longrandomsecretabcdef123456'
|
|
}),
|
|
invoice_name=_('John Doe'),
|
|
invoice_company=_('Sample Company LLC'),
|
|
)
|
|
self.output[l].append(preview_text)
|
|
return self.get(self.request, *self.args, **self.kwargs)
|
|
|
|
for o in orders:
|
|
try:
|
|
invoice_name = o.invoice_address.name
|
|
invoice_company = o.invoice_address.company
|
|
except InvoiceAddress.DoesNotExist:
|
|
invoice_name = ""
|
|
invoice_company = ""
|
|
|
|
try:
|
|
with language(o.locale):
|
|
mail(
|
|
o.email, form.cleaned_data['subject'], form.cleaned_data['message'],
|
|
{
|
|
'event': o.event,
|
|
'order': o.code,
|
|
'order_date': date_format(o.datetime.astimezone(tz), 'SHORT_DATETIME_FORMAT'),
|
|
'due_date': date_format(o.expires, 'SHORT_DATE_FORMAT'),
|
|
'order_url': build_absolute_uri(o.event, 'presale:event.order', kwargs={
|
|
'order': o.code,
|
|
'secret': o.secret
|
|
}),
|
|
'invoice_name': invoice_name,
|
|
'invoice_company': invoice_company,
|
|
},
|
|
self.request.event, locale=o.locale, order=o)
|
|
o.log_action(
|
|
'pretix.plugins.sendmail.order.email.sent',
|
|
user=self.request.user,
|
|
data={
|
|
'subject': form.cleaned_data['subject'],
|
|
'message': form.cleaned_data['message'],
|
|
'recipient': o.email,
|
|
}
|
|
)
|
|
except SendMailException:
|
|
failures.append(o.email)
|
|
self.request.event.log_action('pretix.plugins.sendmail.sent',
|
|
user=self.request.user,
|
|
data=dict(form.cleaned_data))
|
|
if failures:
|
|
messages.error(self.request,
|
|
_('Failed to send mails to the following users: {}'.format(' '.join(failures))))
|
|
else:
|
|
messages.success(self.request, _('Your message has been queued and will be sent to the selected users.'))
|
|
|
|
return redirect(
|
|
'plugins:sendmail:send',
|
|
event=self.request.event.slug,
|
|
organizer=self.request.event.organizer.slug
|
|
)
|
|
|
|
def get_context_data(self, *args, **kwargs):
|
|
ctx = super().get_context_data(*args, **kwargs)
|
|
ctx['output'] = getattr(self, 'output', None)
|
|
return ctx
|
|
|
|
|
|
class EmailHistoryView(EventPermissionRequiredMixin, ListView):
|
|
template_name = 'pretixplugins/sendmail/history.html'
|
|
permission = 'can_change_orders'
|
|
model = LogEntry
|
|
context_object_name = 'logs'
|
|
paginate_by = 5
|
|
|
|
def get_queryset(self):
|
|
qs = LogEntry.objects.filter(
|
|
event=self.request.event,
|
|
action_type='pretix.plugins.sendmail.sent'
|
|
)
|
|
return qs
|
|
|
|
def get_context_data(self, **kwargs):
|
|
ctx = super().get_context_data()
|
|
|
|
status = dict(Order.STATUS_CHOICE)
|
|
status['overdue'] = _('pending with payment overdue')
|
|
for log in ctx['logs']:
|
|
log.pdata = log.parsed_data
|
|
log.pdata['locales'] = {}
|
|
for locale, msg in log.pdata['message'].items():
|
|
log.pdata['locales'][locale] = {
|
|
'message': msg,
|
|
'subject': log.pdata['subject'][locale]
|
|
}
|
|
log.pdata['sendto'] = [
|
|
status[s] for s in log.pdata['sendto']
|
|
]
|
|
if log.pdata.get('subevent'):
|
|
try:
|
|
log.pdata['subevent_obj'] = self.request.event.subevents.get(pk=log.pdata['subevent']['id'])
|
|
except SubEvent.DoesNotExist:
|
|
pass
|
|
|
|
return ctx
|