mirror of
https://github.com/pretix/pretix.git
synced 2026-05-07 15:34:02 +00:00
Model-based mail queuing
This commit is contained in:
@@ -0,0 +1,222 @@
|
||||
{% extends "pretixcontrol/organizers/base.html" %}
|
||||
{% load i18n %}
|
||||
{% load bootstrap3 %}
|
||||
{% load urlreplace %}
|
||||
{% load icon %}
|
||||
{% load compress %}
|
||||
{% load static %}
|
||||
{% block inner %}
|
||||
<h1>
|
||||
{% trans "Outgoing email" %}
|
||||
</h1>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">{% trans "Email details" %}</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="row">
|
||||
<div class="col-lg-7 col-md-12">
|
||||
|
||||
<dl class="dl-horizontal">
|
||||
<dt>{% trans "From" context "email" %}</dt>
|
||||
<dd>{{ mail.sender }}</dd>
|
||||
<dt>{% trans "To" context "email" %}</dt>
|
||||
<dd>{{ mail.to|join:", " }}</dd>
|
||||
{% if mail.cc %}
|
||||
<dt>{% trans "Cc" context "email" %}</dt>
|
||||
<dd>{{ mail.cc|join:", " }}</dd>
|
||||
{% endif %}
|
||||
{% if mail.bcc %}
|
||||
<dt>{% trans "Bcc" context "email" %}</dt>
|
||||
<dd>{{ mail.bcc|join:", " }}</dd>
|
||||
{% endif %}
|
||||
<dt>{% trans "Subject" %}</dt>
|
||||
<dd>{{ mail.subject }}</dd>
|
||||
<dt>{% trans "Status" %}</dt>
|
||||
<dd>
|
||||
{% if mail.status == "queued" %}
|
||||
<span class="label label-info">{% icon "clock-o" %} {% trans "queued" %}</span>
|
||||
{% elif mail.status == "inflight" %}
|
||||
<span class="label label-info">{% icon "send" %} {% trans "being sent" %}</span>
|
||||
{% elif mail.status == "awaiting_retry" %}
|
||||
<span class="label label-warning">{% icon "repeat" %} {% trans "will be retried" %}</span>
|
||||
{% elif mail.status == "failed" %}
|
||||
<span class="label label-danger">{% icon "warning" %} {% trans "failed" %}</span>
|
||||
{% elif mail.status == "bounced" %}
|
||||
<span class="label label-danger">{% icon "exclamation-circle" %} {% trans "bounced" %}</span>
|
||||
{% elif mail.status == "withheld" %}
|
||||
<span class="label label-warning">{% icon "ban" %} {% trans "withheld" %}</span>
|
||||
{% elif mail.status == "aborted" %}
|
||||
<span class="label label-danger">{% icon "ban" %} {% trans "aborted" %}</span>
|
||||
{% elif mail.status == "sent" %}
|
||||
<span class="label label-success">{% icon "check" %} {% trans "sent" %}</span>
|
||||
{% endif %}
|
||||
</dd>
|
||||
<dt>{% trans "Creation" %}</dt>
|
||||
<dd>{{ mail.created|date:"SHORT_DATETIME_FORMAT" }}</dd>
|
||||
{% if mail.sent %}
|
||||
<dt>{% trans "Sent" %}</dt>
|
||||
<dd>{{ mail.sent|date:"SHORT_DATETIME_FORMAT" }}</dd>
|
||||
{% endif %}
|
||||
{% if mail.retry_after and mail.status == "awaiting_retry" %}
|
||||
<dt>{% trans "Next attempt (estimate)" %}</dt>
|
||||
<dd>{{ mail.retry_after|date:"SHORT_DATETIME_FORMAT" }}</dd>
|
||||
{% endif %}
|
||||
{% if mail.event %}
|
||||
<dt>{% trans "Event" %}</dt>
|
||||
<dd>
|
||||
<a href="{% url "control:event.index" organizer=request.organizer.slug event=mail.event.slug %}">
|
||||
{{ mail.event }}
|
||||
</a>
|
||||
</dd>
|
||||
{% endif %}
|
||||
{% if mail.order %}
|
||||
<dt>{% trans "Order" %}</dt>
|
||||
<dd>
|
||||
<a href="{% url "control:event.order" organizer=request.organizer.slug event=mail.event.slug code=mail.order.code %}">
|
||||
{{ mail.order.code }}</a>{% if mail.orderposition %}-
|
||||
{{ mail.orderposition.positionid }}{% endif %}
|
||||
</dd>
|
||||
{% endif %}
|
||||
{% if mail.customer %}
|
||||
<dt>{% trans "Customer" %}</dt>
|
||||
<dd>
|
||||
{% icon "user fa-fw" %}
|
||||
<a href="{% url "control:organizer.customer" organizer=request.organizer.slug customer=mail.customer.identifier %}">
|
||||
{{ mail.customer }}
|
||||
</a>
|
||||
</dd>
|
||||
{% endif %}
|
||||
</dl>
|
||||
</div>
|
||||
{% if mail.actual_attachments %}
|
||||
<div class="col-lg-5 col-md-12">
|
||||
<strong>{% trans "Attachments" %}</strong><br>
|
||||
<ul class="list-unstyled">
|
||||
{% for a in mail.actual_attachments %}
|
||||
<li>
|
||||
{% if a.type == "text/calendar" %}
|
||||
{% icon "calendar-plus-o fa-fw" %}
|
||||
{% elif a.type == "application/pdf" %}
|
||||
{% icon "file-pdf-o fa-fw" %}
|
||||
{% elif "image/" in a.type %}
|
||||
{% icon "file-image-o fa-fw" %}
|
||||
{% elif "msword" in a.type or "document" in a.type %}
|
||||
{% icon "file-word-o fa-fw" %}
|
||||
{% elif "excel" in a.type or "spreadsheet" in a.type %}
|
||||
{% icon "file-excel-o fa-fw" %}
|
||||
{% elif "powerpoint" in a.type or "presentation" in a.type %}
|
||||
{% icon "file-powerpoint-o fa-fw" %}
|
||||
{% elif "pkpass" in a.type %}
|
||||
{% icon "qrcode fa-fw" %}
|
||||
{% else %}
|
||||
{% icon "file-o fa-fw" %}
|
||||
{% endif %}
|
||||
{{ a.name }}
|
||||
<span class="text-muted">
|
||||
({{ a.size|filesizeformat }})
|
||||
</span>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<ul class="nav nav-tabs" role="tablist">
|
||||
{% if mail.is_failed %}
|
||||
<li role="presentation" class="active">
|
||||
<a href="#tab-error" role="tab" data-toggle="tab">
|
||||
<span class="fa fa-warning"></span>
|
||||
{% trans "Error" %}
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if mail.body_html %}
|
||||
<li role="presentation"
|
||||
{% if not mail.is_failed %}class="active"{% endif %}>
|
||||
<a href="#tab-html" role="tab" data-toggle="tab">
|
||||
<span class="fa fa-eye"></span>
|
||||
{% trans "HTML content" %}
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
<li role="presentation"
|
||||
{% if not mail.is_failed and not mail.body_html %}class="active"{% endif %}>
|
||||
<a href="#tab-text" role="tab" data-toggle="tab">
|
||||
<span class="fa fa-file-text-o"></span>
|
||||
{% trans "Text content" %}
|
||||
</a>
|
||||
</li>
|
||||
<li role="presentation">
|
||||
<a href="#tab-headers" role="tab" data-toggle="tab">
|
||||
<span class="fa fa-code"></span>
|
||||
{% trans "Headers" %}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div class="tab-content">
|
||||
{% if mail.is_failed %}
|
||||
<div role="tabpanel" class="tab-pane active" id="tab-error">
|
||||
<strong>
|
||||
{{ mail.error }}
|
||||
</strong>
|
||||
<pre>{{ mail.error_detail }}</pre>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if mail.body_html %}
|
||||
<div role="tabpanel"
|
||||
class="tab-pane {% if not mail.is_failed %}active{% endif %}"
|
||||
id="tab-html">
|
||||
{% if mail.sensitive %}
|
||||
<div class="empty-collection">
|
||||
<p>
|
||||
{% icon "eye-slash fa-4x" %}
|
||||
</p>
|
||||
<p>
|
||||
{% blocktrans trimmed %}
|
||||
Sensitive content not shown for security reasons
|
||||
{% endblocktrans %}
|
||||
</p>
|
||||
</div>
|
||||
{% else %}
|
||||
{{ data_url|json_script:"mail_body_html" }}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
<div role="tabpanel"
|
||||
class="tab-pane {% if not mail.is_failed and not mail.body_html %}active{% endif %}"
|
||||
id="tab-text">
|
||||
{% if mail.sensitive %}
|
||||
<div class="empty-collection">
|
||||
<p>
|
||||
{% icon "eye-slash fa-4x" %}
|
||||
</p>
|
||||
<p>
|
||||
{% blocktrans trimmed %}
|
||||
Sensitive content not shown for security reasons
|
||||
{% endblocktrans %}
|
||||
</p>
|
||||
</div>
|
||||
{% else %}
|
||||
<pre><code>{{ mail.body_plain }}</code></pre>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div role="tabpanel"
|
||||
class="tab-pane"
|
||||
id="tab-headers">
|
||||
<pre><code>{% for k, v in mail.headers.items %}{{ k }}: {{ v }}<br>{% endfor %}</code></pre>
|
||||
<p class="text-muted">
|
||||
{% trans "Additional headers will be added by the mail server and are not visible here." %}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{% compress js %}
|
||||
<script type="text/javascript" src="{% static "pretixcontrol/js/ui/outgoingmail.js" %}"></script>
|
||||
{% endcompress %}
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,185 @@
|
||||
{% extends "pretixcontrol/organizers/base.html" %}
|
||||
{% load i18n %}
|
||||
{% load bootstrap3 %}
|
||||
{% load urlreplace %}
|
||||
{% load icon %}
|
||||
{% block inner %}
|
||||
<h1>
|
||||
{% trans "Outgoing emails" %}
|
||||
</h1>
|
||||
<p>
|
||||
{% blocktrans trimmed with days=days %}
|
||||
This is an overview of all emails sent by your organizer account in the last {{ days }} days.
|
||||
{% endblocktrans %}
|
||||
</p>
|
||||
{% if mails|length == 0 and not filter_form.filtered %}
|
||||
<div class="empty-collection">
|
||||
<p>
|
||||
{% blocktrans trimmed %}
|
||||
You haven't sent any emails recently.
|
||||
{% endblocktrans %}
|
||||
</p>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">{% trans "Filter" %}</h3>
|
||||
</div>
|
||||
<form class="panel-body filter-form" action="" method="get">
|
||||
<div class="row">
|
||||
<div class="col-md-4 col-sm-6 col-xs-12">
|
||||
{% bootstrap_field filter_form.query %}
|
||||
</div>
|
||||
<div class="col-md-3 col-sm-6 col-xs-12">
|
||||
{% bootstrap_field filter_form.status %}
|
||||
</div>
|
||||
<div class="col-md-5 col-sm-6 col-xs-12">
|
||||
{% bootstrap_field filter_form.event %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-right">
|
||||
<button class="btn btn-primary btn-lg" type="submit">
|
||||
<span class="fa fa-filter"></span>
|
||||
{% trans "Filter" %}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<form action="{% url "control:organizer.outgoingmails.bulk_action" organizer=request.organizer.slug %}" method="post">
|
||||
{% csrf_token %}
|
||||
{% for field in filter_form %}
|
||||
{{ field.as_hidden }}
|
||||
{% endfor %}
|
||||
<div class="table-responsive">
|
||||
<table class="table table-condensed table-hover table-quotas">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
<label aria-label="{% trans "select all rows for batch-operation" %}"
|
||||
class="batch-select-label"><input type="checkbox" data-toggle-table/></label>
|
||||
</th>
|
||||
<th>{% trans "Subject" %}</th>
|
||||
<th>{% trans "Recipients" %}</th>
|
||||
<th>{% trans "Context" %}</th>
|
||||
<th>{% trans "Status" %}</th>
|
||||
<th>{% trans "Date" %}
|
||||
<a href="?{% url_replace request 'ordering' '-date' %}"><i
|
||||
class="fa fa-caret-down"></i></a>
|
||||
<a href="?{% url_replace request 'ordering' 'date' %}"><i class="fa fa-caret-up"></i></a>
|
||||
</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
{% if page_obj.paginator.num_pages > 1 %}
|
||||
<tr class="table-select-all warning hidden">
|
||||
<td>
|
||||
<input type="checkbox" name="__ALL" id="__all"
|
||||
data-results-total="{{ page_obj.paginator.count }}">
|
||||
</td>
|
||||
<td colspan="7">
|
||||
<label for="__all">
|
||||
{% trans "Select all results on other pages as well" %}
|
||||
</label>
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for m in mails %}
|
||||
<tr>
|
||||
<td>
|
||||
<label aria-label="{% trans "select row for batch-operation" %}"
|
||||
class="batch-select-label"><input type="checkbox" name="outgoingmail"
|
||||
class="batch-select-checkbox"
|
||||
value="{{ m.pk }}"/></label>
|
||||
</td>
|
||||
<td>
|
||||
<a href="{% url "control:organizer.outgoingmail" organizer=request.organizer.slug mail=m.id %}">
|
||||
{{ m.subject }}
|
||||
</a>
|
||||
{% if m.sensitive %}
|
||||
<span class="text-muted">{% icon "eye-slash" %}</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{{ m.to|join:", " }}
|
||||
{% if m.cc %}
|
||||
<br><small class="text-muted">{% trans "Cc" context "email" %}: {{ m.cc|join:", " }}</small>
|
||||
{% endif %}
|
||||
{% if m.bcc %}
|
||||
<br><small class="text-muted">{% trans "Bcc" context "email" %}: {{ m.bcc|join:", " }}</small>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if m.event %}
|
||||
<div>
|
||||
{% icon "calendar fa-fw" %}
|
||||
<a href="{% url "control:event.index" organizer=request.organizer.slug event=m.event.slug %}">
|
||||
{{ m.event }}
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if m.order %}
|
||||
<div>
|
||||
{% icon "shopping-cart fa-fw" %}
|
||||
<a href="{% url "control:event.order" organizer=request.organizer.slug event=m.event.slug code=m.order.code %}">
|
||||
{{ m.order.code }}</a>{% if m.orderposition %}-{{ m.orderposition.positionid }}{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if m.customer %}
|
||||
<div>
|
||||
{% icon "user fa-fw" %}
|
||||
<a href="{% url "control:organizer.customer" organizer=request.organizer.slug customer=m.customer.identifier %}">
|
||||
{{ m.customer }}
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if m.status == "queued" %}
|
||||
<span class="label label-info">{% icon "clock-o" %} {% trans "queued" %}</span>
|
||||
{% elif m.status == "inflight" %}
|
||||
<span class="label label-info">{% icon "send" %} {% trans "being sent" %}</span>
|
||||
{% elif m.status == "awaiting_retry" %}
|
||||
<span class="label label-warning">{% icon "repeat" %} {% trans "will be retried" %}</span>
|
||||
{% elif m.status == "failed" %}
|
||||
<span class="label label-danger">{% icon "warning" %} {% trans "failed" %}</span>
|
||||
{% elif m.status == "bounced" %}
|
||||
<span class="label label-danger">{% icon "exclamation-circle" %} {% trans "bounced" %}</span>
|
||||
{% elif m.status == "withheld" %}
|
||||
<span class="label label-warning">{% icon "ban" %} {% trans "withheld" %}</span>
|
||||
{% elif m.status == "aborted" %}
|
||||
<span class="label label-danger">{% icon "ban" %} {% trans "aborted" %}</span>
|
||||
{% elif m.status == "sent" %}
|
||||
<span class="label label-success">{% icon "check" %} {% trans "sent" %}</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{{ m.created|date:"SHORT_DATETIME_FORMAT" }}
|
||||
{% if m.sent %}
|
||||
<br>
|
||||
<small class="text-muted">{% trans "Sent:" %} {{ m.sent|date:"SHORT_DATETIME_FORMAT" }}</small>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="text-right flip">
|
||||
<a href="{% url "control:organizer.outgoingmail" organizer=request.organizer.slug mail=m.id %}"
|
||||
class="btn btn-default btn-sm">{% icon "eye" %}</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="batch-select-actions">
|
||||
<button type="submit" class="btn btn-primary btn-save" name="action" value="retry">
|
||||
{% icon "repeat" %}
|
||||
{% trans "Retry (if failed or withheld)" %}
|
||||
</button>
|
||||
<button type="submit" class="btn btn-danger btn-save" name="action" value="abort">
|
||||
{% icon "ban" %}
|
||||
{% trans "Abort (if queued, awaiting retry or withheld)" %}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
{% include "pretixcontrol/pagination.html" %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user