Improved bulk mailer detection and fixes on domain serializer validation

This commit is contained in:
Marc Aymerich 2015-05-28 10:55:48 +00:00
parent 1223ed85e6
commit 7c5eff9a90
10 changed files with 60 additions and 21 deletions

View file

@ -15,7 +15,7 @@ class AccountSerializer(serializers.HyperlinkedModelSerializer):
class AccountSerializerMixin(object):
def __init__(self, *args, **kwargs):
super(AccountSerializerMixin, self).__init__(*args, **kwargs)
self.account = None
self.account = self.get_account()
def get_account(self):
request = self.context.get('request')

View file

@ -93,7 +93,7 @@ hr {
{{ buyer.vat }}<br>
{{ buyer.address }}<br>
{{ buyer.zipcode }} - {{ buyer.city }}<br>
{{ buyer.get_country_display }}<br>
{% trans buyer.get_country_display %}<br>
</div>
<div id="number" class="column-1">

View file

@ -39,9 +39,13 @@ class DomainSerializer(AccountSerializerMixin, HyperlinkedModelSerializer):
def validate(self, data):
""" Checks if everything is consistent """
data = super(DomainSerializer, self).validate(data)
if self.instance and data.get('name'):
name = data.get('name')
if name:
instance = self.instance
if instance is None:
instance = Domain(name=name, account=self.account)
records = data['records']
domain = domain_for_validation(self.instance, records)
domain = domain_for_validation(instance, records)
validators.validate_zone(domain.render_zone())
return data
@ -52,9 +56,9 @@ class DomainSerializer(AccountSerializerMixin, HyperlinkedModelSerializer):
domain.records.create(type=record['type'], value=record['value'])
return domain
def update(self, validated_data):
def update(self, instance, validated_data):
precords = validated_data.pop('records')
domain = super(DomainSerializer, self).update(validated_data)
domain = super(DomainSerializer, self).update(instance, validated_data)
to_delete = []
for erecord in domain.records.all():
match = False
@ -63,7 +67,7 @@ class DomainSerializer(AccountSerializerMixin, HyperlinkedModelSerializer):
match = True
break
if match:
precords.remove(ix)
precords.pop(ix)
else:
to_delete.append(erecord)
for precord in precords:

View file

@ -120,7 +120,10 @@ def validate_zone(zone):
# Don't use /dev/stdin becuase the 'argument list is too long' error
check = run(' '.join([checkzone, zone_name, zone_path]), valid_codes=(0,1,127), display=False)
finally:
os.unlink(zone_path)
try:
os.unlink(zone_path)
except FileNotFoundError:
pass
if check.exit_code == 127:
logger.error("Cannot validate domain zone: %s not installed." % checkzone)
elif check.exit_code == 1:

View file

@ -1,6 +1,9 @@
from django.conf import settings as djsettings
from django.core.mail.backends.base import BaseEmailBackend
from orchestra.core.caches import get_request_cache
from . import settings
from .models import Message
from .tasks import send_message
@ -9,17 +12,27 @@ class EmailBackend(BaseEmailBackend):
"""
A wrapper that manages a queued SMTP system.
"""
messages = 0
def send_messages(self, email_messages):
if not email_messages:
return
num_sent = 0
cache = get_request_cache()
key = 'mailer.sent_messages'
sent_messages = cache.get(key) or 0
sent_messages += 1
cache.set(key, sent_messages)
is_bulk = len(email_messages) > 1
if sent_messages > settings.MAILER_NON_QUEUED_MAILS_PER_REQUEST_THRESHOLD:
is_bulk = True
default_priority = Message.NORMAL if is_bulk else Message.CRITICAL
num_sent = 0
for message in email_messages:
priority = message.extra_headers.get('X-Mail-Priority', default_priority)
content = message.message().as_string()
for to_email in message.recipients():
message = Message.objects.create(
message = Message(
priority=priority,
to_address=to_email,
from_address=getattr(message, 'from_email', djsettings.DEFAULT_FROM_EMAIL),
@ -29,5 +42,7 @@ class EmailBackend(BaseEmailBackend):
if priority == Message.CRITICAL:
# send immidiately
send_message.apply_async(message)
else:
message.save()
num_sent += 1
return num_sent

View file

@ -50,7 +50,7 @@ class Message(models.Model):
def sent(self):
self.state = self.SENT
self.save(update_fields=('state',))
self.save()
def log(self, error):
result = SMTPLog.SUCCESS

View file

@ -1,3 +1,5 @@
from django.utils.translation import ugettext_lazy as _
from orchestra.contrib.settings import Setting
@ -9,3 +11,9 @@ MAILER_DEFERE_SECONDS = Setting('MAILER_DEFERE_SECONDS',
MAILER_MESSAGES_CLEANUP_DAYS = Setting('MAILER_MESSAGES_CLEANUP_DAYS',
7
)
MAILER_NON_QUEUED_MAILS_PER_REQUEST_THRESHOLD = Setting('MAILER_NON_QUEUED_MAILS_PER_REQUEST_THRESHOLD',
2,
help_text=_("Number of emails that will be sent directly before starting to queue them."),
)

View file

@ -27,11 +27,19 @@ def get_request_cache():
class RequestCacheMiddleware(object):
def process_request(self, request):
cache = _request_cache.get(currentThread(), RequestCache())
_request_cache[currentThread()] = cache
current_thread = currentThread()
cache = _request_cache.get(current_thread, RequestCache())
_request_cache[current_thread] = cache
cache.clear()
def process_response(self, request, response):
def clear_cache(self):
current_thread = currentThread()
if currentThread() in _request_cache:
_request_cache[currentThread()].clear()
_request_cache[current_thread].clear()
def process_exception(self, request, exception):
self.clear_cache()
def process_response(self, request, response):
self.clear_cache()
return response

View file

@ -5,7 +5,6 @@ from orchestra.utils.sys import run
def html_to_pdf(html, pagination=False):
""" converts HTL to PDF using wkhtmltopdf """
print(pagination)
context = {
'pagination': textwrap.dedent("""\
--footer-center "Page [page] of [topage]"\\

View file

@ -5,7 +5,7 @@ from django.template.loader import render_to_string
from django.template import Context
def send_email_template(template, context, to, email_from=None, html=None, attachments=[]):
def render_email_template(template, context):
"""
Renders an email template with this format:
{% if subject %}Subject{% endif %}
@ -13,7 +13,6 @@ def send_email_template(template, context, to, email_from=None, html=None, attac
context can be a dictionary or a template.Context instance
"""
if isinstance(context, dict):
context = Context(context)
if isinstance(to, str):
@ -27,13 +26,16 @@ def send_email_template(template, context, to, email_from=None, html=None, attac
'scheme': url.scheme,
'domain': url.netloc,
}
#subject cannot have new lines
subject = render_to_string(template, {'subject': True}, context).strip()
message = render_to_string(template, {'message': True}, context).strip()
return subject, message
def send_email_template(template, context, to, email_from=None, html=None, attachments=[]):
subject, message = render_email_template(template, context)
msg = EmailMultiAlternatives(subject, message, email_from, to, attachments=attachments)
if html:
html_message = render_to_string(html, {'message': True}, context)
subject, html_message = render_email_template(html, context)
msg.attach_alternative(html_message, "text/html")
msg.send()