From fb78e33547b7f77389aee20157f4f649c2ff1519 Mon Sep 17 00:00:00 2001 From: jcadam14 <41971533+jcadam14@users.noreply.github.com> Date: Tue, 24 Sep 2024 17:14:46 -0600 Subject: [PATCH] Added extension field with a max size of 254 (#421) Closes #420 - Added Alembic script to add the extension column to contact_info - Added extension field to the contact info DAO and DTO - Added pytests to test the two things above. - Field is optional --- ...8234fe9eb5_add_extension_to_contactinfo.py | 29 +++++ src/sbl_filing_api/entities/models/dao.py | 1 + src/sbl_filing_api/entities/models/dto.py | 1 + tests/api/routers/test_filing_api.py | 122 ++++++++++++++++++ tests/entities/repos/test_submission_repo.py | 4 + tests/migrations/test_migrations.py | 8 ++ 6 files changed, 165 insertions(+) create mode 100644 db_revisions/versions/ba8234fe9eb5_add_extension_to_contactinfo.py diff --git a/db_revisions/versions/ba8234fe9eb5_add_extension_to_contactinfo.py b/db_revisions/versions/ba8234fe9eb5_add_extension_to_contactinfo.py new file mode 100644 index 00000000..cec87f59 --- /dev/null +++ b/db_revisions/versions/ba8234fe9eb5_add_extension_to_contactinfo.py @@ -0,0 +1,29 @@ +"""add extension to contactinfo + +Revision ID: ba8234fe9eb5 +Revises: 7356a7d7036d +Create Date: 2024-09-24 12:26:46.755693 + +""" + +from typing import Sequence, Union + +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision: str = "ba8234fe9eb5" +down_revision: Union[str, None] = "7356a7d7036d" +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + with op.batch_alter_table("contact_info") as batch_op: + batch_op.add_column(sa.Column("phone_ext", sa.String(254), nullable=True)) + + +def downgrade() -> None: + with op.batch_alter_table("contact_info") as batch_op: + batch_op.drop_column("phone_ext") diff --git a/src/sbl_filing_api/entities/models/dao.py b/src/sbl_filing_api/entities/models/dao.py index 989f99a2..9dd6bf17 100644 --- a/src/sbl_filing_api/entities/models/dao.py +++ b/src/sbl_filing_api/entities/models/dao.py @@ -90,6 +90,7 @@ class ContactInfoDAO(Base): hq_address_zip: Mapped[str] = mapped_column(String(5)) email: Mapped[str] phone_number: Mapped[str] + phone_ext: Mapped[str] = mapped_column(String(254), nullable=True) def __str__(self): return f"ContactInfo ID: {self.id}, First Name: {self.first_name}, Last Name: {self.last_name}, Address Street 1: {self.hq_address_street_1}, Address Street 2: {self.hq_address_street_2}, Address City: {self.hq_address_city}, Address State: {self.hq_address_state}, Address Zip: {self.hq_address_zip}" diff --git a/src/sbl_filing_api/entities/models/dto.py b/src/sbl_filing_api/entities/models/dto.py index 2e0f805a..c40c29fb 100644 --- a/src/sbl_filing_api/entities/models/dto.py +++ b/src/sbl_filing_api/entities/models/dto.py @@ -60,6 +60,7 @@ class ContactInfoDTO(BaseModel): hq_address_zip: str email: str phone_number: str + phone_ext: str | None = Field(None, max_length=254) @model_validator(mode="after") def validate_fi(self) -> "ContactInfoDTO": diff --git a/tests/api/routers/test_filing_api.py b/tests/api/routers/test_filing_api.py index c99871fe..d76a7d41 100644 --- a/tests/api/routers/test_filing_api.py +++ b/tests/api/routers/test_filing_api.py @@ -674,6 +674,7 @@ def test_put_contact_info( hq_address_state="TS", hq_address_zip="12345", phone_number="112-345-6789", + phone_ext="x54321", email="name_1@email.test", ), creator_id=1, @@ -700,6 +701,7 @@ def test_put_contact_info( "hq_address_zip": "12345", "phone_number": "112-345-6789", "email": "name_1@email.test", + "phone_ext": "x54321", } res = client.put( @@ -722,6 +724,7 @@ def test_put_contact_info( assert result["contact_info"]["hq_address_state"] == "TS" assert result["contact_info"]["hq_address_zip"] == "12345" assert result["contact_info"]["phone_number"] == "112-345-6789" + assert result["contact_info"]["phone_ext"] == "x54321" assert result["contact_info"]["email"] == "name_1@email.test" mock.assert_called_with( @@ -739,9 +742,128 @@ def test_put_contact_info( hq_address_zip="12345", email="name_1@email.test", phone_number="112-345-6789", + phone_ext="x54321", ), ) + def test_no_extension( + self, mocker: MockerFixture, app_fixture: FastAPI, authed_user_mock: Mock, get_filing_mock: Mock + ): + get_filing_mock.return_value + + mock = mocker.patch("sbl_filing_api.entities.repos.submission_repo.update_contact_info") + mock.return_value = FilingDAO( + id=1, + lei="1234567890ZXWVUTSR00", + institution_snapshot_id="Snapshot-1", + filing_period="2024", + contact_info=ContactInfoDAO( + id=1, + filing=1, + first_name="test_first_name_1", + last_name="test_last_name_1", + hq_address_street_1="address street 1", + hq_address_street_2="", + hq_address_city="Test City 1", + hq_address_state="TS", + hq_address_zip="12345", + phone_number="112-345-6789", + email="name_1@email.test", + ), + creator_id=1, + creator=UserActionDAO( + id=1, + user_id="123456-7890-ABCDEF-GHIJ", + user_name="test creator", + user_email="test@local.host", + action_type=UserActionType.CREATE, + timestamp=datetime.datetime.now(), + ), + ) + + client = TestClient(app_fixture) + contact_info_json = { + "id": 1, + "filing": 1, + "first_name": "test_first_name_1", + "last_name": "test_last_name_1", + "hq_address_street_1": "address street 1", + "hq_address_street_2": "", + "hq_address_city": "Test City 1", + "hq_address_state": "TS", + "hq_address_zip": "12345", + "phone_number": "112-345-6789", + "email": "name_1@email.test", + } + + res = client.put( + "/v1/filing/institutions/1234567890ZXWVUTSR00/filings/2024/contact-info", json=contact_info_json + ) + + assert res.status_code == 200 + + result = res.json() + assert result["id"] == 1 + assert result["lei"] == "1234567890ZXWVUTSR00" + assert result["institution_snapshot_id"] == "Snapshot-1" + assert result["filing_period"] == "2024" + assert result["contact_info"]["id"] == 1 + assert result["contact_info"]["first_name"] == "test_first_name_1" + assert result["contact_info"]["last_name"] == "test_last_name_1" + assert result["contact_info"]["hq_address_street_1"] == "address street 1" + assert result["contact_info"]["hq_address_street_2"] == "" + assert result["contact_info"]["hq_address_city"] == "Test City 1" + assert result["contact_info"]["hq_address_state"] == "TS" + assert result["contact_info"]["hq_address_zip"] == "12345" + assert result["contact_info"]["phone_number"] == "112-345-6789" + assert result["contact_info"]["email"] == "name_1@email.test" + + mock.assert_called_with( + ANY, + "1234567890ZXWVUTSR00", + "2024", + ContactInfoDTO( + id=1, + first_name="test_first_name_1", + last_name="test_last_name_1", + hq_address_street_1="address street 1", + hq_address_street_2="", + hq_address_city="Test City 1", + hq_address_state="TS", + hq_address_zip="12345", + email="name_1@email.test", + phone_number="112-345-6789", + ), + ) + + def test_bad_extension( + self, mocker: MockerFixture, app_fixture: FastAPI, authed_user_mock: Mock, get_filing_mock: Mock + ): + + client = TestClient(app_fixture) + contact_info_json = { + "id": 1, + "filing": 1, + "first_name": "test_first_name_1", + "last_name": "test_last_name_1", + "hq_address_street_1": "address street 1", + "hq_address_street_2": "", + "hq_address_city": "Test City 1", + "hq_address_state": "TS", + "hq_address_zip": "12345", + "phone_number": "112-345-6789", + "phone_ext": "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", + "email": "name_1@email.test", + } + + res = client.put( + "/v1/filing/institutions/1234567890ZXWVUTSR00/filings/2024/contact-info", json=contact_info_json + ) + + assert res.status_code == 422 + json_error = res.json() + assert "'String should have at most 254 characters'" in json_error["error_detail"] + async def test_accept_submission(self, mocker: MockerFixture, app_fixture: FastAPI, authed_user_mock: Mock): user_action_submit = UserActionDAO( id=2, diff --git a/tests/entities/repos/test_submission_repo.py b/tests/entities/repos/test_submission_repo.py index ae1587b8..0a76394b 100644 --- a/tests/entities/repos/test_submission_repo.py +++ b/tests/entities/repos/test_submission_repo.py @@ -194,6 +194,7 @@ async def setup( hq_address_state="TS", hq_address_zip="12345", phone_number="212-345-6789", + phone_ext="x54321", email="test2@cfpb.gov", ) transaction_session.add(contact_info1) @@ -483,6 +484,7 @@ async def test_get_contact_info(self, query_session: AsyncSession): assert res.contact_info.hq_address_state == "TS" assert res.contact_info.hq_address_zip == "12345" assert res.contact_info.phone_number == "212-345-6789" + assert res.contact_info.phone_ext == "x54321" assert res.contact_info.email == "test2@cfpb.gov" async def test_create_contact_info(self, transaction_session: AsyncSession): @@ -538,6 +540,7 @@ async def test_update_contact_info(self, transaction_session: AsyncSession): hq_address_state="TS", hq_address_zip="12345", phone_number="212-345-6789", + phone_ext="x12345", email="test2_upd@cfpb.gov", ), ) @@ -555,6 +558,7 @@ async def test_update_contact_info(self, transaction_session: AsyncSession): assert filing.contact_info.hq_address_state == "TS" assert filing.contact_info.hq_address_zip == "12345" assert filing.contact_info.phone_number == "212-345-6789" + assert filing.contact_info.phone_ext == "x12345" assert filing.contact_info.email == "test2_upd@cfpb.gov" async def test_get_user_action(self, query_session: AsyncSession): diff --git a/tests/migrations/test_migrations.py b/tests/migrations/test_migrations.py index 77b586f5..657a9890 100644 --- a/tests/migrations/test_migrations.py +++ b/tests/migrations/test_migrations.py @@ -389,3 +389,11 @@ def test_migrations_to_7356a7d7036d(alembic_runner: MigrationContext, alembic_en inspector = sqlalchemy.inspect(alembic_engine) assert "total_records" in set([c["name"] for c in inspector.get_columns("submission")]) + + +def test_migrations_to_ba8234fe9eb5(alembic_runner: MigrationContext, alembic_engine: Engine): + alembic_runner.migrate_up_to("ba8234fe9eb5") + + inspector = sqlalchemy.inspect(alembic_engine) + + assert "phone_ext" in set([c["name"] for c in inspector.get_columns("contact_info")])