Exemple #1
0
    def test_clients_for_officer(self) -> None:
        officer_1 = generate_fake_officer("id_1")
        officer_2 = generate_fake_officer("id_2")
        officer_3 = generate_fake_officer("id_3")
        client_1 = generate_fake_client("client_1", "id_1")
        client_2 = generate_fake_client("client_2", "id_1")
        client_3 = generate_fake_client("client_3", "id_2")
        session = SessionFactory.for_schema_base(CaseTriageBase)
        session.add(officer_1)
        session.add(officer_2)
        session.add(officer_3)
        session.add(client_1)
        session.add(client_2)
        session.add(client_3)
        session.commit()

        read_session = SessionFactory.for_schema_base(CaseTriageBase)
        self.assertEqual(
            len(CaseTriageQuerier.clients_for_officer(read_session,
                                                      officer_1)),
            2,
        )
        self.assertEqual(
            len(CaseTriageQuerier.clients_for_officer(read_session,
                                                      officer_2)),
            1,
        )
        self.assertEqual(
            len(CaseTriageQuerier.clients_for_officer(read_session,
                                                      officer_3)),
            0,
        )
Exemple #2
0
    def test_clients_for_officer(self) -> None:
        officer_1 = generate_fake_officer("id_1")
        officer_2 = generate_fake_officer("id_2")
        officer_3 = generate_fake_officer("id_3")
        auth_store = AuthorizationStore()
        user_context_1 = UserContext(
            email=officer_1.email_address,
            authorization_store=auth_store,
            current_user=officer_1,
        )
        user_context_2 = UserContext(
            email=officer_2.email_address,
            authorization_store=auth_store,
            current_user=officer_2,
        )
        user_context_3 = UserContext(
            email=officer_3.email_address,
            authorization_store=auth_store,
            current_user=officer_3,
        )
        client_1 = generate_fake_client("client_1",
                                        supervising_officer_id="id_1")
        client_2 = generate_fake_client("client_2",
                                        supervising_officer_id="id_1")
        client_3 = generate_fake_client("client_3",
                                        supervising_officer_id="id_2")
        with SessionFactory.using_database(self.database_key) as session:
            session.expire_on_commit = False
            session.add(officer_1)
            session.add(officer_2)
            session.add(officer_3)
            session.add(client_1)
            session.add(client_2)
            session.add(client_3)

        with SessionFactory.using_database(self.database_key,
                                           autocommit=False) as read_session:
            self.assertEqual(
                len(
                    CaseTriageQuerier.clients_for_officer(
                        read_session, user_context_1)),
                2,
            )
            self.assertEqual(
                len(
                    CaseTriageQuerier.clients_for_officer(
                        read_session, user_context_2)),
                1,
            )
            self.assertEqual(
                len(
                    CaseTriageQuerier.clients_for_officer(
                        read_session, user_context_3)),
                0,
            )
Exemple #3
0
    def test_fetch_officer_id_happy_path(self) -> None:
        officer_1 = generate_fake_officer("id_1", "*****@*****.**")
        officer_2 = generate_fake_officer("id_2", "*****@*****.**")
        session = SessionFactory.for_schema_base(CaseTriageBase)
        session.add(officer_1)
        session.add(officer_2)
        session.commit()

        read_session = SessionFactory.for_schema_base(CaseTriageBase)
        first_fetch = CaseTriageQuerier.officer_for_email(
            read_session, "*****@*****.**")
        self.assertEqual(first_fetch.external_id, "id_1")
        second_fetch = CaseTriageQuerier.officer_for_email(
            read_session, "*****@*****.**")
        self.assertEqual(second_fetch.external_id, "id_2")
Exemple #4
0
    def test_fetch_officer_id_happy_path(self) -> None:
        officer_1 = generate_fake_officer("id_1", "*****@*****.**")
        officer_2 = generate_fake_officer("id_2", "*****@*****.**")
        with SessionFactory.using_database(self.database_key) as session:
            session.add(officer_1)
            session.add(officer_2)

        with SessionFactory.using_database(self.database_key,
                                           autocommit=False) as read_session:
            first_fetch = CaseTriageQuerier.officer_for_email(
                read_session, "*****@*****.**")
            self.assertEqual(first_fetch.external_id, "id_1")
            second_fetch = CaseTriageQuerier.officer_for_email(
                read_session, "*****@*****.**")
            self.assertEqual(second_fetch.external_id, "id_2")
Exemple #5
0
 def test_officer_for_hashed_email(_: Session,
                                   _hashed_email: str) -> ETLOfficer:
     return generate_fake_officer(
         officer_id="test",
         email="*****@*****.**",
         state_code="US_XX",
     )
Exemple #6
0
    def test_fetch_officer_by_hash(self) -> None:
        officer_1 = generate_fake_officer("id_1", "*****@*****.**")
        officer_2 = generate_fake_officer("id_2", "*****@*****.**")
        with SessionFactory.using_database(self.database_key) as session:
            session.add(officer_1)
            session.add(officer_2)

        with SessionFactory.using_database(self.database_key,
                                           autocommit=False) as read_session:
            fetch_by_email_address = CaseTriageQuerier.officer_for_hashed_email(
                read_session, hash_email("*****@*****.**"))
            self.assertEqual(fetch_by_email_address.external_id, "id_1")
            fetch_by_hashed_email = CaseTriageQuerier.officer_for_hashed_email(
                read_session,
                hash_email("*****@*****.**"),
            )
            self.assertEqual(fetch_by_hashed_email.external_id, "id_2")
    def setUp(self) -> None:
        local_postgres_helpers.use_on_disk_postgresql_database(CaseTriageBase)

        self.mock_officer = generate_fake_officer("id_1")
        self.mock_client = generate_fake_client(
            "person_id_1",
            last_assessment_date=date(2021, 2, 1),
        )
 def setUp(self) -> None:
     self.mock_officer = generate_fake_officer("officer_id_1")
     self.mock_client = generate_fake_client(
         "person_id_1",
         supervising_officer_id=self.mock_officer.external_id,
         last_assessment_date=date(2021, 2, 1),
         last_face_to_face_date=date(2021, 1, 15),
     )
     self.mock_client.case_updates = []
 def test_admin_can_impersonate_all_states(self) -> None:
     self.assertTrue(
         self.auth_store.can_impersonate(
             "*****@*****.**",
             generate_fake_officer(
                 officer_id="test",
                 email="*****@*****.**",
             ),
         )
     )
 def test_cannot_impersonate_own_self(self) -> None:
     self.assertFalse(
         self.auth_store.can_impersonate(
             "*****@*****.**",
             generate_fake_officer(
                 officer_id="test",
                 email="*****@*****.**",
                 state_code="US_XX",
             ),
         )
     )
Exemple #11
0
    def test_no_opportunities_reported(self) -> None:
        no_opportunity_officer = generate_fake_officer(
            "no_opportunity_officer", "*****@*****.**"
        )
        with SessionFactory.using_database(self.database_key) as session:
            session.expire_on_commit = False
            session.add(no_opportunity_officer)

        self.assertEqual(
            [], _get_mismatch_data_for_officer(no_opportunity_officer.email_address)
        )
 def test_can_impersonate_US_XX(self, email: str, can_impersonate: bool) -> None:
     self.assertEqual(
         self.auth_store.can_impersonate(
             email,
             generate_fake_officer(
                 officer_id="test",
                 email="*****@*****.**",
                 state_code="US_XX",
             ),
         ),
         can_impersonate,
     )
Exemple #13
0
    def test_etl_client_for_officer(self) -> None:
        officer_1 = generate_fake_officer("officer_1")
        officer_2 = generate_fake_officer("officer_2")
        auth_store = AuthorizationStore()
        user_context_1 = UserContext(
            email=officer_1.email_address,
            authorization_store=auth_store,
            current_user=officer_1,
        )
        user_context_2 = UserContext(
            email=officer_2.email_address,
            authorization_store=auth_store,
            current_user=officer_2,
        )
        client_1 = generate_fake_client(
            "client_1", supervising_officer_id=officer_1.external_id)
        with SessionFactory.using_database(self.database_key) as session:
            session.expire_on_commit = False
            session.add(officer_1)
            session.add(officer_2)
            session.add(client_1)

        with SessionFactory.using_database(self.database_key,
                                           autocommit=False) as read_session:
            # Client does not exist at all
            with self.assertRaises(PersonDoesNotExistError):
                CaseTriageQuerier.etl_client_for_officer(
                    read_session, user_context_1, "nonexistent")

            # Client does not exist for the officer
            with self.assertRaises(PersonDoesNotExistError):
                CaseTriageQuerier.etl_client_for_officer(
                    read_session, user_context_2, "client_1")

            # Should not raise an error
            CaseTriageQuerier.etl_client_for_officer(read_session,
                                                     user_context_1,
                                                     "client_1")
    def setUp(self) -> None:
        self.database_key = SQLAlchemyDatabaseKey.for_schema(
            SchemaType.CASE_TRIAGE)
        local_postgres_helpers.use_on_disk_postgresql_database(
            self.database_key)

        self.mock_officer = generate_fake_officer("id_1")
        self.mock_client = generate_fake_client(
            "person_id_1",
            last_assessment_date=date(2021, 2, 1),
        )
        self.mock_context = UserContext(
            email=self.mock_officer.email_address,
            authorization_store=AuthorizationStore(),
            current_user=self.mock_officer,
        )
Exemple #15
0
    def test_opportunities_for_officer(self) -> None:
        officer = generate_fake_officer("officer_1")
        user_context = UserContext(
            current_user=officer,
            authorization_store=AuthorizationStore(),
            email=officer.email_address,
        )
        client = generate_fake_client(
            "client_1", supervising_officer_id=officer.external_id)
        etl_opp = generate_fake_etl_opportunity(
            officer_id=officer.external_id,
            person_external_id=client.person_external_id)
        etl_reminder = generate_fake_reminder(etl_opp)
        with SessionFactory.using_database(self.database_key) as session:
            session.expire_on_commit = False
            session.add(officer)
            session.add(client)
            session.add(etl_opp)
            session.add(etl_reminder)

        with SessionFactory.using_database(self.database_key) as read_session:
            # expect a non-etl opportunity that we want to mark as deferred
            reminder = generate_fake_reminder(
                opportunity=CaseTriageQuerier.opportunities_for_officer(
                    read_session, user_context)[1].opportunity)

        with SessionFactory.using_database(self.database_key) as session:
            session.add(reminder)

        with SessionFactory.using_database(self.database_key) as read_session:
            queried_opps = CaseTriageQuerier.opportunities_for_officer(
                read_session, user_context)

            self.assertEqual(len(queried_opps), 2)

            employment_opp = queried_opps[1]

            self.assertEqual(
                employment_opp.opportunity.opportunity_type,
                OpportunityType.EMPLOYMENT.value,
            )
            self.assertTrue(employment_opp.is_deferred())
Exemple #16
0
    def test_newest_5_mismatches_reported(self) -> None:
        # Since all opportunities are sooner than the cutoff, we take the 5 oldest.
        many_opportunities_officer = generate_fake_officer(
            "many_opportunities_officer", "*****@*****.**"
        )
        many_opportunity_clients = [
            generate_fake_client(
                client_id=f"many_opportunities_client_{i}",
                supervising_officer_id=many_opportunities_officer.external_id,
                supervision_level=StateSupervisionLevel.MEDIUM,
                last_assessment_date=date(2021, 1, i + 1),
                assessment_score=1,
            )
            for i in range(6)
        ]
        opportunities = [
            generate_fake_etl_opportunity(
                officer_id=many_opportunities_officer.external_id,
                person_external_id=client.person_external_id,
                opportunity_type=OpportunityType.OVERDUE_DOWNGRADE,
                opportunity_metadata={
                    "assessmentScore": client.assessment_score,
                    "latestAssessmentDate": str(client.most_recent_assessment_date),
                    "recommendedSupervisionLevel": "MINIMUM",
                },
            )
            for client in many_opportunity_clients
        ]
        with SessionFactory.using_database(self.database_key) as session:
            session.expire_on_commit = False
            session.add_all(
                [many_opportunities_officer, *many_opportunity_clients, *opportunities]
            )

        mismatches = _get_mismatch_data_for_officer(
            many_opportunities_officer.email_address
        )
        self.assertCountEqual(
            [mismatch["person_external_id"] for mismatch in mismatches],
            [client.person_external_id for client in many_opportunity_clients[:5]],
        )
Exemple #17
0
    def setUp(self) -> None:
        self.metadata_patcher = mock.patch(
            "recidiviz.utils.metadata.project_id")
        self.metadata_patcher.start().return_value = "recidiviz-456"

        self.auth_store = AuthorizationStore()
        self.officer = generate_fake_officer("officer_id_1",
                                             "*****@*****.**")

        self.test_app = Flask(__name__)
        self.test_app.secret_key = "NOT-A-SECRET"
        self.helpers = CaseTriageTestHelpers.from_test(self, self.test_app)
        self.test_client = self.helpers.test_client

        @self.test_app.errorhandler(FlaskException)
        def _handle_auth_error(ex: FlaskException) -> Response:
            response = jsonify({
                "code": ex.code,
                "description": ex.description,
            })
            response.status_code = ex.status_code
            return response
Exemple #18
0
    def setUp(self) -> None:
        self.project_id_patcher = patch("recidiviz.utils.metadata.project_id")
        self.email_generation_patcher = patch(
            "recidiviz.reporting.email_generation.generate"
        )
        self.gcs_file_system_patcher = patch(
            "recidiviz.cloud_storage.gcsfs_factory.GcsfsFactory.build"
        )
        self.project_id_patcher.start().return_value = "recidiviz-test"
        self.mock_email_generation = self.email_generation_patcher.start()
        self.gcs_file_system = FakeGCSFileSystem()
        self.mock_gcs_file_system = self.gcs_file_system_patcher.start()
        self.mock_gcs_file_system.return_value = self.gcs_file_system

        self.get_secret_patcher = patch("recidiviz.utils.secrets.get_secret")
        self.get_secret_patcher.start()

        self.state_code = StateCode.US_ID

        self.database_key = SQLAlchemyDatabaseKey.for_schema(SchemaType.CASE_TRIAGE)
        local_postgres_helpers.use_on_disk_postgresql_database(self.database_key)

        self.officer = generate_fake_officer("officer_id_1", "*****@*****.**")
        self.client_downgradable_high = generate_fake_client(
            client_id="client_1",
            supervising_officer_id=self.officer.external_id,
            supervision_level=StateSupervisionLevel.HIGH,
            last_assessment_date=date(2021, 1, 2),
            assessment_score=1,
        )
        self.client_downgradable_medium_1 = generate_fake_client(
            client_id="client_2",
            supervising_officer_id=self.officer.external_id,
            supervision_level=StateSupervisionLevel.MEDIUM,
            last_assessment_date=date(2021, 1, 2),
            assessment_score=1,
        )
        self.client_downgradable_medium_2 = generate_fake_client(
            client_id="client_3",
            supervising_officer_id=self.officer.external_id,
            supervision_level=StateSupervisionLevel.MEDIUM,
            last_assessment_date=date(2021, 1, 2),
            assessment_score=1,
        )
        self.client_no_downgrade = generate_fake_client(
            client_id="client_4",
            supervising_officer_id=self.officer.external_id,
            supervision_level=StateSupervisionLevel.HIGH,
            last_assessment_date=date(2021, 1, 2),
            assessment_score=100,
        )
        self.opportunities = [
            generate_fake_etl_opportunity(
                officer_id=self.officer.external_id,
                person_external_id=client.person_external_id,
                opportunity_type=OpportunityType.OVERDUE_DOWNGRADE,
                opportunity_metadata={
                    "assessmentScore": client.assessment_score,
                    "latestAssessmentDate": str(client.most_recent_assessment_date),
                    "recommendedSupervisionLevel": "MINIMUM",
                },
            )
            for client in [
                self.client_downgradable_high,
                self.client_downgradable_medium_1,
                self.client_downgradable_medium_2,
            ]
        ]

        with SessionFactory.using_database(self.database_key) as session:
            session.expire_on_commit = False
            session.add_all(
                [
                    self.officer,
                    self.client_downgradable_high,
                    self.client_downgradable_medium_1,
                    self.client_downgradable_medium_2,
                    self.client_no_downgrade,
                    *self.opportunities,
                ]
            )

        self.top_opps_email_recipient_patcher = patch(
            "recidiviz.reporting.data_retrieval._top_opps_email_recipient_addresses"
        )
        self.top_opps_email_recipient_patcher.start().return_value = [
            self.officer.email_address
        ]
Exemple #19
0
 def test_officer_for_email(_: Session, email: str) -> ETLOfficer:
     return generate_fake_officer(officer_id="test", email=email)
Exemple #20
0
 def mock_officer_hash(_session: Session,
                       hashed_email: str) -> ETLOfficer:
     if hashed_email == self.officer.hashed_email_address:
         return self.officer
     return generate_fake_officer("test", self.officer.email_address)
Exemple #21
0
    def setUp(self) -> None:
        self.test_app = Flask(__name__)
        self.helpers = CaseTriageTestHelpers.from_test(self, self.test_app)
        self.test_client = self.helpers.test_client
        self.mock_segment_client = self.helpers.mock_segment_client

        self.database_key = SQLAlchemyDatabaseKey.for_schema(
            SchemaType.CASE_TRIAGE)
        self.overridden_env_vars = (
            local_postgres_helpers.update_local_sqlalchemy_postgres_env_vars())
        db_url = local_postgres_helpers.postgres_db_url_from_env_vars()
        engine = setup_scoped_sessions(self.test_app, db_url)
        # Auto-generate all tables that exist in our schema in this database
        self.database_key.declarative_meta.metadata.create_all(engine)
        self.session = self.test_app.scoped_session

        # Add seed data
        self.officer = generate_fake_officer("officer_id_1",
                                             "*****@*****.**")
        self.officer_without_clients = generate_fake_officer(
            "officer_id_2", "*****@*****.**")
        self.client_1 = generate_fake_client(
            client_id="client_1",
            supervising_officer_id=self.officer.external_id,
        )
        self.client_2 = generate_fake_client(
            client_id="client_2",
            supervising_officer_id=self.officer.external_id,
            last_assessment_date=date(2021, 2, 2),
        )
        self.client_3 = generate_fake_client(
            client_id="client_3",
            supervising_officer_id=self.officer.external_id,
        )
        self.client_info_3 = generate_fake_client_info(
            client=self.client_3,
            preferred_name="Alex",
        )
        self.case_update_1 = generate_fake_case_update(
            self.client_1,
            self.officer.external_id,
            action_type=CaseUpdateActionType.COMPLETED_ASSESSMENT,
            last_version=serialize_client_case_version(
                CaseUpdateActionType.COMPLETED_ASSESSMENT,
                self.client_1).to_json(),
        )
        self.case_update_2 = generate_fake_case_update(
            self.client_2,
            self.officer_without_clients.external_id,
            action_type=CaseUpdateActionType.COMPLETED_ASSESSMENT,
            last_version=serialize_client_case_version(
                CaseUpdateActionType.COMPLETED_ASSESSMENT,
                self.client_2).to_json(),
        )
        self.case_update_3 = generate_fake_case_update(
            self.client_1,
            self.officer.external_id,
            action_type=CaseUpdateActionType.NOT_ON_CASELOAD,
            last_version=serialize_client_case_version(
                CaseUpdateActionType.NOT_ON_CASELOAD, self.client_1).to_json(),
        )
        self.client_2.most_recent_assessment_date = date(2022, 2, 2)

        self.opportunity_1 = generate_fake_etl_opportunity(
            officer_id=self.officer.external_id,
            person_external_id=self.client_1.person_external_id,
        )
        tomorrow = datetime.now() + timedelta(days=1)
        self.deferral_1 = generate_fake_reminder(self.opportunity_1, tomorrow)
        self.opportunity_2 = generate_fake_etl_opportunity(
            officer_id=self.officer.external_id,
            person_external_id=self.client_2.person_external_id,
        )
        # all generated fake clients have no employer
        self.num_unemployed_opportunities = 3

        self.session.add_all([
            self.officer,
            self.officer_without_clients,
            self.client_1,
            self.client_2,
            self.client_3,
            self.client_info_3,
            self.case_update_1,
            self.case_update_2,
            self.case_update_3,
            self.opportunity_1,
            self.deferral_1,
            self.opportunity_2,
        ])
        self.session.commit()
Exemple #22
0
    def setUp(self) -> None:
        self.test_app = Flask(__name__)
        self.test_app.register_blueprint(api)
        self.test_client = self.test_app.test_client()

        @self.test_app.errorhandler(FlaskException)
        def _handle_auth_error(ex: FlaskException) -> Response:
            response = jsonify({
                "code": ex.code,
                "description": ex.description,
            })
            response.status_code = ex.status_code
            return response

        self.overridden_env_vars = (
            local_postgres_helpers.update_local_sqlalchemy_postgres_env_vars())
        db_url = local_postgres_helpers.postgres_db_url_from_env_vars()
        setup_scoped_sessions(self.test_app, db_url)

        # Add seed data
        self.officer_1 = generate_fake_officer("officer_id_1")
        self.officer_2 = generate_fake_officer("officer_id_2")
        self.client_1 = generate_fake_client(
            client_id="client_1",
            supervising_officer_id=self.officer_1.external_id,
        )
        self.client_2 = generate_fake_client(
            client_id="client_2",
            supervising_officer_id=self.officer_1.external_id,
            last_assessment_date=date(2021, 2, 2),
        )
        self.case_update_1 = CaseUpdate(
            person_external_id=self.client_1.person_external_id,
            officer_external_id=self.client_1.supervising_officer_external_id,
            state_code=self.client_1.state_code,
            update_metadata={
                "actions":
                CaseUpdatesInterface.serialize_actions(
                    self.client_1,
                    [CaseUpdateActionType.COMPLETED_ASSESSMENT],
                ),
            },
        )
        self.case_update_2 = CaseUpdate(
            person_external_id=self.client_2.person_external_id,
            officer_external_id=self.client_2.supervising_officer_external_id,
            state_code=self.client_2.state_code,
            update_metadata={
                "actions":
                CaseUpdatesInterface.serialize_actions(
                    self.client_2,
                    [CaseUpdateActionType.COMPLETED_ASSESSMENT],
                ),
            },
        )
        self.client_2.most_recent_assessment_date = date(2022, 2, 2)

        sess = SessionFactory.for_schema_base(CaseTriageBase)
        sess.add(self.officer_1)
        sess.add(self.client_1)
        sess.add(self.client_2)
        sess.add(self.case_update_1)
        sess.add(self.case_update_2)
        sess.commit()
Exemple #23
0
 def mock_officer(_session: Session, email: str) -> ETLOfficer:
     if email == self.officer.email_address:
         return self.officer
     return generate_fake_officer("test", email)
    def setUp(self) -> None:
        self.get_local_patcher = mock.patch(
            "recidiviz.case_triage.authorization.get_local_file",
            new=_test_get_local_file,
        )
        self.get_local_patcher.start()

        self.auth_store = AuthorizationStore()
        self.auth_store.refresh()

        self.database_key = SQLAlchemyDatabaseKey.for_schema(SchemaType.CASE_TRIAGE)
        local_postgres_helpers.use_on_disk_postgresql_database(self.database_key)

        self.case_triage_user = generate_fake_user_restrictions(
            "US_XX",
            "*****@*****.**",
            can_access_leadership_dashboard=False,
            can_access_case_triage=True,
        )
        self.dashboard_user = generate_fake_user_restrictions(
            "US_XX",
            "*****@*****.**",
            can_access_leadership_dashboard=True,
            can_access_case_triage=False,
        )
        self.both_user = generate_fake_user_restrictions(
            "US_XX",
            "*****@*****.**",
            can_access_leadership_dashboard=True,
            can_access_case_triage=True,
        )

        self.overridden_user = generate_fake_user_restrictions(
            "US_XX",
            "*****@*****.**",
            can_access_leadership_dashboard=True,
            can_access_case_triage=False,
        )

        self.both_user_different_state = generate_fake_user_restrictions(
            "US_YY",
            "*****@*****.**",
            can_access_leadership_dashboard=True,
            can_access_case_triage=True,
        )

        self.officer = generate_fake_officer(
            "test", "*****@*****.**", state_code="US_XX"
        )

        with SessionFactory.using_database(self.database_key) as session:
            session.expire_on_commit = False
            session.add_all(
                [
                    self.case_triage_user,
                    self.dashboard_user,
                    self.both_user,
                    self.overridden_user,
                    self.both_user_different_state,
                    self.officer,
                ]
            )