Add custom validator for multiple emails in a single text field. Change the widget of the email fields in the mailer app to avoid browser side email validation. Closes GitLab issue #530. Thanks to Mark Maglana @relaxdiego for the report.
Signed-off-by: Roberto Rosario <roberto.rosario.gonzalez@gmail.com>
This commit is contained in:
@@ -8,6 +8,10 @@
|
||||
* Add improvements to the metadata URL encoding and decoding to support
|
||||
ampersand characters as part of the metadata value. GitLab issue
|
||||
#529. Thanks to Mark Maglana @relaxdiego for the report.
|
||||
* Add custom validator for multiple emails in a single text field.
|
||||
Change the widget of the email fields in the mailer app to avoid
|
||||
browser side email validation. Closes GitLab issue #530.
|
||||
Thanks to Mark Maglana @relaxdiego for the report.
|
||||
|
||||
3.1.7 (2018-10-14)
|
||||
==================
|
||||
|
||||
@@ -18,6 +18,7 @@ from .settings import (
|
||||
setting_document_body_template, setting_document_subject_template,
|
||||
setting_link_body_template, setting_link_subject_template
|
||||
)
|
||||
from .validators import validate_email_multiple
|
||||
|
||||
|
||||
class DocumentMailForm(forms.Form):
|
||||
@@ -56,11 +57,11 @@ class DocumentMailForm(forms.Form):
|
||||
except UserMailer.DoesNotExist:
|
||||
pass
|
||||
|
||||
email = forms.EmailField(
|
||||
email = forms.CharField(
|
||||
help_text=_(
|
||||
'Email address of the recipient. Can be multiple addresses '
|
||||
'separated by comma or semicolon.'
|
||||
), label=_('Email address')
|
||||
), label=_('Email address'), validators=[validate_email_multiple]
|
||||
)
|
||||
subject = forms.CharField(label=_('Subject'), required=False)
|
||||
body = forms.CharField(
|
||||
@@ -117,4 +118,9 @@ class UserMailerDynamicForm(DynamicModelForm):
|
||||
|
||||
|
||||
class UserMailerTestForm(forms.Form):
|
||||
email = forms.EmailField(label=_('Email address'))
|
||||
email = forms.CharField(
|
||||
help_text=_(
|
||||
'Email address of the recipient. Can be multiple addresses '
|
||||
'separated by comma or semicolon.'
|
||||
), label=_('Email address'), validators=[validate_email_multiple]
|
||||
)
|
||||
|
||||
@@ -3,10 +3,16 @@ from __future__ import unicode_literals
|
||||
TEST_BODY_HTML = '<strong>test body</strong>'
|
||||
TEST_EMAIL_ADDRESS = 'test@example.com'
|
||||
TEST_RECIPIENTS_MULTIPLE_COMMA = 'test@example.com,test2@example.com'
|
||||
TEST_RECIPIENTS_MULTIPLE_COMMA_RESULT = [
|
||||
'test@example.com', 'test2@example.com'
|
||||
]
|
||||
TEST_RECIPIENTS_MULTIPLE_SEMICOLON = 'test@example.com;test2@example.com'
|
||||
TEST_RECIPIENTS_MULTIPLE_SEMICOLON_RESULT = [
|
||||
'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_RECIPIENTS_MULTIPLE_MIXED_RESULT = [
|
||||
'test@example.com', 'test2@example.com', 'test2@example.com'
|
||||
]
|
||||
TEST_USER_MAILER_BACKEND_PATH = 'mailer.tests.mailers.TestBackend'
|
||||
TEST_USER_MAILER_LABEL = 'test user mailer label'
|
||||
|
||||
16
mayan/apps/mailer/tests/mixins.py
Normal file
16
mayan/apps/mailer/tests/mixins.py
Normal file
@@ -0,0 +1,16 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from ..models import UserMailer
|
||||
|
||||
from .literals import TEST_USER_MAILER_BACKEND_PATH, TEST_USER_MAILER_LABEL
|
||||
|
||||
|
||||
class MailerTestMixin(object):
|
||||
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='{}'
|
||||
)
|
||||
@@ -4,26 +4,16 @@ from django.core import mail
|
||||
|
||||
from documents.tests.test_models import GenericDocumentTestCase
|
||||
|
||||
from ..models import UserMailer
|
||||
|
||||
from .literals import (
|
||||
TEST_BODY_HTML, 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
|
||||
TEST_RECIPIENTS_MULTIPLE_COMMA_RESULT, TEST_RECIPIENTS_MULTIPLE_SEMICOLON,
|
||||
TEST_RECIPIENTS_MULTIPLE_SEMICOLON_RESULT, TEST_RECIPIENTS_MULTIPLE_MIXED,
|
||||
TEST_RECIPIENTS_MULTIPLE_MIXED_RESULT,
|
||||
)
|
||||
from .mixins import MailerTestMixin
|
||||
|
||||
|
||||
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='{}'
|
||||
)
|
||||
|
||||
class ModelTestCase(MailerTestMixin, GenericDocumentTestCase):
|
||||
def test_send_simple(self):
|
||||
self._create_user_mailer()
|
||||
self.user_mailer.send(to=TEST_EMAIL_ADDRESS)
|
||||
@@ -61,7 +51,7 @@ class ModelTestCase(GenericDocumentTestCase):
|
||||
|
||||
self.assertEqual(len(mail.outbox), 1)
|
||||
self.assertEqual(
|
||||
mail.outbox[0].to, TEST_RECIPIENTS_MULTIPLE_COMMA.split(',')
|
||||
mail.outbox[0].to, TEST_RECIPIENTS_MULTIPLE_COMMA_RESULT
|
||||
)
|
||||
|
||||
def test_send_multiple_recipients_semicolon(self):
|
||||
@@ -70,7 +60,7 @@ class ModelTestCase(GenericDocumentTestCase):
|
||||
|
||||
self.assertEqual(len(mail.outbox), 1)
|
||||
self.assertEqual(
|
||||
mail.outbox[0].to, TEST_RECIPIENTS_MULTIPLE_SEMICOLON.split(';')
|
||||
mail.outbox[0].to, TEST_RECIPIENTS_MULTIPLE_SEMICOLON_RESULT
|
||||
)
|
||||
|
||||
def test_send_multiple_recipient_mixed(self):
|
||||
@@ -79,5 +69,5 @@ class ModelTestCase(GenericDocumentTestCase):
|
||||
|
||||
self.assertEqual(len(mail.outbox), 1)
|
||||
self.assertEqual(
|
||||
list(mail.outbox[0].to), list(TEST_RECIPIENTS_MULTIPLE_MIXED_LIST)
|
||||
mail.outbox[0].to, TEST_RECIPIENTS_MULTIPLE_MIXED_RESULT
|
||||
)
|
||||
|
||||
@@ -12,20 +12,14 @@ from ..permissions import (
|
||||
)
|
||||
|
||||
from .literals import (
|
||||
TEST_EMAIL_ADDRESS, TEST_USER_MAILER_BACKEND_PATH, TEST_USER_MAILER_LABEL
|
||||
TEST_EMAIL_ADDRESS, TEST_USER_MAILER_BACKEND_PATH, TEST_USER_MAILER_LABEL,
|
||||
TEST_RECIPIENTS_MULTIPLE_COMMA, TEST_RECIPIENTS_MULTIPLE_COMMA_RESULT,
|
||||
TEST_RECIPIENTS_MULTIPLE_MIXED, TEST_RECIPIENTS_MULTIPLE_MIXED_RESULT,
|
||||
TEST_RECIPIENTS_MULTIPLE_SEMICOLON,
|
||||
TEST_RECIPIENTS_MULTIPLE_SEMICOLON_RESULT
|
||||
)
|
||||
from .mailers import TestBackend
|
||||
|
||||
|
||||
class MailerTestMixin(object):
|
||||
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='{}'
|
||||
)
|
||||
from .mixins import MailerTestMixin
|
||||
|
||||
|
||||
class MailerViewsTestCase(MailerTestMixin, GenericDocumentViewTestCase):
|
||||
@@ -33,7 +27,9 @@ class MailerViewsTestCase(MailerTestMixin, GenericDocumentViewTestCase):
|
||||
return self.post(
|
||||
'mailer:send_document_link', args=(self.document.pk,),
|
||||
data={
|
||||
'email': TEST_EMAIL_ADDRESS,
|
||||
'email': getattr(
|
||||
self, 'test_email_address', TEST_EMAIL_ADDRESS
|
||||
),
|
||||
'user_mailer': self.user_mailer.pk
|
||||
},
|
||||
)
|
||||
@@ -42,7 +38,9 @@ class MailerViewsTestCase(MailerTestMixin, GenericDocumentViewTestCase):
|
||||
return self.post(
|
||||
'mailer:send_document', args=(self.document.pk,),
|
||||
data={
|
||||
'email': TEST_EMAIL_ADDRESS,
|
||||
'email': getattr(
|
||||
self, 'test_email_address', TEST_EMAIL_ADDRESS
|
||||
),
|
||||
'user_mailer': self.user_mailer.pk
|
||||
},
|
||||
)
|
||||
@@ -66,7 +64,9 @@ class MailerViewsTestCase(MailerTestMixin, GenericDocumentViewTestCase):
|
||||
def _request_user_mailer_test(self):
|
||||
return self.post(
|
||||
'mailer:user_mailer_test', args=(self.user_mailer.pk,), data={
|
||||
'email': TEST_EMAIL_ADDRESS
|
||||
'email': getattr(
|
||||
self, 'test_email_address', TEST_EMAIL_ADDRESS
|
||||
)
|
||||
}, follow=True
|
||||
)
|
||||
|
||||
@@ -207,3 +207,141 @@ class MailerViewsTestCase(MailerTestMixin, GenericDocumentViewTestCase):
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(len(mail.outbox), 1)
|
||||
self.assertEqual(mail.outbox[0].to, [TEST_EMAIL_ADDRESS])
|
||||
|
||||
def test_send_multiple_recipients_comma(self):
|
||||
self._create_user_mailer()
|
||||
self.login_user()
|
||||
|
||||
self.grant_access(
|
||||
obj=self.user_mailer, permission=permission_user_mailer_use
|
||||
)
|
||||
|
||||
self.test_email_address = TEST_RECIPIENTS_MULTIPLE_COMMA
|
||||
response = self._request_user_mailer_test()
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(len(mail.outbox), 1)
|
||||
self.assertEqual(
|
||||
mail.outbox[0].to, TEST_RECIPIENTS_MULTIPLE_COMMA_RESULT
|
||||
)
|
||||
|
||||
def test_send_multiple_recipients_mixed(self):
|
||||
self._create_user_mailer()
|
||||
self.login_user()
|
||||
|
||||
self.grant_access(
|
||||
obj=self.user_mailer, permission=permission_user_mailer_use
|
||||
)
|
||||
|
||||
self.test_email_address = TEST_RECIPIENTS_MULTIPLE_MIXED
|
||||
response = self._request_user_mailer_test()
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(len(mail.outbox), 1)
|
||||
self.assertEqual(
|
||||
mail.outbox[0].to, TEST_RECIPIENTS_MULTIPLE_MIXED_RESULT
|
||||
)
|
||||
|
||||
def test_send_multiple_recipients_semicolon(self):
|
||||
self._create_user_mailer()
|
||||
self.login_user()
|
||||
|
||||
self.grant_access(
|
||||
obj=self.user_mailer, permission=permission_user_mailer_use
|
||||
)
|
||||
|
||||
self.test_email_address = TEST_RECIPIENTS_MULTIPLE_SEMICOLON
|
||||
response = self._request_user_mailer_test()
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(len(mail.outbox), 1)
|
||||
self.assertEqual(
|
||||
mail.outbox[0].to, TEST_RECIPIENTS_MULTIPLE_SEMICOLON_RESULT
|
||||
)
|
||||
|
||||
def test_mail_link_view_recipients_comma(self):
|
||||
self._create_user_mailer()
|
||||
self.login_user()
|
||||
|
||||
self.grant_permission(permission=permission_mailing_link)
|
||||
self.grant_permission(permission=permission_user_mailer_use)
|
||||
|
||||
self.test_email_address = TEST_RECIPIENTS_MULTIPLE_COMMA
|
||||
self._request_document_link_send()
|
||||
|
||||
self.assertEqual(len(mail.outbox), 1)
|
||||
self.assertEqual(
|
||||
mail.outbox[0].to, TEST_RECIPIENTS_MULTIPLE_COMMA_RESULT
|
||||
)
|
||||
|
||||
def test_mail_link_view_recipients_mixed(self):
|
||||
self._create_user_mailer()
|
||||
self.login_user()
|
||||
|
||||
self.grant_permission(permission=permission_mailing_link)
|
||||
self.grant_permission(permission=permission_user_mailer_use)
|
||||
|
||||
self.test_email_address = TEST_RECIPIENTS_MULTIPLE_MIXED
|
||||
self._request_document_link_send()
|
||||
|
||||
self.assertEqual(len(mail.outbox), 1)
|
||||
self.assertEqual(
|
||||
mail.outbox[0].to, TEST_RECIPIENTS_MULTIPLE_MIXED_RESULT
|
||||
)
|
||||
|
||||
def test_mail_link_view_recipients_semicolon(self):
|
||||
self._create_user_mailer()
|
||||
self.login_user()
|
||||
|
||||
self.grant_permission(permission=permission_mailing_link)
|
||||
self.grant_permission(permission=permission_user_mailer_use)
|
||||
|
||||
self.test_email_address = TEST_RECIPIENTS_MULTIPLE_SEMICOLON
|
||||
self._request_document_link_send()
|
||||
|
||||
self.assertEqual(len(mail.outbox), 1)
|
||||
self.assertEqual(
|
||||
mail.outbox[0].to, TEST_RECIPIENTS_MULTIPLE_SEMICOLON_RESULT
|
||||
)
|
||||
|
||||
def test_mail_document_view_recipients_comma(self):
|
||||
self._create_user_mailer()
|
||||
self.login_user()
|
||||
|
||||
self.grant_permission(permission=permission_mailing_send_document)
|
||||
self.grant_permission(permission=permission_user_mailer_use)
|
||||
|
||||
self.test_email_address = TEST_RECIPIENTS_MULTIPLE_COMMA
|
||||
self._request_document_send()
|
||||
|
||||
self.assertEqual(len(mail.outbox), 1)
|
||||
self.assertEqual(
|
||||
mail.outbox[0].to, TEST_RECIPIENTS_MULTIPLE_COMMA_RESULT
|
||||
)
|
||||
|
||||
def test_mail_document_view_recipients_mixed(self):
|
||||
self._create_user_mailer()
|
||||
self.login_user()
|
||||
|
||||
self.grant_permission(permission=permission_mailing_send_document)
|
||||
self.grant_permission(permission=permission_user_mailer_use)
|
||||
|
||||
self.test_email_address = TEST_RECIPIENTS_MULTIPLE_MIXED
|
||||
self._request_document_send()
|
||||
|
||||
self.assertEqual(len(mail.outbox), 1)
|
||||
self.assertEqual(
|
||||
mail.outbox[0].to, TEST_RECIPIENTS_MULTIPLE_MIXED_RESULT
|
||||
)
|
||||
|
||||
def test_mail_document_view_recipients_semicolon(self):
|
||||
self._create_user_mailer()
|
||||
self.login_user()
|
||||
|
||||
self.grant_permission(permission=permission_mailing_send_document)
|
||||
self.grant_permission(permission=permission_user_mailer_use)
|
||||
|
||||
self.test_email_address = TEST_RECIPIENTS_MULTIPLE_SEMICOLON
|
||||
self._request_document_send()
|
||||
|
||||
self.assertEqual(len(mail.outbox), 1)
|
||||
self.assertEqual(
|
||||
mail.outbox[0].to, TEST_RECIPIENTS_MULTIPLE_SEMICOLON_RESULT
|
||||
)
|
||||
|
||||
18
mayan/apps/mailer/validators.py
Normal file
18
mayan/apps/mailer/validators.py
Normal file
@@ -0,0 +1,18 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.core import validators
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from .utils import split_recipient_list
|
||||
|
||||
|
||||
def validate_email_multiple(value):
|
||||
recipient_list = split_recipient_list(recipients=[value])
|
||||
|
||||
for recipient in recipient_list:
|
||||
validate_email = validators.EmailValidator(
|
||||
message=_('%(email)s is not a valid email address.') % {
|
||||
'email': recipient
|
||||
}
|
||||
)
|
||||
validate_email(value=recipient)
|
||||
Reference in New Issue
Block a user