diff --git a/app/main/forms.py b/app/main/forms.py index c7dd469c4..48f39cbab 100644 --- a/app/main/forms.py +++ b/app/main/forms.py @@ -1,4 +1,3 @@ -import re import pytz import weakref @@ -30,7 +29,14 @@ from wtforms.fields.html5 import EmailField, TelField, SearchField from wtforms.validators import (DataRequired, Email, Length, Regexp, Optional) from flask_wtf.file import FileField as FileField_wtf, FileAllowed -from app.main.validators import (Blacklist, CsvFileValidator, ValidGovEmail, NoCommasInPlaceHolders, OnlyGSMCharacters) +from app.main.validators import ( + Blacklist, + CsvFileValidator, + ValidGovEmail, + NoCommasInPlaceHolders, + OnlyGSMCharacters, + LettersNumbersAndFullStopsOnly, +) def get_time_value_and_label(future_time): @@ -553,15 +559,12 @@ class ServiceSmsSenderForm(StripWhitespaceForm): 'Text message sender', validators=[ DataRequired(message="Can’t be empty"), - Length(max=11, message="Enter 11 characters or fewer") + Length(max=11, message="Enter 11 characters or fewer"), + LettersNumbersAndFullStopsOnly(), ] ) is_default = BooleanField("Make this text message sender the default") - def validate_sms_sender(self, field): - if field.data and not re.match(r'^[a-zA-Z0-9\s]+$', field.data): - raise ValidationError('Use letters and numbers only') - class ServiceEditInboundNumberForm(StripWhitespaceForm): is_default = BooleanField("Make this text message sender the default") diff --git a/app/main/validators.py b/app/main/validators.py index 709274dda..92074b1d6 100644 --- a/app/main/validators.py +++ b/app/main/validators.py @@ -1,3 +1,4 @@ +import re from wtforms import ValidationError from notifications_utils.field import Field from notifications_utils.gsm import get_non_gsm_compatible_characters @@ -63,3 +64,15 @@ class OnlyGSMCharacters: ('It' if len(non_gsm_characters) == 1 else 'They') ) ) + + +class LettersNumbersAndFullStopsOnly: + + regex = re.compile(r'^[a-zA-Z0-9\s\.]+$') + + def __init__(self, message='Use letters and numbers only'): + self.message = message + + def __call__(self, form, field): + if field.data and not re.match(self.regex, field.data): + raise ValidationError(self.message) diff --git a/tests/app/main/views/test_service_settings.py b/tests/app/main/views/test_service_settings.py index b87f3a572..efd719c0f 100644 --- a/tests/app/main/views/test_service_settings.py +++ b/tests/app/main/views/test_service_settings.py @@ -809,23 +809,36 @@ def test_incorrect_letter_contact_block_input( @pytest.mark.parametrize('sms_sender_input, expected_error', [ + ('elevenchars', None), + ('11 chars', None), ('', 'Can’t be empty'), - ('abcdefghijkhgkg', 'Enter 11 characters or fewer') + ('abcdefghijkhgkg', 'Enter 11 characters or fewer'), + (' ¯\_(ツ)_/¯ ', 'Use letters and numbers only'), + ('blood.co.uk', None), ]) def test_incorrect_sms_sender_input( sms_sender_input, expected_error, client_request, - no_sms_senders + no_sms_senders, + mock_add_sms_sender, ): page = client_request.post( 'main.service_add_sms_sender', service_id=SERVICE_ONE_ID, _data={'sms_sender': sms_sender_input}, - _expected_status=200 + _expected_status=(200 if expected_error else 302) ) - assert normalize_spaces(page.select_one('.error-message').text) == expected_error + error_message = page.select_one('.error-message') + count_of_api_calls = len(mock_add_sms_sender.call_args_list) + + if not expected_error: + assert not error_message + assert count_of_api_calls == 1 + else: + assert normalize_spaces(error_message.text) == expected_error + assert count_of_api_calls == 0 @pytest.mark.parametrize('fixture, data, api_default_args', [