merge from main

This commit is contained in:
Kenneth Kehl
2024-06-06 13:12:37 -07:00
11 changed files with 111 additions and 91 deletions
+4 -1
View File
@@ -24,7 +24,8 @@ from app.notifications.process_notifications import persist_notification
from app.notifications.validators import check_service_over_total_message_limit from app.notifications.validators import check_service_over_total_message_limit
from app.serialised_models import SerialisedService, SerialisedTemplate from app.serialised_models import SerialisedService, SerialisedTemplate
from app.service.utils import service_allowed_to_send_to from app.service.utils import service_allowed_to_send_to
from app.utils import DATETIME_FORMAT, utc_now from app.utils import DATETIME_FORMAT, hilite, scrub, utc_now
from app.errors import TotalRequestsError
from notifications_utils.recipients import RecipientCSV from notifications_utils.recipients import RecipientCSV
@@ -189,6 +190,7 @@ def save_sms(self, service_id, notification_id, encrypted_notification, sender_i
# Return False when trial mode services try sending notifications # Return False when trial mode services try sending notifications
# to non-team and non-simulated recipients. # to non-team and non-simulated recipients.
if not service_allowed_to_send_to(notification["to"], service, KeyType.NORMAL): if not service_allowed_to_send_to(notification["to"], service, KeyType.NORMAL):
current_app.logger.info(hilite(scrub(f"service not allowed to send to {notification['to']}, aborting")))
current_app.logger.debug( current_app.logger.debug(
"SMS {} failed as restricted service".format(notification_id) "SMS {} failed as restricted service".format(notification_id)
) )
@@ -219,6 +221,7 @@ def save_sms(self, service_id, notification_id, encrypted_notification, sender_i
) )
# Kick off sns process in provider_tasks.py # Kick off sns process in provider_tasks.py
current_app.logger.info(hilite(scrub(f"Going to deliver sms for recipient: {notification['to']}")))
provider_tasks.deliver_sms.apply_async( provider_tasks.deliver_sms.apply_async(
[str(saved_notification.id)], queue=QueueNames.SEND_SMS [str(saved_notification.id)], queue=QueueNames.SEND_SMS
) )
+4 -1
View File
@@ -9,7 +9,7 @@ from flask import current_app
from app.clients import AWS_CLIENT_CONFIG, Client from app.clients import AWS_CLIENT_CONFIG, Client
from app.cloudfoundry_config import cloud_config from app.cloudfoundry_config import cloud_config
from app.exceptions import NotificationTechnicalFailureException from app.exceptions import NotificationTechnicalFailureException
from app.utils import utc_now from app.utils import hilite, scrub, utc_now
class AwsCloudwatchClient(Client): class AwsCloudwatchClient(Client):
@@ -124,6 +124,7 @@ class AwsCloudwatchClient(Client):
self.warn_if_dev_is_opted_out( self.warn_if_dev_is_opted_out(
message["delivery"]["providerResponse"], notification_id message["delivery"]["providerResponse"], notification_id
) )
current_app.logger.info(hilite(scrub(f"DELIVERED: {message}")))
return ( return (
"success", "success",
message["delivery"]["providerResponse"], message["delivery"]["providerResponse"],
@@ -140,6 +141,8 @@ class AwsCloudwatchClient(Client):
self.warn_if_dev_is_opted_out( self.warn_if_dev_is_opted_out(
message["delivery"]["providerResponse"], notification_id message["delivery"]["providerResponse"], notification_id
) )
current_app.logger.info(hilite(scrub(f"FAILED: {message}")))
return ( return (
"failure", "failure",
message["delivery"]["providerResponse"], message["delivery"]["providerResponse"],
+7 -3
View File
@@ -13,7 +13,7 @@ from app.dao.provider_details_dao import get_provider_details_by_notification_ty
from app.enums import BrandType, KeyType, NotificationStatus, NotificationType from app.enums import BrandType, KeyType, NotificationStatus, NotificationType
from app.exceptions import NotificationTechnicalFailureException from app.exceptions import NotificationTechnicalFailureException
from app.serialised_models import SerialisedService, SerialisedTemplate from app.serialised_models import SerialisedService, SerialisedTemplate
from app.utils import utc_now from app.utils import hilite, scrub, utc_now
from notifications_utils.template import ( from notifications_utils.template import (
HTMLEmailTemplate, HTMLEmailTemplate,
PlainTextEmailTemplate, PlainTextEmailTemplate,
@@ -109,15 +109,19 @@ def send_sms_to_provider(notification):
"international": notification.international, "international": notification.international,
} }
db.session.close() # no commit needed as no changes to objects have been made above db.session.close() # no commit needed as no changes to objects have been made above
current_app.logger.info("sending to sms")
message_id = provider.send_sms(**send_sms_kwargs) message_id = provider.send_sms(**send_sms_kwargs)
current_app.logger.info(f"got message_id {message_id}") current_app.logger.info(f"got message_id {message_id}")
except Exception as e: except Exception as e:
current_app.logger.error(e) msg = f"FAILED sending message for this recipient: {recipient} to sms"
current_app.logger.error(hilite(scrub(f"{msg} {e}")))
notification.billable_units = template.fragment_count notification.billable_units = template.fragment_count
dao_update_notification(notification) dao_update_notification(notification)
raise e raise e
else: else:
msg = f"Sending message for this recipient: {recipient} to sms"
current_app.logger.info(hilite(scrub(msg)))
notification.billable_units = template.fragment_count notification.billable_units = template.fragment_count
update_notification_to_sending(notification, provider) update_notification_to_sending(notification, provider)
return message_id return message_id
+3 -1
View File
@@ -12,7 +12,8 @@ from app.dao.notifications_dao import (
from app.enums import KeyType, NotificationStatus, NotificationType from app.enums import KeyType, NotificationStatus, NotificationType
from app.errors import BadRequestError from app.errors import BadRequestError
from app.models import Notification from app.models import Notification
from app.utils import utc_now from app.utils import hilite, scrub, utc_now
from app.errors import BadRequestError
from notifications_utils.recipients import ( from notifications_utils.recipients import (
format_email_address, format_email_address,
get_international_phone_info, get_international_phone_info,
@@ -110,6 +111,7 @@ def persist_notification(
formatted_recipient = validate_and_format_phone_number( formatted_recipient = validate_and_format_phone_number(
recipient, international=True recipient, international=True
) )
current_app.logger.info(hilite(scrub(f"Persisting notification with recipient {formatted_recipient}")))
recipient_info = get_international_phone_info(formatted_recipient) recipient_info = get_international_phone_info(formatted_recipient)
notification.normalised_to = formatted_recipient notification.normalised_to = formatted_recipient
notification.international = recipient_info.international notification.international = recipient_info.international
-5
View File
@@ -473,11 +473,6 @@ def get_all_notifications_for_service(service_id):
) )
current_app.logger.debug(f"number of notifications are {len(notifications)}") current_app.logger.debug(f"number of notifications are {len(notifications)}")
if len(notifications) > 0:
current_app.logger.debug(f"first notification is {notifications[0]}")
else:
current_app.logger.debug("there are no notifications to show")
# We try and get the next page of results to work out if we need provide a pagination link to the next page # We try and get the next page of results to work out if we need provide a pagination link to the next page
# in our response if it exists. Note, this could be done instead by changing `count_pages` in the previous # in our response if it exists. Note, this could be done instead by changing `count_pages` in the previous
# call to be True which will enable us to use Flask-Sqlalchemy to tell if there is a next page of results but # call to be True which will enable us to use Flask-Sqlalchemy to tell if there is a next page of results but
+13
View File
@@ -1,3 +1,4 @@
import re
from datetime import datetime, timedelta, timezone from datetime import datetime, timedelta, timezone
from flask import url_for from flask import url_for
@@ -144,3 +145,15 @@ def naive_utcnow():
def utc_now(): def utc_now():
return naive_utcnow() return naive_utcnow()
def scrub(msg):
# Eventually we want to scrub all messages in all logs for phone numbers
# and email addresses, masking them. Ultimately this will probably get
# refactored into a 'SafeLogger' subclass or something, but let's start here
# with phones.
phones = re.findall("(?:\\+ *)?\\d[\\d\\- ]{7,}\\d", msg)
phones = [phone.replace("-", "").replace(" ", "") for phone in phones]
for phone in phones:
msg = msg.replace(phone, f"1XXXXX{phone[-5:]}")
return msg
Generated
+57 -57
View File
@@ -204,17 +204,17 @@ tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "p
[[package]] [[package]]
name = "awscli" name = "awscli"
version = "1.32.117" version = "1.33.2"
description = "Universal Command Line Environment for AWS." description = "Universal Command Line Environment for AWS."
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
{file = "awscli-1.32.117-py3-none-any.whl", hash = "sha256:c4131b9d2f648f8064d82cc01f24b4187e4656dd70396beb863ba242e30ee83e"}, {file = "awscli-1.33.2-py3-none-any.whl", hash = "sha256:b8246ef8085df75ba20537c5ac0a621a4dbae1f084dc536bdc49cf2736fd0d3c"},
{file = "awscli-1.32.117.tar.gz", hash = "sha256:85424436d9c1f2add7045d607fb51426ea8caf40561fb67dfed517b55218b362"}, {file = "awscli-1.33.2.tar.gz", hash = "sha256:4f692fff0e75fc2505f9a7cb613ec09426c6ed52bcd5a99246f58426b16a1bb6"},
] ]
[package.dependencies] [package.dependencies]
botocore = "1.34.117" botocore = "1.34.120"
colorama = ">=0.2.5,<0.4.7" colorama = ">=0.2.5,<0.4.7"
docutils = ">=0.10,<0.17" docutils = ">=0.10,<0.17"
PyYAML = ">=3.10,<6.1" PyYAML = ">=3.10,<6.1"
@@ -403,17 +403,17 @@ files = [
[[package]] [[package]]
name = "boto3" name = "boto3"
version = "1.34.116" version = "1.34.119"
description = "The AWS SDK for Python" description = "The AWS SDK for Python"
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
{file = "boto3-1.34.116-py3-none-any.whl", hash = "sha256:e7f5ab2d1f1b90971a2b9369760c2c6bae49dae98c084a5c3f5c78e3968ace15"}, {file = "boto3-1.34.119-py3-none-any.whl", hash = "sha256:8f9c43c54b3dfaa36c4a0d7b42c417227a515bc7a2e163e62802780000a5a3e2"},
{file = "boto3-1.34.116.tar.gz", hash = "sha256:53cb8aeb405afa1cd2b25421e27a951aeb568026675dec020587861fac96ac87"}, {file = "boto3-1.34.119.tar.gz", hash = "sha256:cea2365a25b2b83a97e77f24ac6f922ef62e20636b42f9f6ee9f97188f9c1c03"},
] ]
[package.dependencies] [package.dependencies]
botocore = ">=1.34.116,<1.35.0" botocore = ">=1.34.119,<1.35.0"
jmespath = ">=0.7.1,<2.0.0" jmespath = ">=0.7.1,<2.0.0"
s3transfer = ">=0.10.0,<0.11.0" s3transfer = ">=0.10.0,<0.11.0"
@@ -422,13 +422,13 @@ crt = ["botocore[crt] (>=1.21.0,<2.0a0)"]
[[package]] [[package]]
name = "botocore" name = "botocore"
version = "1.34.117" version = "1.34.120"
description = "Low-level, data-driven core of boto 3." description = "Low-level, data-driven core of boto 3."
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
{file = "botocore-1.34.117-py3-none-any.whl", hash = "sha256:26a431997f882bcdd1e835f44c24b2a1752b1c4e5183c2ce62999ce95d518d6c"}, {file = "botocore-1.34.120-py3-none-any.whl", hash = "sha256:92bd739938078c7a0b110689a3eee21ecb3954d90653da013d9f98ef1165d6f7"},
{file = "botocore-1.34.117.tar.gz", hash = "sha256:4637ca42e6c51aebc4d9a2d92f97bf4bdb042e3f7985ff31a659a11e4c170e73"}, {file = "botocore-1.34.120.tar.gz", hash = "sha256:5cc0fca43cb2aad54917a394a001ac9ba774d21ad6a08828002d54b601776f78"},
] ]
[package.dependencies] [package.dependencies]
@@ -553,13 +553,13 @@ zstd = ["zstandard (==0.22.0)"]
[[package]] [[package]]
name = "certifi" name = "certifi"
version = "2024.2.2" version = "2024.6.2"
description = "Python package for providing Mozilla's CA Bundle." description = "Python package for providing Mozilla's CA Bundle."
optional = false optional = false
python-versions = ">=3.6" python-versions = ">=3.6"
files = [ files = [
{file = "certifi-2024.2.2-py3-none-any.whl", hash = "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1"}, {file = "certifi-2024.6.2-py3-none-any.whl", hash = "sha256:ddc6c8ce995e6987e7faf5e3f1b02b302836a0e5d98ece18392cb1a36c72ad56"},
{file = "certifi-2024.2.2.tar.gz", hash = "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f"}, {file = "certifi-2024.6.2.tar.gz", hash = "sha256:3cd43f1c6fa7dedc5899d69d3ad0398fd018ad1a17fba83ddaf78aa46c747516"},
] ]
[[package]] [[package]]
@@ -939,43 +939,43 @@ files = [
[[package]] [[package]]
name = "cryptography" name = "cryptography"
version = "42.0.7" version = "42.0.8"
description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers."
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
{file = "cryptography-42.0.7-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:a987f840718078212fdf4504d0fd4c6effe34a7e4740378e59d47696e8dfb477"}, {file = "cryptography-42.0.8-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:81d8a521705787afe7a18d5bfb47ea9d9cc068206270aad0b96a725022e18d2e"},
{file = "cryptography-42.0.7-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:bd13b5e9b543532453de08bcdc3cc7cebec6f9883e886fd20a92f26940fd3e7a"}, {file = "cryptography-42.0.8-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:961e61cefdcb06e0c6d7e3a1b22ebe8b996eb2bf50614e89384be54c48c6b63d"},
{file = "cryptography-42.0.7-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a79165431551042cc9d1d90e6145d5d0d3ab0f2d66326c201d9b0e7f5bf43604"}, {file = "cryptography-42.0.8-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e3ec3672626e1b9e55afd0df6d774ff0e953452886e06e0f1eb7eb0c832e8902"},
{file = "cryptography-42.0.7-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a47787a5e3649008a1102d3df55424e86606c9bae6fb77ac59afe06d234605f8"}, {file = "cryptography-42.0.8-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e599b53fd95357d92304510fb7bda8523ed1f79ca98dce2f43c115950aa78801"},
{file = "cryptography-42.0.7-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:02c0eee2d7133bdbbc5e24441258d5d2244beb31da5ed19fbb80315f4bbbff55"}, {file = "cryptography-42.0.8-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:5226d5d21ab681f432a9c1cf8b658c0cb02533eece706b155e5fbd8a0cdd3949"},
{file = "cryptography-42.0.7-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:5e44507bf8d14b36b8389b226665d597bc0f18ea035d75b4e53c7b1ea84583cc"}, {file = "cryptography-42.0.8-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:6b7c4f03ce01afd3b76cf69a5455caa9cfa3de8c8f493e0d3ab7d20611c8dae9"},
{file = "cryptography-42.0.7-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:7f8b25fa616d8b846aef64b15c606bb0828dbc35faf90566eb139aa9cff67af2"}, {file = "cryptography-42.0.8-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:2346b911eb349ab547076f47f2e035fc8ff2c02380a7cbbf8d87114fa0f1c583"},
{file = "cryptography-42.0.7-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:93a3209f6bb2b33e725ed08ee0991b92976dfdcf4e8b38646540674fc7508e13"}, {file = "cryptography-42.0.8-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:ad803773e9df0b92e0a817d22fd8a3675493f690b96130a5e24f1b8fabbea9c7"},
{file = "cryptography-42.0.7-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:e6b8f1881dac458c34778d0a424ae5769de30544fc678eac51c1c8bb2183e9da"}, {file = "cryptography-42.0.8-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:2f66d9cd9147ee495a8374a45ca445819f8929a3efcd2e3df6428e46c3cbb10b"},
{file = "cryptography-42.0.7-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:3de9a45d3b2b7d8088c3fbf1ed4395dfeff79d07842217b38df14ef09ce1d8d7"}, {file = "cryptography-42.0.8-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:d45b940883a03e19e944456a558b67a41160e367a719833c53de6911cabba2b7"},
{file = "cryptography-42.0.7-cp37-abi3-win32.whl", hash = "sha256:789caea816c6704f63f6241a519bfa347f72fbd67ba28d04636b7c6b7da94b0b"}, {file = "cryptography-42.0.8-cp37-abi3-win32.whl", hash = "sha256:a0c5b2b0585b6af82d7e385f55a8bc568abff8923af147ee3c07bd8b42cda8b2"},
{file = "cryptography-42.0.7-cp37-abi3-win_amd64.whl", hash = "sha256:8cb8ce7c3347fcf9446f201dc30e2d5a3c898d009126010cbd1f443f28b52678"}, {file = "cryptography-42.0.8-cp37-abi3-win_amd64.whl", hash = "sha256:57080dee41209e556a9a4ce60d229244f7a66ef52750f813bfbe18959770cfba"},
{file = "cryptography-42.0.7-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:a3a5ac8b56fe37f3125e5b72b61dcde43283e5370827f5233893d461b7360cd4"}, {file = "cryptography-42.0.8-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:dea567d1b0e8bc5764b9443858b673b734100c2871dc93163f58c46a97a83d28"},
{file = "cryptography-42.0.7-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:779245e13b9a6638df14641d029add5dc17edbef6ec915688f3acb9e720a5858"}, {file = "cryptography-42.0.8-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4783183f7cb757b73b2ae9aed6599b96338eb957233c58ca8f49a49cc32fd5e"},
{file = "cryptography-42.0.7-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d563795db98b4cd57742a78a288cdbdc9daedac29f2239793071fe114f13785"}, {file = "cryptography-42.0.8-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0608251135d0e03111152e41f0cc2392d1e74e35703960d4190b2e0f4ca9c70"},
{file = "cryptography-42.0.7-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:31adb7d06fe4383226c3e963471f6837742889b3c4caa55aac20ad951bc8ffda"}, {file = "cryptography-42.0.8-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:dc0fdf6787f37b1c6b08e6dfc892d9d068b5bdb671198c72072828b80bd5fe4c"},
{file = "cryptography-42.0.7-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:efd0bf5205240182e0f13bcaea41be4fdf5c22c5129fc7ced4a0282ac86998c9"}, {file = "cryptography-42.0.8-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:9c0c1716c8447ee7dbf08d6db2e5c41c688544c61074b54fc4564196f55c25a7"},
{file = "cryptography-42.0.7-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:a9bc127cdc4ecf87a5ea22a2556cab6c7eda2923f84e4f3cc588e8470ce4e42e"}, {file = "cryptography-42.0.8-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:fff12c88a672ab9c9c1cf7b0c80e3ad9e2ebd9d828d955c126be4fd3e5578c9e"},
{file = "cryptography-42.0.7-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:3577d029bc3f4827dd5bf8bf7710cac13527b470bbf1820a3f394adb38ed7d5f"}, {file = "cryptography-42.0.8-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:cafb92b2bc622cd1aa6a1dce4b93307792633f4c5fe1f46c6b97cf67073ec961"},
{file = "cryptography-42.0.7-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:2e47577f9b18723fa294b0ea9a17d5e53a227867a0a4904a1a076d1646d45ca1"}, {file = "cryptography-42.0.8-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:31f721658a29331f895a5a54e7e82075554ccfb8b163a18719d342f5ffe5ecb1"},
{file = "cryptography-42.0.7-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:1a58839984d9cb34c855197043eaae2c187d930ca6d644612843b4fe8513c886"}, {file = "cryptography-42.0.8-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b297f90c5723d04bcc8265fc2a0f86d4ea2e0f7ab4b6994459548d3a6b992a14"},
{file = "cryptography-42.0.7-cp39-abi3-win32.whl", hash = "sha256:e6b79d0adb01aae87e8a44c2b64bc3f3fe59515280e00fb6d57a7267a2583cda"}, {file = "cryptography-42.0.8-cp39-abi3-win32.whl", hash = "sha256:2f88d197e66c65be5e42cd72e5c18afbfae3f741742070e3019ac8f4ac57262c"},
{file = "cryptography-42.0.7-cp39-abi3-win_amd64.whl", hash = "sha256:16268d46086bb8ad5bf0a2b5544d8a9ed87a0e33f5e77dd3c3301e63d941a83b"}, {file = "cryptography-42.0.8-cp39-abi3-win_amd64.whl", hash = "sha256:fa76fbb7596cc5839320000cdd5d0955313696d9511debab7ee7278fc8b5c84a"},
{file = "cryptography-42.0.7-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:2954fccea107026512b15afb4aa664a5640cd0af630e2ee3962f2602693f0c82"}, {file = "cryptography-42.0.8-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:ba4f0a211697362e89ad822e667d8d340b4d8d55fae72cdd619389fb5912eefe"},
{file = "cryptography-42.0.7-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:362e7197754c231797ec45ee081f3088a27a47c6c01eff2ac83f60f85a50fe60"}, {file = "cryptography-42.0.8-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:81884c4d096c272f00aeb1f11cf62ccd39763581645b0812e99a91505fa48e0c"},
{file = "cryptography-42.0.7-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:4f698edacf9c9e0371112792558d2f705b5645076cc0aaae02f816a0171770fd"}, {file = "cryptography-42.0.8-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c9bb2ae11bfbab395bdd072985abde58ea9860ed84e59dbc0463a5d0159f5b71"},
{file = "cryptography-42.0.7-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:5482e789294854c28237bba77c4c83be698be740e31a3ae5e879ee5444166582"}, {file = "cryptography-42.0.8-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:7016f837e15b0a1c119d27ecd89b3515f01f90a8615ed5e9427e30d9cdbfed3d"},
{file = "cryptography-42.0.7-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:e9b2a6309f14c0497f348d08a065d52f3020656f675819fc405fb63bbcd26562"}, {file = "cryptography-42.0.8-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5a94eccb2a81a309806027e1670a358b99b8fe8bfe9f8d329f27d72c094dde8c"},
{file = "cryptography-42.0.7-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:d8e3098721b84392ee45af2dd554c947c32cc52f862b6a3ae982dbb90f577f14"}, {file = "cryptography-42.0.8-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:dec9b018df185f08483f294cae6ccac29e7a6e0678996587363dc352dc65c842"},
{file = "cryptography-42.0.7-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c65f96dad14f8528a447414125e1fc8feb2ad5a272b8f68477abbcc1ea7d94b9"}, {file = "cryptography-42.0.8-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:343728aac38decfdeecf55ecab3264b015be68fc2816ca800db649607aeee648"},
{file = "cryptography-42.0.7-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:36017400817987670037fbb0324d71489b6ead6231c9604f8fc1f7d008087c68"}, {file = "cryptography-42.0.8-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:013629ae70b40af70c9a7a5db40abe5d9054e6f4380e50ce769947b73bf3caad"},
{file = "cryptography-42.0.7.tar.gz", hash = "sha256:ecbfbc00bf55888edda9868a4cf927205de8499e7fabe6c050322298382953f2"}, {file = "cryptography-42.0.8.tar.gz", hash = "sha256:8d09d05439ce7baa8e9e95b07ec5b6c886f548deb7e0f69ef25f64b3bce842f2"},
] ]
[package.dependencies] [package.dependencies]
@@ -1261,13 +1261,13 @@ tests = ["coverage", "coveralls", "dill", "mock", "nose"]
[[package]] [[package]]
name = "faker" name = "faker"
version = "25.3.0" version = "25.5.0"
description = "Faker is a Python package that generates fake data for you." description = "Faker is a Python package that generates fake data for you."
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
{file = "Faker-25.3.0-py3-none-any.whl", hash = "sha256:0158d47e955b6ec22134c0a74ebb7ed34fe600896208bafbf1008db831b17f04"}, {file = "Faker-25.5.0-py3-none-any.whl", hash = "sha256:edb85040a47ef1b30ccd8c4b6f07ee3cb4bd64aab1483be4efe75816ee2e2e36"},
{file = "Faker-25.3.0.tar.gz", hash = "sha256:bcbe31eee5ef4bbf87ce36c4eba53c01e2a1d912fde2a4d3528b430d2beb784f"}, {file = "Faker-25.5.0.tar.gz", hash = "sha256:84d454fc9fef0b73428e00bdf45a36c04568c75f22727e990071580840cfbb84"},
] ]
[package.dependencies] [package.dependencies]
@@ -2823,13 +2823,13 @@ ptyprocess = ">=0.5"
[[package]] [[package]]
name = "phonenumbers" name = "phonenumbers"
version = "8.13.37" version = "8.13.38"
description = "Python version of Google's common library for parsing, formatting, storing and validating international phone numbers." description = "Python version of Google's common library for parsing, formatting, storing and validating international phone numbers."
optional = false optional = false
python-versions = "*" python-versions = "*"
files = [ files = [
{file = "phonenumbers-8.13.37-py2.py3-none-any.whl", hash = "sha256:4ea00ef5012422c08c7955c21131e7ae5baa9a3ef52cf2d561e963f023006b80"}, {file = "phonenumbers-8.13.38-py2.py3-none-any.whl", hash = "sha256:d22aa747fb591ef2a18afec13cab5a0e294ab20fce5a1560e4949e459e70eeef"},
{file = "phonenumbers-8.13.37.tar.gz", hash = "sha256:bd315fed159aea0516f7c367231810fe8344d5bec26156b88fa18374c11d1cf2"}, {file = "phonenumbers-8.13.38.tar.gz", hash = "sha256:2822c74ee9334e9d8ad792fc352cc8d21004307349b6b1bb61da12937fa2eaba"},
] ]
[[package]] [[package]]
@@ -3296,13 +3296,13 @@ files = [
[[package]] [[package]]
name = "pytest" name = "pytest"
version = "8.2.1" version = "8.2.2"
description = "pytest: simple powerful testing with Python" description = "pytest: simple powerful testing with Python"
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
{file = "pytest-8.2.1-py3-none-any.whl", hash = "sha256:faccc5d332b8c3719f40283d0d44aa5cf101cec36f88cde9ed8f2bc0538612b1"}, {file = "pytest-8.2.2-py3-none-any.whl", hash = "sha256:c434598117762e2bd304e526244f67bf66bbd7b5d6cf22138be51ff661980343"},
{file = "pytest-8.2.1.tar.gz", hash = "sha256:5046e5b46d8e4cac199c373041f26be56fdb81eb4e67dc11d4e10811fc3408fd"}, {file = "pytest-8.2.2.tar.gz", hash = "sha256:de4bb8104e201939ccdc688b27a89a7be2079b22e2bd2b07f806b6ba71117977"},
] ]
[package.dependencies] [package.dependencies]
@@ -4748,4 +4748,4 @@ multidict = ">=4.0"
[metadata] [metadata]
lock-version = "2.0" lock-version = "2.0"
python-versions = "^3.12.2" python-versions = "^3.12.2"
content-hash = "992e87226ec344fcbe1cf74b813f1fca3e993efe727d9b688e31f459abdada2b" content-hash = "93b100659a8d3a34589593cc61e30b792d5f14371904c91fc2435cdcf04e479e"
+6 -6
View File
@@ -11,8 +11,8 @@ python = "^3.12.2"
alembic = "==1.13.1" alembic = "==1.13.1"
amqp = "==5.2.0" amqp = "==5.2.0"
beautifulsoup4 = "==4.12.3" beautifulsoup4 = "==4.12.3"
boto3 = "^1.34.116" boto3 = "^1.34.119"
botocore = "^1.34.117" botocore = "^1.34.120"
cachetools = "==5.3.3" cachetools = "==5.3.3"
celery = {version = "==5.4.0", extras = ["redis"]} celery = {version = "==5.4.0", extras = ["redis"]}
certifi = ">=2022.12.7" certifi = ">=2022.12.7"
@@ -48,14 +48,14 @@ pyjwt = "==2.8.0"
python-dotenv = "==1.0.1" python-dotenv = "==1.0.1"
sqlalchemy = "==2.0.30" sqlalchemy = "==2.0.30"
werkzeug = "^3.0.3" werkzeug = "^3.0.3"
faker = "^25.3.0" faker = "^25.5.0"
async-timeout = "^4.0.3" async-timeout = "^4.0.3"
bleach = "^6.1.0" bleach = "^6.1.0"
geojson = "^3.1.0" geojson = "^3.1.0"
govuk-bank-holidays = "^0.14" govuk-bank-holidays = "^0.14"
numpy = "^1.26.4" numpy = "^1.26.4"
ordered-set = "^4.1.0" ordered-set = "^4.1.0"
phonenumbers = "^8.13.36" phonenumbers = "^8.13.38"
python-json-logger = "^2.0.7" python-json-logger = "^2.0.7"
pytz = "^2024.1" pytz = "^2024.1"
regex = "^2024.5.15" regex = "^2024.5.15"
@@ -63,7 +63,7 @@ shapely = "^2.0.4"
smartypants = "^2.0.1" smartypants = "^2.0.1"
mistune = "0.8.4" mistune = "0.8.4"
blinker = "^1.8.2" blinker = "^1.8.2"
cryptography = "^42.0.7" cryptography = "^42.0.8"
idna = "^3.7" idna = "^3.7"
jmespath = "^1.0.1" jmespath = "^1.0.1"
markupsafe = "^2.1.5" markupsafe = "^2.1.5"
@@ -95,7 +95,7 @@ jinja2-cli = {version = "==0.8.2", extras = ["yaml"]}
moto = "==5.0.9" moto = "==5.0.9"
pip-audit = "*" pip-audit = "*"
pre-commit = "^3.7.1" pre-commit = "^3.7.1"
pytest = "^8.2.1" pytest = "^8.2.2"
pytest-env = "^1.1.3" pytest-env = "^1.1.3"
pytest-mock = "^3.14.0" pytest-mock = "^3.14.0"
pytest-cov = "^5.0.0" pytest-cov = "^5.0.0"
+4 -7
View File
@@ -3,35 +3,32 @@ locals {
cf_space_name = "notify-sandbox" cf_space_name = "notify-sandbox"
env = "sandbox" env = "sandbox"
app_name = "notify-api" app_name = "notify-api"
recursive_delete = true recursive_delete = true # deprecated, still used in shared modules
} }
module "database" { module "database" {
source = "github.com/18f/terraform-cloudgov//database?ref=v0.7.1" source = "github.com/GSA-TTS/terraform-cloudgov//database?ref=v1.0.0"
cf_org_name = local.cf_org_name cf_org_name = local.cf_org_name
cf_space_name = local.cf_space_name cf_space_name = local.cf_space_name
name = "${local.app_name}-rds-${local.env}" name = "${local.app_name}-rds-${local.env}"
recursive_delete = local.recursive_delete
rds_plan_name = "micro-psql" rds_plan_name = "micro-psql"
} }
module "redis" { module "redis" {
source = "github.com/18f/terraform-cloudgov//redis?ref=v0.9.1" source = "github.com/GSA-TTS/terraform-cloudgov//redis?ref=v1.0.0"
cf_org_name = local.cf_org_name cf_org_name = local.cf_org_name
cf_space_name = local.cf_space_name cf_space_name = local.cf_space_name
name = "${local.app_name}-redis-${local.env}" name = "${local.app_name}-redis-${local.env}"
recursive_delete = local.recursive_delete
redis_plan_name = "redis-dev" redis_plan_name = "redis-dev"
} }
module "csv_upload_bucket" { module "csv_upload_bucket" {
source = "github.com/18f/terraform-cloudgov//s3?ref=v0.9.1" source = "github.com/GSA-TTS/terraform-cloudgov//s3?ref=v1.0.0"
cf_org_name = local.cf_org_name cf_org_name = local.cf_org_name
cf_space_name = local.cf_space_name cf_space_name = local.cf_space_name
recursive_delete = local.recursive_delete
name = "${local.app_name}-csv-upload-bucket-${local.env}" name = "${local.app_name}-csv-upload-bucket-${local.env}"
} }
+5 -10
View File
@@ -159,16 +159,11 @@ def test_dao_update_service_sms_sender_switches_default(notify_db_session):
is_default=True, is_default=True,
sms_sender="updated", sms_sender="updated",
) )
sms_senders = ( sms_senders = ServiceSmsSender.query.filter_by(service_id=service.id).all()
ServiceSmsSender.query.filter_by(service_id=service.id)
.order_by(ServiceSmsSender.created_at) expected = {("testing", False), ("updated", True)}
.all() results = {(sender.sms_sender, sender.is_default) for sender in sms_senders}
) assert expected == results
assert len(sms_senders) == 2
assert sms_senders[0].sms_sender == "testing"
assert not sms_senders[0].is_default
assert sms_senders[1].sms_sender == "updated"
assert sms_senders[1].is_default
def test_dao_update_service_sms_sender_raises_exception_when_no_default_after_update( def test_dao_update_service_sms_sender_raises_exception_when_no_default_after_update(
+8
View File
@@ -13,6 +13,7 @@ from app.utils import (
get_reference_from_personalisation, get_reference_from_personalisation,
get_uuid_string_or_none, get_uuid_string_or_none,
midnight_n_days_ago, midnight_n_days_ago,
scrub,
) )
@@ -94,6 +95,13 @@ def test_get_public_notify_type_text():
) )
def test_scrub():
result = scrub(
"This is a message with 17775554324, and also 18884449323 and also 17775554324"
)
assert result == "This is a message with 1XXXXX54324, and also 1XXXXX49323 and also 1XXXXX54324"
# This method is used for simulating bulk sends. We use localstack and run on a developer's machine to do the # This method is used for simulating bulk sends. We use localstack and run on a developer's machine to do the
# simulation. Please see docs->bulk_testing.md for instructions. # simulation. Please see docs->bulk_testing.md for instructions.
# def test_generate_csv_for_bulk_testing(): # def test_generate_csv_for_bulk_testing():