def test_preflight_valid(self):
        # setup pre-flight conditions expected to pass
        ds_p3p = INTERVENTION.decision_support_p3p
        ds_client = Client(client_id='12345',
                           client_secret='54321',
                           user_id=TEST_USER_ID,
                           intervention=ds_p3p,
                           _redirect_uris='http://testsite.org',
                           callback_url='http://callback.one')
        service = self.add_service_user(sponsor=self.test_user)

        with SessionScope(db):
            db.session.add(ds_client)
            db.session.commit()

        ds_client = db.session.merge(ds_client)
        service = db.session.merge(service)
        create_service_token(client=ds_client, user=service)

        # Export
        sp = SitePersistence(target_dir=self.tmpdir)
        sp.export(staging_exclusion=True)

        assert Token.query.count() == 1

        # Delete service account, expect it to return
        with SessionScope(db):
            db.session.delete(service)
            db.session.commit()

        assert User.query.count() == 1
        assert Token.query.count() == 0

        # Import
        sp.import_(keep_unmentioned=True, staging_exclusion=True)

        assert Token.query.count() == 1
        assert User.query.count() == 2
Пример #2
0
    def test_unique(self):
        """Try adding a non-unique identifier, expect exception"""
        constrained = Identifier(
            system='http://us.truenth.org/identity-codes/external-study-id',
            value='unique-one')
        with SessionScope(db):
            db.session.add(constrained)
        second_user = self.add_user('second')
        constrained = db.session.merge(constrained)
        second_user.add_identifier(constrained)

        user = db.session.merge(self.test_user)
        with pytest.raises(Conflict):
            user.add_identifier(constrained)
Пример #3
0
    def shallow_org_tree(self):
        """Create shallow org tree for common test needs"""
        org_101 = Organization(id=101, name='101')
        org_102 = Organization(id=102, name='102')
        org_1001 = Organization(id=1001, name='1001', partOf_id=101)

        already_done = Organization.query.get(101)
        if already_done:
            return

        with SessionScope(db):
            [db.session.add(org) for org in (org_101, org_102, org_1001)]
            db.session.commit()
        OrgTree.invalidate_cache()
Пример #4
0
 def test_ill_formed_ident_search(self):
     ident = Identifier(system='http://example.com', value='testy')
     ui = UserIdentifier(identifier=ident, user_id=TEST_USER_ID)
     with SessionScope(db):
         db.session.add(ident)
         db.session.add(ui)
         db.session.commit()
     self.promote_user(role_name=ROLE.PATIENT)
     self.login()
     ident = db.session.merge(ident)
     rv = self.client.get(
         '/api/patient?identifier=system"http://example.com",value="testy"',
         follow_redirects=True)
     self.assert400(rv)
Пример #5
0
    def test_group_list(self):
        grp1 = Group(name='test_1')
        grp2 = Group(name='test_2')
        with SessionScope(db):
            db.session.add(grp1)
            db.session.add(grp2)
            db.session.commit()

        # use api to obtain list
        self.login()
        rv = self.client.get('/api/group/')
        self.assert200(rv)
        bundle = rv.json
        self.assertEquals(len(bundle['groups']), 2)
Пример #6
0
 def create_fake_relationships(self):
     other_user = self.add_user(username='******')
     partner = Relationship.query.filter_by(name='partner').first()
     rel = UserRelationship(user_id=TEST_USER_ID,
                            relationship_id=partner.id,
                            other_user_id=other_user.id)
     sponsor = Relationship.query.filter_by(name='sponsor').first()
     rel2 = UserRelationship(user_id=other_user.id,
                            relationship_id=sponsor.id,
                            other_user_id=TEST_USER_ID)
     with SessionScope(db):
         db.session.add(rel)
         db.session.add(rel2)
         db.session.commit()
Пример #7
0
    def test_get(self):
        audit = Audit(user_id=TEST_USER_ID, subject_id=TEST_USER_ID)
        tou = ToU(audit=audit,
                  agreement_url=tou_url,
                  type='website terms of use')
        with SessionScope(db):
            db.session.add(tou)
            db.session.commit()

        self.login()
        rv = self.client.get('/api/user/{}/tou'.format(TEST_USER_ID))
        doc = json.loads(rv.data)
        self.assert200(rv)
        self.assertEquals(len(doc['tous']), 1)
Пример #8
0
    def test_get(self):
        audit = Audit(user_id=TEST_USER_ID, subject_id=TEST_USER_ID)
        tou = ToU(audit=audit,
                  agreement_url=tou_url,
                  type='website terms of use')
        with SessionScope(db):
            db.session.add(tou)
            db.session.commit()

        self.login()
        response = self.client.get('/api/user/{}/tou'.format(TEST_USER_ID))
        doc = response.json
        assert response.status_code == 200
        assert len(doc['tous']) == 1
 def test_ident_search(self):
     ident = Identifier(system='http://example.com', value='testy')
     ui = UserIdentifier(identifier=ident, user_id=TEST_USER_ID)
     with SessionScope(db):
         db.session.add(ident)
         db.session.add(ui)
         db.session.commit()
     self.promote_user(role_name=ROLE.PATIENT.value)
     self.login()
     ident = db.session.merge(ident)
     response = self.client.get('/api/patient?identifier={}'.format(
         json.dumps(ident.as_fhir())),
                                follow_redirects=True)
     assert response.status_code == 200
Пример #10
0
    def test_group_list(self):
        grp1 = Group(name='test_1')
        grp2 = Group(name='test_2')
        with SessionScope(db):
            db.session.add(grp1)
            db.session.add(grp2)
            db.session.commit()

        # use api to obtain list
        self.login()
        response = self.client.get('/api/group/')
        assert response.status_code == 200
        bundle = response.json
        assert len(bundle['groups']) == 2
Пример #11
0
    def test_organization_search(self):
        self.shallow_org_tree()
        count = Organization.query.count()
        assert count > 1

        # add region to one org, we should get only that one back
        region = Identifier(value='state:NY', system=PRACTICE_REGION)
        with SessionScope(db):
            db.session.add(region)
            db.session.commit()
        region = db.session.merge(region)
        oi = OrganizationIdentifier(organization_id=1001,
                                    identifier_id=region.id)
        with SessionScope(db):
            db.session.add(oi)
            db.session.commit()

        # use api to obtain FHIR bundle
        self.login()
        response = self.client.get('/api/organization?state=NY')
        assert response.status_code == 200
        bundle = response.json
        assert bundle['resourceType'] == 'Bundle'
        assert len(bundle['entry']) == 1
Пример #12
0
    def test_unique_deleted(self):
        """Try adding a non-unique identifier from deleted user"""
        constrained = Identifier(
            system='http://us.truenth.org/identity-codes/external-study-id',
            value='unique-one')
        with SessionScope(db):
            db.session.add(constrained)
        second_user = self.add_user('second')
        constrained = db.session.merge(constrained)
        second_user.add_identifier(constrained)
        second_user.delete_user(acting_user=self.test_user)

        user = db.session.merge(self.test_user)
        user.add_identifier(constrained)
        assert constrained in user.identifiers
    def test_delete_unnamed(self):
        keeper = AppText(name='keep me', custom_text='worthy')
        mp = ModelPersistence(
            AppText, lookup_field='name', sequence_name='apptext_id_seq',
            target_dir=self.tmpdir)
        with SessionScope(db):
            db.session.add(keeper)
            db.session.commit()
        mp.export()

        # Add another app text, expecting it'll be removed
        bogus = AppText(name='temp', custom_text='not worthy')
        with SessionScope(db):
            db.session.add(bogus)
            db.session.commit()

        # Import w/ keep_unmentioned and expect both
        mp.import_(keep_unmentioned=True)
        assert AppText.query.count() == 2

        # Now import, and expect only keeper to remain
        mp.import_(keep_unmentioned=False)
        assert AppText.query.count() == 1
        assert AppText.query.first().name == 'keep me'
Пример #14
0
    def test_lookup_for_user(self):
        crv = Organization(name='CRV')
        epic26 = Questionnaire(name='epic26')
        eproms_add = Questionnaire(name='eproms_add')
        comorb = Questionnaire(name='comorb')
        with SessionScope(db):
            db.session.add(crv)
            db.session.add(epic26)
            db.session.add(eproms_add)
            db.session.add(comorb)
            db.session.commit()
        crv, epic26, eproms_add, comorb = map(
            db.session.merge, (crv, epic26, eproms_add, comorb))

        bank = QuestionnaireBank(name='CRV', organization_id=crv.id)
        for rank, q in enumerate((epic26, eproms_add, comorb)):
            qbq = QuestionnaireBankQuestionnaire(questionnaire_id=q.id,
                                                 days_till_due=7,
                                                 days_till_overdue=90,
                                                 rank=rank)
            bank.questionnaires.append(qbq)

        self.test_user.organizations.append(crv)
        with SessionScope(db):
            db.session.add(bank)
            db.session.commit()

        # User associated with CRV org should generate appropriate
        # questionnaires
        self.test_user = db.session.merge(self.test_user)
        qd = QuestionnaireDetails(self.test_user, datetime.utcnow())
        results = list(qd.baseline())
        self.assertEquals(3, len(results))
        # confirm rank sticks
        self.assertEquals(results[0]['name'], 'epic26')
        self.assertEquals(results[2]['name'], 'comorb')
Пример #15
0
 def setup_org_n_rp(org=None,
                    org_name='org',
                    rp_name='proto',
                    retired_as_of=None):
     """Create simple test org with RP, return (org, rp, rp_id)"""
     if not org:
         org = Organization(name=org_name)
     rp = ResearchProtocol(name=rp_name)
     with SessionScope(db):
         db.session.add(org)
         db.session.add(rp)
         db.session.commit()
     org, rp = map(db.session.merge, (org, rp))
     if not retired_as_of:
         org.research_protocols.append(rp)
     else:
         o_rp = OrganizationResearchProtocol(research_protocol=rp,
                                             organization=org,
                                             retired_as_of=retired_as_of)
         with SessionScope(db):
             db.session.add(o_rp)
             db.session.commit()
         org, rp = map(db.session.merge, (org, rp))
     return (org, rp, rp.id)
Пример #16
0
    def test_multiple_rps_in_fhir(self):
        yesterday = datetime.utcnow() - timedelta(days=1)
        lastyear = datetime.utcnow() - timedelta(days=365)
        org = Organization(name='Testy')
        rp1 = ResearchProtocol(name='rp1')
        rp2 = ResearchProtocol(name='yesterday')
        rp3 = ResearchProtocol(name='last year')
        with SessionScope(db):
            map(db.session.add, (org, rp1, rp2, rp3))
            db.session.commit()
        org, rp1, rp2, rp3 = map(db.session.merge, (org, rp1, rp2, rp3))
        o_rp1 = OrganizationResearchProtocol(research_protocol=rp1,
                                             organization=org)
        o_rp2 = OrganizationResearchProtocol(research_protocol=rp2,
                                             organization=org,
                                             retired_as_of=yesterday)
        o_rp3 = OrganizationResearchProtocol(research_protocol=rp3,
                                             organization=org,
                                             retired_as_of=lastyear)
        with SessionScope(db):
            map(db.session.add, (o_rp1, o_rp2, o_rp3))
            db.session.commit()
        org, rp1, rp2, rp3 = map(db.session.merge, (org, rp1, rp2, rp3))
        data = org.as_fhir()
        assert org.name == data['name']
        rps = [
            extension for extension in data['extension']
            if extension['url'] == ResearchProtocolExtension.extension_url
        ]

        assert len(rps) == 1
        assert len(rps[0]['research_protocols']) == 3

        # confirm the order is descending in the custom accessor method
        results = [(rp, retired) for rp, retired in org.rps_w_retired()]
        assert [(rp1, None), (rp2, yesterday), (rp3, lastyear)] == results
    def test_organization_search(self):
        self.shallow_org_tree()
        count = Organization.query.count()
        self.assertTrue(count > 1)

        # add region to one org, we should get only that one back
        region = Identifier(value='state:NY', system=PRACTICE_REGION)
        with SessionScope(db):
            db.session.add(region)
            db.session.commit()
        region = db.session.merge(region)
        oi = OrganizationIdentifier(organization_id=1001,
                                    identifier_id=region.id)
        with SessionScope(db):
            db.session.add(oi)
            db.session.commit()

        # use api to obtain FHIR bundle
        self.login()
        rv = self.client.get('/api/organization?state=NY')
        self.assert200(rv)
        bundle = rv.json
        self.assertTrue(bundle['resourceType'], 'Bundle')
        self.assertEquals(len(bundle['entry']), 1)
Пример #18
0
    def add_service_user(self, sponsor=None):
        """create and return a service user for sponsor

        Assign any user to sponsor to use a sponsor other than the default
        test_user

        """
        if not sponsor:
            sponsor = self.test_user
        if sponsor not in db.session:
            sponsor = db.session.merge(sponsor)
        service_user = sponsor.add_service_account()
        with SessionScope(db):
            db.session.add(service_user)
            db.session.commit()
        return db.session.merge(service_user)
Пример #19
0
 def test_ident_nomatch_search(self):
     ident = Identifier(system='http://example.com', value='testy')
     ui = UserIdentifier(identifier=ident, user_id=TEST_USER_ID)
     with SessionScope(db):
         db.session.add(ident)
         db.session.add(ui)
         db.session.commit()
     self.promote_user(role_name=ROLE.PATIENT)
     self.login()
     ident = db.session.merge(ident)
     # modify the system to mis match
     id_str = json.dumps(ident.as_fhir()).replace("example.com",
                                                  "wrong-system.com")
     rv = self.client.get('/api/patient?identifier={}'.format(id_str),
                          follow_redirects=True)
     self.assert404(rv)
    def test_org_rp_reference(self):
        rp = ResearchProtocol(name="test_rp")
        with SessionScope(db):
            db.session.add(rp)
            db.session.commit()
        rp = db.session.merge(rp)

        org_data = {"name": "test_org",
                    "extension": [
                    {"url": TRUENTH_RP_EXTENSION,
                     "research_protocols": [{'name': "test_rp"}]}
                    ]}

        org = Organization.from_fhir(org_data)
        self.assertEqual(1, len(org.research_protocols))
        self.assertEqual(org.research_protocols[0].id, rp.id)
Пример #21
0
    def test_SR_timeout(self):
        # SR users get 1 hour
        ui = UserIntervention(user_id=TEST_USER_ID,
                              intervention_id=INTERVENTION.SEXUAL_RECOVERY.id)
        with SessionScope(db):
            db.session.add(ui)
            db.session.commit()

        self.login()
        response = self.client.get('/next-after-login', follow_redirects=False)
        cookies = SimpleCookie()
        [
            cookies.load(item[1]) for item in response.headers
            if item[0] == 'Set-Cookie'
        ]
        assert int(cookies['SS_INACTIVITY_TIMEOUT'].value) == 60 * 60
Пример #22
0
    def test_service_account_promotion(self):
        """Confirm we can not promote a service account """
        self.add_client()
        test_user = User.query.get(TEST_USER_ID)
        service_user = test_user.add_service_account()

        with SessionScope(db):
            db.session.add(service_user)
            db.session.commit()
        service_user = db.session.merge(service_user)

        # try to promote - which should fail
        assert pytest.raises(RoleError, add_role, service_user,
                             ROLE.APPLICATION_DEVELOPER.value)

        assert len(service_user.roles) == 1
Пример #23
0
    def test_australian_indigenous_status(self):
        """Apply a few indigenous via FHIR from the NHHD_291036 value set"""

        # Add two indigenous directly - one in and one not in extension below
        concepts = Coding.query.filter(
            and_(Coding.code.in_(('1', '4')),
                 Coding.system == TRUENTH_VALUESET_NHHD_291036)).all()
        with SessionScope(db):
            db.session.add(UserIndigenous(user_id=TEST_USER_ID,
                                         coding_id=concepts[0].id))
            db.session.add(UserIndigenous(user_id=TEST_USER_ID,
                                         coding_id=concepts[1].id))
            db.session.commit()
        self.test_user = db.session.merge(self.test_user)
        self.assertEquals(2, self.test_user.indigenous.count())

        extension = {"url": TRUENTH_EXTENSTION_NHHD_291036}
        kls = user_extension_map(user=self.test_user, extension=extension)
        self.assertTrue(isinstance(kls, UserIndigenousStatusExtension))

        # generate FHIR from user's ethnicities
        fhir_data = kls.as_fhir()

        self.assertEquals(2, len(fhir_data['valueCodeableConcept']['coding']))
        codes = [c['code'] for c in fhir_data['valueCodeableConcept']['coding']]
        self.assertIn('1', codes)
        self.assertIn('4', codes)

        # now create a new extension (FHIR like) and apply to the user
        extension = {"url": TRUENTH_EXTENSTION_NHHD_291036,
            "valueCodeableConcept": {
                "coding": [
                    {"system": TRUENTH_VALUESET_NHHD_291036,
                     "code": "1"
                    },
                    {"system": TRUENTH_VALUESET_NHHD_291036,
                     "code": "9"
                    },
                ]
            }}

        ue = UserIndigenousStatusExtension(self.test_user, extension)
        ue.apply_fhir()
        self.assertEquals(2, self.test_user.indigenous.count())
        found = [c.code for c in self.test_user.indigenous]
        self.assertIn('1', found)
        self.assertIn('9', found)
    def test_job_delete(self):
        self.promote_user(role_name=ROLE.ADMIN.value)
        self.login()

        job = ScheduledJob(name="test_del", task="test", schedule="0 0 * * *")
        with SessionScope(db):
            db.session.add(job)
            db.session.commit()
            job = db.session.merge(job)
            job_id = job.id

        resp = self.client.delete('/api/scheduled_job/{}'.format(job_id))
        self.assert200(resp)
        self.assertFalse(ScheduledJob.query.all())

        resp = self.client.delete('/api/scheduled_job/999')
        self.assert404(resp)
Пример #25
0
    def test_get_by_type(self):
        timestamp = datetime.utcnow()
        audit = Audit(user_id=TEST_USER_ID,
                      subject_id=TEST_USER_ID,
                      timestamp=timestamp)
        tou = ToU(audit=audit, agreement_url=tou_url, type='privacy policy')
        with SessionScope(db):
            db.session.add(tou)
            db.session.commit()

        self.login()
        rv = self.client.get(
            '/api/user/{}/tou/privacy-policy'.format(TEST_USER_ID))
        self.assert200(rv)
        self.assertEquals(rv.json['accepted'],
                          timestamp.strftime("%Y-%m-%dT%H:%M:%S"))
        self.assertEquals(rv.json['type'], 'privacy policy')
Пример #26
0
 def add_user(
         self, username, first_name="", last_name="", image_url=None,
         pre_registered=False):
     """Create a user and add to test db, and return it"""
     # Unless testing a pre_registered case, give the user a fake password
     # so they appear registered
     password = None if pre_registered else 'fakePa$$'
     test_user = User(
         username=username, first_name=first_name, last_name=last_name,
         image_url=image_url, password=password)
     with SessionScope(db):
         db.session.add(test_user)
         db.session.commit()
     test_user = db.session.merge(test_user)
     # Avoid testing cached/stale data
     invalidate_assessment_status_cache(test_user.id)
     return test_user
Пример #27
0
    def test_no_email(self):
        # User w/o email shouldn't trigger communication

        mock_communication_request('localized', '{"days": 14}')

        # Fake a user associated with localized org
        # and mark all baseline questionnaires as in-progress
        self.bless_with_basics(backdate=relativedelta(days=22),
                               local_metastatic='localized')
        self.test_user = db.session.merge(self.test_user)
        self.test_user.email = NO_EMAIL_PREFIX
        with SessionScope(db):
            db.session.commit()

        update_patient_loop(update_cache=False, queue_messages=True)
        expected = Communication.query
        assert expected.count() == 0
Пример #28
0
    def test_redirect_validation(self):
        self.promote_user(role_name=ROLE.ADMIN.value)
        self.promote_user(role_name=ROLE.STAFF.value)

        org = Organization(name='test org')
        user = get_user(TEST_USER_ID)
        with SessionScope(db):
            db.session.add(org)
            user.organizations.append(org)
            db.session.commit()

        self.login()

        client = self.add_client()
        client_url = client._redirect_uris
        local_url = "http://{}/home?test".format(self.app.config.get('SERVER_NAME'))
        invalid_url = 'http://invalid.org'

        # validate redirect of /website-consent-script GET
        rv = self.client.get('/website-consent-script/{}?redirect_url='
                             '{}'.format(TEST_USER_ID, local_url))
        self.assert200(rv)

        rv2 = self.client.get('/website-consent-script/{}?redirect_url='
                              '{}'.format(TEST_USER_ID, invalid_url))
        self.assert401(rv2)

        # validate redirect of /login/<provider> GET
        rv3 = self.client.get('/login/TESTING?user_id={}&next='
                              '{}'.format(TEST_USER_ID, client_url),
                              follow_redirects=True)
        self.assert200(rv3)

        rv4 = self.client.get('/login/TESTING?user_id={}&next='
                              '{}'.format(TEST_USER_ID, invalid_url),
                              follow_redirects=True)
        self.assert401(rv4)

        # validate redirect of /challenge POST
        formdata = {'user_id': TEST_USER_ID, 'next_url': local_url}
        rv5 = self.client.post('/challenge', data=formdata)
        self.assert200(rv5)

        formdata['next_url'] = invalid_url
        rv6 = self.client.post('/challenge', data=formdata)
        self.assert401(rv6)
    def test_job_get(self):
        self.promote_user(role_name=ROLE.ADMIN.value)
        self.login()

        job = ScheduledJob(name="test_get", task="test", schedule="0 0 * * *")
        with SessionScope(db):
            db.session.add(job)
            db.session.commit()
            job = db.session.merge(job)
            job_id = job.id

        resp = self.client.get('/api/scheduled_job/{}'.format(job_id))
        self.assert200(resp)
        self.assertEqual(resp.json['task'], 'test')

        resp = self.client.get('/api/scheduled_job/999')
        self.assert404(resp)
Пример #30
0
    def test_completed_older_rp(self):
        """If current qb completed on older rp, should show as done"""
        fourmonthsago = now - timedelta(days=120)
        weekago = now - timedelta(weeks=1)
        twoweeksago = now - timedelta(weeks=2)
        org = self.setup_org_qbs(rp_name='v2', retired_as_of=weekago)
        org_id = org.id
        self.setup_org_qbs(org=org, rp_name='v3')

        self.promote_user(role_name=ROLE.PATIENT.value)
        self.test_user = db.session.merge(self.test_user)
        self.test_user.organizations.append(org)
        audit = Audit(user_id=TEST_USER_ID, subject_id=TEST_USER_ID)
        uc = UserConsent(user_id=TEST_USER_ID,
                         organization_id=org_id,
                         audit=audit,
                         agreement_url='http://no.com',
                         acceptance_date=fourmonthsago)
        with SessionScope(db):
            db.session.add(audit)
            db.session.add(uc)
            db.session.commit()
        user = db.session.merge(self.test_user)

        # Now, should still be rp v3, 3mo recurrence
        a_s = QB_Status(user=user, as_of_date=now)
        assert (a_s.current_qbd().questionnaire_bank.name ==
                'CRV_recurring_3mo_period v3')
        assert a_s.instruments_needing_full_assessment() == [
            'epic26_v3', 'eortc_v3'
        ]

        # Complete the questionnaire from the 3mo v2 QB
        v2qb = QuestionnaireBank.query.filter(
            QuestionnaireBank.name == 'CRV_recurring_3mo_period v2').one()
        mock_qr('epic26_v2', timestamp=twoweeksago, qb=v2qb, iteration=0)
        mock_qr('eortc_v2', timestamp=twoweeksago, qb=v2qb, iteration=0)

        # Two weeks ago, should be completed
        user = db.session.merge(user)
        a_s = QB_Status(user=user, as_of_date=twoweeksago)
        assert a_s.overall_status == OverallStatus.completed

        # Current should also be completed, even tho protocol changed
        a_s = QB_Status(user=user, as_of_date=now)
        assert a_s.overall_status == OverallStatus.completed