Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove old phonenumber validation #5294

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# This file was automatically copied from notifications-utils@90.0.0
# This file was automatically copied from notifications-utils@91.0.1

repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
Expand Down
3 changes: 2 additions & 1 deletion app/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,14 @@
formatted_list,
get_lines_with_normalised_whitespace,
)
from notifications_utils.recipient_validation.phone_number import format_phone_number_human_readable
from notifications_utils.safe_string import make_string_safe_for_email_local_part, make_string_safe_for_id
from notifications_utils.sanitise_text import SanitiseASCII
from werkzeug.exceptions import HTTPException as WerkzeugHTTPException
from werkzeug.exceptions import abort
from werkzeug.local import LocalProxy

from app.utils.validation import format_phone_number_human_readable

# must be declared before rest of app is imported to satisfy circular import
# ruff: noqa: E402
memo_resetters: list[Callable] = []
Expand Down
4 changes: 2 additions & 2 deletions app/formatters.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from notifications_utils.field import Field
from notifications_utils.formatters import make_quotes_smart
from notifications_utils.formatters import nl2br as utils_nl2br
from notifications_utils.recipient_validation.phone_number import InvalidPhoneError, validate_phone_number
from notifications_utils.recipient_validation.phone_number import InvalidPhoneError, PhoneNumber
from notifications_utils.take import Take
from notifications_utils.timezones import utc_string_to_aware_gmt_datetime

Expand Down Expand Up @@ -143,7 +143,7 @@ def format_delta_days(date, numeric_prefix=""):

def valid_phone_number(phone_number):
try:
validate_phone_number(phone_number)
PhoneNumber(phone_number)
return True
except InvalidPhoneError:
return False
Expand Down
16 changes: 10 additions & 6 deletions app/main/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
from notifications_utils.insensitive_dict import InsensitiveDict
from notifications_utils.recipient_validation.email_address import validate_email_address
from notifications_utils.recipient_validation.errors import InvalidEmailError, InvalidPhoneError
from notifications_utils.recipient_validation.phone_number import normalise_phone_number
from notifications_utils.recipient_validation.phone_number import PhoneNumber as PhoneNumberUtils
from notifications_utils.recipient_validation.postal_address import PostalAddress
from notifications_utils.safe_string import make_string_safe_for_email_local_part
from ordered_set import OrderedSet
Expand Down Expand Up @@ -1805,12 +1805,16 @@ def validate(self, *args, **kwargs):
# and disallow emergency 3-digit numbers
def valid_non_emergency_phone_number(self, num):
try:
normalised_number = normalise_phone_number(num.data)
PhoneNumberUtils(num.data, is_service_contact_number=True)
except InvalidPhoneError as e:
raise ValidationError("Enter a phone number in the correct format") from e

if normalised_number in {"999", "112"}:
raise ValidationError("Phone number cannot be an emergency number")
if e.code == InvalidPhoneError.Codes.UNSUPPORTED_EMERGENCY_NUMBER:
raise ValidationError(str(e)) from e
elif e.code == InvalidPhoneError.Codes.TOO_LONG:
# assume the number is an extension and return the number with minimal normalisation
return True

else:
raise ValidationError("Enter a phone number in the correct format") from e

return True

Expand Down
16 changes: 7 additions & 9 deletions app/main/validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from notifications_utils.formatters import formatted_list
from notifications_utils.recipient_validation.email_address import validate_email_address
from notifications_utils.recipient_validation.errors import InvalidEmailError, InvalidPhoneError
from notifications_utils.recipient_validation.phone_number import PhoneNumber, validate_phone_number
from notifications_utils.recipient_validation.phone_number import PhoneNumber
from notifications_utils.sanitise_text import SanitiseSMS
from ordered_set import OrderedSet
from wtforms import ValidationError
Expand Down Expand Up @@ -97,19 +97,17 @@ def __init__(
InvalidPhoneError.Codes.NOT_A_UK_MOBILE: "%s does not look like a UK mobile number",
InvalidPhoneError.Codes.UNSUPPORTED_COUNTRY_CODE: "Country code for %s not found",
InvalidPhoneError.Codes.UNKNOWN_CHARACTER: "%s can only include: 0 1 2 3 4 5 6 7 8 9 ( ) + -",
InvalidPhoneError.Codes.INVALID_NUMBER: "%s is not valid – double check the phone number you entered",
}

def __call__(self, form, field):
try:
if field.data:
if self.allow_sms_to_uk_landlines:
number = PhoneNumber(field.data)
number.validate(
allow_international_number=self.allow_international_sms,
allow_uk_landline=self.allow_sms_to_uk_landlines,
)
else:
validate_phone_number(field.data, international=self.allow_international_sms)
number = PhoneNumber(field.data)
number.validate(
allow_international_number=self.allow_international_sms,
allow_uk_landline=self.allow_sms_to_uk_landlines,
)
except InvalidPhoneError as e:
error_message = str(e)
if hasattr(field, "error_summary_messages"):
Expand Down
2 changes: 1 addition & 1 deletion app/main/views/conversation.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from flask import jsonify, redirect, render_template, request, session, url_for
from flask_login import current_user
from notifications_python_client.errors import HTTPError
from notifications_utils.recipient_validation.phone_number import format_phone_number_human_readable
from notifications_utils.template import SMSPreviewTemplate

from app import current_service, notification_api_client, service_api_client
Expand All @@ -10,6 +9,7 @@
from app.models.notification import InboundSMSMessage, InboundSMSMessages, Notifications
from app.models.template_list import UserTemplateList
from app.utils.user import user_has_permissions
from app.utils.validation import format_phone_number_human_readable


@main.route("/services/<uuid:service_id>/conversation/<uuid:notification_id>")
Expand Down
2 changes: 1 addition & 1 deletion app/main/views/dashboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

from flask import Response, abort, jsonify, render_template, request, session, url_for
from flask_login import current_user
from notifications_utils.recipient_validation.phone_number import format_phone_number_human_readable
from werkzeug.utils import redirect

from app import (
Expand Down Expand Up @@ -36,6 +35,7 @@
from app.utils.pagination import generate_next_dict, generate_previous_dict, get_page_from_request
from app.utils.time import get_current_financial_year
from app.utils.user import user_has_permissions
from app.utils.validation import format_phone_number_human_readable


@main.route("/services/<uuid:service_id>/dashboard")
Expand Down
2 changes: 1 addition & 1 deletion app/main/views/pricing.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def guidance_pricing_text_messages():
"views/guidance/pricing/text-message-pricing.html",
sms_rate=SMSRate(),
international_sms_rates=sorted(
[(cc, country["names"], country["billable_units"]) for cc, country in INTERNATIONAL_BILLING_RATES.items()],
[(cc, country["names"], country["rate_multiplier"]) for cc, country in INTERNATIONAL_BILLING_RATES.items()],
key=lambda x: x[0],
),
_search_form=SearchByNameForm(),
Expand Down
11 changes: 11 additions & 0 deletions app/utils/validation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from notifications_utils.recipient_validation.errors import InvalidPhoneError
from notifications_utils.recipient_validation.phone_number import PhoneNumber


def format_phone_number_human_readable(number):
try:
phone_number = PhoneNumber(number)
except InvalidPhoneError:
# if there was a validation error, we want to shortcut out here, but still display the number on the front end
return number
return phone_number.get_human_readable_format()
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# This file was automatically copied from notifications-utils@90.0.0
# This file was automatically copied from notifications-utils@91.0.1

[tool.black]
line-length = 120
Expand Down
2 changes: 1 addition & 1 deletion requirements.in
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ notifications-python-client==10.0.0
fido2==1.1.3

# Run `make bump-utils` to update to the latest version
notifications-utils @ git+https://github.com/alphagov/notifications-utils.git@90.0.0
notifications-utils @ git+https://github.com/alphagov/notifications-utils.git@91.0.1

govuk-frontend-jinja==3.4.0

Expand Down
4 changes: 2 additions & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -107,15 +107,15 @@ mistune==0.8.4
# via notifications-utils
notifications-python-client==10.0.0
# via -r requirements.in
notifications-utils @ git+https://github.com/alphagov/notifications-utils.git@90.0.0
notifications-utils @ git+https://github.com/alphagov/notifications-utils.git@91.0.1
# via -r requirements.in
openpyxl==3.0.10
# via pyexcel-xlsx
ordered-set==4.1.0
# via notifications-utils
packaging==23.1
# via gunicorn
phonenumbers==8.13.48
phonenumbers==8.13.50
# via notifications-utils
pillow==10.3.0
# via -r requirements.in
Expand Down
4 changes: 2 additions & 2 deletions requirements_for_test.txt
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ mypy-extensions==1.0.0
# via black
notifications-python-client==10.0.0
# via -r requirements.in
notifications-utils @ git+https://github.com/alphagov/notifications-utils.git@90.0.0
notifications-utils @ git+https://github.com/alphagov/notifications-utils.git@91.0.1
# via -r requirements.in
openpyxl==3.0.10
# via pyexcel-xlsx
Expand All @@ -155,7 +155,7 @@ packaging==23.1
# pytest
pathspec==0.12.1
# via black
phonenumbers==8.13.48
phonenumbers==8.13.50
# via notifications-utils
pillow==10.3.0
# via -r requirements.in
Expand Down
2 changes: 1 addition & 1 deletion requirements_for_test_common.in
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# This file was automatically copied from notifications-utils@90.0.0
# This file was automatically copied from notifications-utils@91.0.1

beautifulsoup4==4.11.1
pytest==7.2.0
Expand Down
2 changes: 1 addition & 1 deletion tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -425,7 +425,7 @@ def inbound_sms_json():
(4, 5, "33(0)1 12345678"), # France
(5, 7, "1-202-555-0104"), # USA in one format
(6, 9, "+12025550104"), # USA in another format
(7, 9, "+68212345"), # Cook Islands
(7, 9, "+68223001"), # Cook Islands
)
],
}
Expand Down
15 changes: 14 additions & 1 deletion tests/app/main/forms/test_service_contact_details_form.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,6 @@ def test_form_phone_number_allows_non_emergency_3_digit_numbers(notify_admin, sh

with notify_admin.test_request_context(method="POST", data=data):
form = ServiceContactDetailsForm()

if allowed:
assert form.validate_on_submit()
assert len(form.errors) == 0
Expand All @@ -122,3 +121,17 @@ def test_form_phone_number_allows_non_emergency_3_digit_numbers(notify_admin, sh
assert not form.validate_on_submit()
assert len(form.errors) == 1
assert form.errors["phone_number"] == ["Phone number cannot be an emergency number"]


@pytest.mark.parametrize(
"short_number, allowed",
(("01572 812241 7081", True),),
)
def test_form_phone_number_allows_non_emergency_numbers_with_extensions(notify_admin, short_number, allowed):
data = {"contact_details_type": "phone_number", "phone_number": short_number}

with notify_admin.test_request_context(method="POST", data=data):
form = ServiceContactDetailsForm()
assert form.validate_on_submit()
assert len(form.errors) == 0
assert form.errors == {}
2 changes: 1 addition & 1 deletion tests/app/main/test_validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ def test_invalid_list_of_white_list_email_domains(
def test_uk_mobile_number_validation_messages_match(mocker):
mock_field = _gen_mock_field("notanumber", error_summary_messages=[])
mocker.patch(
"app.main.validators.validate_phone_number",
"app.main.validators.PhoneNumber",
side_effect=InvalidPhoneError(code=InvalidPhoneError.Codes.UNKNOWN_CHARACTER),
)
with pytest.raises(ValidationError) as error:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4925,7 +4925,7 @@ def test_send_files_by_email_contact_details_prefills_the_form_with_the_existing
[
("url", "http://example.com/", "http://new-link.com/"),
("email_address", "[email protected]", "[email protected]"),
("phone_number", "0207 12345", "0207 56789"),
("phone_number", "020 3451 9002", "020 3451 9001"),
],
)
def test_send_files_by_email_contact_details_updates_contact_details_and_redirects_to_settings_page(
Expand Down
6 changes: 3 additions & 3 deletions tests/app/main/views/test_api_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -558,8 +558,8 @@ def test_should_update_guestlist(
data = {
"email_addresses-1": "[email protected]",
"email_addresses-3": "[email protected]",
"phone_numbers-0": "07900900000",
"phone_numbers-2": "+1800-555-555",
"phone_numbers-0": "07988057616",
"phone_numbers-2": "+1 202-555-0104",
}

client_request.post(
Expand All @@ -572,7 +572,7 @@ def test_should_update_guestlist(
SERVICE_ONE_ID,
{
"email_addresses": ["[email protected]", "[email protected]"],
"phone_numbers": ["07900900000", "+1800-555-555"],
"phone_numbers": ["07988057616", "+1 202-555-0104"],
},
)

Expand Down
2 changes: 1 addition & 1 deletion tests/app/main/views/test_code_not_received.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ def test_should_render_correct_resend_template_for_pending_user(
"phone_number_to_register_with",
[
"+447700900460",
"+1800-555-555",
"+1 202-555-0104",
],
)
def test_should_resend_verify_code_and_update_mobile_for_pending_user(
Expand Down
4 changes: 2 additions & 2 deletions tests/app/main/views/test_conversation.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@ def test_get_user_phone_number_when_only_outbound_exists(notify_admin, mocker):
side_effect=HTTPError(response=Mock(status_code=404)),
)
mock_get_notification = mocker.patch(
"app.main.views.conversation.notification_api_client.get_notification", return_value={"to": "15550000000"}
"app.main.views.conversation.notification_api_client.get_notification", return_value={"to": "14157711401"}
)
assert get_user_number("service", "notification") == "+1 555-000-0000"
assert get_user_number("service", "notification") == "+1 415-771-1401"
mock_get_inbound_sms.assert_called_once_with("service", "notification")
mock_get_notification.assert_called_once_with("service", "notification")

Expand Down
4 changes: 2 additions & 2 deletions tests/app/main/views/test_dashboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ def test_inbound_messages_shows_count_of_messages_when_there_are_no_messages(
"+33 1 12 34 56 78 message-5 5 hours ago",
"+1 202-555-0104 message-6 7 hours ago",
"+1 202-555-0104 message-7 9 hours ago",
"+682 12345 message-8 9 hours ago",
"+682 23 001 message-8 9 hours ago",
]
),
)
Expand Down Expand Up @@ -437,7 +437,7 @@ def test_download_inbox(
"+33 1 12 34 56 78,message-5,2016-07-01 08:59\r\n"
"+1 202-555-0104,message-6,2016-07-01 06:59\r\n"
"+1 202-555-0104,message-7,2016-07-01 04:59\r\n"
"+682 12345,message-8,2016-07-01 04:59\r\n"
"+682 23 001,message-8,2016-07-01 04:59\r\n"
)


Expand Down
2 changes: 1 addition & 1 deletion tests/app/main/views/test_register.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def test_logged_in_user_redirects_to_account(
"phone_number_to_register_with",
[
"+4407700900460",
"+1800-555-555",
"+1 202-555-0104",
],
)
@pytest.mark.parametrize(
Expand Down
2 changes: 1 addition & 1 deletion tests/app/main/views/test_user_profile.py
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ def test_delete_mobile_number(client_request, api_user_active_email_auth, mocker
"phone_number_to_register_with",
[
"+4407700900460",
"+1800-555-555",
"+1 202-555-0104",
],
)
def test_should_redirect_after_mobile_number_change(
Expand Down
4 changes: 2 additions & 2 deletions tests/app/main/views/uploads/test_upload_contact_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,11 +127,11 @@ def test_upload_contact_list_page(client_request):
(
"""
phone number
+447700900
+44770
""",
"There’s a problem with invalid.csv You need to fix 1 phone number.",
"Row in file 1 phone number",
"2 Mobile number is too short +447700900",
"2 Mobile number is too short +44770",
),
(
"""
Expand Down