diff --git a/app/celery/tasks.py b/app/celery/tasks.py index dfb0c2c9f..69cce3e56 100644 --- a/app/celery/tasks.py +++ b/app/celery/tasks.py @@ -1,3 +1,4 @@ +import itertools from datetime import datetime from flask import current_app @@ -12,7 +13,8 @@ from utils.template import Template from utils.recipients import ( RecipientCSV, - validate_and_format_phone_number + validate_and_format_phone_number, + allowed_to_send_to ) from app import ( @@ -195,9 +197,16 @@ def remove_job(job_id): def send_sms(service_id, notification_id, encrypted_notification, created_at): notification = encryption.decrypt(encrypted_notification) service = dao_fetch_service_by_id(service_id) - client = firetext_client + restricted = False + + if not service_allowed_to_send_to(notification['to'], service): + current_app.logger.info( + "SMS {} failed as restricted service".format(notification_id) + ) + restricted = True + try: sent_at = datetime.utcnow() notification_db_object = Notification( @@ -206,7 +215,7 @@ def send_sms(service_id, notification_id, encrypted_notification, created_at): to=notification['to'], service_id=service_id, job_id=notification.get('job', None), - status='sent', + status='failed' if restricted else 'sent', created_at=datetime.strptime(created_at, DATETIME_FORMAT), sent_at=sent_at, sent_by=client.get_name() @@ -214,6 +223,9 @@ def send_sms(service_id, notification_id, encrypted_notification, created_at): dao_create_notification(notification_db_object, TEMPLATE_TYPE_SMS) + if restricted: + return + try: template = Template( dao_get_template_by_id(notification['template']).__dict__, @@ -245,6 +257,15 @@ def send_sms(service_id, notification_id, encrypted_notification, created_at): def send_email(service_id, notification_id, subject, from_address, encrypted_notification, created_at): notification = encryption.decrypt(encrypted_notification) client = aws_ses_client + service = dao_fetch_service_by_id(service_id) + + restricted = False + + if not service_allowed_to_send_to(notification['to'], service): + current_app.logger.info( + "Email {} failed as restricted service".format(notification_id) + ) + restricted = True try: sent_at = datetime.utcnow() @@ -254,13 +275,16 @@ def send_email(service_id, notification_id, subject, from_address, encrypted_not to=notification['to'], service_id=service_id, job_id=notification.get('job', None), - status='sent', + status='failed' if restricted else 'sent', created_at=datetime.strptime(created_at, DATETIME_FORMAT), sent_at=sent_at, sent_by=client.get_name() ) dao_create_notification(notification_db_object, TEMPLATE_TYPE_EMAIL) + if restricted: + return + try: template = Template( dao_get_template_by_id(notification['template']).__dict__, @@ -395,3 +419,16 @@ def email_registration_verification(encrypted_verification_message): url=verification_message['url'])) except AwsSesClientException as e: current_app.logger.exception(e) + + +def service_allowed_to_send_to(recipient, service): + + if not service.restricted: + return True + + return allowed_to_send_to( + recipient, + itertools.chain.from_iterable( + [user.mobile_number, user.email_address] for user in service.users + ) + ) diff --git a/tests/app/celery/test_tasks.py b/tests/app/celery/test_tasks.py index 3996ef1cc..51f3c6242 100644 --- a/tests/app/celery/test_tasks.py +++ b/tests/app/celery/test_tasks.py @@ -359,6 +359,31 @@ def test_should_send_sms_if_restricted_service_and_valid_number(notify_db, notif ) +def test_should_not_send_sms_if_restricted_service_and_invalid_number(notify_db, notify_db_session, mocker): + user = sample_user(notify_db, notify_db_session, mobile_numnber="07700 900205") + service = sample_service(notify_db, notify_db_session, user=user, restricted=True) + template = sample_template(notify_db, notify_db_session, service=service) + + notification = { + "template": template.id, + "to": "07700 900849" + } + mocker.patch('app.encryption.decrypt', return_value=notification) + mocker.patch('app.firetext_client.send_sms') + mocker.patch('app.firetext_client.get_name', return_value="firetext") + + notification_id = uuid.uuid4() + now = datetime.utcnow() + send_sms( + service.id, + notification_id, + "encrypted-in-reality", + now.strftime(DATETIME_FORMAT) + ) + + firetext_client.send_sms.assert_not_called() + + def test_should_send_email_if_restricted_service_and_valid_email(notify_db, notify_db_session, mocker): user = sample_user(notify_db, notify_db_session, email="test@restricted.com") service = sample_service(notify_db, notify_db_session, user=user, restricted=True) @@ -391,6 +416,32 @@ def test_should_send_email_if_restricted_service_and_valid_email(notify_db, noti ) +def test_should_not_send_email_if_restricted_service_and_invalid_email_address(notify_db, notify_db_session, mocker): + user = sample_user(notify_db, notify_db_session) + service = sample_service(notify_db, notify_db_session, user=user, restricted=True) + template = sample_template( + notify_db, notify_db_session, service=service, template_type='email', subject_line='Hello' + ) + + notification = { + "template": template.id, + "to": "test@example.com" + } + mocker.patch('app.encryption.decrypt', return_value=notification) + mocker.patch('app.aws_ses_client.send_email') + + notification_id = uuid.uuid4() + now = datetime.utcnow() + send_sms( + service.id, + notification_id, + "encrypted-in-reality", + now.strftime(DATETIME_FORMAT) + ) + + aws_ses_client.send_email.assert_not_called() + + def test_should_send_template_to_correct_sms_provider_and_persist_with_job_id(sample_job, mocker): notification = { "template": sample_job.template.id,