Add support for emailing documents to a recipient list. GitLab #396

Signed-off-by: Roberto Rosario <roberto.rosario.gonzalez@gmail.com>
This commit is contained in:
Roberto Rosario
2017-07-12 02:50:29 -04:00
parent b9994dbf40
commit cc33e1d259
8 changed files with 145 additions and 53 deletions

View File

@@ -1,7 +1,8 @@
2.5.3 (2017-07-XX)
==================
- Fix HTML mark up in window title. GitLab issue #397.
- Fix HTML mark up in window title. GitLab #397.
- Add support for emailing documents to a recipient list. GitLab #396
2.5.2 (2017-07-08)
==================
- Improve new document creation signal handling.

View File

@@ -14,3 +14,5 @@ DEFAULT_LINK_BODY_TEMPLATE = _(
'{{ link }}\n\n--------\n '
'This email has been sent from %(project_title)s (%(project_website)s)'
)
EMAIL_SEPARATORS = (',', ';')

View File

@@ -8,6 +8,8 @@ from django.db import models
from django.utils.module_loading import import_string
from django.utils.translation import ugettext_lazy as _
from .utils import split_recipient_list
logger = logging.getLogger(__name__)
@@ -80,36 +82,28 @@ class UserMailer(models.Model):
self.backend_data = json.dumps(data)
self.save()
def send(self, **kwargs):
"""
https://docs.djangoproject.com/en/1.11/topics/email
#django.core.mail.EmailMessage
subject: The subject line of the email.
body: The body text. This should be a plain text message.
from_email: The sender's address. Both fred@example.com and Fred
<fred@example.com> forms are legal. If omitted,
the DEFAULT_FROM_EMAIL setting is used.
to: A list or tuple of recipient addresses.
bcc: A list or tuple of addresses used in the "Bcc" header when
sending the email.
connection: An email backend instance. Use this parameter if you want
to use the same connection for multiple messages. If omitted, a new
connection is created when send() is called.
attachments: A list of attachments to put on the message. These can be
either email.MIMEBase.MIMEBase instances, or (filename, content,
mimetype) triples.
headers: A dictionary of extra headers to put on the message. The
keys are the header name, values are the header values. It's up to
the caller to ensure header names and values are in the correct
format for an email message. The corresponding attribute is
extra_headers.
cc: A list or tuple of recipient addresses used in the "Cc"
header when sending the email.
reply_to: A list or tuple of recipient addresses used in the
"Reply-To" header when sending the email.
"""
def send(self, subject='', body='', to=None, document=None, as_attachment=False):
recipient_list = split_recipient_list(recipients=[to])
with self.get_connection() as connection:
mail.EmailMessage(connection=connection, **kwargs).send()
email_message = mail.EmailMultiAlternatives(
subject=subject, body=body, to=recipient_list,
connection=connection
)
if as_attachment:
with document.open() as descriptor:
email_message.attach(
filename=document.label, content=descriptor.read(),
mimetype=document.file_mimetype
)
try:
email_message.send()
except Exception as exception:
self.error_log.create(message=exception)
else:
self.error_log.all().delete()
def test(self, to):
self.send(to=to, subject=_('Test email from Mayan EDMS'))

View File

@@ -1,37 +1,27 @@
from __future__ import unicode_literals
from django.apps import apps
from django.core.mail import EmailMultiAlternatives
from documents.models import Document
from mayan.celery import app
@app.task(ignore_result=True)
def task_send_document(subject_text, body_text_content, sender, recipient, document_id, user_mailer_id, as_attachment=False):
def task_send_document(subject_text, body_text_content, sender, recipient, user_mailer_id, as_attachment=False, document_id=None):
Document = apps.get_model(
app_label='documents', model_name='Document'
)
UserMailer = apps.get_model(
app_label='mailer', model_name='UserMailer'
)
if document_id:
document = Document.objects.get(pk=document_id)
else:
document = None
user_mailer = UserMailer.objects.get(pk=user_mailer_id)
connection = user_mailer.get_connection()
email_msg = EmailMultiAlternatives(
subject_text, body_text_content, sender, [recipient],
connection=connection,
user_mailer.send(
subject=subject_text, body=body_text_content, to=recipient,
document=document, as_attachment=as_attachment
)
if as_attachment:
document = Document.objects.get(pk=document_id)
with document.open() as descriptor:
email_msg.attach(
document.label, descriptor.read(), document.file_mimetype
)
try:
email_msg.send()
except Exception as exception:
user_mailer.error_log.create(message=exception)
else:
user_mailer.error_log.all().delete()

View File

@@ -1,5 +1,11 @@
from __future__ import unicode_literals
TEST_EMAIL_ADDRESS = 'test@example.com'
TEST_RECIPIENTS_MULTIPLE_COMMA = 'test@example.com,test2@example.com'
TEST_RECIPIENTS_MULTIPLE_SEMICOLON = 'test@example.com;test2@example.com'
TEST_RECIPIENTS_MULTIPLE_MIXED = 'test@example.com,test2@example.com;test2@example.com'
TEST_RECIPIENTS_MULTIPLE_MIXED_LIST = (
'test@example.com', 'test2@example.com', 'test2@example.com',
)
TEST_USER_MAILER_LABEL = 'test user mailer label'
TEST_USER_MAILER_BACKEND_PATH = 'mailer.tests.mailers.TestBackend'

View File

@@ -4,5 +4,8 @@ from ..classes import MailerBackend
class TestBackend(MailerBackend):
"""
User mailer backend to use with tests
"""
class_path = 'django.core.mail.backends.locmem.EmailBackend'
label = 'Django local memory backend'

View File

@@ -0,0 +1,75 @@
from __future__ import absolute_import, unicode_literals
from django.core import mail
from documents.tests.test_models import GenericDocumentTestCase
from ..models import UserMailer
from .literals import (
TEST_EMAIL_ADDRESS, TEST_RECIPIENTS_MULTIPLE_COMMA,
TEST_RECIPIENTS_MULTIPLE_SEMICOLON, TEST_RECIPIENTS_MULTIPLE_MIXED,
TEST_RECIPIENTS_MULTIPLE_MIXED_LIST, TEST_USER_MAILER_LABEL,
TEST_USER_MAILER_BACKEND_PATH
)
class ModelTestCase(GenericDocumentTestCase):
def _create_user_mailer(self):
self.user_mailer = UserMailer.objects.create(
default=True,
enabled=True,
label=TEST_USER_MAILER_LABEL,
backend_path=TEST_USER_MAILER_BACKEND_PATH,
backend_data='{}'
)
def test_send_simple(self):
self._create_user_mailer()
self.user_mailer.send(to=TEST_EMAIL_ADDRESS)
self.assertEqual(len(mail.outbox), 1)
self.assertEqual(mail.outbox[0].to, [TEST_EMAIL_ADDRESS])
def test_send_attachment(self):
self._create_user_mailer()
self.user_mailer.send(
to=TEST_EMAIL_ADDRESS, document=self.document, as_attachment=True
)
self.assertEqual(len(mail.outbox), 1)
self.assertEqual(mail.outbox[0].to, [TEST_EMAIL_ADDRESS])
with self.document.open() as file_object:
self.assertEqual(
mail.outbox[0].attachments[0], (
self.document.label, file_object.read(),
self.document.file_mimetype
)
)
def test_send_multiple_recipients_comma(self):
self._create_user_mailer()
self.user_mailer.send(to=TEST_RECIPIENTS_MULTIPLE_COMMA)
self.assertEqual(len(mail.outbox), 1)
self.assertEqual(
mail.outbox[0].to, TEST_RECIPIENTS_MULTIPLE_COMMA.split(',')
)
def test_send_multiple_recipients_semicolon(self):
self._create_user_mailer()
self.user_mailer.send(to=TEST_RECIPIENTS_MULTIPLE_SEMICOLON)
self.assertEqual(len(mail.outbox), 1)
self.assertEqual(
mail.outbox[0].to, TEST_RECIPIENTS_MULTIPLE_SEMICOLON.split(';')
)
def test_send_multiple_recipient_mixed(self):
self._create_user_mailer()
self.user_mailer.send(to=TEST_RECIPIENTS_MULTIPLE_MIXED)
self.assertEqual(len(mail.outbox), 1)
self.assertEqual(
list(mail.outbox[0].to), list(TEST_RECIPIENTS_MULTIPLE_MIXED_LIST)
)

View File

@@ -0,0 +1,21 @@
from __future__ import unicode_literals
from .literals import EMAIL_SEPARATORS
def split_recipient_list(recipients, separator_list=None, separator_index=0):
separator_list = separator_list or EMAIL_SEPARATORS
try:
separator = separator_list[separator_index]
except IndexError:
return recipients
else:
result = []
for recipient in recipients:
result.extend(recipient.split(separator))
return split_recipient_list(
recipients=result, separator_list=separator_list,
separator_index=separator_index + 1
)