mirror of
https://github.com/pretix/pretix.git
synced 2026-05-06 15:24:02 +00:00
Model-based mail queuing
This commit is contained in:
@@ -39,14 +39,15 @@ from email.mime.text import MIMEText
|
||||
import pytest
|
||||
from django.conf import settings
|
||||
from django.core import mail as djmail
|
||||
from django.test import override_settings
|
||||
from django.utils.timezone import now
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django_scopes import scope
|
||||
from i18nfield.strings import LazyI18nString
|
||||
|
||||
from pretix.base.email import get_email_context
|
||||
from pretix.base.models import Event, Organizer, User
|
||||
from pretix.base.services.mail import mail
|
||||
from pretix.base.models import Event, Organizer, OutgoingMail, User
|
||||
from pretix.base.services.mail import mail, mail_send_task
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
@@ -162,6 +163,101 @@ def test_send_mail_with_user_locale(env):
|
||||
assert 'The language code used for rendering this email is de.' in djmail.outbox[0].body
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_queue_state_sent(env):
|
||||
m = OutgoingMail.objects.create(
|
||||
to=['recipient@example.com'],
|
||||
subject='Test',
|
||||
body_plain='Test',
|
||||
sender='sender@example.com',
|
||||
headers={},
|
||||
)
|
||||
assert m.status == OutgoingMail.STATUS_QUEUED
|
||||
mail_send_task.apply(kwargs={
|
||||
'outgoing_mail': m.pk,
|
||||
}, max_retries=0)
|
||||
m.refresh_from_db()
|
||||
assert m.status == OutgoingMail.STATUS_SENT
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@override_settings(EMAIL_BACKEND='pretix.testutils.mail.PermanentlyFailingEmailBackend')
|
||||
def test_queue_state_permanent_failure(env):
|
||||
m = OutgoingMail.objects.create(
|
||||
to=['recipient@example.com'],
|
||||
subject='Test',
|
||||
body_plain='Test',
|
||||
sender='sender@example.com',
|
||||
headers={},
|
||||
)
|
||||
assert m.status == OutgoingMail.STATUS_QUEUED
|
||||
mail_send_task.apply(kwargs={
|
||||
'outgoing_mail': m.pk,
|
||||
}, max_retries=0)
|
||||
m.refresh_from_db()
|
||||
assert m.status == OutgoingMail.STATUS_FAILED
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@override_settings(EMAIL_BACKEND='pretix.testutils.mail.FailingEmailBackend')
|
||||
def test_queue_state_retry_failure(env, monkeypatch):
|
||||
def retry(*args, **kwargs):
|
||||
raise Exception()
|
||||
|
||||
monkeypatch.setattr('celery.app.task.Task.retry', retry, raising=True)
|
||||
m = OutgoingMail.objects.create(
|
||||
to=['recipient@example.com'],
|
||||
subject='Test',
|
||||
body_plain='Test',
|
||||
sender='sender@example.com',
|
||||
headers={},
|
||||
)
|
||||
assert m.status == OutgoingMail.STATUS_QUEUED
|
||||
mail_send_task.apply(kwargs={
|
||||
'outgoing_mail': m.pk,
|
||||
}, max_retries=0)
|
||||
m.refresh_from_db()
|
||||
assert m.status == OutgoingMail.STATUS_AWAITING_RETRY
|
||||
assert m.retry_after > now()
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_queue_state_foreign_key_handling():
|
||||
o = Organizer.objects.create(name='Dummy', slug='dummy')
|
||||
event = Event.objects.create(
|
||||
organizer=o, name='Dummy', slug='dummy',
|
||||
date_from=now()
|
||||
)
|
||||
|
||||
mail_queued = OutgoingMail.objects.create(
|
||||
organizer=o,
|
||||
event=event,
|
||||
to=['recipient@example.com'],
|
||||
subject='Test',
|
||||
body_plain='Test',
|
||||
sender='sender@example.com',
|
||||
headers={},
|
||||
)
|
||||
mail_sent = OutgoingMail.objects.create(
|
||||
organizer=o,
|
||||
event=event,
|
||||
to=['recipient@example.com'],
|
||||
subject='Test',
|
||||
body_plain='Test',
|
||||
sender='sender@example.com',
|
||||
headers={},
|
||||
status=OutgoingMail.STATUS_SENT,
|
||||
)
|
||||
|
||||
event.delete()
|
||||
|
||||
assert not OutgoingMail.objects.filter(pk=mail_queued.pk).exists()
|
||||
assert OutgoingMail.objects.get(pk=mail_sent.pk).event is None
|
||||
|
||||
o.delete()
|
||||
assert not OutgoingMail.objects.filter(pk=mail_sent.pk).exists()
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_sendmail_placeholder(env):
|
||||
djmail.outbox = []
|
||||
|
||||
@@ -31,7 +31,7 @@ from django_scopes import scope
|
||||
|
||||
from pretix.base.models import (
|
||||
CachedCombinedTicket, CachedTicket, Event, InvoiceAddress, Order,
|
||||
OrderPayment, OrderPosition, Organizer, QuestionAnswer,
|
||||
OrderPayment, OrderPosition, Organizer, OutgoingMail, QuestionAnswer,
|
||||
)
|
||||
from pretix.base.services.invoices import generate_invoice, invoice_pdf_task
|
||||
from pretix.base.services.tickets import generate
|
||||
@@ -111,6 +111,15 @@ def test_email_shredder(event, order):
|
||||
'new_email': 'foo@bar.com',
|
||||
}
|
||||
)
|
||||
m = OutgoingMail.objects.create(
|
||||
event=event,
|
||||
order=order,
|
||||
to=['recipient@example.com'],
|
||||
subject='Test',
|
||||
body_plain='Test',
|
||||
sender='sender@example.com',
|
||||
headers={},
|
||||
)
|
||||
|
||||
s = EmailAddressShredder(event)
|
||||
f = list(s.generate_files())
|
||||
@@ -129,6 +138,7 @@ def test_email_shredder(event, order):
|
||||
assert 'Foo' not in l1.data
|
||||
l2.refresh_from_db()
|
||||
assert '@' not in l2.data
|
||||
assert not OutgoingMail.objects.filter(pk=m.pk).exists()
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
|
||||
@@ -24,12 +24,13 @@ from smtplib import SMTPResponseException
|
||||
|
||||
import pytest
|
||||
import responses
|
||||
from django.conf import settings
|
||||
from django.db import transaction
|
||||
from django.test.utils import override_settings
|
||||
from django_scopes import scopes_disabled
|
||||
from tests.base import SoupTest, extract_form_fields
|
||||
|
||||
from pretix.base.models import Event, Organizer, Team, User
|
||||
from pretix.base.models import Event, Organizer, OutgoingMail, Team, User
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
@@ -453,3 +454,111 @@ class OrganizerTest(SoupTest):
|
||||
self.event1.refresh_from_db()
|
||||
assert 'pretix.plugins.banktransfer' not in self.event1.get_plugins()
|
||||
assert 'pretix.plugins.stripe' in self.event1.get_plugins()
|
||||
|
||||
def test_outgoing_mails_list_and_detail(self):
|
||||
m1 = OutgoingMail.objects.create(
|
||||
organizer=self.orga1,
|
||||
to=['rightrecipient@example.com'],
|
||||
subject='Test',
|
||||
body_plain='Test',
|
||||
sender='sender@example.com',
|
||||
headers={},
|
||||
)
|
||||
m2 = OutgoingMail.objects.create(
|
||||
organizer=self.orga2,
|
||||
to=['wrongrecipient@example.com'],
|
||||
subject='Test',
|
||||
body_plain='Test',
|
||||
sender='sender@example.com',
|
||||
headers={},
|
||||
)
|
||||
resp = self.client.get('/control/organizer/%s/outgoingmails' % self.orga1.slug)
|
||||
assert resp.status_code == 200
|
||||
assert b"rightrecipient@example.com" in resp.content
|
||||
assert b"wrongrecipient@example.com" not in resp.content
|
||||
|
||||
resp = self.client.get('/control/organizer/%s/outgoingmails?status=queued' % self.orga1.slug)
|
||||
assert resp.status_code == 200
|
||||
assert b"rightrecipient@example.com" in resp.content
|
||||
resp = self.client.get('/control/organizer/%s/outgoingmails?status=sent' % self.orga1.slug)
|
||||
assert resp.status_code == 200
|
||||
assert b"rightrecipient@example.com" not in resp.content
|
||||
|
||||
if 'postgresql' in settings.DATABASES['default']['ENGINE']:
|
||||
resp = self.client.get('/control/organizer/%s/outgoingmails?query=RIGHTrecipient@example.com' % self.orga1.slug)
|
||||
assert resp.status_code == 200
|
||||
assert b"rightrecipient@example.com" in resp.content
|
||||
resp = self.client.get('/control/organizer/%s/outgoingmails?query=wrongrecipient@example.com' % self.orga1.slug)
|
||||
assert resp.status_code == 200
|
||||
assert b"rightrecipient@example.com" not in resp.content
|
||||
|
||||
resp = self.client.get('/control/organizer/%s/outgoingmail/%d/' % (self.orga1.slug, m1.pk))
|
||||
assert resp.status_code == 200
|
||||
assert b"rightrecipient@example.com" in resp.content
|
||||
|
||||
resp = self.client.get('/control/organizer/%s/outgoingmail/%d/' % (self.orga1.slug, m2.pk))
|
||||
assert resp.status_code == 404
|
||||
|
||||
def test_outgoing_mails_retry(self):
|
||||
m1 = OutgoingMail.objects.create(
|
||||
organizer=self.orga1,
|
||||
status=OutgoingMail.STATUS_SENT,
|
||||
to=['rightrecipient@example.com'],
|
||||
subject='Test',
|
||||
body_plain='Test',
|
||||
sender='sender@example.com',
|
||||
headers={},
|
||||
)
|
||||
m2 = OutgoingMail.objects.create(
|
||||
organizer=self.orga1,
|
||||
status=OutgoingMail.STATUS_FAILED,
|
||||
to=['rightrecipient@example.com'],
|
||||
subject='Test',
|
||||
body_plain='Test',
|
||||
sender='sender@example.com',
|
||||
headers={},
|
||||
)
|
||||
resp = self.client.post(
|
||||
'/control/organizer/%s/outgoingmail/bulk_action' % self.orga1.slug,
|
||||
data={
|
||||
"action": "retry",
|
||||
"outgoingmail": [m1.pk, m2.pk]
|
||||
}
|
||||
)
|
||||
assert resp.status_code == 302
|
||||
m1.refresh_from_db()
|
||||
m2.refresh_from_db()
|
||||
assert m1.status == OutgoingMail.STATUS_SENT
|
||||
assert m2.status in (OutgoingMail.STATUS_SENT, OutgoingMail.STATUS_QUEUED)
|
||||
|
||||
def test_outgoing_mails_abort(self):
|
||||
m1 = OutgoingMail.objects.create(
|
||||
organizer=self.orga1,
|
||||
status=OutgoingMail.STATUS_SENT,
|
||||
to=['rightrecipient@example.com'],
|
||||
subject='Test',
|
||||
body_plain='Test',
|
||||
sender='sender@example.com',
|
||||
headers={},
|
||||
)
|
||||
m2 = OutgoingMail.objects.create(
|
||||
organizer=self.orga1,
|
||||
status=OutgoingMail.STATUS_QUEUED,
|
||||
to=['rightrecipient@example.com'],
|
||||
subject='Test',
|
||||
body_plain='Test',
|
||||
sender='sender@example.com',
|
||||
headers={},
|
||||
)
|
||||
resp = self.client.post(
|
||||
'/control/organizer/%s/outgoingmail/bulk_action' % self.orga1.slug,
|
||||
data={
|
||||
"action": "abort",
|
||||
"__ALL": "on",
|
||||
}
|
||||
)
|
||||
assert resp.status_code == 302
|
||||
m1.refresh_from_db()
|
||||
m2.refresh_from_db()
|
||||
assert m1.status == OutgoingMail.STATUS_SENT
|
||||
assert m2.status == OutgoingMail.STATUS_ABORTED
|
||||
|
||||
@@ -192,6 +192,9 @@ organizer_urls = [
|
||||
'organizer/abc/team/1/edit',
|
||||
'organizer/abc/team/1/delete',
|
||||
'organizer/abc/team/add',
|
||||
'organizer/abc/outgoingmails',
|
||||
'organizer/abc/outgoingmail/bulk_action',
|
||||
'organizer/abc/outgoingmail/1/',
|
||||
'organizer/abc/devices',
|
||||
'organizer/abc/device/add',
|
||||
'organizer/abc/device/bulk_edit',
|
||||
@@ -528,6 +531,9 @@ organizer_permission_urls = [
|
||||
("can_change_organizer_settings", "organizer/dummy/settings/plugins/pretix.plugins.sendmail/events", 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/outgoingmails", 200),
|
||||
("can_change_organizer_settings", "organizer/dummy/outgoingmail/1/", 404),
|
||||
("can_change_organizer_settings", "organizer/dummy/outgoingmail/bulk_action", 405),
|
||||
("can_change_organizer_settings", "organizer/dummy/devices", 200),
|
||||
("can_change_organizer_settings", "organizer/dummy/devices/select2", 200),
|
||||
("can_change_organizer_settings", "organizer/dummy/device/add", 200),
|
||||
|
||||
Reference in New Issue
Block a user