diff --git a/backend/app/db/models/uploaded_file.py b/backend/app/db/models/uploaded_file.py index f3cfee79..b6a73d5d 100644 --- a/backend/app/db/models/uploaded_file.py +++ b/backend/app/db/models/uploaded_file.py @@ -25,6 +25,7 @@ class FileTypeEnum(enum.Enum): class FileSourceEnum(enum.Enum): PAS_HUB = "pas hub" + COORDINATION_HUB = "coordination_hub" SHAREPOINT = "sharepoint" HUBSPOT = "hubspot" ECMK = "ecmk" diff --git a/backend/pashub_fetcher/pashub_service.py b/backend/pashub_fetcher/pashub_service.py index 13498a32..f7f6ccd9 100644 --- a/backend/pashub_fetcher/pashub_service.py +++ b/backend/pashub_fetcher/pashub_service.py @@ -60,9 +60,10 @@ class PashubService: else: try: uprn = active_client.get_uprn_by_job_id(job_id) - logger.info(f"Failed to access job {job_id} with PasHub credentials") except UnauthorizedError: - logger.info(f"Trying CoordinationHub credentials for job {job_id}") + logger.info( + f"PasHub credentials unauthorized for job {job_id}; retrying with CoordinationHub credentials" + ) active_client = self._get_coordination_client() uprn = active_client.get_uprn_by_job_id(job_id) @@ -85,8 +86,13 @@ class PashubService: if uprn or hubspot_deal_id: logger.info("Uploading files to s3") + file_source = ( + FileSourceEnum.PAS_HUB + if active_client is self._pashub_client + else FileSourceEnum.COORDINATION_HUB + ) upload_records = self._upload_to_s3_and_update_db( - job_files, uprn, hubspot_deal_id + job_files, uprn, hubspot_deal_id, file_source ) self._save_site_notes(upload_records) @@ -108,6 +114,7 @@ class PashubService: job_files: List[str], uprn: Optional[str], hubspot_deal_id: Optional[str], + file_source: FileSourceEnum, ) -> List[_FileUploadRecord]: if not uprn and not hubspot_deal_id: return [] @@ -133,7 +140,7 @@ class PashubService: s3_upload_timestamp=datetime.now(timezone.utc), uprn=int(uprn) if uprn else None, hubspot_deal_id=hubspot_deal_id, - file_source=FileSourceEnum.PAS_HUB.value, + file_source=file_source.value, file_type=get_file_type_string(filename), ) file_paths.append(file_path) diff --git a/backend/pashub_fetcher/tests/test_pashub_service.py b/backend/pashub_fetcher/tests/test_pashub_service.py index 991d2a46..1f750117 100644 --- a/backend/pashub_fetcher/tests/test_pashub_service.py +++ b/backend/pashub_fetcher/tests/test_pashub_service.py @@ -1,8 +1,9 @@ import pytest -from typing import Callable, Optional +from typing import Any, Callable, Optional from unittest.mock import MagicMock, call, patch +from backend.app.db.models.uploaded_file import FileSourceEnum from backend.pashub_fetcher.pashub_client import PashubClient, UnauthorizedError from backend.pashub_fetcher.pashub_service import PashubService from backend.pashub_fetcher.pashub_to_ara_trigger_request import ( @@ -147,10 +148,11 @@ def test_run_persists_uploaded_file_records_to_db() -> None: service.run(make_request(uprn="12345")) fake_session.add_all.assert_called_once() - added: list = fake_session.add_all.call_args[0][0] + added: list[Any] = fake_session.add_all.call_args[0][0] assert len(added) == 1 assert added[0].s3_file_bucket == "test-bucket" assert added[0].uprn == 12345 + assert added[0].file_source == FileSourceEnum.PAS_HUB.value # --------------------------------------------------------------------------- @@ -306,6 +308,57 @@ def test_run_raises_unauthorized_when_both_clients_401() -> None: service.run(make_request()) +def test_run_persists_coordination_hub_file_source_when_pas_401_on_uprn_lookup() -> None: + pas_client = MagicMock(spec=PashubClient) + pas_client.get_uprn_by_job_id.side_effect = UnauthorizedError() + + coord_client = MagicMock(spec=PashubClient) + coord_client.get_uprn_by_job_id.return_value = "99999" + coord_client.get_core_evidence_files_by_job_id.return_value = ["/tmp/a.pdf"] + + factory = MagicMock(return_value=coord_client) + fake_session = MagicMock() + + service = make_service(pashub_client=pas_client, coordination_client_factory=factory) + + with ( + patch("backend.pashub_fetcher.pashub_service.upload_file_to_s3"), + patch("backend.pashub_fetcher.pashub_service.db_session") as mock_db, + patch("backend.pashub_fetcher.pashub_service.os.remove"), + ): + mock_db.return_value.__enter__.return_value = fake_session + service.run(make_request()) + + fake_session.add_all.assert_called_once() + added: list[Any] = fake_session.add_all.call_args[0][0] + assert added[0].file_source == FileSourceEnum.COORDINATION_HUB.value + + +def test_run_persists_coordination_hub_file_source_when_pas_401_on_file_listing() -> None: + pas_client = MagicMock(spec=PashubClient) + pas_client.get_core_evidence_files_by_job_id.side_effect = UnauthorizedError() + + coord_client = MagicMock(spec=PashubClient) + coord_client.get_core_evidence_files_by_job_id.return_value = ["/tmp/a.pdf"] + + factory = MagicMock(return_value=coord_client) + fake_session = MagicMock() + + service = make_service(pashub_client=pas_client, coordination_client_factory=factory) + + with ( + patch("backend.pashub_fetcher.pashub_service.upload_file_to_s3"), + patch("backend.pashub_fetcher.pashub_service.db_session") as mock_db, + patch("backend.pashub_fetcher.pashub_service.os.remove"), + ): + mock_db.return_value.__enter__.return_value = fake_session + service.run(make_request(uprn="12345")) + + fake_session.add_all.assert_called_once() + added: list[Any] = fake_session.add_all.call_args[0][0] + assert added[0].file_source == FileSourceEnum.COORDINATION_HUB.value + + def test_run_warns_and_continues_when_site_notes_parsing_fails() -> None: mock_client = MagicMock(spec=PashubClient) mock_client.get_uprn_by_job_id.return_value = None