From d4cc6388e0134261a8b9e95a835399a9c8640b02 Mon Sep 17 00:00:00 2001 From: guffee23 Date: Tue, 26 Nov 2024 16:27:49 -0600 Subject: [PATCH] 495 sign confirm email (#510) Closes #495 --- src/sbl_filing_api/routers/filing.py | 10 ++++-- .../services/request_handler.py | 31 +++++++++++++++++++ tests/api/routers/test_filing_api.py | 8 +++++ tests/services/test_request_handler.py | 31 +++++++++++++++++++ 4 files changed, 77 insertions(+), 3 deletions(-) create mode 100644 src/sbl_filing_api/services/request_handler.py create mode 100644 tests/services/test_request_handler.py diff --git a/src/sbl_filing_api/routers/filing.py b/src/sbl_filing_api/routers/filing.py index f0c83d7d..f7c44263 100644 --- a/src/sbl_filing_api/routers/filing.py +++ b/src/sbl_filing_api/routers/filing.py @@ -37,6 +37,8 @@ from regtech_api_commons.api.dependencies import verify_user_lei_relation +from src.sbl_filing_api.services.request_handler import send_confirmation_email + logger = logging.getLogger(__name__) @@ -165,10 +167,12 @@ async def sign_filing(request: Request, lei: str, period_code: str): action_type=UserActionType.SIGN, ), ) - filing.confirmation_id = ( - lei + "-" + period_code + "-" + str(latest_sub.counter) + "-" + str(int(sig.timestamp.timestamp())) - ) + sig_timestamp = int(sig.timestamp.timestamp()) + filing.confirmation_id = lei + "-" + period_code + "-" + str(latest_sub.counter) + "-" + str(sig_timestamp) filing.signatures.append(sig) + send_confirmation_email( + request.user.name, request.user.email, filing.contact_info.email, filing.confirmation_id, sig_timestamp + ) return await repo.upsert_filing(request.state.db_session, filing) diff --git a/src/sbl_filing_api/services/request_handler.py b/src/sbl_filing_api/services/request_handler.py new file mode 100644 index 00000000..8a56ebd9 --- /dev/null +++ b/src/sbl_filing_api/services/request_handler.py @@ -0,0 +1,31 @@ +import logging + +import httpx +from pydantic import EmailStr +from sbl_filing_api.config import settings + +logger = logging.getLogger(__name__) + + +def send_confirmation_email( + user_full_name: str, + user_email: EmailStr, + contact_info_email: EmailStr, + confirmation_id: str, + timestamp: int, +): + confirmation_request = { + "confirmation_id": confirmation_id, + "signer_email": user_email, + "signer_name": user_full_name, + "contact_email": contact_info_email, + "timestamp": timestamp, + } + try: + res = httpx.post(settings.mail_api_url, json=confirmation_request) + if res.status_code != 200: + logger.error(res.text) + else: + logger.info(res.text) + except Exception: + logger.exception(f"Failed to send confirmation email for {user_full_name}") diff --git a/tests/api/routers/test_filing_api.py b/tests/api/routers/test_filing_api.py index e4426505..73a2a90e 100644 --- a/tests/api/routers/test_filing_api.py +++ b/tests/api/routers/test_filing_api.py @@ -1027,6 +1027,9 @@ async def test_good_sign_filing( action_type=UserActionType.SIGN, ) + send_email_mock = mocker.patch("sbl_filing_api.routers.filing.send_confirmation_email") + send_email_mock.return_value = None + upsert_mock = mocker.patch("sbl_filing_api.entities.repos.submission_repo.upsert_filing") updated_filing_obj = deepcopy(get_filing_mock.return_value) upsert_mock.return_value = updated_filing_obj @@ -1042,6 +1045,9 @@ async def test_good_sign_filing( action_type=UserActionType.SIGN, ), ) + send_email_mock.assert_called_with("Test User", "test@local.host", "test1@cfpb.gov", ANY, ANY) + assert send_email_mock.call_args.args[3].startswith("1234567890ABCDEFGH00-2024-5-") + assert float(send_email_mock.call_args.args[4]) == pytest.approx(int(dt.now().timestamp()), abs=1.5) assert upsert_mock.call_args.args[1].confirmation_id.startswith("1234567890ABCDEFGH00-2024-5-") assert res.status_code == 200 assert float(upsert_mock.call_args.args[1].confirmation_id.split("-")[3]) == pytest.approx( @@ -1052,6 +1058,8 @@ async def test_errors_sign_filing( self, mocker: MockerFixture, app_fixture: FastAPI, authed_user_mock: Mock, get_filing_mock: Mock ): sub_mock = mocker.patch("sbl_filing_api.entities.repos.submission_repo.get_latest_submission") + send_email_mock = mocker.patch("sbl_filing_api.services.request_handler.send_confirmation_email") + send_email_mock.return_value = None sub_mock.return_value = SubmissionDAO( id=1, submitter=UserActionDAO( diff --git a/tests/services/test_request_handler.py b/tests/services/test_request_handler.py new file mode 100644 index 00000000..14ce6020 --- /dev/null +++ b/tests/services/test_request_handler.py @@ -0,0 +1,31 @@ +from unittest.mock import ANY +from pytest_mock import MockerFixture +from sbl_filing_api.services.request_handler import send_confirmation_email + + +def test_send_confirmation_email(mocker: MockerFixture, caplog): + # No errors + post_mock = mocker.patch("sbl_filing_api.services.request_handler.httpx.post") + post_mock.return_value.status_code = 200 + send_confirmation_email("full_name", "user@email.com", "contact@info.com", "confirmation", 12345) + post_mock.assert_called_with( + ANY, + json={ + "confirmation_id": "confirmation", + "contact_email": "contact@info.com", + "signer_email": "user@email.com", + "signer_name": "full_name", + "timestamp": 12345, + }, + ) + + # With errors + post_mock.side_effect = None + post_mock.return_value.status_code = 400 + post_mock.return_value.text = "Email_response" + send_confirmation_email("full_name", "user@email.com", "contact@info.com", "confirmation", 12345) + assert "Email_response" in caplog.messages[0] + + post_mock.side_effect = IOError("test") + send_confirmation_email("full_name", "user@email.com", "contact@info.com", "confirmation", 12345) + assert "Failed to send confirmation email for full_name" in caplog.messages[1]