diff --git a/app/main/forms.py b/app/main/forms.py index e4559a164..9259f5c6f 100644 --- a/app/main/forms.py +++ b/app/main/forms.py @@ -1,3 +1,4 @@ +import re from flask_wtf import Form from wtforms import ( @@ -24,6 +25,45 @@ def email_address(): Regexp(regex=gov_uk_email, message='Enter a gov.uk email address')]) +class UKMobileNumber(StringField): + + def pre_validate(self, form): + + self.data = self.data.replace('(', '') + self.data = self.data.replace(')', '') + self.data = self.data.replace(' ', '') + self.data = self.data.replace('-', '') + + if self.data.startswith('+'): + self.data = self.data[1:] + + if not sum([ + self.data.startswith(prefix) for prefix in ['07', '447', '4407', '00447'] + ]): + raise ValidationError('Must be a mobile number') + + for digit in self.data: + try: + int(digit) + except(ValueError): + raise ValidationError('Must not contain letters or symbols') + + self.data = self.data.split('7', 1)[1] + + if len(self.data) > 9: + raise ValidationError('Too many digits') + + if len(self.data) < 9: + raise ValidationError('Too few digits') + + def post_validate(self, form, validation_stopped): + + if len(self.data) != 9: + return + + self.data = '+44 7{} {} {}'.format(*re.findall('...', self.data)) + + def mobile_number(): mobile_number_regex = "^\\+44[\\d]{10}$" return StringField('Mobile phone number', diff --git a/tests/app/main/test_phone_number_form_field.py b/tests/app/main/test_phone_number_form_field.py new file mode 100644 index 000000000..a6994fce5 --- /dev/null +++ b/tests/app/main/test_phone_number_form_field.py @@ -0,0 +1,68 @@ +import pytest +from wtforms import Form +from app.main.forms import UKMobileNumber + + +class FormExample(Form): + phone_number = UKMobileNumber() + +phone_numbers = { + 'invalid': [ + # Too long + '0712345678910', + '0044712345678910', + '0044712345678910', + '+44 (0)7123 456 789 10', + # Too short + '0712345678', + '004471234567', + '00447123456', + '+44 (0)7123 456 78', + # Not mobile (from https://fakenumber.org/generator/freephone) + '08081 570364', + '+44 8081 570364', + '0117 496 0860', + '+44 117 496 0860', + '020 7946 0991', + '+44 20 7946 0991', + # Contains non-numbers + '07890x32109', + '07123 456789...', + '07123 ☟☜⬇⬆☞☝', + '07123☟☜⬇⬆☞☝', + '07";DROP TABLE;"', + '+44 07ab cde fgh', + ], + 'valid': [ + '07123456789', + '07123 456789', + '07123-456-789', + '00447123456789', + '00 44 7123456789', + '+447123456789', + '+44 7123 456 789', + '+44 (0)7123 456 789' + ] +} + + +@pytest.mark.parametrize("phone_number", phone_numbers['valid']) +def test_phone_number_accepts_valid_values(phone_number): + form = FormExample(phone_number=phone_number) + form.validate() + assert form.errors == {} + + +@pytest.mark.parametrize("phone_number", phone_numbers['invalid']) +def test_phone_number_rejects_invalid_values(phone_number): + form = FormExample(phone_number=phone_number) + form.validate() + print(phone_number) + assert form.errors != {} + + +@pytest.mark.parametrize("phone_number", phone_numbers['valid']) +def test_phone_number_outputs_in_correct_format(phone_number): + form = FormExample(phone_number=phone_number) + form.validate() + assert form.phone_number.data == '+44 7123 456 789'