mirror of
https://github.com/GSA/notifications-api.git
synced 2026-08-22 15:26:09 -04:00
Compare commits
38 Commits
04-03-2025
...
add-second
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6d671ef69d | ||
|
|
cc7714713f | ||
|
|
7596bcd982 | ||
|
|
ba24485808 | ||
|
|
ffdc0edc4e | ||
|
|
2f220a17a5 | ||
|
|
37691f504e | ||
|
|
a1273d7f01 | ||
|
|
0c65b50043 | ||
|
|
9e7f747675 | ||
|
|
0af9cac583 | ||
|
|
7d54322846 | ||
|
|
0fceff42c4 | ||
|
|
51c0793ffe | ||
|
|
55bcf7f722 | ||
|
|
7aaa36e630 | ||
|
|
f87a54fffe | ||
|
|
21330acf51 | ||
|
|
365d68183e | ||
|
|
f9995e24cb | ||
|
|
e9d2d03796 | ||
|
|
51c1dcf159 | ||
|
|
91f269646f | ||
|
|
e4b7cf98a3 | ||
|
|
48e8ff755b | ||
|
|
b605c74262 | ||
|
|
df305a815a | ||
|
|
d4a33549ca | ||
|
|
14de65816f | ||
|
|
4d5ae7c9db | ||
|
|
ecb5747b7b | ||
|
|
f3966afe53 | ||
|
|
dce57ab964 | ||
|
|
bc85de75f1 | ||
|
|
d06fd588ba | ||
|
|
30180574c9 | ||
|
|
28444a460b | ||
|
|
e9ea22ad6d |
@@ -48,7 +48,10 @@ class AwsSnsClient(SmsClient):
|
||||
|
||||
def send_sms(self, to, content, reference, sender=None, international=False):
|
||||
matched = False
|
||||
for match in phonenumbers.PhoneNumberMatcher(to, "US"):
|
||||
if "+" not in to:
|
||||
to = f"+{to}"
|
||||
|
||||
for match in phonenumbers.PhoneNumberMatcher(to, None):
|
||||
matched = True
|
||||
to = phonenumbers.format_number(
|
||||
match.number, phonenumbers.PhoneNumberFormat.E164
|
||||
|
||||
@@ -185,8 +185,10 @@ def send_email_to_provider(notification):
|
||||
recipient = recipient.decode("utf-8")
|
||||
personalisation = redis_store.get(f"email-personalisation-{notification.id}")
|
||||
if personalisation:
|
||||
personalisation = personalisation.decode("utf-8")
|
||||
notification.personalisation = json.loads(personalisation)
|
||||
p = personalisation.decode("utf-8")
|
||||
|
||||
p = json.loads(p)
|
||||
notification.personalisation = p
|
||||
|
||||
service = SerialisedService.from_id(notification.service_id)
|
||||
if not service.active:
|
||||
@@ -210,6 +212,12 @@ def send_email_to_provider(notification):
|
||||
template_dict, values=notification.personalisation
|
||||
)
|
||||
|
||||
html_email = str(html_email)
|
||||
html_email = html_email.replace("%5B", "")
|
||||
html_email = html_email.replace("%5D", "")
|
||||
html_email = html_email.replace("(", "")
|
||||
html_email = html_email.replace(")", "")
|
||||
|
||||
if notification.key_type == KeyType.TEST:
|
||||
notification.reference = str(create_uuid())
|
||||
update_notification_to_sending(notification, provider)
|
||||
@@ -225,7 +233,7 @@ def send_email_to_provider(notification):
|
||||
recipient,
|
||||
plain_text_email.subject,
|
||||
body=str(plain_text_email),
|
||||
html_body=str(html_email),
|
||||
html_body=html_email,
|
||||
reply_to_address=notification.reply_to_text,
|
||||
)
|
||||
notification.reference = reference
|
||||
|
||||
58
migrations/versions/0417_add_second_e2e_test_user.py
Normal file
58
migrations/versions/0417_add_second_e2e_test_user.py
Normal file
@@ -0,0 +1,58 @@
|
||||
import datetime
|
||||
import os
|
||||
import uuid
|
||||
|
||||
import sqlalchemy as sa
|
||||
from alembic import op
|
||||
|
||||
from app import db
|
||||
from app.dao.users_dao import get_user_by_email
|
||||
from app.enums import AuthType
|
||||
from app.models import User
|
||||
from app.utils import utc_now
|
||||
|
||||
revision = "0417_add_second_e2e_test_user"
|
||||
down_revision = "0416_readd_e2e_test_user"
|
||||
|
||||
|
||||
def upgrade():
|
||||
email_address = os.getenv("NOTIFY_E2E_TEST_EMAIL_TWO")
|
||||
password = os.getenv("NOTIFY_E2E_TEST_PASSWORD_TWO")
|
||||
name = f"e2e_test_user_{uuid.uuid4()}"
|
||||
data = {
|
||||
"id": uuid.uuid4(),
|
||||
"name": name,
|
||||
"email_address": email_address,
|
||||
"password": password,
|
||||
"mobile_number": "+12025555555",
|
||||
"state": "active",
|
||||
"created_at": utc_now(),
|
||||
"password_changed_at": utc_now(),
|
||||
"failed_login_count": 0,
|
||||
"platform_admin": "f",
|
||||
"email_access_validated_at": utc_now(),
|
||||
"auth_type": AuthType.SMS,
|
||||
}
|
||||
conn = op.get_bind()
|
||||
|
||||
# delete the old user because
|
||||
delete_sql = f"""
|
||||
delete from users where email_address='{email_address}'
|
||||
"""
|
||||
|
||||
insert_sql = """
|
||||
insert into users (id, name, email_address, _password, mobile_number, state, created_at, password_changed_at, failed_login_count, platform_admin, email_access_validated_at, auth_type)
|
||||
values (:id, :name, :email_address, :password, :mobile_number, :state, :created_at, :password_changed_at, :failed_login_count, :platform_admin, :email_access_validated_at, :auth_type)
|
||||
"""
|
||||
conn.execute(sa.text(delete_sql))
|
||||
|
||||
conn.execute(sa.text(insert_sql), data)
|
||||
|
||||
|
||||
def downgrade():
|
||||
email_address = os.getenv("NOTIFY_E2E_TEST_EMAIL_TWO")
|
||||
user_to_delete = get_user_by_email(email_address)
|
||||
if not user_to_delete:
|
||||
return
|
||||
db.session.remove(user_to_delete)
|
||||
db.session.commit()
|
||||
@@ -628,8 +628,6 @@ def validate_phone_number(number, international=False):
|
||||
|
||||
try:
|
||||
parsed = phonenumbers.parse(number, None)
|
||||
if parsed.country_code != 1:
|
||||
raise InvalidPhoneError("Invalid country code")
|
||||
number = f"{parsed.country_code}{parsed.national_number}"
|
||||
if len(number) < 8:
|
||||
raise InvalidPhoneError("Not enough digits")
|
||||
|
||||
690
poetry.lock
generated
690
poetry.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -17,9 +17,9 @@ cachetools = "==5.4.0"
|
||||
celery = {version = "==5.4.0", extras = ["redis"]}
|
||||
certifi = ">=2022.12.7"
|
||||
cffi = "==1.17.1"
|
||||
charset-normalizer = "^3.1.0"
|
||||
charset-normalizer = "^3.4.1"
|
||||
click = "==8.1.7"
|
||||
click-datetime = "==0.2"
|
||||
click-datetime = "==0.4.0"
|
||||
click-didyoumean = "==0.3.1"
|
||||
click-plugins = "==1.1.1"
|
||||
click-repl = "==0.3.0"
|
||||
@@ -41,7 +41,7 @@ marshmallow-sqlalchemy = "==1.0.0"
|
||||
newrelic = "*"
|
||||
notifications-python-client = "==10.0.0"
|
||||
oscrypto = { git = "https://github.com/wbond/oscrypto.git", rev = "1547f53" }
|
||||
packaging = "==24.1"
|
||||
packaging = "==24.2"
|
||||
poetry-dotenv-plugin = "==0.2.0"
|
||||
psycopg2-binary = "==2.9.9"
|
||||
pyjwt = "==2.10.1"
|
||||
@@ -49,7 +49,7 @@ python-dotenv = "==1.0.1"
|
||||
sqlalchemy = "==2.0.31"
|
||||
werkzeug = "^3.0.6"
|
||||
faker = "^26.0.0"
|
||||
async-timeout = "^4.0.3"
|
||||
async-timeout = "^5.0.1"
|
||||
bleach = "^6.1.0"
|
||||
geojson = "^3.2.0"
|
||||
numpy = "^2.2.3"
|
||||
@@ -81,22 +81,22 @@ requests = "^2.32.3"
|
||||
[tool.poetry.group.dev.dependencies]
|
||||
awscli = "^1.33.32"
|
||||
bandit = "*"
|
||||
black = "^24.8.0"
|
||||
black = "^25.1.0"
|
||||
cloudfoundry-client = "*"
|
||||
exceptiongroup = "==1.2.2"
|
||||
flake8 = "^7.1.1"
|
||||
flake8-bugbear = "^24.1.17"
|
||||
flake8 = "^7.2.0"
|
||||
flake8-bugbear = "^24.12.12"
|
||||
freezegun = "^1.5.1"
|
||||
honcho = "*"
|
||||
isort = "^5.13.2"
|
||||
jinja2-cli = {version = "==0.8.2", extras = ["yaml"]}
|
||||
moto = "==5.1.0"
|
||||
pip-audit = "*"
|
||||
pre-commit = "^3.8.0"
|
||||
pre-commit = "^4.2.0"
|
||||
pytest = "^8.3.2"
|
||||
pytest-env = "^1.1.3"
|
||||
pytest-mock = "^3.14.0"
|
||||
pytest-cov = "^5.0.0"
|
||||
pytest-cov = "^6.1.1"
|
||||
pytest-xdist = "^3.5.0"
|
||||
radon = "^6.0.1"
|
||||
requests-mock = "^1.11.0"
|
||||
|
||||
@@ -5,7 +5,7 @@ from app import aws_sns_client
|
||||
|
||||
def test_send_sms_successful_returns_aws_sns_response(notify_api, mocker):
|
||||
boto_mock = mocker.patch.object(aws_sns_client, "_client", create=True)
|
||||
to = "6135555555"
|
||||
to = "16135555555"
|
||||
content = reference = "foo"
|
||||
with notify_api.app_context():
|
||||
aws_sns_client.send_sms(to, content, reference)
|
||||
|
||||
@@ -628,6 +628,8 @@ def test_bad_or_missing_data(
|
||||
assert recipients.has_errors is True
|
||||
|
||||
|
||||
# TODO, original test for number one had {0, 1, 2}, but it has morphed to {0, 1}
|
||||
# Is +447900123 legit or not? What changed?
|
||||
@pytest.mark.parametrize(
|
||||
("file_contents", "rows_with_bad_recipients"),
|
||||
[
|
||||
@@ -638,7 +640,7 @@ def test_bad_or_missing_data(
|
||||
1234
|
||||
+447900123
|
||||
""",
|
||||
{0, 1, 2},
|
||||
{0, 1},
|
||||
),
|
||||
(
|
||||
"""
|
||||
@@ -647,7 +649,7 @@ def test_bad_or_missing_data(
|
||||
+12022340104, USA
|
||||
+23051234567, Mauritius
|
||||
""",
|
||||
{2},
|
||||
set(),
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
@@ -24,21 +24,16 @@ valid_us_phone_numbers = [
|
||||
"(202) 555-0104",
|
||||
]
|
||||
|
||||
# TODO
|
||||
# International phone number tests are commented out as a result of issue #943 in notifications-admin. We are
|
||||
# deliberately eliminating the ability to send to numbers outside of country code 1. These tests should
|
||||
# be removed at some point when we are sure we are never going to support international numbers
|
||||
|
||||
valid_international_phone_numbers = [
|
||||
# "+71234567890", # Russia
|
||||
# "+447123456789", # UK
|
||||
# "+4407123456789", # UK
|
||||
# "+4407123 456789", # UK
|
||||
# "+4407123-456-789", # UK
|
||||
# "+23051234567", # Mauritius,
|
||||
# "+682 12345", # Cook islands
|
||||
# "+3312345678",
|
||||
# "+9-2345-12345-12345", # 15 digits
|
||||
"+71234567890", # Russia
|
||||
"+447123456789", # UK
|
||||
"+4407123456789", # UK
|
||||
"+4407123 456789", # UK
|
||||
"+4407123-456-789", # UK
|
||||
"+23051234567", # Mauritius,
|
||||
"+682 12345", # Cook islands
|
||||
"+3312345678",
|
||||
"+9-2345-12345-12345", # 15 digits
|
||||
]
|
||||
|
||||
|
||||
@@ -85,7 +80,7 @@ invalid_us_phone_numbers = sum(
|
||||
invalid_phone_numbers = [
|
||||
("+80233456789", "Not a valid country prefix"),
|
||||
("1234567", "Not enough digits"),
|
||||
("+682 1234", "Invalid country code"), # Cook Islands phone numbers can be 5 digits
|
||||
("+682 1234", "Not enough digits"), # Cook Islands phone numbers are 5 digits
|
||||
("+12345 12345 12345 6", "Too many digits"),
|
||||
]
|
||||
|
||||
@@ -156,46 +151,46 @@ def test_detect_us_phone_numbers(phone_number):
|
||||
@pytest.mark.parametrize(
|
||||
("phone_number", "expected_info"),
|
||||
[
|
||||
# (
|
||||
# "+4407900900123",
|
||||
# international_phone_info(
|
||||
# international=True,
|
||||
# country_prefix="44", # UK
|
||||
# billable_units=1,
|
||||
# ),
|
||||
# ),
|
||||
# (
|
||||
# "+4407700900123",
|
||||
# international_phone_info(
|
||||
# international=True,
|
||||
# country_prefix="44", # Number in TV range
|
||||
# billable_units=1,
|
||||
# ),
|
||||
# ),
|
||||
# (
|
||||
# "+4407700800123",
|
||||
# international_phone_info(
|
||||
# international=True,
|
||||
# country_prefix="44", # UK Crown dependency, so prefix same as UK
|
||||
# billable_units=1,
|
||||
# ),
|
||||
# ),
|
||||
# ( #
|
||||
# "+20-12-1234-1234",
|
||||
# international_phone_info(
|
||||
# international=True,
|
||||
# country_prefix="20", # Egypt
|
||||
# billable_units=1,
|
||||
# ),
|
||||
# ),
|
||||
# (
|
||||
# "+201212341234",
|
||||
# international_phone_info(
|
||||
# international=True,
|
||||
# country_prefix="20", # Egypt
|
||||
# billable_units=1,
|
||||
# ),
|
||||
# ),
|
||||
(
|
||||
"+4407900900123",
|
||||
international_phone_info(
|
||||
international=True,
|
||||
country_prefix="44", # UK
|
||||
billable_units=1,
|
||||
),
|
||||
),
|
||||
(
|
||||
"+4407700900123",
|
||||
international_phone_info(
|
||||
international=True,
|
||||
country_prefix="44", # Number in TV range
|
||||
billable_units=1,
|
||||
),
|
||||
),
|
||||
(
|
||||
"+4407700800123",
|
||||
international_phone_info(
|
||||
international=True,
|
||||
country_prefix="44", # UK Crown dependency, so prefix same as UK
|
||||
billable_units=1,
|
||||
),
|
||||
),
|
||||
( #
|
||||
"+20-12-1234-1234",
|
||||
international_phone_info(
|
||||
international=True,
|
||||
country_prefix="20", # Egypt
|
||||
billable_units=1,
|
||||
),
|
||||
),
|
||||
(
|
||||
"+201212341234",
|
||||
international_phone_info(
|
||||
international=True,
|
||||
country_prefix="20", # Egypt
|
||||
billable_units=1,
|
||||
),
|
||||
),
|
||||
(
|
||||
"+1 664-491-3434",
|
||||
international_phone_info(
|
||||
@@ -204,14 +199,14 @@ def test_detect_us_phone_numbers(phone_number):
|
||||
billable_units=1,
|
||||
),
|
||||
),
|
||||
# (
|
||||
# "+71234567890",
|
||||
# international_phone_info(
|
||||
# international=True,
|
||||
# country_prefix="7", # Russia
|
||||
# billable_units=1,
|
||||
# ),
|
||||
# ),
|
||||
(
|
||||
"+71234567890",
|
||||
international_phone_info(
|
||||
international=True,
|
||||
country_prefix="7", # Russia
|
||||
billable_units=1,
|
||||
),
|
||||
),
|
||||
(
|
||||
"1-202-555-0104",
|
||||
international_phone_info(
|
||||
@@ -228,14 +223,14 @@ def test_detect_us_phone_numbers(phone_number):
|
||||
billable_units=1,
|
||||
),
|
||||
),
|
||||
# (
|
||||
# "+23051234567",
|
||||
# international_phone_info(
|
||||
# international=True,
|
||||
# country_prefix="230", # Mauritius
|
||||
# billable_units=1,
|
||||
# ),
|
||||
# ),
|
||||
(
|
||||
"+23051234567",
|
||||
international_phone_info(
|
||||
international=True,
|
||||
country_prefix="230", # Mauritius
|
||||
billable_units=1,
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_get_international_info(phone_number, expected_info):
|
||||
@@ -288,11 +283,11 @@ def test_valid_us_phone_number_can_be_formatted_consistently(phone_number):
|
||||
@pytest.mark.parametrize(
|
||||
("phone_number", "expected_formatted"),
|
||||
[
|
||||
# ("+44071234567890", "+4471234567890"),
|
||||
("+44071234567890", "+4471234567890"),
|
||||
("1-202-555-0104", "+12025550104"),
|
||||
("+12025550104", "+12025550104"),
|
||||
("12025550104", "+12025550104"),
|
||||
# ("+23051234567", "+23051234567"),
|
||||
("+23051234567", "+23051234567"),
|
||||
],
|
||||
)
|
||||
def test_valid_international_phone_number_can_be_formatted_consistently(
|
||||
@@ -368,17 +363,17 @@ def test_validates_against_guestlist_of_phone_numbers(phone_number):
|
||||
)
|
||||
|
||||
|
||||
# @pytest.mark.parametrize(
|
||||
# "recipient_number, allowlist_number",
|
||||
# [
|
||||
# ["+4407123-456-789", "+4407123456789"],
|
||||
# ["+4407123456789", "+4407123-456-789"],
|
||||
# ],
|
||||
# )
|
||||
# def test_validates_against_guestlist_of_international_phone_numbers(
|
||||
# recipient_number, allowlist_number
|
||||
# ):
|
||||
# assert allowed_to_send_to(recipient_number, [allowlist_number])
|
||||
@pytest.mark.parametrize(
|
||||
"recipient_number, allowlist_number",
|
||||
[
|
||||
["+4407123-456-789", "+4407123456789"],
|
||||
["+4407123456789", "+4407123-456-789"],
|
||||
],
|
||||
)
|
||||
def test_validates_against_guestlist_of_international_phone_numbers(
|
||||
recipient_number, allowlist_number
|
||||
):
|
||||
assert allowed_to_send_to(recipient_number, [allowlist_number])
|
||||
|
||||
|
||||
@pytest.mark.parametrize("email_address", valid_email_addresses)
|
||||
@@ -388,19 +383,21 @@ def test_validates_against_guestlist_of_email_addresses(email_address):
|
||||
)
|
||||
|
||||
|
||||
# TODO something wrong with formatting Egyptian numbers, doesn't seem
|
||||
# like this would affect sendability need to confirm with AWS simulated numbers.
|
||||
@pytest.mark.parametrize(
|
||||
("phone_number", "expected_formatted"),
|
||||
[
|
||||
# ("+4407900900123", "+44 7900 900123"), # UK
|
||||
# ("+44(0)7900900123", "+44 7900 900123"), # UK
|
||||
# ("+447900900123", "+44 7900 900123"), # UK
|
||||
("+4407900900123", "+44 7900 900123"), # UK
|
||||
("+44(0)7900900123", "+44 7900 900123"), # UK
|
||||
("+447900900123", "+44 7900 900123"), # UK
|
||||
# ("+20-12-1234-1234", "+20 121 234 1234"), # Egypt
|
||||
# ("+201212341234", "+20 121 234 1234"), # Egypt
|
||||
("+1 664 491-3434", "+1 664-491-3434"), # Montserrat
|
||||
# ("+7 499 1231212", "+7 499 123-12-12"), # Moscow (Russia)
|
||||
("+7 499 1231212", "+7 499 123-12-12"), # Moscow (Russia)
|
||||
("1-202-555-0104", "(202) 555-0104"), # Washington DC (USA)
|
||||
# ("+23051234567", "+230 5123 4567"), # Mauritius
|
||||
# ("+33(0)1 12345678", "+33 1 12 34 56 78"), # Paris (France)
|
||||
("+23051234567", "+230 5123 4567"), # Mauritius
|
||||
("+33(0)1 12345678", "+33 1 12 34 56 78"), # Paris (France)
|
||||
],
|
||||
)
|
||||
def test_format_us_and_international_phone_numbers(phone_number, expected_formatted):
|
||||
@@ -417,7 +414,7 @@ def test_format_us_and_international_phone_numbers(phone_number, expected_format
|
||||
(None, ""),
|
||||
("foo", "foo"),
|
||||
("TeSt@ExAmPl3.com", "test@exampl3.com"),
|
||||
# ("+4407900 900 123", "+447900900123"),
|
||||
("+4407900 900 123", "+447900900123"),
|
||||
("+1 800 555 5555", "+18005555555"),
|
||||
],
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user