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
|
* Add improvements to the metadata URL encoding and decoding to support
|
||||||
ampersand characters as part of the metadata value. GitLab issue
|
ampersand characters as part of the metadata value. GitLab issue
|
||||||
#529. Thanks to Mark Maglana @relaxdiego for the report.
|
#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)
|
3.1.7 (2018-10-14)
|
||||||
==================
|
==================
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ from .settings import (
|
|||||||
setting_document_body_template, setting_document_subject_template,
|
setting_document_body_template, setting_document_subject_template,
|
||||||
setting_link_body_template, setting_link_subject_template
|
setting_link_body_template, setting_link_subject_template
|
||||||
)
|
)
|
||||||
|
from .validators import validate_email_multiple
|
||||||
|
|
||||||
|
|
||||||
class DocumentMailForm(forms.Form):
|
class DocumentMailForm(forms.Form):
|
||||||
@@ -56,11 +57,11 @@ class DocumentMailForm(forms.Form):
|
|||||||
except UserMailer.DoesNotExist:
|
except UserMailer.DoesNotExist:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
email = forms.EmailField(
|
email = forms.CharField(
|
||||||
help_text=_(
|
help_text=_(
|
||||||
'Email address of the recipient. Can be multiple addresses '
|
'Email address of the recipient. Can be multiple addresses '
|
||||||
'separated by comma or semicolon.'
|
'separated by comma or semicolon.'
|
||||||
), label=_('Email address')
|
), label=_('Email address'), validators=[validate_email_multiple]
|
||||||
)
|
)
|
||||||
subject = forms.CharField(label=_('Subject'), required=False)
|
subject = forms.CharField(label=_('Subject'), required=False)
|
||||||
body = forms.CharField(
|
body = forms.CharField(
|
||||||
@@ -117,4 +118,9 @@ class UserMailerDynamicForm(DynamicModelForm):
|
|||||||
|
|
||||||
|
|
||||||
class UserMailerTestForm(forms.Form):
|
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_BODY_HTML = '<strong>test body</strong>'
|
||||||
TEST_EMAIL_ADDRESS = 'test@example.com'
|
TEST_EMAIL_ADDRESS = 'test@example.com'
|
||||||
TEST_RECIPIENTS_MULTIPLE_COMMA = 'test@example.com,test2@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 = '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 = 'test@example.com,test2@example.com;test2@example.com'
|
||||||
TEST_RECIPIENTS_MULTIPLE_MIXED_LIST = (
|
TEST_RECIPIENTS_MULTIPLE_MIXED_RESULT = [
|
||||||
'test@example.com', 'test2@example.com', 'test2@example.com',
|
'test@example.com', 'test2@example.com', 'test2@example.com'
|
||||||
)
|
]
|
||||||
TEST_USER_MAILER_BACKEND_PATH = 'mailer.tests.mailers.TestBackend'
|
TEST_USER_MAILER_BACKEND_PATH = 'mailer.tests.mailers.TestBackend'
|
||||||
TEST_USER_MAILER_LABEL = 'test user mailer label'
|
TEST_USER_MAILER_LABEL = 'test user mailer label'
|
||||||
|
|||||||
@@ -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 documents.tests.test_models import GenericDocumentTestCase
|
||||||
|
|
||||||
from ..models import UserMailer
|
|
||||||
|
|
||||||
from .literals import (
|
from .literals import (
|
||||||
TEST_BODY_HTML, TEST_EMAIL_ADDRESS, TEST_RECIPIENTS_MULTIPLE_COMMA,
|
TEST_BODY_HTML, TEST_EMAIL_ADDRESS, TEST_RECIPIENTS_MULTIPLE_COMMA,
|
||||||
TEST_RECIPIENTS_MULTIPLE_SEMICOLON, TEST_RECIPIENTS_MULTIPLE_MIXED,
|
TEST_RECIPIENTS_MULTIPLE_COMMA_RESULT, TEST_RECIPIENTS_MULTIPLE_SEMICOLON,
|
||||||
TEST_RECIPIENTS_MULTIPLE_MIXED_LIST, TEST_USER_MAILER_LABEL,
|
TEST_RECIPIENTS_MULTIPLE_SEMICOLON_RESULT, TEST_RECIPIENTS_MULTIPLE_MIXED,
|
||||||
TEST_USER_MAILER_BACKEND_PATH
|
TEST_RECIPIENTS_MULTIPLE_MIXED_RESULT,
|
||||||
)
|
)
|
||||||
|
from .mixins import MailerTestMixin
|
||||||
|
|
||||||
|
|
||||||
class ModelTestCase(GenericDocumentTestCase):
|
class ModelTestCase(MailerTestMixin, 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):
|
def test_send_simple(self):
|
||||||
self._create_user_mailer()
|
self._create_user_mailer()
|
||||||
self.user_mailer.send(to=TEST_EMAIL_ADDRESS)
|
self.user_mailer.send(to=TEST_EMAIL_ADDRESS)
|
||||||
@@ -61,7 +51,7 @@ class ModelTestCase(GenericDocumentTestCase):
|
|||||||
|
|
||||||
self.assertEqual(len(mail.outbox), 1)
|
self.assertEqual(len(mail.outbox), 1)
|
||||||
self.assertEqual(
|
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):
|
def test_send_multiple_recipients_semicolon(self):
|
||||||
@@ -70,7 +60,7 @@ class ModelTestCase(GenericDocumentTestCase):
|
|||||||
|
|
||||||
self.assertEqual(len(mail.outbox), 1)
|
self.assertEqual(len(mail.outbox), 1)
|
||||||
self.assertEqual(
|
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):
|
def test_send_multiple_recipient_mixed(self):
|
||||||
@@ -79,5 +69,5 @@ class ModelTestCase(GenericDocumentTestCase):
|
|||||||
|
|
||||||
self.assertEqual(len(mail.outbox), 1)
|
self.assertEqual(len(mail.outbox), 1)
|
||||||
self.assertEqual(
|
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 (
|
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
|
from .mailers import TestBackend
|
||||||
|
from .mixins import MailerTestMixin
|
||||||
|
|
||||||
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='{}'
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class MailerViewsTestCase(MailerTestMixin, GenericDocumentViewTestCase):
|
class MailerViewsTestCase(MailerTestMixin, GenericDocumentViewTestCase):
|
||||||
@@ -33,7 +27,9 @@ class MailerViewsTestCase(MailerTestMixin, GenericDocumentViewTestCase):
|
|||||||
return self.post(
|
return self.post(
|
||||||
'mailer:send_document_link', args=(self.document.pk,),
|
'mailer:send_document_link', args=(self.document.pk,),
|
||||||
data={
|
data={
|
||||||
'email': TEST_EMAIL_ADDRESS,
|
'email': getattr(
|
||||||
|
self, 'test_email_address', TEST_EMAIL_ADDRESS
|
||||||
|
),
|
||||||
'user_mailer': self.user_mailer.pk
|
'user_mailer': self.user_mailer.pk
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@@ -42,7 +38,9 @@ class MailerViewsTestCase(MailerTestMixin, GenericDocumentViewTestCase):
|
|||||||
return self.post(
|
return self.post(
|
||||||
'mailer:send_document', args=(self.document.pk,),
|
'mailer:send_document', args=(self.document.pk,),
|
||||||
data={
|
data={
|
||||||
'email': TEST_EMAIL_ADDRESS,
|
'email': getattr(
|
||||||
|
self, 'test_email_address', TEST_EMAIL_ADDRESS
|
||||||
|
),
|
||||||
'user_mailer': self.user_mailer.pk
|
'user_mailer': self.user_mailer.pk
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@@ -66,7 +64,9 @@ class MailerViewsTestCase(MailerTestMixin, GenericDocumentViewTestCase):
|
|||||||
def _request_user_mailer_test(self):
|
def _request_user_mailer_test(self):
|
||||||
return self.post(
|
return self.post(
|
||||||
'mailer:user_mailer_test', args=(self.user_mailer.pk,), data={
|
'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
|
}, follow=True
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -207,3 +207,141 @@ class MailerViewsTestCase(MailerTestMixin, GenericDocumentViewTestCase):
|
|||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertEqual(len(mail.outbox), 1)
|
self.assertEqual(len(mail.outbox), 1)
|
||||||
self.assertEqual(mail.outbox[0].to, [TEST_EMAIL_ADDRESS])
|
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
|
||||||
|
)
|
||||||
|
|||||||
@@ -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