def do_task(self, task, study_id, workflow_id, *args, **kwargs):
        self.check_args(args, 2)
        prefix = None
        if len(args) > 1:
            prefix = args[1]
        cmd = args[0]
        # study_info = {}
        # if self.__class__.__name__ in task.data:
        #     study_info = task.data[self.__class__.__name__]
        retval = None
        if cmd == 'info':
            study = session.query(StudyModel).filter_by(id=study_id).first()
            schema = StudySchema()
            retval = schema.dump(study)
        if cmd == 'investigators':
            retval = StudyService().get_investigators(study_id)
        if cmd == 'roles':
            retval = StudyService().get_investigators(study_id, all=True)
        if cmd == 'details':
            details = self.pb.get_study_details(study_id)
            if len(details) > 0:
                retval = details[0]
            else:
                retval = None
        if cmd == 'sponsors':
            retval = self.pb.get_sponsors(study_id)
        if cmd == 'documents':
            retval = StudyService().get_documents_status(study_id)

        return self.box_it(retval, prefix)
Exemple #2
0
def update_study(study_id, body):
    if study_id is None:
        raise ApiError('unknown_study', 'Please provide a valid Study ID.')

    study_model = session.query(StudyModel).filter_by(id=study_id).first()
    if study_model is None:
        raise ApiError('unknown_study',
                       'The study "' + study_id + '" is not recognized.')

    study: Study = StudySchema().load(body)
    study.update_model(study_model)
    session.add(study_model)
    session.commit()
    return StudySchema().dump(study)
Exemple #3
0
def get_study(study_id):
    study = StudyService.get_study(study_id)
    if (study is None):
        raise ApiError("unknown_study",
                       'The study "' + study_id + '" is not recognized.',
                       status_code=404)
    return StudySchema().dump(study)
Exemple #4
0
    def test_get_study(self):
        """Generic test, but pretty detailed, in that the study should return a categorized list of workflows
        This starts with out loading the example data, to show that all the bases are covered from ground 0."""
        """NOTE:  The protocol builder is not enabled or mocked out.  As the master workflow (which is empty),
        and the test workflow do not need it, and it is disabled in the configuration."""
        self.load_example_data()
        new_study = self.add_test_study()
        new_study = session.query(StudyModel).filter_by(
            id=new_study["id"]).first()

        api_response = self.app.get('/v1.0/study/%i' % new_study.id,
                                    headers=self.logged_in_headers(),
                                    content_type="application/json")
        self.assert_success(api_response)
        study = StudySchema().loads(api_response.get_data(as_text=True))

        self.assertEqual(study.title, self.TEST_STUDY['title'])
        self.assertEqual(study.primary_investigator_id,
                         self.TEST_STUDY['primary_investigator_id'])
        self.assertEqual(study.user_uid, self.TEST_STUDY['user_uid'])

        # Categories are read only, so switching to sub-scripting here.
        # This assumes there is one test category set up in the example data.
        category = study.categories[0]
        self.assertEqual("test_category", category['name'])
        self.assertEqual("Test Category", category['display_name'])
        self.assertEqual(1, len(category["workflows"]))
        workflow = category["workflows"][0]
        self.assertEqual("random_fact", workflow["name"])
        self.assertEqual("optional", workflow["state"])
        self.assertEqual("not_started", workflow["status"])
        self.assertEqual(0, workflow["total_tasks"])
        self.assertEqual(0, workflow["completed_tasks"])
Exemple #5
0
    def test_nonadmin_cannot_access_admin_only_endpoints(self):
        # Switch production mode on
        app.config['PRODUCTION'] = True

        self.load_example_data()

        # Non-admin user should not be able to delete a study
        non_admin_user = self._login_as_non_admin()
        non_admin_token_headers = dict(Authorization='Bearer ' +
                                       non_admin_user.encode_auth_token())
        non_admin_study = self._make_fake_study(non_admin_user.uid)

        rv_add_study = self.app.post('/v1.0/study',
                                     content_type="application/json",
                                     headers=non_admin_token_headers,
                                     data=json.dumps(
                                         StudySchema().dump(non_admin_study)))
        self.assert_success(rv_add_study,
                            'Non-admin user should be able to add a study')

        new_non_admin_study = json.loads(rv_add_study.get_data(as_text=True))
        db_non_admin_study = session.query(StudyModel).filter_by(
            id=new_non_admin_study['id']).first()
        self.assertIsNotNone(db_non_admin_study)

        rv_non_admin_del_study = self.app.delete(
            '/v1.0/study/%i' % db_non_admin_study.id,
            follow_redirects=False,
            headers=non_admin_token_headers)
        self.assert_failure(rv_non_admin_del_study, 401)

        # Switch production mode back off
        app.config['PRODUCTION'] = False
Exemple #6
0
    def test_get_study_has_details_about_files(self):

        # Set up the study and attach a file to it.
        self.load_example_data()
        self.create_reference_document()
        workflow = self.create_workflow('file_upload_form')
        processor = WorkflowProcessor(workflow)
        task = processor.next_task()
        irb_code = "UVACompl_PRCAppr"  # The first file referenced in pb required docs.
        FileService.add_workflow_file(workflow_id=workflow.id,
                                      name="anything.png",
                                      content_type="png",
                                      binary_data=b'1234',
                                      irb_doc_code=irb_code)

        api_response = self.app.get('/v1.0/study/%i' % workflow.study_id,
                                    headers=self.logged_in_headers(),
                                    content_type="application/json")
        self.assert_success(api_response)
        study = StudySchema().loads(api_response.get_data(as_text=True))
        self.assertEqual(1, len(study.files))
        self.assertEqual("UVA Compliance/PRC Approval",
                         study.files[0]["category"])
        self.assertEqual("Cancer Center's PRC Approval Form",
                         study.files[0]["description"])
        self.assertEqual("UVA Compliance/PRC Approval.png",
                         study.files[0]["download_name"])
def add_study(body):
    """Or any study like object. Body should include a title, and primary_investigator_id """
    if 'primary_investigator_id' not in body:
        raise ApiError(
            "missing_pi",
            "Can't create a new study without a Primary Investigator.")
    if 'title' not in body:
        raise ApiError("missing_title",
                       "Can't create a new study without a title.")

    study_model = StudyModel(
        user_uid=UserService.current_user().uid,
        title=body['title'],
        primary_investigator_id=body['primary_investigator_id'],
        last_updated=datetime.utcnow(),
        status=StudyStatus.in_progress)
    session.add(study_model)
    StudyService.add_study_update_event(study_model,
                                        status=StudyStatus.in_progress,
                                        event_type=StudyEventType.user,
                                        user_uid=g.user.uid)

    errors = StudyService._add_all_workflow_specs_to_study(study_model)
    session.commit()
    study = StudyService().get_study(study_model.id, do_status=True)
    study_data = StudySchema().dump(study)
    study_data["errors"] = ApiErrorSchema(many=True).dump(errors)
    return study_data
Exemple #8
0
 def add_test_study(self):
     rv = self.app.post('/v1.0/study',
                        content_type="application/json",
                        headers=self.logged_in_headers(),
                        data=json.dumps(StudySchema().dump(
                            self.TEST_STUDY)))
     self.assert_success(rv)
     return json.loads(rv.get_data(as_text=True))
 def add_test_study(self):
     study_schema = StudySchema().dump(self.TEST_STUDY)
     study_schema['status'] = StudyStatus.in_progress.value
     rv = self.app.post('/v1.0/study',
                        content_type="application/json",
                        headers=self.logged_in_headers(),
                        data=json.dumps(study_schema))
     self.assert_success(rv)
     return json.loads(rv.get_data(as_text=True))
    def put_study_on_hold(self, study_id):
        study = session.query(StudyModel).filter_by(id=study_id).first()

        study_schema = StudySchema().dump(study)
        study_schema['status'] = 'hold'
        study_schema['comment'] = 'This is my hold comment'

        self.update_study_status(study, study_schema)

        study_result = session.query(StudyModel).filter(StudyModel.id == study_id).first()
        return study_result
def user_studies():
    """Returns all the studies associated with the current user. """
    user = UserService.current_user(allow_admin_impersonate=True)
    StudyService.synch_with_protocol_builder_if_enabled(user)
    studies = StudyService().get_studies_for_user(user)
    if len(studies) == 0:
        studies = StudyService().get_studies_for_user(user,
                                                      include_invalid=True)
        if len(studies) > 0:
            message = f"All studies associated with User: {user.uid} failed study validation"
            raise ApiError(code="study_integrity_error", message=message)

    results = StudySchema(many=True).dump(studies)
    return results
    def test_abandon_study(self, mock_details):
        self.load_example_data()
        details_response = self.protocol_builder_response('study_details.json')
        mock_details.return_value = json.loads(details_response)

        study = session.query(StudyModel).first()
        self.assertEqual(study.status, StudyStatus.in_progress)

        study_schema = StudySchema().dump(study)
        study_schema['status'] = 'abandoned'
        study_schema['comment'] = 'This is my abandon comment'

        study_result = self.update_study_status(study, study_schema)
        self.assertEqual(StudyStatus.abandoned, study_result.status)
Exemple #13
0
 def test_update_study(self):
     self.load_example_data()
     study: StudyModel = session.query(StudyModel).first()
     study.title = "Pilot Study of Fjord Placement for Single Fraction Outcomes to Cortisol Susceptibility"
     study.protocol_builder_status = ProtocolBuilderStatus.ACTIVE
     rv = self.app.put('/v1.0/study/%i' % study.id,
                       content_type="application/json",
                       headers=self.logged_in_headers(),
                       data=json.dumps(StudySchema().dump(study)))
     self.assert_success(rv)
     json_data = json.loads(rv.get_data(as_text=True))
     self.assertEqual(study.title, json_data['title'])
     self.assertEqual(study.protocol_builder_status.name,
                      json_data['protocol_builder_status'])
Exemple #14
0
    def test_admin_can_access_admin_only_endpoints(self):
        # Switch production mode on
        app.config['PRODUCTION'] = True

        self.load_example_data()

        admin_uids = app.config['ADMIN_UIDS']
        self.assertGreater(len(admin_uids), 0)
        admin_uid = admin_uids[0]
        self.assertEqual(admin_uid,
                         'dhf8r')  # This user is in the test ldap system.
        admin_headers = dict(Uid=admin_uid)

        rv = self.app.get('v1.0/login',
                          follow_redirects=False,
                          headers=admin_headers)
        self.assert_success(rv)

        admin_user = db.session.query(UserModel).filter(
            UserModel.uid == admin_uid).first()
        self.assertIsNotNone(admin_user)
        self.assertEqual(admin_uid, admin_user.uid)

        admin_study = self._make_fake_study(admin_uid)

        admin_token_headers = dict(Authorization='Bearer ' +
                                   admin_user.encode_auth_token().decode())

        rv_add_study = self.app.post('/v1.0/study',
                                     content_type="application/json",
                                     headers=admin_token_headers,
                                     data=json.dumps(
                                         StudySchema().dump(admin_study)),
                                     follow_redirects=False)
        self.assert_success(rv_add_study,
                            'Admin user should be able to add a study')

        new_admin_study = json.loads(rv_add_study.get_data(as_text=True))
        db_admin_study = db.session.query(StudyModel).filter_by(
            id=new_admin_study['id']).first()
        self.assertIsNotNone(db_admin_study)

        rv_del_study = self.app.delete('/v1.0/study/%i' % db_admin_study.id,
                                       follow_redirects=False,
                                       headers=admin_token_headers)
        self.assert_success(rv_del_study,
                            'Admin user should be able to delete a study')

        # Switch production mode back off
        app.config['PRODUCTION'] = False
    def test_open_enrollment_study(self, mock_details):
        self.load_example_data()
        details_response = self.protocol_builder_response('study_details.json')
        mock_details.return_value = json.loads(details_response)

        study = session.query(StudyModel).first()
        self.assertEqual(study.status, StudyStatus.in_progress)

        study_schema = StudySchema().dump(study)
        study_schema['status'] = 'open_for_enrollment'
        study_schema['comment'] = 'This is my open enrollment comment'
        study_schema['enrollment_date'] = '2021-01-04T05:00:00.000Z'

        study_result = self.update_study_status(study, study_schema)
        self.assertEqual(StudyStatus.open_for_enrollment, study_result.status)
Exemple #16
0
    def do_task(self, task, study_id, workflow_id, *args, **kwargs):
        self.check_args(args)

        cmd = args[0]
        study_info = {}
        if self.__class__.__name__ in task.data:
            study_info = task.data[self.__class__.__name__]

        if cmd == 'info':
            study = session.query(StudyModel).filter_by(id=study_id).first()
            schema = StudySchema()
            self.add_data_to_task(task, {cmd: schema.dump(study)})
        if cmd == 'investigators':
            self.add_data_to_task(task, {cmd: StudyService().get_investigators(study_id)})
        if cmd == 'roles':
            self.add_data_to_task(task, {cmd: StudyService().get_investigators(study_id, all=True)})
        if cmd == 'details':
            self.add_data_to_task(task, {cmd: self.pb.get_study_details(study_id)})
        if cmd == 'approvals':
            self.add_data_to_task(task, {cmd: StudyService().get_approvals(study_id)})
        if cmd == 'documents':
            self.add_data_to_task(task, {cmd: StudyService().get_documents_status(study_id)})
        if cmd == 'protocol':
            self.add_data_to_task(task, {cmd: StudyService().get_protocol(study_id)})
Exemple #17
0
    def test_get_study_has_details_about_approvals(self):
        self.load_example_data()
        full_study = self._create_study_workflow_approvals(
            user_uid="dhf8r",
            title="first study",
            primary_investigator_id="lb3dp",
            approver_uids=["lb3dp", "dhf8r"],
            statuses=[
                ApprovalStatus.PENDING.value, ApprovalStatus.PENDING.value
            ])

        api_response = self.app.get('/v1.0/study/%i' % full_study['study'].id,
                                    headers=self.logged_in_headers(),
                                    content_type="application/json")
        self.assert_success(api_response)
        study = StudySchema().loads(api_response.get_data(as_text=True))

        self.assertEqual(len(study.approvals), 2)

        for approval in study.approvals:
            self.assertEqual(full_study['study'].title, approval['title'])
def update_study(study_id, body):
    """Pretty limited, but allows manual modifications to the study status """
    if study_id is None:
        raise ApiError('unknown_study', 'Please provide a valid Study ID.')

    study_model = session.query(StudyModel).filter_by(id=study_id).first()
    if study_model is None:
        raise ApiError('unknown_study',
                       'The study "' + study_id + '" is not recognized.')

    study: Study = StudyForUpdateSchema().load(body)

    status = StudyStatus(study.status)
    study_model.last_updated = datetime.utcnow()

    if study_model.status != status:
        study_model.status = status
        StudyService.add_study_update_event(
            study_model,
            status,
            StudyEventType.user,
            user_uid=UserService.current_user().uid
            if UserService.has_user() else None,
            comment='' if not hasattr(study, 'comment') else study.comment,
        )

    if status == StudyStatus.open_for_enrollment:
        study_model.enrollment_date = study.enrollment_date

    session.add(study_model)
    session.commit()

    if status == StudyStatus.abandoned or status == StudyStatus.hold:
        WorkflowService.process_workflows_for_cancels(study_id)

    # Need to reload the full study to return it to the frontend
    study = StudyService.get_study(study_id)
    return StudySchema().dump(study)
    def test_update_study(self):
        self.load_example_data()
        update_comment = 'Updating the study'
        study: StudyModel = session.query(StudyModel).first()
        study.title = "Pilot Study of Fjord Placement for Single Fraction Outcomes to Cortisol Susceptibility"
        study_schema = StudySchema().dump(study)
        study_schema['status'] = StudyStatus.hold.value
        study_schema['comment'] = update_comment
        rv = self.app.put('/v1.0/study/%i' % study.id,
                          content_type="application/json",
                          headers=self.logged_in_headers(),
                          data=json.dumps(study_schema))
        self.assert_success(rv)
        json_data = json.loads(rv.get_data(as_text=True))
        self.assertEqual(study.title, json_data['title'])
        self.assertEqual(study.status.value, json_data['status'])

        # Making sure events history is being properly recorded
        study_event = session.query(StudyEvent).first()
        self.assertIsNotNone(study_event)
        self.assertEqual(study_event.status, StudyStatus.hold)
        self.assertEqual(study_event.event_type, StudyEventType.user)
        self.assertEqual(study_event.comment, update_comment)
        self.assertEqual(study_event.user_uid, self.test_uid)
Exemple #20
0
def add_study(body):
    """Or any study like object. Body should include a title, and primary_investigator_id """
    if 'primary_investigator_id' not in body:
        raise ApiError(
            "missing_pi",
            "Can't create a new study without a Primary Investigator.")
    if 'title' not in body:
        raise ApiError("missing_title",
                       "Can't create a new study without a title.")

    study_model = StudyModel(
        user_uid=g.user.uid,
        title=body['title'],
        primary_investigator_id=body['primary_investigator_id'],
        last_updated=datetime.now(),
        protocol_builder_status=ProtocolBuilderStatus.ACTIVE)

    session.add(study_model)
    errors = StudyService._add_all_workflow_specs_to_study(study_model)
    session.commit()
    study = StudyService().get_study(study_model.id)
    study_data = StudySchema().dump(study)
    study_data["errors"] = ApiErrorSchema(many=True).dump(errors)
    return study_data
Exemple #21
0
def all_studies():
    """Returns all studies (regardless of user) with submitted files"""
    studies = StudyService.get_all_studies_with_files()
    results = StudySchema(many=True).dump(studies)
    return results
Exemple #22
0
    def test_admin_can_impersonate_another_user(self, mock_details):
        details_response = self.protocol_builder_response('study_details.json')
        mock_details.return_value = json.loads(details_response)
        # Switch production mode on
        app.config['PRODUCTION'] = True

        self.load_example_data()

        admin_user = self._login_as_admin()
        admin_token_headers = dict(Authorization='Bearer ' +
                                   admin_user.encode_auth_token())

        # User should not be in the system yet.
        # non_admin_user = session.query(UserModel).filter(UserModel.uid == self.non_admin_uid).first()
        # self.assertIsNone(non_admin_user)

        # Admin should not be able to impersonate non-existent user
        # rv_1 = self.app.get(
        #    '/v1.0/user?admin_impersonate_uid=' + self.non_admin_uid,
        #    content_type="application/json",
        #    headers=admin_token_headers,
        #    follow_redirects=False
        #)
        # self.assert_failure(rv_1, 400)

        # Add the non-admin user now
        self.logout()
        non_admin_user = self._login_as_non_admin()
        self.assertEqual(non_admin_user.uid, self.non_admin_uid)
        non_admin_token_headers = dict(Authorization='Bearer ' +
                                       non_admin_user.encode_auth_token())

        # Add a study for the non-admin user
        non_admin_study = self._make_fake_study(self.non_admin_uid)
        rv_add_study = self.app.post('/v1.0/study',
                                     content_type="application/json",
                                     headers=non_admin_token_headers,
                                     data=json.dumps(
                                         StudySchema().dump(non_admin_study)))
        self.assert_success(rv_add_study,
                            'Non-admin user should be able to add a study')
        self.logout()

        # Admin should be able to impersonate user now
        admin_user = self._login_as_admin()
        rv_2 = self.app.get('/v1.0/user?admin_impersonate_uid=' +
                            self.non_admin_uid,
                            content_type="application/json",
                            headers=admin_token_headers,
                            follow_redirects=False)
        self.assert_success(rv_2)
        user_data_2 = json.loads(rv_2.get_data(as_text=True))
        self.assertEqual(user_data_2['uid'], self.non_admin_uid,
                         'Admin user should impersonate non-admin user')

        # Study endpoint should return non-admin user's studies
        rv_study = self.app.get('/v1.0/study',
                                content_type="application/json",
                                headers=admin_token_headers,
                                follow_redirects=False)
        self.assert_success(
            rv_study,
            'Admin user should be able to get impersonated user studies')
        study_data = json.loads(rv_study.get_data(as_text=True))
        self.assertGreaterEqual(len(study_data), 1)
        self.assertEqual(study_data[0]['user_uid'], self.non_admin_uid)

        # Switch production mode back off
        app.config['PRODUCTION'] = False
Exemple #23
0
def user_studies():
    """Returns all the studies associated with the current user. """
    StudyService.synch_with_protocol_builder_if_enabled(g.user)
    studies = StudyService.get_studies_for_user(g.user)
    results = StudySchema(many=True).dump(studies)
    return results