From a16f2ac18fdcd5f32eb277a84f610bf50c3d824f Mon Sep 17 00:00:00 2001 From: srh-sloan Date: Mon, 2 Dec 2024 13:42:09 +0000 Subject: [PATCH] Fspt 111 single template ids (#296) * Adding new template IDs * Integration test for new template * Adding additional personalisation parameters * updating content for incomplete application notification * Fixing logging --------- Co-authored-by: srh-sloan --- app/notification/application/map_contents.py | 2 + app/notification/model/notification.py | 5 +- app/notification/model/notifier.py | 40 ++++++----- config/envs/default.py | 74 +++----------------- config/envs/unit_test.py | 1 + pytest.ini | 5 +- tests/test_application/test_application.py | 5 +- tests/test_integration.py | 61 ++++++++++++++++ 8 files changed, 106 insertions(+), 87 deletions(-) create mode 100644 tests/test_integration.py diff --git a/app/notification/application/map_contents.py b/app/notification/application/map_contents.py index 084b6033..cc71dff0 100644 --- a/app/notification/application/map_contents.py +++ b/app/notification/application/map_contents.py @@ -25,6 +25,7 @@ class Application(_NotificationContents): submission_date: str = None caveats: str = None language: str = None + prospectus_url: str = None @property def format_submission_date(self): @@ -65,4 +66,5 @@ def from_notification(cls, notification: Notification): notification.content.get(NotifyConstants.MAGIC_LINK_CONTACT_HELP_EMAIL_FIELD) ], caveats=caveats, + prospectus_url=application_data.get("prospectus_url", ""), ) diff --git a/app/notification/model/notification.py b/app/notification/model/notification.py index 5f976275..9156c8e8 100644 --- a/app/notification/model/notification.py +++ b/app/notification/model/notification.py @@ -93,5 +93,8 @@ def email_recipient(json_data: dict): return template_type_error(json_data) except Exception as e: - current_app.logger.error("An exception occurred while selecting email template to send", e) + current_app.logger.error( + "An exception occurred while selecting email template to send: {error_msg}", + extra=dict(error_msg=str(e)), + ) raise Exception("An error occurred while selecting email template to send") from e diff --git a/app/notification/model/notifier.py b/app/notification/model/notifier.py index 03d29afb..2ecd3b90 100644 --- a/app/notification/model/notifier.py +++ b/app/notification/model/notifier.py @@ -3,6 +3,7 @@ from typing import TYPE_CHECKING from flask import current_app +from fsd_utils.config.notify_constants import NotifyConstants from notifications_python_client import NotificationsAPIClient from notifications_python_client import errors @@ -53,7 +54,7 @@ def send_magic_link(notification: Notification, code: int = 200) -> tuple: return invalid_data_error(MagicLink.from_notification(notification)) @staticmethod - def send_submitted_application(notification: Notification, code: int = 200) -> tuple: + def send_submitted_application(notification: Notification) -> tuple: """Function makes a call to govuk-notify-service with mapped contents that are expected by the govuk-notify-service template. @@ -62,16 +63,20 @@ def send_submitted_application(notification: Notification, code: int = 200) -> t Raises HTTPError if any of the required contents are incorrect or missing. """ + try: notifications_client = NotificationsAPIClient(Config.GOV_NOTIFY_API_KEY) contents = Application.from_notification(notification) - response = notifications_client.send_email_notification( - email_address=contents.contact_info, - template_id=Config.APPLICATION_RECORD_TEMPLATE_ID[contents.fund_id]["template_id"].get( - contents.language, "en" - ), - email_reply_to_id=contents.reply_to_email_id, - personalisation={ + template_id = ( + Config.APPLICATION_SUBMISSION_TEMPLATE_ID_CY + if contents.language == "cy" + else Config.APPLICATION_SUBMISSION_TEMPLATE_ID_EN + ) + notify_payload = { + "email_address": contents.contact_info, + "template_id": template_id, + "email_reply_to_id": contents.reply_to_email_id, + "personalisation": { "name of fund": contents.fund_name, "application reference": contents.reference, "date submitted": contents.format_submission_date, @@ -82,13 +87,15 @@ def send_submitted_application(notification: Notification, code: int = 200) -> t "confirm_email_before_download": None, "retention_period": None, }, + "URL of prospectus": contents.prospectus_url, + "contact email": notification.content.get(NotifyConstants.MAGIC_LINK_CONTACT_HELP_EMAIL_FIELD), }, - ) - current_app.logger.info("Call made to govuk Notify API") - return response, code + } + response = notifications_client.send_email_notification(**notify_payload) + return response, 200 - except errors.HTTPError: - current_app.logger.exception("HTTPError while sending notification") + except errors.HTTPError as e: + current_app.logger.error("HTTPError while sending notification: {error}", extra=dict(error=str(e))) return invalid_data_error(Application.from_notification(notification)) @staticmethod @@ -146,13 +153,12 @@ def send_incomplete_application(notification: Notification, code: int = 200) -> notifications_client = NotificationsAPIClient(Config.GOV_NOTIFY_API_KEY) contents = Application.from_notification(notification) current_app.logger.info( - f"Getting template for fund id [{contents.fund_id}] " - f"and template id {Config.INCOMPLETE_APPLICATION_TEMPLATE_ID[contents.fund_id]['template_id']}" + "Sending incomplete application email for {app_ref}", extra=dict(app_ref=contents.reference) ) response = notifications_client.send_email_notification( email_address=contents.contact_info, email_reply_to_id=contents.reply_to_email_id, - template_id=Config.INCOMPLETE_APPLICATION_TEMPLATE_ID[contents.fund_id]["template_id"], + template_id=Config.APPLICATION_INCOMPLETE_TEMPLATE_ID, personalisation={ "name of fund": contents.fund_name, "application reference": contents.reference, @@ -163,9 +169,9 @@ def send_incomplete_application(notification: Notification, code: int = 200) -> "confirm_email_before_download": None, "retention_period": None, }, + "contact email": notification.content.get(NotifyConstants.MAGIC_LINK_CONTACT_HELP_EMAIL_FIELD), }, ) - current_app.logger.info("Call made to govuk Notify API") return response, code except errors.HTTPError: diff --git a/config/envs/default.py b/config/envs/default.py index 51bb0052..cccd9ba9 100644 --- a/config/envs/default.py +++ b/config/envs/default.py @@ -55,72 +55,16 @@ class DefaultConfig: }, } - APPLICATION_RECORD_TEMPLATE_ID = { - "47aef2f5-3fcb-4d45-acb5-f0152b5f03c4": { - "fund_name": "COF", - "template_id": { - "en": "0ddadcb3-ebe7-44f9-90e6-80ff3b61e0cb", - "cy": "8ffc87bc-16d8-4273-82bf-c06bdf0cf047", - }, - }, - "604450fe-65c0-4a2e-a4ba-30ccf256056b": { - "fund_name": "COF25", - "template_id": { - "en": "6441da8a-1a42-4fe1-ad05-b7fb5f46a761", - "cy": "129490b8-4e35-4dc2-a8fb-bfd3be9e90d0", - }, - }, - "3dcfa617-cff8-4c2c-9edd-9568aa367d13": { - "fund_name": "CTDF", - "template_id": { - "en": "6441da8a-1a42-4fe1-ad05-b7fb5f46a761", - "cy": "129490b8-4e35-4dc2-a8fb-bfd3be9e90d0", - }, - }, - "13b95669-ed98-4840-8652-d6b7a19964db": { - "fund_name": "NSTF", - "template_id": {"en": "487c62f1-9aeb-4cc2-b996-5bdf0d02854b", "cy": "487c62f1-9aeb-4cc2-b996-5bdf0d02854b"}, - }, - "1baa0f68-4e0a-4b02-9dfe-b5646f089e65": { - "fund_name": "CYP", - "template_id": {"en": "1c69f104-edfa-49d7-9bab-cbbd30c323f3", "cy": "1c69f104-edfa-49d7-9bab-cbbd30c323f3"}, - }, - "f493d512-5eb4-11ee-8c99-0242ac120002": { - "fund_name": "DPI", - "template_id": {"en": "6e1d80ac-c843-4b47-9946-ecad542dd5de", "cy": "6e1d80ac-c843-4b47-9946-ecad542dd5de"}, - }, - "1e4bd8b0-b399-466d-bbd1-572171bbc7bd": { - "fund_name": "HSRA", - "template_id": {"en": "52decdde-e796-4b16-a1a0-5f56c9a61b0f", "cy": "52decdde-e796-4b16-a1a0-5f56c9a61b0f"}, - }, - } + APPLICATION_SUBMISSION_TEMPLATE_ID_EN = os.environ.get( + "APPLICATION_SUBMISSION_TEMPLATE_ID_EN", "6adbba70-2fde-4ca7-94cb-7f7eb264efaa" + ) + APPLICATION_SUBMISSION_TEMPLATE_ID_CY = os.environ.get( + "APPLICATION_SUBMISSION_TEMPLATE_ID_CY", "6adbba70-2fde-4ca7-94cb-7f7eb264efaa" + ) # TODO update once translation received - INCOMPLETE_APPLICATION_TEMPLATE_ID = { - "47aef2f5-3fcb-4d45-acb5-f0152b5f03c4": { - "fund_name": "COF", - "template_id": "fc8cff7c-a595-4590-a1a4-eccda48d8604", - }, - "604450fe-65c0-4a2e-a4ba-30ccf256056b": { - "fund_name": "COF25", - "template_id": "98ad5284-b3eb-4520-b367-3fbc56b36c16", - }, - "13b95669-ed98-4840-8652-d6b7a19964db": { - "fund_name": "NSTF", - "template_id": "d4c9cb6f-c36d-4157-a5e4-0b7bc323e332", - }, - "1baa0f68-4e0a-4b02-9dfe-b5646f089e65": { - "fund_name": "CYP", - "template_id": "5e308d1e-4d1d-4572-9c99-9a8396224aed", - }, - "f493d512-5eb4-11ee-8c99-0242ac120002": { - "fund_name": "DPI", - "template_id": "7980eee3-5a40-42b8-98dc-ba3b11ea4e65", - }, - "1e4bd8b0-b399-466d-bbd1-572171bbc7bd": { - "fund_name": "HSRA", - "template_id": "b577de1a-7242-4f9b-b823-6d4f50ad5f19", - }, - } + APPLICATION_INCOMPLETE_TEMPLATE_ID = os.environ.get( + "APPLICATION_INCOMPLETE_TEMPLATE_ID", "944cb37d-c9e0-4731-88f5-d752514da57f" + ) APPLICATION_DEADLINE_REMINDER_TEMPLATE_ID = os.environ.get( "APPLICATION_DEADLINE_REMINDER_TEMPLATE_ID", diff --git a/config/envs/unit_test.py b/config/envs/unit_test.py index c35ad9fe..04803497 100644 --- a/config/envs/unit_test.py +++ b/config/envs/unit_test.py @@ -15,6 +15,7 @@ class UnitTestConfig(DefaultConfig): FSD_LOG_LEVEL = logging.DEBUG REPLY_TO_EMAILS_WITH_NOTIFY_ID = { + "FundingService@communities.gov.uk": "10668b8d-9472-4ce8-ae07-4fcc7bf93a9d", "nope@wrong.gov.uk": "100", "COF@communities.gov.uk": "10668b8d-9472-4ce8-ae07-4fcc7bf93a9d", "transformationfund@levellingup.gov.uk": ("25286d9a-8543-41b5-a00f-331b999e51f0"), diff --git a/pytest.ini b/pytest.ini index a11c5775..86b37ca3 100644 --- a/pytest.ini +++ b/pytest.ini @@ -3,7 +3,8 @@ env = FLASK_ENV=unit_test FLASK_DEBUG=1 AWS_REGION=eu-west-2 - # To make the unit tests work, add the following env var with an appropriate value: - # GOV_NOTIFY_API_KEY=xxxx + # To make the integration tests work, add the following env var with an appropriate value: + GOV_NOTIFY_API_KEY= + # Without this set in the env you may see the following error: # - Missing Service ID diff --git a/tests/test_application/test_application.py b/tests/test_application/test_application.py index f304adac..45393d0c 100644 --- a/tests/test_application/test_application.py +++ b/tests/test_application/test_application.py @@ -6,6 +6,7 @@ from app.notification.application_reminder.map_contents import ApplicationReminder from app.notification.model.notification import Notification from app.notification.model.notifier import Notifier +from config import Config from examplar_data.application_data import expected_application_reminder_json from examplar_data.application_data import notification_class_data_for_application from examplar_data.application_data import notification_class_data_for_cof_application @@ -113,8 +114,8 @@ def test_send_submitted_application( @pytest.mark.parametrize( "mock_notifications_api_client, language, template_id", [ - (2, "en", "0ddadcb3-ebe7-44f9-90e6-80ff3b61e0cb"), - (2, "cy", "8ffc87bc-16d8-4273-82bf-c06bdf0cf047"), + (2, "en", Config.APPLICATION_SUBMISSION_TEMPLATE_ID_EN), + (2, "cy", Config.APPLICATION_SUBMISSION_TEMPLATE_ID_CY), ], indirect=["mock_notifications_api_client"], ) diff --git a/tests/test_integration.py b/tests/test_integration.py new file mode 100644 index 00000000..2962c7be --- /dev/null +++ b/tests/test_integration.py @@ -0,0 +1,61 @@ +import pytest +from fsd_utils.config.notify_constants import NotifyConstants + +from app.notification.model.notification import Notification + + +@pytest.mark.skip(reason="Integration test") +@pytest.mark.parametrize( + "template_type,data_to_send", + [ + ( + NotifyConstants.TEMPLATE_TYPE_APPLICATION, + { + "to": "submitted@unittest.com", + "full_name": "unit test", + "content": { + NotifyConstants.APPLICATION_FIELD: { + "fund_name": "unit test fund", + "round_name": "unit test round", + "questions_file": "dGhpcyBpcyBhIHRlc3Q=", + "date_submitted": "2024-11-26T11:23:03.000", + "fund_id": "asdf-wer-234-asdf", + "reference": "TEST-ABC", + "language": "en", + "prospectus_url": "https://google.com", + }, + NotifyConstants.MAGIC_LINK_CONTACT_HELP_EMAIL_FIELD: "FundingService@communities.gov.uk", + }, + }, + ), + ( + NotifyConstants.TEMPLATE_TYPE_INCOMPLETE_APPLICATION, + { + "to": "incomplete@unittest.com", + "full_name": "unit test", + "content": { + NotifyConstants.APPLICATION_FIELD: { + "fund_name": "unit test fund", + "round_name": "unit test round", + "questions_file": "dGhpcyBpcyBhIHRlc3Q=", + "date_submitted": "2024-11-26T11:23:03.000", + "fund_id": "asdf-wer-234-asdf", + "reference": "TEST-ABC", + "language": "en", + "prospectus_url": "https://google.com", + }, + NotifyConstants.MAGIC_LINK_CONTACT_HELP_EMAIL_FIELD: "FundingService@communities.gov.uk", + }, + }, + ), + ], +) +def test_send_real_notification(flask_test_client, template_type, data_to_send): + """ + This is an integration test that hits the real notify service. + To make this work, unskip it and add the notify API key to pytest.ini + """ + with flask_test_client.app.app.test_request_context(): + data_to_send["type"] = template_type + _, code = Notification.email_recipient(json_data=data_to_send) + assert code == 200