diff --git a/db_revisions/versions/ef815604e2a9_user_action_add_filing_submission_fks.py b/db_revisions/versions/ef815604e2a9_user_action_add_filing_submission_fks.py new file mode 100644 index 00000000..5e0408ad --- /dev/null +++ b/db_revisions/versions/ef815604e2a9_user_action_add_filing_submission_fks.py @@ -0,0 +1,116 @@ +"""user_action add filing submission fks + +Revision ID: ef815604e2a9 +Revises: 6ec12afa5b37 +Create Date: 2025-01-24 10:15:32.975738 + +""" + +from typing import Sequence, Union + +from alembic import op +import sqlalchemy as sa + +from sbl_filing_api.entities.models.model_enums import UserActionType + +# revision identifiers, used by Alembic. +revision: str = "ef815604e2a9" +down_revision: Union[str, None] = "6ec12afa5b37" +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + # Add links to Filing and Submission to user_action + with op.batch_alter_table("user_action", schema=None) as batch_op: + batch_op.add_column(sa.Column("filing_id", sa.Integer, nullable=True)) + batch_op.create_foreign_key("user_action_filing_fkey", "filing", ["filing_id"], ["id"]) + batch_op.add_column(sa.Column("submission_id", sa.Integer, nullable=True)) + batch_op.create_foreign_key("user_action_submission_fkey", "submission", ["submission_id"], ["id"]) + # Update links with existing info + op.execute( + """ + UPDATE user_action + SET filing_id = COALESCE( + (SELECT id FROM filing WHERE creator_id = user_action.id), + (SELECT filing FROM filing_signature WHERE user_action = user_action.id), + (SELECT filing FROM submission WHERE submitter_id = user_action.id OR accepter_id = user_action.id) + ) + """ + ) + op.execute( + """ + UPDATE user_action + SET submission_id = (SELECT id FROM submission WHERE submitter_id = user_action.id OR accepter_id = user_action.id) + """ + ) + # Index the foreign keys + op.create_index("user_action_filing_id", table_name="user_action", columns=["filing_id"]) + op.create_index("user_action_submission_id", table_name="user_action", columns=["submission_id"]) + with op.batch_alter_table("user_action", schema=None) as batch_op: + batch_op.alter_column("filing_id", nullable=False) + batch_op.alter_column("submission_id", nullable=True) + # Drop old table and columns no longer needed + op.drop_table("filing_signature") + with op.batch_alter_table("filing", schema=None) as batch_op: + batch_op.drop_column("creator_id") + with op.batch_alter_table("submission", schema=None) as batch_op: + batch_op.drop_column("submitter_id") + batch_op.drop_column("accepter_id") + + +def downgrade() -> None: + # recreate the filing_signature table + op.create_table( + "filing_signature", + sa.Column("user_action", sa.INTEGER, primary_key=True, unique=True, nullable=False), + sa.Column("filing", sa.Integer, nullable=False), + sa.PrimaryKeyConstraint("user_action", name="filing_signatures_pkey"), + sa.ForeignKeyConstraint(["user_action"], ["user_action.id"], name="filing_signatures_user_action_fkey"), + sa.ForeignKeyConstraint(["filing"], ["filing.id"], name="filing_signatures_filing_fkey"), + ) + # re-add link columns + with op.batch_alter_table("filing", schema=None) as batch_op: + batch_op.add_column(sa.Column("creator_id", sa.Integer)) + batch_op.create_foreign_key("filing_creator_fkey", "user_action", ["creator_id"], ["id"]) + + with op.batch_alter_table("submission", schema=None) as batch_op: + batch_op.add_column(sa.Column("submitter_id", sa.Integer)) + batch_op.add_column(sa.Column("accepter_id", sa.Integer)) + batch_op.create_foreign_key("submission_submitter_fkey", "user_action", ["submitter_id"], ["id"]) + batch_op.create_foreign_key("submission_accepter_fkey", "user_action", ["accepter_id"], ["id"]) + + # re-populate data + op.execute( + f""" + INSERT INTO filing_signature (user_action, filing) + SELECT id, filing_id FROM user_action WHERE action_type = '{UserActionType.SIGN}' + """ + ) + op.execute( + f""" + UPDATE submission + SET submitter_id = (SELECT id FROM user_action WHERE submission.id = user_action.submission_id AND action_type = '{UserActionType.SUBMIT}'), + accepter_id = (SELECT id FROM user_action WHERE submission.id = user_action.submission_id AND action_type = '{UserActionType.ACCEPT}') + """ + ) + op.execute( + f""" + UPDATE filing + SET creator_id = (SELECT id FROM user_action WHERE filing.id = user_action.filing_id AND action_type = '{UserActionType.CREATE}') + """ + ) + + # Make columns non-nullable + with op.batch_alter_table("filing", schema=None) as batch_op: + batch_op.alter_column("creator_id", nullable=False) + with op.batch_alter_table("submission", schema=None) as batch_op: + batch_op.alter_column("submitter_id", nullable=False) + + # Drop new columns + op.drop_index("user_action_filing_id", table_name="user_action") + op.drop_index("user_action_submission_id", table_name="user_action") + op.drop_constraint(constraint_name="user_action_filing_fkey", table_name="user_action") + op.drop_column("user_action", "filing_id") + op.drop_constraint(constraint_name="user_action_submission_fkey", table_name="user_action") + op.drop_column("user_action", "submission_id") diff --git a/src/sbl_filing_api/entities/models/dao.py b/src/sbl_filing_api/entities/models/dao.py index e1593fa5..e7f1b0bd 100644 --- a/src/sbl_filing_api/entities/models/dao.py +++ b/src/sbl_filing_api/entities/models/dao.py @@ -15,6 +15,8 @@ class Base(AsyncAttrs, DeclarativeBase): class UserActionDAO(Base): __tablename__ = "user_action" id: Mapped[int] = mapped_column(index=True, primary_key=True, autoincrement=True) + filing_id: Mapped[int] = mapped_column(ForeignKey("filing.id")) + submission_id: Mapped[int | None] = mapped_column(ForeignKey("submission.id"), nullable=True) user_id: Mapped[str] = mapped_column(String(36)) user_name: Mapped[str] = mapped_column(String(255)) user_email: Mapped[str] = mapped_column(String(255)) @@ -27,16 +29,15 @@ class SubmissionDAO(Base): id: Mapped[int] = mapped_column(index=True, primary_key=True, autoincrement=True) filing: Mapped[int] = mapped_column(ForeignKey("filing.id")) counter: Mapped[int] - submitter_id: Mapped[int] = mapped_column(ForeignKey("user_action.id")) - submitter: Mapped[UserActionDAO] = relationship(lazy="selectin", foreign_keys=[submitter_id]) - accepter_id: Mapped[int] = mapped_column(ForeignKey("user_action.id"), nullable=True) - accepter: Mapped[UserActionDAO] = relationship(lazy="selectin", foreign_keys=[accepter_id]) state: Mapped[SubmissionState] = mapped_column(SAEnum(SubmissionState)) validation_ruleset_version: Mapped[str] = mapped_column(nullable=True) validation_results: Mapped[dict[str, Any]] = mapped_column(JSON, nullable=True) submission_time: Mapped[datetime] = mapped_column(server_default=func.now()) filename: Mapped[str] total_records: Mapped[int] = mapped_column(nullable=True) + user_actions: Mapped[List[UserActionDAO] | None] = relationship( + "UserActionDAO", lazy="selectin", cascade="all, delete-orphan" + ) __table_args__ = (UniqueConstraint("filing", "counter", name="unique_filing_counter"),) @@ -99,14 +100,6 @@ 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}" -class FilingSignatureDAO(Base): - __tablename__ = "filing_signature" - user_action: Mapped[int] = mapped_column( - ForeignKey("user_action.id"), nullable=False, primary_key=True, unique=True - ) - filing: Mapped[int] = mapped_column(ForeignKey("filing.id"), index=True, nullable=False) - - class FilingDAO(Base): __tablename__ = "filing" id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True) @@ -118,13 +111,11 @@ class FilingDAO(Base): submissions: Mapped[List[SubmissionDAO] | None] = relationship( "SubmissionDAO", lazy="select", order_by=desc(SubmissionDAO.submission_time) ) - signatures: Mapped[List[UserActionDAO] | None] = relationship( - "UserActionDAO", secondary="filing_signature", lazy="selectin", order_by="desc(UserActionDAO.timestamp)" - ) confirmation_id: Mapped[str] = mapped_column(nullable=True) - creator_id: Mapped[int] = mapped_column(ForeignKey("user_action.id")) - creator: Mapped[UserActionDAO] = relationship(lazy="selectin", foreign_keys=[creator_id]) is_voluntary: Mapped[bool] = mapped_column(nullable=True) + user_actions: Mapped[List[UserActionDAO] | None] = relationship( + "UserActionDAO", lazy="selectin", cascade="all, delete-orphan" + ) def __str__(self): return f"ID: {self.id}, Filing Period: {self.filing_period}, LEI: {self.lei}, Tasks: {self.tasks}, Institution Snapshot ID: {self.institution_snapshot_id}, Contact Info: {self.contact_info}" diff --git a/src/sbl_filing_api/entities/models/dto.py b/src/sbl_filing_api/entities/models/dto.py index 5f535dc3..3cd7b6ee 100644 --- a/src/sbl_filing_api/entities/models/dto.py +++ b/src/sbl_filing_api/entities/models/dto.py @@ -1,12 +1,14 @@ from sbl_filing_api.config import regex_configs from datetime import datetime -from typing import Dict, Any, List -from pydantic import BaseModel, ConfigDict, Field, model_validator +from typing import Dict, Any, List, Annotated +from pydantic import BaseModel, ConfigDict, Field, model_validator, computed_field from sbl_filing_api.entities.models.model_enums import FilingType, FilingTaskState, SubmissionState, UserActionType class UserActionDTO(BaseModel): id: int | None = None + filing_id: int | None = None + submission_id: int | None = None user_id: str = Field(max_length=36) user_name: str = Field(max_length=255) user_email: str = Field(max_length=255) @@ -25,8 +27,17 @@ class SubmissionDTO(BaseModel): submission_time: datetime | None = None filename: str total_records: int | None = None - submitter: UserActionDTO - accepter: UserActionDTO | None = None + user_actions: Annotated[List[UserActionDTO] | None, Field(exclude=True)] = None + + @computed_field + @property + def submitter(self) -> UserActionDTO | None: + return next((action for action in self.user_actions if action.action_type == UserActionType.SUBMIT), None) + + @computed_field + @property + def accepter(self) -> UserActionDTO | None: + return next((action for action in self.user_actions if action.action_type == UserActionType.ACCEPT), None) class FilingTaskDTO(BaseModel): @@ -86,9 +97,22 @@ class FilingDTO(BaseModel): institution_snapshot_id: str | None = None contact_info: ContactInfoDTO | None = None confirmation_id: str | None = None - signatures: List[UserActionDTO] = [] - creator: UserActionDTO is_voluntary: bool | None = None + user_actions: Annotated[List[UserActionDTO] | None, Field(exclude=True)] = None + + @computed_field + @property + def creator(self) -> UserActionDTO | None: + return next((action for action in self.user_actions if action.action_type == UserActionType.CREATE), None) + + @computed_field + @property + def signatures(self) -> List[UserActionDTO]: + return sorted( + [action for action in self.user_actions if action.action_type == UserActionType.SIGN], + key=lambda action: action.timestamp, + reverse=True, + ) class FilingPeriodDTO(BaseModel): @@ -103,7 +127,7 @@ class FilingPeriodDTO(BaseModel): class SnapshotUpdateDTO(BaseModel): - model_config = ConfigDict(from_attribute=True) + model_config = ConfigDict(from_attributes=True) institution_snapshot_id: str @@ -115,6 +139,6 @@ class StateUpdateDTO(BaseModel): class VoluntaryUpdateDTO(BaseModel): - model_config = ConfigDict(from_attribute=True) + model_config = ConfigDict(from_attributes=True) is_voluntary: bool diff --git a/src/sbl_filing_api/entities/models/model_enums.py b/src/sbl_filing_api/entities/models/model_enums.py index 81e4053c..78931a80 100644 --- a/src/sbl_filing_api/entities/models/model_enums.py +++ b/src/sbl_filing_api/entities/models/model_enums.py @@ -1,14 +1,14 @@ -from enum import Enum +from enum import StrEnum -class UserActionType(str, Enum): +class UserActionType(StrEnum): SUBMIT = "SUBMIT" ACCEPT = "ACCEPT" SIGN = "SIGN" CREATE = "CREATE" -class SubmissionState(str, Enum): +class SubmissionState(StrEnum): SUBMISSION_ACCEPTED = "SUBMISSION_ACCEPTED" SUBMISSION_STARTED = "SUBMISSION_STARTED" SUBMISSION_UPLOAD_MALFORMED = "SUBMISSION_UPLOAD_MALFORMED" @@ -22,11 +22,11 @@ class SubmissionState(str, Enum): VALIDATION_WITH_WARNINGS = "VALIDATION_WITH_WARNINGS" -class FilingTaskState(str, Enum): +class FilingTaskState(StrEnum): NOT_STARTED = "NOT_STARTED" IN_PROGRESS = "IN_PROGRESS" COMPLETED = "COMPLETED" -class FilingType(str, Enum): +class FilingType(StrEnum): ANNUAL = "ANNUAL" diff --git a/src/sbl_filing_api/entities/repos/submission_repo.py b/src/sbl_filing_api/entities/repos/submission_repo.py index 70580ee2..a3dee543 100644 --- a/src/sbl_filing_api/entities/repos/submission_repo.py +++ b/src/sbl_filing_api/entities/repos/submission_repo.py @@ -95,7 +95,9 @@ async def get_user_actions(session: AsyncSession) -> List[UserActionDAO]: return await query_helper(session, UserActionDAO) -async def add_submission(session: AsyncSession, filing_id: int, filename: str, submitter_id: int) -> SubmissionDAO: +async def add_submission( + session: AsyncSession, filing_id: int, filename: str, submitter: UserActionDAO +) -> SubmissionDAO: stmt = select(SubmissionDAO).filter_by(filing=filing_id).order_by(desc(SubmissionDAO.counter)).limit(1) last_sub = await session.scalar(stmt) current_count = last_sub.counter if last_sub else 0 @@ -103,12 +105,13 @@ async def add_submission(session: AsyncSession, filing_id: int, filename: str, s filing=filing_id, state=SubmissionState.SUBMISSION_STARTED, filename=filename, - submitter_id=submitter_id, counter=(current_count + 1), + user_actions=[submitter], ) # this returns the attached object, most importantly with the new submission id new_sub = await session.merge(new_sub) await session.commit() + await session.refresh(new_sub) return new_sub @@ -138,8 +141,8 @@ async def upsert_filing(session: AsyncSession, filing: FilingDTO) -> FilingDAO: return await upsert_helper(session, filing, FilingDAO) -async def create_new_filing(session: AsyncSession, lei: str, filing_period: str, creator_id: int) -> FilingDAO: - new_filing = FilingDAO(filing_period=filing_period, lei=lei, creator_id=creator_id) +async def create_new_filing(session: AsyncSession, lei: str, filing_period: str, creator: UserActionDAO) -> FilingDAO: + new_filing = FilingDAO(filing_period=filing_period, lei=lei, user_actions=[creator]) return await upsert_helper(session, new_filing, FilingDAO) diff --git a/src/sbl_filing_api/routers/filing.py b/src/sbl_filing_api/routers/filing.py index 8e954705..8a37b307 100644 --- a/src/sbl_filing_api/routers/filing.py +++ b/src/sbl_filing_api/routers/filing.py @@ -11,7 +11,7 @@ from regtech_api_commons.api.exceptions import RegTechHttpException from regtech_api_commons.models.auth import AuthenticatedUser -from sbl_filing_api.entities.models.dao import FilingDAO +from sbl_filing_api.entities.models.dao import FilingDAO, UserActionDAO from sbl_filing_api.entities.models.model_enums import UserActionType from sbl_filing_api.services import submission_processor from sbl_filing_api.services.multithread_handler import handle_submission @@ -86,27 +86,16 @@ async def get_filings(request: Request, period_code: str): ) @requires("authenticated") async def post_filing(request: Request, lei: str, period_code: str): - creator = None - try: - creator = await repo.add_user_action( - request.state.db_session, - UserActionDTO( - user_id=request.user.id, - user_name=request.user.name, - user_email=request.user.email, - action_type=UserActionType.CREATE, - ), - ) - except Exception: - logger.exception("Error while trying to create the filing.creator UserAction.") - raise RegTechHttpException( - status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, - name="Filing.creator UserAction error", - detail="Error while trying to create the filing.creator UserAction.", - ) + # TODO consider moving this into create_new_filing + creator = UserActionDAO( + user_id=request.user.id, + user_name=request.user.name, + user_email=request.user.email, + action_type=UserActionType.CREATE, + ) try: - return await repo.create_new_filing(request.state.db_session, lei, period_code, creator_id=creator.id) + return await repo.create_new_filing(request.state.db_session, lei, period_code, creator) except Exception: raise RegTechHttpException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, @@ -126,19 +115,23 @@ async def post_filing(request: Request, lei: str, period_code: str): @requires("authenticated") async def sign_filing(request: Request, lei: str, period_code: str): filing: FilingDAO = request.state.context["filing"] + # Is it possible this is the wrong submission? UI should be able to know which submission is being signed, or maybe + # it needs to be a transaction and check status? latest_sub = (await filing.awaitable_attrs.submissions)[0] sig = await repo.add_user_action( request.state.db_session, UserActionDTO( user_id=request.user.id, + filing_id=filing.id, user_name=request.user.name, user_email=request.user.email, action_type=UserActionType.SIGN, ), ) + # TODO consider what happens if anything after this point fails. Can we retry just this part? sig_timestamp = int(sig.timestamp.timestamp()) filing.confirmation_id = lei + "-" + period_code + "-" + str(latest_sub.counter) + "-" + str(sig_timestamp) - filing.signatures.append(sig) + filing.user_actions.append(sig) send_confirmation_email( request.user.name, request.user.email, filing.contact_info.email, filing.confirmation_id, sig_timestamp ) @@ -160,19 +153,18 @@ async def upload_file(request: Request, lei: str, period_code: str, file: Upload ) submission = None try: - submitter = await repo.add_user_action( - request.state.db_session, - UserActionDTO( - user_id=request.user.id, - user_name=request.user.name, - user_email=request.user.email, - action_type=UserActionType.SUBMIT, - ), + # TODO consider moving this to add_submission + submitter = UserActionDAO( + user_id=request.user.id, + filing_id=filing.id, + user_name=request.user.name, + user_email=request.user.email, + action_type=UserActionType.SUBMIT, ) - submission = await repo.add_submission(request.state.db_session, filing.id, file.filename, submitter.id) + submission = await repo.add_submission(request.state.db_session, filing.id, file.filename, submitter) try: submission_processor.upload_to_storage( - period_code, lei, submission.counter, content, file.filename.split(".")[-1] + period_code, lei, str(submission.counter), content, file.filename.split(".")[-1] ) submission.state = SubmissionState.SUBMISSION_UPLOADED @@ -269,18 +261,17 @@ async def accept_submission(request: Request, counter: int, lei: str, period_cod detail=f"Submission {counter} for LEI {lei} in filing period {period_code} is not in an acceptable state. Submissions must be validated successfully or with only warnings to be accepted.", ) - accepter = await repo.add_user_action( - request.state.db_session, - UserActionDTO( + submission.state = SubmissionState.SUBMISSION_ACCEPTED + submission.user_actions.append( + UserActionDAO( + filing_id=submission.filing, + submission_id=submission.id, user_id=request.user.id, user_name=request.user.name, user_email=request.user.email, action_type=UserActionType.ACCEPT, - ), + ) ) - - submission.accepter_id = accepter.id - submission.state = SubmissionState.SUBMISSION_ACCEPTED submission = await repo.update_submission(request.state.db_session, submission) return submission diff --git a/src/sbl_filing_api/services/request_action_validator.py b/src/sbl_filing_api/services/request_action_validator.py index 2723e032..4226df61 100644 --- a/src/sbl_filing_api/services/request_action_validator.py +++ b/src/sbl_filing_api/services/request_action_validator.py @@ -67,7 +67,7 @@ def set_context(requirements: Set[UserActionContext]): Sets a `context` object on `request.state`; this should typically include the institution, and filing; `context` should be set before running any validation dependencies Args: - requst (Request): request from the API endpoint + request (Request): request from the API endpoint lei: comes from request path param period: filing period comes from request path param """ diff --git a/tests/api/conftest.py b/tests/api/conftest.py index 482378d1..d6e4b214 100644 --- a/tests/api/conftest.py +++ b/tests/api/conftest.py @@ -85,15 +85,16 @@ def get_filing_mock(mocker: MockerFixture) -> Mock: phone_number="112-345-6789", email="test1@cfpb.gov", ), - creator_id=1, - creator=UserActionDAO( - id=1, - user_id="123456-7890-ABCDEF-GHIJ", - user_name="test submitter", - user_email="test@local.host", - action_type=UserActionType.SUBMIT, - timestamp=datetime.now(), - ), + user_actions=[ + UserActionDAO( + id=1, + user_id="123456-7890-ABCDEF-GHIJ", + user_name="test submitter", + user_email="test@local.host", + action_type=UserActionType.SUBMIT, + timestamp=datetime.now(), + ), + ], ) return mock @@ -120,15 +121,16 @@ def get_filings_mock(mocker: MockerFixture) -> Mock: phone_number="112-345-6789", email="test1@cfpb.gov", ), - creator_id=1, - creator=UserActionDAO( - id=1, - user_id="123456-7890-ABCDEF-GHIJ", - user_name="test submitter", - user_email="test@local.host", - action_type=UserActionType.SUBMIT, - timestamp=datetime.now(), - ), + user_actions=[ + UserActionDAO( + id=1, + user_id="123456-7890-ABCDEF-GHIJ", + user_name="test submitter", + user_email="test@local.host", + action_type=UserActionType.SUBMIT, + timestamp=datetime.now(), + ), + ], ), FilingDAO( id=1, @@ -148,15 +150,16 @@ def get_filings_mock(mocker: MockerFixture) -> Mock: phone_number="112-345-6789", email="test1@cfpb.gov", ), - creator_id=1, - creator=UserActionDAO( - id=1, - user_id="123456-7890-ABCDEF-GHIJ", - user_name="test submitter", - user_email="test@local.host", - action_type=UserActionType.SUBMIT, - timestamp=datetime.now(), - ), + user_actions=[ + UserActionDAO( + id=1, + user_id="123456-7890-ABCDEF-GHIJ", + user_name="test submitter", + user_email="test@local.host", + action_type=UserActionType.SUBMIT, + timestamp=datetime.now(), + ), + ], ), FilingDAO( id=1, @@ -176,15 +179,16 @@ def get_filings_mock(mocker: MockerFixture) -> Mock: phone_number="112-345-6789", email="test1@cfpb.gov", ), - creator_id=1, - creator=UserActionDAO( - id=1, - user_id="123456-7890-ABCDEF-GHIJ", - user_name="test submitter", - user_email="test@local.host", - action_type=UserActionType.SUBMIT, - timestamp=datetime.now(), - ), + user_actions=[ + UserActionDAO( + id=1, + user_id="123456-7890-ABCDEF-GHIJ", + user_name="test submitter", + user_email="test@local.host", + action_type=UserActionType.SUBMIT, + timestamp=datetime.now(), + ), + ], ), ] return mock @@ -211,15 +215,16 @@ def post_filing_mock(mocker: MockerFixture) -> Mock: phone_number="312-345-6789", email="test3@cfpb.gov", ), - 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.now(), - ), + user_actions=[ + UserActionDAO( + id=1, + user_id="123456-7890-ABCDEF-GHIJ", + user_name="test creator", + user_email="test@local.host", + action_type=UserActionType.CREATE, + timestamp=datetime.now(), + ), + ], ) return mock diff --git a/tests/api/routers/test_filing_api.py b/tests/api/routers/test_filing_api.py index 4f298b19..6dd2f9a7 100644 --- a/tests/api/routers/test_filing_api.py +++ b/tests/api/routers/test_filing_api.py @@ -117,26 +117,7 @@ def test_post_filing( ) get_filing_period_by_code_mock.return_value = get_filing_period_mock.return_value - user_action_create = 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(), - ) - mock_add_creator = mocker.patch("sbl_filing_api.entities.repos.submission_repo.add_user_action") - mock_add_creator.side_effect = Exception("Error while trying to process CREATE User Action") - - log_mock = mocker.patch("sbl_filing_api.routers.filing.logger.exception") - res = client.post("/v1/filing/institutions/1234567890ZXWVUTSR00/filings/2025/") - assert res.status_code == 500 - assert res.json()["error_detail"] == "Error while trying to create the filing.creator UserAction." - log_mock.assert_called_with("Error while trying to create the filing.creator UserAction.") - - mock_add_creator.return_value = user_action_create - mock_add_creator.side_effect = None post_filing_mock.side_effect = IntegrityError(None, None, None) res = client.post("/v1/filing/institutions/1234567890ZXWVUTSR00/filings/2024/") assert res.status_code == 500 @@ -148,7 +129,17 @@ def test_post_filing( post_filing_mock.side_effect = None res = client.post("/v1/filing/institutions/1234567890ZXWVUTSR00/filings/2024/") - post_filing_mock.assert_called_with(ANY, "1234567890ZXWVUTSR00", "2024", creator_id=1) + post_filing_mock.assert_called_with(ANY, "1234567890ZXWVUTSR00", "2024", ANY) + creator_arg = post_filing_mock.call_args.args[-1] + # These properties will be filled in by the ORM + assert creator_arg.id is None + assert creator_arg.filing_id is None + assert creator_arg.submission_id is None + assert creator_arg.timestamp is None + assert creator_arg.action_type == UserActionType.CREATE + assert creator_arg.user_email == "test@local.host" + assert creator_arg.user_id == "123456-7890-ABCDEF-GHIJ" + assert creator_arg.user_name == "Test User" assert res.status_code == 200 assert res.json()["lei"] == "1234567890ZXWVUTSR00" assert res.json()["filing_period"] == "2024" @@ -178,8 +169,7 @@ async def test_get_submissions(self, mocker: MockerFixture, app_fixture: FastAPI validation_ruleset_version="v1", submission_time=datetime.datetime.now(), filename="file1.csv", - submitter_id=2, - submitter=user_action_submit, + user_actions=[user_action_submit], ) ] @@ -227,8 +217,7 @@ async def test_get_latest_submission( validation_ruleset_version="v1", submission_time=datetime.datetime.now(), filename="file1.csv", - submitter_id=2, - submitter=user_action_submit, + user_actions=[user_action_submit], ) client = TestClient(app_fixture) @@ -274,8 +263,7 @@ async def test_get_submission_by_counter(self, mocker: MockerFixture, app_fixtur validation_ruleset_version="v1", submission_time=datetime.datetime.now(), filename="file1.csv", - submitter_id=2, - submitter=user_action_submit, + user_actions=[user_action_submit], ) client = TestClient(app_fixture) @@ -312,8 +300,7 @@ def test_authed_upload_file( counter=1, state=SubmissionState.SUBMISSION_UPLOADED, filename="submission.csv", - submitter_id=1, - submitter=user_action_submit, + user_actions=[user_action_submit], ) mock_validate_file = mocker.patch("sbl_filing_api.services.submission_processor.validate_file_processable") @@ -341,7 +328,17 @@ def test_authed_upload_file( client = TestClient(app_fixture) res = client.post("/v1/filing/institutions/1234567890ZXWVUTSR00/filings/2024/submissions", files=files) - mock_add_submission.assert_called_with(ANY, 1, "submission.csv", user_action_submit.id) + mock_add_submission.assert_called_with(ANY, 1, "submission.csv", ANY) + submitter_arg = mock_add_submission.call_args.args[-1] + # These properties will be filled in by the ORM + assert submitter_arg.id is None + assert submitter_arg.submission_id is None + assert submitter_arg.timestamp is None + assert submitter_arg.filing_id == 1 + assert submitter_arg.user_id == "123456-7890-ABCDEF-GHIJ" + assert submitter_arg.user_name == "Test User" + assert submitter_arg.user_email == "test@local.host" + assert submitter_arg.action_type == UserActionType.SUBMIT mock_event_loop.run_in_executor.assert_called_with( ANY, handle_submission, "2024", "1234567890ZXWVUTSR00", return_sub, open(submission_csv, "rb").read(), ANY ) @@ -420,16 +417,10 @@ def test_submission_update_fail( ) mock_add_submitter = mocker.patch("sbl_filing_api.entities.repos.submission_repo.add_user_action") - mock_add_submitter.side_effect = RuntimeError("Failed to add submitter.") file = {"file": ("submission.csv", open(submission_csv, "rb"))} client = TestClient(app_fixture) - res = client.post("/v1/filing/institutions/1234567890ZXWVUTSR00/filings/2024/submissions", files=file) - assert res.status_code == 500 - assert res.json()["error_detail"] == "Error while trying to process SUBMIT User Action" - - mock_add_submitter.side_effect = None mock_add_submitter.return_value = UserActionDAO( id=2, user_id="123456-7890-ABCDEF-GHIJ", @@ -723,15 +714,16 @@ def test_put_contact_info( phone_ext="x54321", 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(), - ), + user_actions=[ + 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) @@ -816,15 +808,16 @@ def test_no_extension( 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(), - ), + user_actions=[ + 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) @@ -921,8 +914,8 @@ async def test_accept_submission(self, mocker: MockerFixture, app_fixture: FastA user_action_accept = UserActionDAO( id=3, - user_id="1234-5678-ABCD-EFGH", - user_name="test accepter", + user_id="123456-7890-ABCDEF-GHIJ", + user_name="Test User", user_email="test@local.host", action_type=UserActionType.ACCEPT, timestamp=datetime.datetime.now(), @@ -936,13 +929,9 @@ async def test_accept_submission(self, mocker: MockerFixture, app_fixture: FastA validation_ruleset_version="v1", submission_time=datetime.datetime.now(), filename="file1.csv", - submitter_id=2, - submitter=user_action_submit, + user_actions=[user_action_submit], ) - update_accepter_mock = mocker.patch("sbl_filing_api.entities.repos.submission_repo.add_user_action") - update_accepter_mock.return_value = user_action_accept - update_mock = mocker.patch("sbl_filing_api.entities.repos.submission_repo.update_submission") update_mock.return_value = SubmissionDAO( id=1, @@ -952,10 +941,7 @@ async def test_accept_submission(self, mocker: MockerFixture, app_fixture: FastA validation_ruleset_version="v1", submission_time=datetime.datetime.now(), filename="file1.csv", - submitter_id=2, - submitter=user_action_submit, - accepter_id=update_accepter_mock.return_value.id, - accepter=update_accepter_mock.return_value, + user_actions=[user_action_submit, user_action_accept], ) client = TestClient(app_fixture) @@ -969,22 +955,23 @@ async def test_accept_submission(self, mocker: MockerFixture, app_fixture: FastA mock.return_value.state = SubmissionState.VALIDATION_SUCCESSFUL res = client.put("/v1/filing/institutions/1234567890ZXWVUTSR00/filings/2024/submissions/4/accept") update_mock.assert_called_once() - update_accepter_mock.assert_called_once_with( - ANY, - UserActionDTO( - user_id="123456-7890-ABCDEF-GHIJ", - user_name="Test User", - user_email="test@local.host", - action_type=UserActionType.ACCEPT, - ), - ) + submission_arg = update_mock.call_args.args[-1] + accepter = submission_arg.user_actions[-1] + assert accepter.id is None + assert accepter.timestamp is None + assert accepter.filing_id == 1 + assert accepter.submission_id == 1 + assert accepter.user_id == "123456-7890-ABCDEF-GHIJ" + assert accepter.user_name == "Test User" + assert accepter.user_email == "test@local.host" + assert accepter.action_type == UserActionType.ACCEPT assert res.json()["state"] == "SUBMISSION_ACCEPTED" assert res.json()["id"] == 1 assert res.json()["counter"] == 4 assert res.json()["accepter"]["id"] == 3 - assert res.json()["accepter"]["user_id"] == "1234-5678-ABCD-EFGH" - assert res.json()["accepter"]["user_name"] == "test accepter" + assert res.json()["accepter"]["user_id"] == "123456-7890-ABCDEF-GHIJ" + assert res.json()["accepter"]["user_name"] == "Test User" assert res.json()["accepter"]["user_email"] == "test@local.host" assert res.json()["accepter"]["action_type"] == UserActionType.ACCEPT assert res.status_code == 200 @@ -1005,19 +992,21 @@ async def test_good_sign_filing( SubmissionDAO( id=1, counter=5, - submitter=UserActionDAO( - id=1, - user_id="123456-7890-ABCDEF-GHIJ", - user_name="Test Submitter User", - user_email="test1@cfpb.gov", - action_type=UserActionType.SUBMIT, - timestamp=datetime.datetime.now(), - ), filing=1, state=SubmissionState.SUBMISSION_ACCEPTED, validation_ruleset_version="v1", submission_time=datetime.datetime.now(), filename="file1.csv", + user_actions=[ + UserActionDAO( + id=1, + user_id="123456-7890-ABCDEF-GHIJ", + user_name="Test Submitter User", + user_email="test1@cfpb.gov", + action_type=UserActionType.SUBMIT, + timestamp=datetime.datetime.now(), + ), + ], ) ] @@ -1050,6 +1039,7 @@ async def test_good_sign_filing( add_sig_mock.assert_called_with( ANY, UserActionDTO( + filing_id=1, user_id="123456-7890-ABCDEF-GHIJ", user_name="Test User", user_email="test@local.host", @@ -1074,19 +1064,21 @@ async def test_errors_sign_filing( get_filing_mock.return_value.submissions = [ SubmissionDAO( id=1, - submitter=UserActionDAO( - id=1, - user_id="1234-5678-ABCD-EFGH", - user_name="Test Submitter User", - user_email="test1@cfpb.gov", - action_type=UserActionType.SUBMIT, - timestamp=datetime.datetime.now(), - ), filing=1, state=SubmissionState.VALIDATION_SUCCESSFUL, validation_ruleset_version="v1", submission_time=datetime.datetime.now(), filename="file1.csv", + user_actions=[ + UserActionDAO( + id=1, + user_id="1234-5678-ABCD-EFGH", + user_name="Test Submitter User", + user_email="test1@cfpb.gov", + action_type=UserActionType.SUBMIT, + timestamp=datetime.datetime.now(), + ), + ], ) ] get_filing_mock.return_value.contact_info = None @@ -1145,19 +1137,21 @@ async def test_get_latest_sub_report( sub_mock.return_value = SubmissionDAO( id=1, counter=3, - submitter=UserActionDAO( - id=1, - user_id="1234-5678-ABCD-EFGH", - user_name="Test Submitter User", - user_email="test1@cfpb.gov", - action_type=UserActionType.SUBMIT, - timestamp=datetime.datetime.now(), - ), filing=1, state=SubmissionState.VALIDATION_SUCCESSFUL, validation_ruleset_version="v1", submission_time=datetime.datetime.now(), filename="file1.csv", + user_actions=[ + UserActionDAO( + id=1, + user_id="1234-5678-ABCD-EFGH", + user_name="Test Submitter User", + user_email="test1@cfpb.gov", + action_type=UserActionType.SUBMIT, + timestamp=datetime.datetime.now(), + ), + ], ) file_content = "Test" @@ -1176,19 +1170,21 @@ async def test_get_latest_sub_report( sub_mock.return_value = SubmissionDAO( id=1, - submitter=UserActionDAO( - id=1, - user_id="1234-5678-ABCD-EFGH", - user_name="Test Submitter User", - user_email="test1@cfpb.gov", - action_type=UserActionType.SUBMIT, - timestamp=datetime.datetime.now(), - ), filing=1, state=SubmissionState.VALIDATION_IN_PROGRESS, validation_ruleset_version="v1", submission_time=datetime.datetime.now(), filename="file1.csv", + user_actions=[ + UserActionDAO( + id=1, + user_id="1234-5678-ABCD-EFGH", + user_name="Test Submitter User", + user_email="test1@cfpb.gov", + action_type=UserActionType.SUBMIT, + timestamp=datetime.datetime.now(), + ), + ], ) client = TestClient(app_fixture) @@ -1212,19 +1208,21 @@ async def test_get_sub_report(self, mocker: MockerFixture, app_fixture: FastAPI, sub_mock.return_value = SubmissionDAO( id=2, counter=4, - submitter=UserActionDAO( - id=1, - user_id="1234-5678-ABCD-EFGH", - user_name="Test Submitter User", - user_email="test1@cfpb.gov", - action_type=UserActionType.SUBMIT, - timestamp=datetime.datetime.now(), - ), filing=1, state=SubmissionState.VALIDATION_SUCCESSFUL, validation_ruleset_version="v1", submission_time=datetime.datetime.now(), filename="file1.csv", + user_actions=[ + UserActionDAO( + id=1, + user_id="1234-5678-ABCD-EFGH", + user_name="Test Submitter User", + user_email="test1@cfpb.gov", + action_type=UserActionType.SUBMIT, + timestamp=datetime.datetime.now(), + ), + ], ) file_content = "Test" diff --git a/tests/entities/repos/test_submission_repo.py b/tests/entities/repos/test_submission_repo.py index ab9bb6b8..68340e0f 100644 --- a/tests/entities/repos/test_submission_repo.py +++ b/tests/entities/repos/test_submission_repo.py @@ -32,53 +32,6 @@ async def setup( ): mocker.patch.object(repo, "SessionLocal", return_value=session_generator()) - user_action1 = UserActionDAO( - id=1, - user_id="test@local.host", - user_name="signer name", - user_email="test@local.host", - action_type=UserActionType.SIGN, - timestamp=dt.now(), - ) - user_action2 = UserActionDAO( - id=2, - user_id="test@local.host", - user_name="submitter name", - user_email="test@local.host", - action_type=UserActionType.SUBMIT, - timestamp=dt.now(), - ) - user_action3 = UserActionDAO( - id=3, - user_id="test@local.host", - user_name="accepter name", - user_email="test@local.host", - action_type=UserActionType.ACCEPT, - timestamp=dt.now(), - ) - user_action4 = UserActionDAO( - id=4, - user_id="test@local.host", - user_name="creator name", - user_email="test@local.host", - action_type=UserActionType.CREATE, - timestamp=dt.now(), - ) - user_action5 = UserActionDAO( - id=5, - user_id="test_sig@local.host", - user_name="signer name", - user_email="test_sig@local.host", - action_type=UserActionType.SIGN, - timestamp=dt.now(), - ) - - transaction_session.add(user_action1) - transaction_session.add(user_action2) - transaction_session.add(user_action3) - transaction_session.add(user_action4) - transaction_session.add(user_action5) - filing_task_1 = FilingTaskDAO(name="Task-1", task_order=1) filing_task_2 = FilingTaskDAO(name="Task-2", task_order=2) transaction_session.add(filing_task_1) @@ -99,23 +52,55 @@ async def setup( lei="1234567890", institution_snapshot_id="Snapshot-1", filing_period="2024", + user_actions=[ + UserActionDAO( + user_id="test@local.host", + user_name="signer name", + user_email="test@local.host", + action_type=UserActionType.SIGN, + ), + UserActionDAO( + user_id="test@local.host", + user_name="creator name", + user_email="test@local.host", + action_type=UserActionType.CREATE, + ), + UserActionDAO( + user_id="test_sig@local.host", + user_name="signer name", + user_email="test_sig@local.host", + action_type=UserActionType.SIGN, + ), + ], ) filing2 = FilingDAO( id=2, lei="ABCDEFGHIJ", institution_snapshot_id="Snapshot-1", filing_period="2024", + user_actions=[ + UserActionDAO( + user_id="test@local.host", + user_name="creator name", + user_email="test@local.host", + action_type=UserActionType.CREATE, + ), + ], ) filing3 = FilingDAO( id=3, lei="ZYXWVUTSRQP", institution_snapshot_id="Snapshot-1", filing_period="2024", + user_actions=[ + UserActionDAO( + user_id="test@local.host", + user_name="creator name", + user_email="test@local.host", + action_type=UserActionType.CREATE, + ), + ], ) - filing1.creator = user_action4 - filing2.creator = user_action4 - filing3.creator = user_action4 - filing1.signatures = [user_action1, user_action5] transaction_session.add(filing1) transaction_session.add(filing2) @@ -133,33 +118,64 @@ async def setup( submission1 = SubmissionDAO( id=1, filing=1, - submitter_id=2, state=SubmissionState.SUBMISSION_UPLOADED, validation_ruleset_version="v1", submission_time=dt.now(), filename="file1.csv", counter=1, + user_actions=[ + UserActionDAO( + filing_id=1, + user_id="test@local.host", + user_name="submitter name", + user_email="test@local.host", + action_type=UserActionType.SUBMIT, + ), + UserActionDAO( + filing_id=1, + user_id="test@local.host", + user_name="accepter name", + user_email="test@local.host", + action_type=UserActionType.ACCEPT, + ), + ], ) submission2 = SubmissionDAO( id=2, filing=2, - submitter_id=2, state=SubmissionState.SUBMISSION_UPLOADED, validation_ruleset_version="v1", submission_time=(dt.now() - datetime.timedelta(seconds=200)), filename="file2.csv", counter=1, + user_actions=[ + UserActionDAO( + filing_id=2, + user_id="test@local.host", + user_name="submitter name", + user_email="test@local.host", + action_type=UserActionType.SUBMIT, + ), + ], ) submission3 = SubmissionDAO( id=3, filing=2, - submitter_id=2, state=SubmissionState.SUBMISSION_UPLOADED, validation_ruleset_version="v1", submission_time=dt.now(), filename="file3.csv", counter=2, + user_actions=[ + UserActionDAO( + filing_id=2, + user_id="test@local.host", + user_name="submitter name", + user_email="test@local.host", + action_type=UserActionType.SUBMIT, + ), + ], ) submission4 = SubmissionDAO( id=4, @@ -170,10 +186,6 @@ async def setup( filename="file4.csv", counter=2, ) - submission1.submitter = user_action2 - submission2.submitter = user_action2 - submission3.submitter = user_action2 - submission4.submitter = user_action2 transaction_session.add(submission1) transaction_session.add(submission2) @@ -241,37 +253,31 @@ async def test_get_filing_period(self, query_session: AsyncSession): assert res.filing_type == FilingType.ANNUAL async def test_add_filing(self, transaction_session: AsyncSession): - user_action_create = await repo.add_user_action( - transaction_session, - UserActionDTO( - user_id="123456-7890-ABCDEF-GHIJ", - user_name="test creator", - user_email="test@local.host", - action_type=UserActionType.CREATE, - ), + user_action_create = UserActionDAO( + user_id="123456-7890-ABCDEF-GHIJ", + user_name="test creator", + user_email="test@local.host", + action_type=UserActionType.CREATE, ) res = await repo.create_new_filing( - transaction_session, lei="12345ABCDE", filing_period="2024", creator_id=user_action_create.id + transaction_session, lei="12345ABCDE", filing_period="2024", creator=user_action_create ) assert res.id == 4 assert res.filing_period == "2024" assert res.lei == "12345ABCDE" assert res.institution_snapshot_id is None - assert res.creator.id == user_action_create.id - assert res.creator.user_id == "123456-7890-ABCDEF-GHIJ" - assert res.creator.user_name == "test creator" - assert res.creator.user_email == "test@local.host" - assert res.creator.action_type == UserActionType.CREATE + assert res.user_actions[0].id is not None + assert res.user_actions[0].user_id == "123456-7890-ABCDEF-GHIJ" + assert res.user_actions[0].user_name == "test creator" + assert res.user_actions[0].user_email == "test@local.host" + assert res.user_actions[0].action_type == UserActionType.CREATE async def test_modify_filing(self, transaction_session: AsyncSession): - user_action_create = await repo.add_user_action( - transaction_session, - UserActionDTO( - user_id="123456-7890-ABCDEF-GHIJ", - user_name="test creator", - user_email="test@local.host", - action_type=UserActionType.CREATE, - ), + user_action_create = UserActionDAO( + user_id="123456-7890-ABCDEF-GHIJ", + user_name="test creator", + user_email="test@local.host", + action_type=UserActionType.CREATE, ) mod_filing = FilingDAO( @@ -280,7 +286,7 @@ async def test_modify_filing(self, transaction_session: AsyncSession): institution_snapshot_id="Snapshot-2", filing_period="2024", tasks=[], - creator_id=user_action_create.id, + user_actions=[user_action_create], ) res = await repo.upsert_filing(transaction_session, mod_filing) @@ -288,18 +294,19 @@ async def test_modify_filing(self, transaction_session: AsyncSession): assert res.filing_period == "2024" assert res.lei == "ZYXWVUTSRQP" assert res.institution_snapshot_id == "Snapshot-2" - assert res.creator.id == user_action_create.id - assert res.creator.user_id == "123456-7890-ABCDEF-GHIJ" - assert res.creator.user_name == "test creator" + assert res.user_actions[0].id is not None + assert res.user_actions[0].user_id == "123456-7890-ABCDEF-GHIJ" + assert res.user_actions[0].user_name == "test creator" async def test_get_filing(self, query_session: AsyncSession, mocker: MockerFixture): res1 = await repo.get_filing(query_session, lei="1234567890", filing_period="2024") assert res1.id == 1 assert res1.filing_period == "2024" assert res1.lei == "1234567890" - assert len(res1.signatures) == 2 - assert res1.signatures[0].id == 5 - assert res1.signatures[0].user_id == "test_sig@local.host" + signatures = [action for action in res1.user_actions if action.action_type == UserActionType.SIGN] + assert len(signatures) == 2 + assert signatures[1].id == 3 + assert signatures[1].user_id == "test_sig@local.host" res2 = await repo.get_filing(query_session, lei="ABCDEFGHIJ", filing_period="2024") assert res2.id == 2 @@ -369,28 +376,27 @@ async def test_get_submissions(self, query_session: AsyncSession): assert len(res) == 0 async def test_add_submission(self, transaction_session: AsyncSession): - user_action_submit = await repo.add_user_action( - transaction_session, - UserActionDTO( - user_id="123456-7890-ABCDEF-GHIJ", - user_name="test submitter", - user_email="test@local.host", - action_type=UserActionType.SUBMIT, - ), + user_action_submit = UserActionDAO( + filing_id=1, + user_id="123456-7890-ABCDEF-GHIJ", + user_name="test submitter", + user_email="test@local.host", + action_type=UserActionType.SUBMIT, ) res = await repo.add_submission( - transaction_session, filing_id=1, filename="file1.csv", submitter_id=user_action_submit.id + transaction_session, filing_id=1, filename="file1.csv", submitter=user_action_submit ) assert res.id == 5 assert res.filing == 1 assert res.counter == 3 assert res.state == SubmissionState.SUBMISSION_STARTED - assert res.submitter.id == user_action_submit.id - assert res.submitter.user_id == user_action_submit.user_id - assert res.submitter.user_name == user_action_submit.user_name - assert res.submitter.user_email == user_action_submit.user_email - assert res.submitter.action_type == UserActionType.SUBMIT + submitter = next(action for action in res.user_actions if action.action_type == UserActionType.SUBMIT) + assert submitter.id is not None + assert submitter.user_id == user_action_submit.user_id + assert submitter.user_name == user_action_submit.user_name + assert submitter.user_email == user_action_submit.user_email + assert submitter.action_type == UserActionType.SUBMIT async def test_error_out_submission(self, transaction_session: AsyncSession): await repo.error_out_submission(4) @@ -409,7 +415,7 @@ async def test_update_submission(self, session_generator: async_scoped_session): ) async with session_generator() as add_session: res = await repo.add_submission( - add_session, filing_id=1, filename="file1.csv", submitter_id=user_action_submit.id + add_session, filing_id=1, filename="file1.csv", submitter=user_action_submit ) async with session_generator() as update_session: @@ -596,7 +602,7 @@ async def test_update_contact_info_invalid_field_length(self, transaction_sessio assert isinstance(e.value, ValidationError) async def test_get_user_action(self, query_session: AsyncSession): - res = await repo.get_user_action(session=query_session, id=3) + res = await repo.get_user_action(session=query_session, id=7) assert res.user_id == "test@local.host" assert res.user_name == "accepter name" @@ -606,7 +612,7 @@ async def test_get_user_action(self, query_session: AsyncSession): async def test_get_user_actions(self, query_session: AsyncSession): res = await repo.get_user_actions(session=query_session) - assert len(res) == 5 + assert len(res) == 9 assert res[0].id == 1 assert res[0].user_name == "signer name" @@ -616,6 +622,8 @@ async def test_add_user_action(self, query_session: AsyncSession, transaction_se accepter = await repo.add_user_action( transaction_session, UserActionDTO( + filing_id=2, + submission_id=2, user_id="test2@cfpb.gov", user_name="test2 accepter name", user_email="test2@cfpb.gov", diff --git a/tests/migrations/test_migrations.py b/tests/migrations/test_migrations.py index bb8aec29..6b1ebd12 100644 --- a/tests/migrations/test_migrations.py +++ b/tests/migrations/test_migrations.py @@ -462,3 +462,26 @@ def test_migrations_to_63138f5cf036(alembic_runner: MigrationContext, alembic_en inspector = sqlalchemy.inspect(alembic_engine) columns = inspector.get_columns("filing") assert next(c for c in columns if c["name"] == "is_voluntary")["nullable"] + + +def test_migrations_to_ef815604e2a9(alembic_runner: MigrationContext, alembic_engine: Engine): + alembic_runner.migrate_up_to("ef815604e2a9") + + inspector = sqlalchemy.inspect(alembic_engine) + user_action_columns = inspector.get_columns("user_action") + filing_id_col = next(c for c in user_action_columns if c["name"] == "filing_id") + submission_id_col = next(c for c in user_action_columns if c["name"] == "submission_id") + assert filing_id_col + assert submission_id_col + assert not filing_id_col["nullable"] + assert submission_id_col["nullable"] + + tables = inspector.get_table_names() + assert "filing_signature" not in tables + + filing_columns = inspector.get_columns("filing") + assert not [c for c in filing_columns if c["name"] == "creator_id"] + + submission_columns = inspector.get_columns("submission") + assert not [c for c in submission_columns if c["name"] == "submitter_id"] + assert not [c for c in submission_columns if c["name"] == "accepter_id"]