From 4fe42891e3af937a1879838090721ba0804ec2b3 Mon Sep 17 00:00:00 2001 From: Serghei Mihai Date: Fri, 6 May 2016 17:21:56 +0200 Subject: [PATCH] announces send command (#10805) --- corbo/models.py | 38 ++++++++++++++++++++++++++++++++ corbo/settings.py | 3 +++ requirements.txt | 3 +++ setup.py | 5 ++++- tests/test_emailing.py | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 tests/test_emailing.py diff --git a/corbo/models.py b/corbo/models.py index 3c22ec9..ad5b8a2 100644 --- a/corbo/models.py +++ b/corbo/models.py @@ -1,6 +1,13 @@ +from datetime import datetime +import logging +from html2text import HTML2Text +from emails.django import Message +from lxml.etree import HTML as HTMLTree + from django.utils import timezone from django.conf import settings from django.db import models +from django.core.files.storage import DefaultStorage from django.utils.translation import ugettext_lazy as _ from ckeditor.fields import RichTextField @@ -10,6 +17,8 @@ channel_choices = ( ('homepage', _('Homepage')) ) +logger = logging.getLogger(__name__) + class Category(models.Model): name = models.CharField(max_length=64, blank=False, null=False) ctime = models.DateTimeField(auto_now_add=True) @@ -62,6 +71,35 @@ class Broadcast(models.Model): id=self.announce.id, time=self.deliver_time) return u'announce {id} to deliver'.format(id=self.announce.id) + def send(self): + subscriptions = self.announce.category.subscription_set.all() + total_sent = 0 + handler = HTML2Text() + m = Message(html=self.announce.text, subject=self.announce.title, + text=handler.handle(self.announce.text), + mail_from=settings.DEFAULT_FROM_EMAIL) + html_tree = HTMLTree(self.announce.text) + storage = DefaultStorage() + for img in html_tree.xpath('//img/@src'): + img_path = img.lstrip(settings.MEDIA_URL) + m.attach(filename=img, data=storage.open(img_path)) + m.attachments[img].is_inline = True + m.transformer.synchronize_inline_images() + m.transformer.save() + for s in subscriptions: + if not s.identifier: + continue + sent = m.send(to=s.identifier) + if sent: + total_sent += 1 + logger.info('Announce "%s" sent to %s', self.announce.title, s.identifier) + else: + logger.warning('Error occured while sending announce "%s" to %s.', + self.announce.title, s.identifier) + self.result = total_sent + self.deliver_time = timezone.now() + self.save() + class Meta: verbose_name = _('sent') ordering = ('-deliver_time',) diff --git a/corbo/settings.py b/corbo/settings.py index 654c98c..a70dacc 100644 --- a/corbo/settings.py +++ b/corbo/settings.py @@ -104,6 +104,9 @@ RSS_DESCRIPTION = '' RSS_LINK = '' RSS_LINK_TEMPLATE = '/#announce{0}' +# default mass emails expeditor +CORBO_DEFAULT_FROM_EMAIL = 'webmaster@localhost' + # django-mellon settings MELLON_ATTRIBUTE_MAPPING = { 'username': '{attributes[username][0]}', diff --git a/requirements.txt b/requirements.txt index 2f6bdfc..2d0946c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,7 @@ Django>=1.7, <1.8 django-ckeditor<4.5.3 djangorestframework +html2text +emails -e git+http://repos.entrouvert.org/gadjo.git/#egg=gadjo + diff --git a/setup.py b/setup.py index e59a798..2254dba 100644 --- a/setup.py +++ b/setup.py @@ -96,7 +96,10 @@ setup( install_requires=['django>=1.7, <1.8', 'django-ckeditor<4.5.3', 'djangorestframework', - 'gadjo' + 'html2text', + 'gadjo', + 'emails', + 'lxml', ], zip_safe=False, cmdclass={ diff --git a/tests/test_emailing.py b/tests/test_emailing.py new file mode 100644 index 0000000..7a16e48 --- /dev/null +++ b/tests/test_emailing.py @@ -0,0 +1,59 @@ +import pytest +import json +from uuid import uuid4 + + +from django.core.urlresolvers import reverse +from django.utils.http import urlencode +from django.core import mail +from django.utils import timezone + +from corbo.models import Category, Announce, Subscription, Broadcast +from corbo.models import channel_choices + +pytestmark = pytest.mark.django_db + +CATEGORIES = ('Alerts', 'News') + + +@pytest.fixture +def categories(): + categories = [] + for category in CATEGORIES: + c, created = Category.objects.get_or_create(name=category) + categories.append(c) + return categories + +@pytest.fixture +def announces(): + announces = [] + for category in Category.objects.all(): + a = Announce.objects.create(category=category, title='Announce 1', + publication_time=timezone.now(), + text='

Announce 1

') + Broadcast.objects.create(announce=a) + announces.append(a) + a = Announce.objects.create(category=category, title='Announce 2', + publication_time=timezone.now(), + text='Announce 2') + Broadcast.objects.create(announce=a) + announces.append(a) + return announces + +def test_emailing_with_no_subscriptions(app, categories, announces): + for announce in announces: + broadcast = Broadcast.objects.get(announce=announce) + broadcast.send() + assert not broadcast.result + assert not mail.outbox + +def test_send_email(app, categories, announces): + for category in categories: + uuid = uuid4() + s = Subscription.objects.create(category=category, + identifier='%s@example.net' % uuid, uuid=uuid) + for announce in announces: + broadcast= Broadcast.objects.get(announce=announce) + broadcast.send() + assert broadcast.result + assert mail.outbox -- 2.8.1