def test_user_consent(self):
        self.shallow_org_tree()
        org1, org2 = [
            org
            for org in Organization.query.filter(Organization.id > 0).limit(2)
        ]

        audit = Audit(user_id=TEST_USER_ID, subject_id=TEST_USER_ID)
        uc1 = UserConsent(organization_id=org1.id,
                          user_id=TEST_USER_ID,
                          agreement_url=self.url,
                          audit=audit)
        uc2 = UserConsent(organization_id=org2.id,
                          user_id=TEST_USER_ID,
                          agreement_url=self.url,
                          audit=audit)
        uc1.staff_editable = True
        uc1.send_reminders = False
        uc2.staff_editable = True
        uc2.send_reminders = False
        uc2.status = 'suspended'
        with SessionScope(db):
            db.session.add(uc1)
            db.session.add(uc2)
            db.session.commit()
        self.test_user = db.session.merge(self.test_user)
        self.login()
        response = self.client.get('/api/user/{}/consent'.format(TEST_USER_ID))
        assert response.status_code == 200
        assert len(response.json['consent_agreements']) == 2
        assert 'send_reminders' not in response.json['consent_agreements'][0]
        assert 'staff_editable' in response.json['consent_agreements'][0]
        assert response.json['consent_agreements'][0]['status'] == 'consented'
        assert response.json['consent_agreements'][1]['status'] == 'suspended'
    def test_user_consent(self):
        self.shallow_org_tree()
        org1, org2 = [
            org
            for org in Organization.query.filter(Organization.id > 0).limit(2)
        ]

        audit = Audit(user_id=TEST_USER_ID, subject_id=TEST_USER_ID)
        uc1 = UserConsent(organization_id=org1.id,
                          user_id=TEST_USER_ID,
                          agreement_url=self.url,
                          audit=audit)
        uc2 = UserConsent(organization_id=org2.id,
                          user_id=TEST_USER_ID,
                          agreement_url=self.url,
                          audit=audit)
        uc1.staff_editable = True
        uc1.send_reminders = False
        uc2.staff_editable = True
        uc2.send_reminders = False
        with SessionScope(db):
            db.session.add(uc1)
            db.session.add(uc2)
            db.session.commit()
        self.test_user = db.session.merge(self.test_user)
        self.login()
        rv = self.client.get('/api/user/{}/consent'.format(TEST_USER_ID))
        self.assert200(rv)
        self.assertEquals(len(rv.json['consent_agreements']), 2)
        self.assertTrue(
            'send_reminders' not in rv.json['consent_agreements'][0])
        self.assertTrue('staff_editable' in rv.json['consent_agreements'][0])
Exemple #3
0
 def test_staff_access(self):
     staff = self.add_user('*****@*****.**')
     self.promote_user(role_name=ROLE.PATIENT)
     self.promote_user(staff, role_name=ROLE.STAFF)
     self.shallow_org_tree()
     org = Organization.query.filter(Organization.id > 0).first()
     staff.organizations.append(org)
     self.test_user.organizations.append(org)
     audit = Audit(user_id=TEST_USER_ID,
                   subject_id=TEST_USER_ID,
                   comment='just test data')
     consent = UserConsent(user_id=TEST_USER_ID,
                           organization_id=org.id,
                           audit=audit,
                           agreement_url='http://fake.org')
     with SessionScope(db):
         db.session.add(audit)
         db.session.add(consent)
         db.session.commit()
     staff = db.session.merge(staff)
     self.login(staff.id)
     rv = self.client.get('/api/user/{}/audit'.format(TEST_USER_ID))
     self.assert200(rv)
     self.assertEquals(1, len(rv.json['audits']))
     self.assertEquals(
         rv.json['audits'][0]['by']['reference'],
         Reference.patient(TEST_USER_ID).as_fhir()['reference'])
     self.assertEquals(rv.json['audits'][0]['on'],
                       Reference.patient(TEST_USER_ID).as_fhir())
     self.assertEquals(rv.json['audits'][0]['context'], 'other')
     self.assertEquals(rv.json['audits'][0]['comment'], 'just test data')
    def test_content_options(self):
        audit = Audit(user_id=TEST_USER_ID, subject_id=TEST_USER_ID)
        self.shallow_org_tree()
        org1, _ = [org for org in Organization.query.filter(
            Organization.id > 0).limit(2)]
        uc = UserConsent(
            user_id=TEST_USER_ID, organization=org1,
            audit=audit, agreement_url='http://no.com')
        uc.include_in_reports = True
        with SessionScope(db):
            db.session.add(uc)
            db.session.commit()

        uc = UserConsent.query.first()
        assert uc.include_in_reports
        assert not uc.staff_editable
        assert not uc.send_reminders
    def test_user_consent(self):
        self.shallow_org_tree()
        org1, org2 = [org for org in Organization.query.filter(
            Organization.id > 0).limit(2)]

        audit = Audit(user_id=TEST_USER_ID, subject_id=TEST_USER_ID)
        uc1 = UserConsent(
            organization_id=org1.id, user_id=TEST_USER_ID,
            agreement_url=self.url, audit=audit)
        uc2 = UserConsent(
            organization_id=org2.id, user_id=TEST_USER_ID,
            agreement_url=self.url, audit=audit)
        uc1.staff_editable = True
        uc1.send_reminders = False
        uc2.staff_editable = True
        uc2.send_reminders = False
        uc2.status = 'suspended'
        with SessionScope(db):
            db.session.add(uc1)
            db.session.add(uc2)
            db.session.commit()
        self.test_user = db.session.merge(self.test_user)
        self.login()
        response = self.client.get('/api/user/{}/consent'.format(TEST_USER_ID))
        assert response.status_code == 200
        assert len(response.json['consent_agreements']) == 2
        assert 'send_reminders' not in response.json['consent_agreements'][0]
        assert 'staff_editable' in response.json['consent_agreements'][0]
        org1, org2 = db.session.merge(org1), db.session.merge(org2)
        org1_consent = [ca for ca in response.json[
            'consent_agreements'] if ca['organization_id'] == org1.id][0]
        org2_consent = [ca for ca in response.json[
            'consent_agreements'] if ca['organization_id'] == org2.id][0]
        assert org1_consent['status'] == 'consented'
        assert org2_consent['status'] == 'suspended'
Exemple #6
0
    def test_submit_assessment_for_qb(self):
        swagger_spec = swagger(self.app)
        data = swagger_spec['definitions']['QuestionnaireResponse']['example']

        rp = ResearchProtocol(name='proto')
        with SessionScope(db):
            db.session.add(rp)
            db.session.commit()
        rp = db.session.merge(rp)
        rp_id = rp.id

        qn = self.add_questionnaire(name='epic26')
        org = Organization(name="testorg")
        org.research_protocols.append(rp)
        with SessionScope(db):
            db.session.add(qn)
            db.session.add(org)
            db.session.commit()

        qn, org = map(db.session.merge, (qn, org))
        qb = QuestionnaireBank(name='Test Questionnaire Bank',
                               classification='baseline',
                               research_protocol_id=rp_id,
                               start='{"days": 0}',
                               overdue='{"days": 7}',
                               expired='{"days": 90}')
        qbq = QuestionnaireBankQuestionnaire(questionnaire=qn, rank=0)
        qb.questionnaires.append(qbq)

        test_user = get_user(TEST_USER_ID)
        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=org,
                         audit=audit,
                         agreement_url='http://no.com')

        with SessionScope(db):
            db.session.add(qb)
            db.session.add(test_user)
            db.session.add(audit)
            db.session.add(uc)
            db.session.commit()
        qb = db.session.merge(qb)

        self.login()
        response = self.client.post(
            '/api/patient/{}/assessment'.format(TEST_USER_ID),
            content_type='application/json',
            data=json.dumps(data),
        )
        assert response.status_code == 200
        test_user = get_user(TEST_USER_ID)
        assert test_user.questionnaire_responses.count() == 1
        assert test_user.questionnaire_responses[0].questionnaire_bank_id ==\
            qb.id
    def test_delete_user_consent(self):
        self.shallow_org_tree()
        org1, org2 = [
            org
            for org in Organization.query.filter(Organization.id > 0).limit(2)
        ]
        org1_id, org2_id = org1.id, org2.id
        data = {'organization_id': org1_id}

        audit = Audit(user_id=TEST_USER_ID, subject_id=TEST_USER_ID)
        uc1 = UserConsent(organization_id=org1_id,
                          user_id=TEST_USER_ID,
                          agreement_url=self.url,
                          audit=audit)
        uc2 = UserConsent(organization_id=org2_id,
                          user_id=TEST_USER_ID,
                          agreement_url=self.url,
                          audit=audit)
        with SessionScope(db):
            db.session.add(uc1)
            db.session.add(uc2)
            db.session.commit()
        self.test_user = db.session.merge(self.test_user)
        assert self.test_user.valid_consents.count() == 2
        self.login()

        response = self.client.delete(
            '/api/user/{}/consent'.format(TEST_USER_ID),
            content_type='application/json',
            data=json.dumps(data))
        assert response.status_code == 200
        assert self.test_user.valid_consents.count() == 1
        assert self.test_user.valid_consents[0].organization_id == org2_id

        # We no longer omit deleted consent rows, but rather, include
        # their audit data.
        response = self.client.get('/api/user/{}/consent'.format(TEST_USER_ID))
        assert 'deleted' in json.dumps(response.json)

        # confirm deleted status
        dc = UserConsent.query.filter_by(user_id=TEST_USER_ID,
                                         organization_id=org1_id).first()
        assert dc.status == 'deleted'
Exemple #8
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_qbs(rp_name='v2', retired_as_of=weekago)
        org_id = org.id
        self.setup_qbs(org=org, rp_name='v3')

        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()

        # Two weeks ago, still on rp v2, should be in 3mo recurrence
        user = db.session.merge(self.test_user)
        a_s = AssessmentStatus(user=user, as_of_date=twoweeksago)
        v2qb = a_s.qb_data.qbd.questionnaire_bank
        self.assertEqual('CRV_recurring_3mo_period v2',
                         a_s.qb_data.qbd.questionnaire_bank.name)
        self.assertEqual('CRV_recurring_3mo_period v2', a_s.qb_name)
        self.assertEqual(['epic26_v2'],
                         a_s.instruments_needing_full_assessment())

        # Now, should still be rp v3, 3mo recurrence
        a_s = AssessmentStatus(user=user, as_of_date=now)
        self.assertEqual('CRV_recurring_3mo_period v3',
                         a_s.qb_data.qbd.questionnaire_bank.name)
        self.assertEqual(['epic26_v3'],
                         a_s.instruments_needing_full_assessment())

        # Complete the questionnaire from the 3mo v2 QB
        mock_qr('epic26_v2', timestamp=twoweeksago, qb=v2qb, iteration=0)

        # Two weeks ago, should be completed
        user = db.session.merge(user)
        a_s = AssessmentStatus(user=user, as_of_date=twoweeksago)
        self.assertEqual('Completed', a_s.overall_status)

        # Current should also be completed, even tho protocol changed
        a_s = AssessmentStatus(user=user, as_of_date=now)
        self.assertEqual('Completed', a_s.overall_status)

        # Should see both as candidates
        qbds = QuestionnaireBank.qbs_for_user(user,
                                              classification='recurring',
                                              as_of_date=now)
        self.assertEqual(len(qbds), 2)
    def test_content_options(self):
        audit = Audit(user_id=TEST_USER_ID, subject_id=TEST_USER_ID)
        self.shallow_org_tree()
        org1, _ = [
            org
            for org in Organization.query.filter(Organization.id > 0).limit(2)
        ]
        uc = UserConsent(user_id=TEST_USER_ID,
                         organization=org1,
                         audit=audit,
                         agreement_url='http://no.com')
        uc.include_in_reports = True
        with SessionScope(db):
            db.session.add(uc)
            db.session.commit()

        uc = UserConsent.query.first()
        self.assertTrue(uc.include_in_reports)
        self.assertFalse(uc.staff_editable)
        self.assertFalse(uc.send_reminders)
Exemple #10
0
    def test_qb_pre_retired(self):
        # Confirm backdating returns the correct QB
        weekago = now - timedelta(days=7)
        org, rpv3, rpv3_id = self.setup_org_n_rp(rp_name='v3')
        org, rpv2, rpv2_id = self.setup_org_n_rp(org=org,
                                                 rp_name='v2',
                                                 retired_as_of=weekago)
        qn3 = self.add_questionnaire(name='epic26-v3')
        qn2 = self.add_questionnaire(name='epic26-v2')
        qb3 = QuestionnaireBank(name='Test Questionnaire Bank v3',
                                classification='baseline',
                                research_protocol_id=rpv3_id,
                                start='{"days": 0}',
                                overdue='{"days": 7}',
                                expired='{"days": 90}')
        qbq3 = QuestionnaireBankQuestionnaire(questionnaire=qn3, rank=0)
        qb3.questionnaires.append(qbq3)
        qb2 = QuestionnaireBank(name='Test Questionnaire Bank v2',
                                classification='baseline',
                                research_protocol_id=rpv2_id,
                                start='{"days": 0}',
                                overdue='{"days": 7}',
                                expired='{"days": 90}')
        qbq2 = QuestionnaireBankQuestionnaire(questionnaire=qn2, rank=0)
        qb2.questionnaires.append(qbq2)

        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=org,
                         audit=audit,
                         agreement_url='http://no.com')

        with SessionScope(db):
            map(db.session.add, (qb2, qb3))
            db.session.add(audit)
            db.session.add(uc)
            db.session.commit()
        user, org, qb2, qb3 = map(db.session.merge,
                                  (self.test_user, org, qb2, qb3))

        # w/o backdating, should get current QB
        self.assertEqual(
            qb3,
            QuestionnaireBank.most_current_qb(
                user, as_of_date=now).questionnaire_bank)

        # backdate prior to retirement of previous, should get the previous QB
        pre_retirement = weekago - timedelta(days=1)
        self.assertEqual(
            qb2,
            QuestionnaireBank.most_current_qb(
                user, as_of_date=pre_retirement).questionnaire_bank)
    def test_consent_order(self):
        self.shallow_org_tree()
        org1, org2 = [org for org in Organization.query.filter(
            Organization.id > 0).limit(2)]
        old = datetime.now() - relativedelta(years=10)
        older = old - relativedelta(years=10)
        oldest = older - relativedelta(years=50)

        audit = Audit(user_id=TEST_USER_ID, subject_id=TEST_USER_ID)
        uc1 = UserConsent(
            organization_id=org1.id, user_id=TEST_USER_ID,
            agreement_url=self.url, audit=audit, acceptance_date=older)
        uc2 = UserConsent(
            organization_id=org2.id, user_id=TEST_USER_ID,
            agreement_url=self.url, audit=audit, acceptance_date=oldest)
        uc3 = UserConsent(
            organization_id=0, user_id=TEST_USER_ID,
            agreement_url=self.url, audit=audit, acceptance_date=old)
        with SessionScope(db):
            db.session.add(uc1)
            db.session.add(uc2)
            db.session.add(uc3)
            db.session.commit()
        self.test_user = db.session.merge(self.test_user)
        self.login()
        response = self.client.get(
            '/api/user/{}/consent'.format(TEST_USER_ID))
        assert response.status_code == 200
        assert len(response.json['consent_agreements']) == 3
        # should be ordered by acceptance date, descending: (uc3, uc1, uc2)
        uc1, uc2, uc3 = map(db.session.merge, (uc1, uc2, uc3))
        assert response.json['consent_agreements'][0] == uc3.as_json()
        assert response.json['consent_agreements'][1] == uc1.as_json()
        assert response.json['consent_agreements'][2] == uc2.as_json()
    def test_delete_user_consent(self):
        self.shallow_org_tree()
        org1, org2 = [
            org
            for org in Organization.query.filter(Organization.id > 0).limit(2)
        ]
        org1_id, org2_id = org1.id, org2.id
        data = {'organization_id': org1_id}

        audit = Audit(user_id=TEST_USER_ID, subject_id=TEST_USER_ID)
        uc1 = UserConsent(organization_id=org1_id,
                          user_id=TEST_USER_ID,
                          agreement_url=self.url,
                          audit=audit)
        uc2 = UserConsent(organization_id=org2_id,
                          user_id=TEST_USER_ID,
                          agreement_url=self.url,
                          audit=audit)
        with SessionScope(db):
            db.session.add(uc1)
            db.session.add(uc2)
            db.session.commit()
        self.test_user = db.session.merge(self.test_user)
        self.assertEqual(self.test_user.valid_consents.count(), 2)
        self.login()

        rv = self.client.delete('/api/user/{}/consent'.format(TEST_USER_ID),
                                content_type='application/json',
                                data=json.dumps(data))
        self.assert200(rv)
        self.assertEqual(self.test_user.valid_consents.count(), 1)
        self.assertEqual(self.test_user.valid_consents[0].organization_id,
                         org2_id)

        # We no longer omit deleted consent rows, but rather, include
        # their audit data.
        rv = self.client.get('/api/user/{}/consent'.format(TEST_USER_ID))
        self.assertTrue('deleted' in json.dumps(rv.json))
    def test_consent_order(self):
        self.shallow_org_tree()
        org1, org2 = [
            org
            for org in Organization.query.filter(Organization.id > 0).limit(2)
        ]
        old = datetime.now() - relativedelta(years=10)
        older = old - relativedelta(years=10)
        oldest = older - relativedelta(years=50)

        audit = Audit(user_id=TEST_USER_ID, subject_id=TEST_USER_ID)
        uc1 = UserConsent(organization_id=org1.id,
                          user_id=TEST_USER_ID,
                          agreement_url=self.url,
                          audit=audit,
                          acceptance_date=older)
        uc2 = UserConsent(organization_id=org2.id,
                          user_id=TEST_USER_ID,
                          agreement_url=self.url,
                          audit=audit,
                          acceptance_date=oldest)
        uc3 = UserConsent(organization_id=0,
                          user_id=TEST_USER_ID,
                          agreement_url=self.url,
                          audit=audit,
                          acceptance_date=old)
        with SessionScope(db):
            db.session.add(uc1)
            db.session.add(uc2)
            db.session.add(uc3)
            db.session.commit()
        self.test_user = db.session.merge(self.test_user)
        self.login()
        response = self.client.get('/api/user/{}/consent'.format(TEST_USER_ID))
        assert response.status_code == 200
        assert len(response.json['consent_agreements']) == 3
        # should be ordered by acceptance date, descending: (uc3, uc1, uc2)
        uc1, uc2, uc3 = map(db.session.merge, (uc1, uc2, uc3))
        assert response.json['consent_agreements'][0] == uc3.as_json()
        assert response.json['consent_agreements'][1] == uc1.as_json()
        assert response.json['consent_agreements'][2] == uc2.as_json()
Exemple #14
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
Exemple #15
0
    def bless_with_basics(self, backdate=None, setdate=None):
        """Bless test user with basic requirements for coredata

        :param backdate: timedelta value.  Define to mock consents
          happening said period in the past.  See
          ``associative_backdate`` for issues with 'months'.

        :param setdate: datetime value.  Define to mock consents
          happening at exact time in the past

        """
        self.test_user = db.session.merge(self.test_user)
        self.test_user.birthdate = datetime.utcnow()

        # Register with a clinic
        self.shallow_org_tree()
        org = Organization.query.filter(
            Organization.partOf_id != None).first()
        assert org
        self.test_user.organizations.append(org)

        # Agree to Terms of Use and sign consent
        audit = Audit(user_id=TEST_USER_ID, subject_id=TEST_USER_ID)
        tou = ToU(audit=audit, agreement_url='http://not.really.org',
                  type='website terms of use')
        privacy = ToU(audit=audit, agreement_url='http://not.really.org',
                  type='privacy policy')
        parent_org = OrgTree().find(org.id).top_level()
        options = (STAFF_EDITABLE_MASK | INCLUDE_IN_REPORTS_MASK |
                   SEND_REMINDERS_MASK)
        consent = UserConsent(
            user_id=TEST_USER_ID, organization_id=parent_org,
            options=options, audit=audit, agreement_url='http://fake.org',
            acceptance_date=calc_date_params(
                backdate=backdate, setdate=setdate))
        with SessionScope(db):
            db.session.add(tou)
            db.session.add(privacy)
            db.session.add(consent)
            db.session.commit()

        # Invalidate org tree cache, in case orgs are added by other
        # tests.  W/o doing so, the new orgs aren't in the orgtree
        OrgTree.invalidate_cache()
Exemple #16
0
    def consent_with_org(self, org_id, user_id=TEST_USER_ID,
                         backdate=None, setdate=None):
        """Bless given user with a valid consent with org

        :param backdate: timedelta value.  Define to mock consents
          happening said period in the past

        :param setdate: datetime value.  Define to mock consents
          happening at exact time in the past

        """
        audit = Audit(user_id=user_id, subject_id=user_id)
        consent = UserConsent(
            user_id=user_id, organization_id=org_id,
            audit=audit, agreement_url='http://fake.org',
            acceptance_date=calc_date_params(
                backdate=backdate, setdate=setdate))
        with SessionScope(db):
            db.session.add(consent)
            db.session.commit()
    def test_user_check_roles(self):
        org = Organization(name='members only')
        user = self.test_user
        user.organizations.append(org)
        u2 = self.add_user(username='******')
        member_of = self.add_user(username='******')
        member_of.organizations.append(org)
        audit = Audit(comment='test data', user_id=TEST_USER_ID,
            subject_id=TEST_USER_ID)
        self.promote_user(user, ROLE.STAFF)
        self.promote_user(u2, ROLE.PATIENT)
        self.promote_user(member_of, ROLE.PATIENT)
        user, org, u2, member_of = map(
            db.session.merge, (user, org, u2, member_of))
        consent = UserConsent(
            user_id=member_of.id, organization_id=org.id,
            audit=audit, agreement_url='http://example.org',
            options=STAFF_EDITABLE_MASK)
        with SessionScope(db):
            db.session.add(consent)
            db.session.commit()
        user, org, u2, member_of = map(
            db.session.merge, (user, org, u2, member_of))

        kwargs = {'permission': 'view', 'other_id': user.id}
        self.assertTrue(user.check_role(**kwargs))

        kwargs = {'permission': 'edit', 'other_id': u2.id}
        self.assertRaises(Unauthorized, user.check_role, **kwargs)

        kwargs = {'permission': 'view', 'other_id': u2.id}
        self.assertRaises(Unauthorized, user.check_role, **kwargs)

        kwargs = {'permission': 'edit', 'other_id': member_of.id}
        self.assertTrue(user.check_role(**kwargs))

        kwargs = {'permission': 'view', 'other_id': member_of.id}
        self.assertTrue(user.check_role(**kwargs))
    def test_withdraw_user_consent(self):
        self.shallow_org_tree()
        org = Organization.query.filter(Organization.id > 0).first()
        org_id = org.id

        audit = Audit(user_id=TEST_USER_ID, subject_id=TEST_USER_ID)
        uc = UserConsent(organization_id=org_id,
                         user_id=TEST_USER_ID,
                         agreement_url=self.url,
                         audit=audit)
        with SessionScope(db):
            db.session.add(uc)
            db.session.commit()
        self.test_user = db.session.merge(self.test_user)
        assert self.test_user.valid_consents.count() == 1

        data = {'organization_id': org_id}
        self.login()
        resp = self.client.post('/api/user/{}/consent/'
                                'withdraw'.format(TEST_USER_ID),
                                content_type='application/json',
                                data=json.dumps(data))
        assert resp.status_code == 200

        # check that old consent is marked as deleted
        old_consent = UserConsent.query.filter_by(user_id=TEST_USER_ID,
                                                  organization_id=org_id,
                                                  status='deleted').first()
        assert old_consent.deleted_id

        # check new withdrawn consent
        new_consent = UserConsent.query.filter_by(user_id=TEST_USER_ID,
                                                  organization_id=org_id,
                                                  status='suspended').first()
        assert old_consent.agreement_url == new_consent.agreement_url
        assert new_consent.staff_editable == \
            (not current_app.config.get('GIL'))
        assert not new_consent.send_reminders
Exemple #19
0
    def consent_with_org(self, org_id, user_id=TEST_USER_ID,
                         backdate=None, setdate=None):
        """Bless given user with a valid consent with org

        NB - if existing consent for user/org is present, simply update
        with new date values

        :param backdate: timedelta value.  Define to mock consents
          happening said period in the past

        :param setdate: datetime value.  Define to mock consents
          happening at exact time in the past

        """
        # doesn't make sense to consent w/o an association, add if missing
        user = User.query.get(user_id)
        if org_id not in (o.id for o in user.organizations):
            user.organizations.append(Organization.query.get(org_id))

        acceptance_date = calc_date_params(
            backdate=backdate, setdate=setdate)
        consent = UserConsent.query.filter(
            UserConsent.user_id == user_id).filter(
            UserConsent.organization_id == org_id).first()
        if consent:
            consent.acceptance_date = acceptance_date
        else:
            audit = Audit(user_id=user_id, subject_id=user_id)
            consent = UserConsent(
                user_id=user_id, organization_id=org_id,
                audit=audit, agreement_url='http://fake.org',
                acceptance_date=acceptance_date)
        with SessionScope(db):
            if consent not in db.session:
                db.session.add(consent)
            db.session.commit()
Exemple #20
0
    def test_outdated_done_indef(self):
        """Confirm completed indefinite counts after RP switch"""

        # boiler plate to create baseline and indef with retired RP
        yesterday = now - timedelta(days=1)
        weekago = now - timedelta(weeks=1)
        org, rp2, rp2_id = self.setup_org_n_rp(org_name='testorg',
                                               rp_name='v2',
                                               retired_as_of=yesterday)
        org, rp3, rp3_id = self.setup_org_n_rp(org=org, rp_name='v3')
        org_id = org.id
        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=weekago)
        with SessionScope(db):
            db.session.add(audit)
            db.session.add(uc)
            db.session.commit()

        self.setup_qb(questionnaire_name='epic23',
                      qb_name='baseline v2',
                      classification='baseline',
                      rp_id=rp2_id)
        self.setup_qb(questionnaire_name='epic26',
                      qb_name='baseline v3',
                      classification='baseline',
                      rp_id=rp3_id)
        qb2_indef = self.setup_qb(questionnaire_name='irondemog',
                                  qb_name='indef v2',
                                  classification='indefinite',
                                  rp_id=rp2_id)
        self.setup_qb(questionnaire_name='irondemog_v3',
                      qb_name='indef v3',
                      classification='indefinite',
                      rp_id=rp3_id)

        # for today, should get the v3 baseline
        user = db.session.merge(self.test_user)
        a_s = QB_Status(user=user, as_of_date=now)
        assert ([
            'epic26', 'irondemog_v3'
        ] == a_s.instruments_needing_full_assessment(classification='all'))

        # create done QNR for indefinite dated prior to rp transition
        # belonging to older qb - confirm that clears indef work as of then
        mock_qr('irondemog', timestamp=weekago, qb=qb2_indef)
        user = db.session.merge(self.test_user)
        invalidate_users_QBT(user_id=TEST_USER_ID)
        a_s = QB_Status(user=user, as_of_date=weekago)
        assert (a_s.instruments_needing_full_assessment(
            classification='indefinite') == [])

        # move forward in time; user should no longer need indefinite, even
        # tho RP changed
        qb2_indef = db.session.merge(qb2_indef)
        a_s = QB_Status(user=user, as_of_date=now)
        assert qb2_indef == a_s.current_qbd(
            classification='indefinite').questionnaire_bank
        assert (a_s.instruments_needing_full_assessment(
            classification='indefinite') == [])
        assert (a_s.instruments_needing_full_assessment(
            classification='all') == ['epic26'])
def patch_deceased_user_consents(uid):
    user = User.query.get(uid)
    user_consents = UserConsent.query.filter(
        UserConsent.user_id == uid).order_by(UserConsent.id).all()

    # if no user_consents exist for user, we're done
    if not user_consents:
        return

    # acquire the deceased date
    dd = user.deceased.timestamp

    # if the most recent consent looks correct, assume we're done
    if user_consents[-1].status == 'suspended' and not (
            user_consents[-1].options & SEND_REMINDERS_MASK):
        return

    admin = User.query.filter_by(email='__system__').first()

    log.info("Patching broken consents for {}, with deceased date {}".format(
        user, dd))
    keeper = user_consents.pop(0)
    log.info(" keeping original user_consent {} {} {} {}".format(
        keeper.id, keeper.status, keeper.options, keeper.acceptance_date))
    obsolete_audits, obsolete_consents = [], []
    for uc in user_consents:
        log.info(" deleting user_consent {} {} {} {}".format(
            uc.id, uc.status, uc.options, uc.acceptance_date))
        a = Audit.query.get(uc.audit_id)
        log.info("  and the related {}".format(a))
        obsolete_audits.append(a.id)
        obsolete_consents.append(uc.id)

    # out of loop, delete the unwanted
    db.session.query(UserConsent).filter(
        UserConsent.id.in_(obsolete_consents)).delete(
            synchronize_session=False)
    db.session.query(Audit).filter(
        Audit.id.in_(obsolete_audits)).delete(synchronize_session=False)
    db.session.commit()

    # now add back in the corrected consent, from the initial
    deceased_options = STAFF_EDITABLE_MASK | INCLUDE_IN_REPORTS_MASK
    deceased_consent = UserConsent(user_id=uid,
                                   organization_id=keeper.organization_id,
                                   agreement_url=keeper.agreement_url,
                                   acceptance_date=dd,
                                   options=deceased_options,
                                   status='suspended')

    user.update_consents(consent_list=[deceased_consent], acting_user=admin)

    # The updated consent may have altered the cached assessment
    # status - invalidate this user's data at this time.
    invalidate_users_QBT(user_id=user.id)
    db.session.commit()

    log.info(" Done, results:")
    for uc in UserConsent.query.filter(UserConsent.user_id == uid):
        log.info("  {} {} {} {}".format(uc, uc.acceptance_date, uc.status,
                                        uc.options))
    def test_deep_tree_check_role(self):
        self.deepen_org_tree()

        org_102 = Organization.query.get(102)
        org_1002 = Organization.query.get(1002)
        org_10031 = Organization.query.get(10031)
        org_10032 = Organization.query.get(10032)
        audit = Audit(comment="testing", user_id=TEST_USER_ID,
                      subject_id=TEST_USER_ID, context='consent')

        staff_top = self.add_user('Staff 102')
        self.promote_user(staff_top, ROLE.STAFF)
        staff_top.organizations.append(org_102)

        staff_leaf = self.add_user('Staff 10031')
        self.promote_user(staff_leaf, ROLE.STAFF)
        staff_leaf.organizations.append(org_10031)

        staff_mid = self.add_user('Staff 1002')
        self.promote_user(staff_mid, ROLE.STAFF)
        staff_mid.organizations.append(org_1002)

        patient_w = self.add_user('patient w')
        patient_w_id = patient_w.id
        self.promote_user(patient_w, ROLE.PATIENT)
        patient_w.organizations.append(org_10032)
        uc_w = UserConsent(
            audit=audit, agreement_url='http://fake.org',
            user_id=patient_w_id, organization=org_10032,
            options=STAFF_EDITABLE_MASK)

        patient_x = self.add_user('patient x')
        patient_x_id = patient_x.id
        self.promote_user(patient_x, ROLE.PATIENT)
        patient_x.organizations.append(org_10032)
        uc_x = UserConsent(
            audit=audit, agreement_url='http://fake.org',
            user_id=patient_x_id, organization=org_102,
            options=STAFF_EDITABLE_MASK)

        patient_y = self.add_user('patient y')
        patient_y_id = patient_y.id
        self.promote_user(patient_y, ROLE.PATIENT)
        patient_y.organizations.append(org_102)
        uc_y = UserConsent(
            audit=audit, agreement_url='http://fake.org',
            user_id=patient_y_id, organization=org_10031,
            options=STAFF_EDITABLE_MASK)

        patient_z = self.add_user('patient z')
        patient_z_id = patient_z.id
        self.promote_user(patient_z, ROLE.PATIENT)
        patient_z.organizations.append(org_10031)
        uc_z = UserConsent(
            audit=audit, agreement_url='http://fake.org',
            user_id=patient_z_id, organization=org_10031,
            options=STAFF_EDITABLE_MASK)

        with SessionScope(db):
            db.session.add(uc_w)
            db.session.add(uc_x)
            db.session.add(uc_y)
            db.session.add(uc_z)
            db.session.commit()
        patient_w, patient_x, patient_y, patient_z = map(db.session.merge,(
            patient_w, patient_x, patient_y, patient_z))

        ###
        # Setup complete - test access
        ###

        # top level staff can view/edit all
        staff_top = db.session.merge(staff_top)
        for perm in ('view', 'edit'):
            for patient in (
                patient_w_id, patient_x_id, patient_y_id, patient_z_id):
                self.assertTrue(
                    staff_top.check_role(perm, other_id=patient))

        # mid level staff can view/edit all
        staff_mid = db.session.merge(staff_mid)
        for perm in ('view', 'edit'):
            for patient in (
                patient_w_id, patient_x_id, patient_y_id, patient_z_id):
                self.assertTrue(
                    staff_mid.check_role(perm, other_id=patient))

        # low level staff can view/edit only those w/ same org
        staff_leaf = db.session.merge(staff_leaf)
        for perm in ('view', 'edit'):
            for patient in (patient_w_id, patient_x_id):
                self.assertRaises(
                    Unauthorized, staff_leaf.check_role, perm, patient)
        for perm in ('view', 'edit'):
            for patient in (patient_y_id, patient_z_id):
                self.assertTrue(
                    staff_leaf.check_role(perm, other_id=patient))

        # Now remove the staff editable flag from the consents, which should
        # preserve view but remove edit permission
        for uc in (uc_w, uc_x, uc_y, uc_z):
            uc = db.session.merge(uc)
            uc.staff_editable = False

        with SessionScope(db):
            db.session.commit()
        patient_w, patient_x, patient_y, patient_z = map(db.session.merge,(
            patient_w, patient_x, patient_y, patient_z))

        # top level staff can view all, edit none
        staff_top = db.session.merge(staff_top)
        for patient in (
            patient_w_id, patient_x_id, patient_y_id, patient_z_id):
            self.assertTrue(
                staff_top.check_role('view', other_id=patient))
            self.assertRaises(
                Unauthorized, staff_top.check_role, 'edit', other_id=patient)

        # mid level staff can view all, edit none
        staff_mid = db.session.merge(staff_mid)
        for patient in (
            patient_w_id, patient_x_id, patient_y_id, patient_z_id):
            self.assertTrue(
                staff_mid.check_role('view', other_id=patient))
            self.assertRaises(
                Unauthorized, staff_mid.check_role, 'edit', other_id=patient)

        # low level staff can view only those w/ same org; edit none
        staff_leaf = db.session.merge(staff_leaf)
        for perm in ('view', 'edit'):
            for patient in (patient_w_id, patient_x_id):
                self.assertRaises(
                    Unauthorized, staff_leaf.check_role, perm, patient)
        for patient in (patient_y_id, patient_z_id):
            self.assertTrue(
                staff_leaf.check_role('view', other_id=patient))
            self.assertRaises(
                Unauthorized, staff_leaf.check_role, 'edit', patient)
    def test_permanently_delete_user(self):
        # created acting user and to-be-deleted user
        actor = self.add_user('actor')
        deleted = self.add_user('deleted')
        deleted, actor = map(db.session.merge, (deleted, actor))
        deleted_id, actor_id = deleted.id, actor.id
        deleted_email, actor_email = deleted.email, actor.email
        self.promote_user(user=actor, role_name=ROLE.ADMIN)
        with SessionScope(db):
            db.session.commit()
        deleted = db.session.merge(deleted)

        # create observation and user_observation
        audit = Audit(user_id=TEST_USER_ID, subject_id=TEST_USER_ID)
        observation = Observation()
        coding = Coding(system='SNOMED-CT', code='372278000',
                        display='Gleason score')
        cc = CodeableConcept(codings=[coding, ])
        observation.codeable_concept = cc
        observation.value_quantity = ValueQuantity(value=2)
        performer = Performer(reference_txt=json.dumps(
            Reference.patient(TEST_USER_ID).as_fhir()))
        observation.performers.append(performer)
        enc = Encounter(status='planned', auth_method='url_authenticated',
                        user_id=TEST_USER_ID, start_time=datetime.utcnow())
        with SessionScope(db):
            db.session.add(observation)
            db.session.add(enc)
            db.session.commit()
        observation, enc = map(db.session.merge, (observation, enc))
        observation_id, enc_id = observation.id, enc.id
        user_obs = UserObservation(user_id=deleted_id, audit=audit,
                                   observation_id=observation_id,
                                   encounter_id=enc_id)
        with SessionScope(db):
            db.session.add(user_obs)
            db.session.commit()
        user_obs = db.session.merge(user_obs)
        user_obs_id = user_obs.id

        # create user and subject audits
        subj_audit = Audit(user_id=TEST_USER_ID, subject_id=deleted_id)
        user_audit = Audit(user_id=deleted_id, subject_id=TEST_USER_ID)
        with SessionScope(db):
            db.session.add(subj_audit)
            db.session.add(user_audit)
            db.session.commit()
        subj_audit, user_audit = map(db.session.merge,
                                     (subj_audit, user_audit))
        subj_audit_id, user_audit_id = subj_audit.id, user_audit.id

        # create user_consent and audit
        consent_org = Organization(name='test org')
        consent_audit = Audit(user_id=TEST_USER_ID, subject_id=TEST_USER_ID)
        with SessionScope(db):
            db.session.add(consent_org)
            db.session.add(consent_audit)
            db.session.commit()
            db.session.add(UserConsent(
                                user_id=deleted_id,
                                organization_id=consent_org.id,
                                audit=consent_audit,
                                agreement_url='http://example.org',
                                options=STAFF_EDITABLE_MASK))
            db.session.commit()
        consent_org, consent_audit = map(db.session.merge,
                                         (consent_org, consent_audit))
        co_id, ca_id = consent_org.id, consent_audit.id

        # permanently deleted user, check deletion cascades
        permanently_delete_user(deleted_email, actor=actor_email)
        self.assertFalse(User.query.get(deleted_id))
        self.assertFalse(UserObservation.query.get(user_obs_id))
        self.assertTrue(Observation.query.get(observation_id))
        self.assertFalse(Audit.query.get(subj_audit_id))
        self.assertFalse(Audit.query.get(user_audit_id))
        self.assertFalse(UserConsent.query.get(co_id))
        self.assertFalse(Audit.query.get(ca_id))
Exemple #24
0
    def bless_with_basics(
            self, user=None, backdate=None, setdate=None,
            local_metastatic=None, make_patient=True):
        """Bless user with basic requirements for coredata

        :param user: user to bless, self.test_user by default
        :param backdate: timedelta value.  Define to mock consents
          happening said period in the past.  See
          ``associative_backdate`` for issues with 'months'.
        :param setdate: datetime value.  Define to mock consents
          happening at exact time in the past
        :param local_metastatic: set to 'localized' or 'metastatic' for
          tests needing those respective orgs assigned to the user
        :param make_patient: add patient role unless set False

        """
        if not user:
            user = db.session.merge(self.test_user)
        else:
            user = db.session.merge(user)
        user_id = user.id
        user.birthdate = datetime.utcnow()

        if make_patient:
            self.promote_user(user=user, role_name=ROLE.PATIENT.value)

        # Register with a clinic
        self.shallow_org_tree()

        if local_metastatic:
            org = Organization.query.filter(
                Organization.name == local_metastatic).one()
        else:
            org = Organization.query.filter(
                Organization.partOf_id.isnot(None)).first()
        assert org
        user = db.session.merge(user)
        user.organizations.append(org)

        # Agree to Terms of Use and sign consent
        audit = Audit(user_id=user_id, subject_id=user_id)
        tou = ToU(
            audit=audit, agreement_url='http://not.really.org',
            type='website terms of use')
        privacy = ToU(
            audit=audit, agreement_url='http://not.really.org',
            type='privacy policy')
        parent_org = OrgTree().find(org.id).top_level()
        options = (STAFF_EDITABLE_MASK | INCLUDE_IN_REPORTS_MASK |
                   SEND_REMINDERS_MASK)
        consent = UserConsent(
            user_id=user_id, organization_id=parent_org,
            options=options, audit=audit, agreement_url='http://fake.org',
            acceptance_date=calc_date_params(
                backdate=backdate, setdate=setdate))
        with SessionScope(db):
            db.session.add(tou)
            db.session.add(privacy)
            db.session.add(consent)
            db.session.commit()

        # Invalidate org tree cache, in case orgs are added by other
        # tests.  W/o doing so, the new orgs aren't in the orgtree
        OrgTree.invalidate_cache()
Exemple #25
0
    def test_outdated_inprogress_qb(self):
        # create base QB/RP
        org, rp, rp_id = self.setup_org_n_rp(org_name='testorg')
        qn = self.add_questionnaire(name='epic26')
        qn, org, self.test_user = map(db.session.merge,
                                      (qn, org, self.test_user))
        org_id = org.id
        qb = QuestionnaireBank(name='Test Questionnaire Bank',
                               classification='baseline',
                               research_protocol_id=rp_id,
                               start='{"days": 0}',
                               overdue='{"days": 7}',
                               expired='{"days": 90}')
        qbq = QuestionnaireBankQuestionnaire(questionnaire=qn, rank=0)
        qb.questionnaires.append(qbq)

        self.test_user.organizations.append(org)
        self.promote_user(role_name=ROLE.PATIENT.value)

        audit = Audit(user_id=TEST_USER_ID, subject_id=TEST_USER_ID)
        uc = UserConsent(user_id=TEST_USER_ID,
                         organization=org,
                         audit=audit,
                         agreement_url='http://no.com',
                         acceptance_date=now)

        with SessionScope(db):
            db.session.add(qb)
            db.session.add(self.test_user)
            db.session.add(audit)
            db.session.add(uc)
            db.session.commit()
        qb = db.session.merge(qb)

        # create in-progress QNR for User/QB/RP
        mock_qr(instrument_id='epic26',
                status='in-progress',
                timestamp=now,
                qb=qb)

        # User associated with CRV org should generate appropriate
        # questionnaires
        self.test_user = db.session.merge(self.test_user)
        qb_stat = QB_Status(self.test_user, now)
        qb = qb_stat.current_qbd().questionnaire_bank
        assert qb.research_protocol.name == 'proto'

        # Pointing the User's org to a new QB/RP
        # marking the old RP as retired as of yesterday
        old_rp = OrganizationResearchProtocol.query.filter(
            OrganizationResearchProtocol.organization_id == org_id,
            OrganizationResearchProtocol.research_protocol_id == rp_id).one()
        old_rp.retired_as_of = now - timedelta(days=1)
        rp2 = ResearchProtocol(name='new_proto')
        qn2 = self.add_questionnaire(name='epic27')
        with SessionScope(db):
            db.session.add(rp2)
            db.session.commit()
        rp2 = db.session.merge(rp2)
        rp2_id = rp2.id

        qn2, org = map(db.session.merge, (qn2, org))
        qb2 = QuestionnaireBank(name='Test Questionnaire Bank 2',
                                classification='baseline',
                                research_protocol_id=rp2_id,
                                start='{"days": 0}',
                                overdue='{"days": 7}',
                                expired='{"days": 90}')
        qbq2 = QuestionnaireBankQuestionnaire(questionnaire=qn2, rank=0)
        qb2.questionnaires.append(qbq2)

        org.research_protocols.append(rp2)

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

        # outdated QB/RP should be used as long as User has in-progress QNR
        self.test_user = db.session.merge(self.test_user)
        qb_stat = QB_Status(self.test_user, now)
        qb = qb_stat.current_qbd().questionnaire_bank
        assert qb.name == 'Test Questionnaire Bank'
        assert qb.research_protocol.name == 'proto'

        # completing QNR should result in completed status
        # shouldn't pick up new protocol till next iteration
        mock_qr(instrument_id='epic26',
                status='completed',
                timestamp=now,
                qb=qb)

        self.test_user = db.session.merge(self.test_user)
        invalidate_users_QBT(TEST_USER_ID)
        qb_stat = QB_Status(self.test_user, now)
        qb = qb_stat.current_qbd().questionnaire_bank
        assert qb.name == 'Test Questionnaire Bank'
        assert qb_stat.overall_status == OverallStatus.completed