Ejemplo n.º 1
0
def sample_template_checks(study_id, user, check_exists=False):
    """Performs different checks and raises errors if any of the checks fail

    Parameters
    ----------
    study_id : int
        The study id
    user : qiita_db.user.User
        The user trying to access the study
    check_exists : bool, optional
        If true, check if the sample template exists

    Raises
    ------
    HTTPError
        404 if the study does not exist
        403 if the user does not have access to the study
        404 if check_exists == True and the sample template doesn't exist
    """
    try:
        study = Study(int(study_id))
    except QiitaDBUnknownIDError:
        raise HTTPError(404, reason='Study does not exist')
    if not study.has_access(user):
        raise HTTPError(403, reason='User does not have access to study')

    # Check if the sample template exists
    if check_exists and not SampleTemplate.exists(study_id):
        raise HTTPError(404,
                        reason="Study %s doesn't have sample information" %
                        study_id)
Ejemplo n.º 2
0
    def test_build_study_info(self):
        for a in Study(1).artifacts():
            a.visibility = 'private'

        obs = _build_study_info(User('*****@*****.**'), 'user')
        self.assertEqual(obs, self.exp)

        obs = _build_study_info(User('*****@*****.**'), 'public')
        self.assertEqual(obs, [])

        obs = _build_study_info(User('*****@*****.**'), 'public')
        self.assertEqual(obs, [])

        # make all the artifacts public - (1) the only study in the tests,
        for a in Study(1).artifacts():
            a.visibility = 'public'
        self.exp[0]['status'] = 'public'

        obs = _build_study_info(User('*****@*****.**'), 'user')
        self.assertEqual(obs, self.exp)

        obs = _build_study_info(User('*****@*****.**'), 'public')
        self.assertEqual(obs, [])

        obs = _build_study_info(User('*****@*****.**'), 'public')
        self.assertEqual(obs, self.exp)

        # return to it's private status
        for a in Study(1).artifacts():
            a.visibility = 'private'
Ejemplo n.º 3
0
    def test_create_nonqiita_portal(self):
        qiita_config.portal = "EMP"
        Study.create(User("*****@*****.**"), "NEW!", [1], self.info, Investigation(1))

        # make sure portal is associated
        obs = self.conn_handler.execute_fetchall("SELECT * from qiita.study_portal WHERE study_id = 2")
        self.assertEqual(obs, [[2, 2], [2, 1]])
Ejemplo n.º 4
0
    def setUp(self):
        fd, self.seqs_fp = mkstemp(suffix='_seqs.fastq')
        close(fd)
        fd, self.barcodes_fp = mkstemp(suffix='_barcodes.fastq')
        close(fd)
        self.filetype = 2
        self.filepaths = [(self.seqs_fp, 1), (self.barcodes_fp, 2)]
        self.studies = [Study(1)]
        _, self.db_test_raw_dir = get_mountpoint('raw_data')[0]

        with open(self.seqs_fp, "w") as f:
            f.write("\n")
        with open(self.barcodes_fp, "w") as f:
            f.write("\n")
        self._clean_up_files = []

        # Create a new study
        info = {
            "timeseries_type_id": 1,
            "metadata_complete": True,
            "mixs_compliant": True,
            "number_samples_collected": 25,
            "number_samples_promised": 28,
            "portal_type_id": 3,
            "study_alias": "FCM",
            "study_description": "Microbiome of people who eat nothing but "
                                 "fried chicken",
            "study_abstract": "Exploring how a high fat diet changes the "
                              "gut microbiome",
            "emp_person_id": StudyPerson(2),
            "principal_investigator_id": StudyPerson(3),
            "lab_person_id": StudyPerson(1)
        }
        Study.create(User("*****@*****.**"), "Test study 2", [1], info)
Ejemplo n.º 5
0
    def delete_study(self, study, user, callback):
        """Delete study

        Parameters
        ----------
        study : Study
            The current study object
        user : User
            The current user object
        callback : function
            The callback function to call with the results once the processing
            is done and it fails
        """
        study_id = study.id
        study_title = study.title

        try:
            Study.delete(study_id)

            # redirecting to list but also passing messages
            # we need to change the request.method to GET
            self.request.method = 'GET'
            ListStudiesHandler(self.application, self.request)._execute(
                [t(self.request) for t in self.application.transforms],
                message=('Study "%s" has been deleted' % study_title),
                msg_level='success')
        except Exception as e:
            msg = "Couldn't remove study %d: %s" % (study_id, str(e))
            msg_level = "danger"

            callback((msg, msg_level, 'study_information_tab', None, None))
Ejemplo n.º 6
0
    def test_delete_study(self):
        # as samples have been submitted to EBI, this will fail
        job = self._create_job('delete_study', {'study': 1})
        private_task(job.id)
        self.assertEqual(job.status, 'error')
        self.assertIn(
            "Cannot delete artifact 2: Artifact 2 has been "
            "submitted to EBI", job.log.msg)
        # making sure the analysis, first thing to delete, still exists
        self.assertTrue(Analysis.exists(1))

        # delete everything from the EBI submissions and the processing job so
        # we can try again: test success (with tags)
        with TRN:
            sql = """DELETE FROM qiita.ebi_run_accession"""
            TRN.add(sql)
            sql = """DELETE FROM qiita.artifact_processing_job"""
            TRN.add(sql)
            TRN.execute()

            # adding tags
            Study(1).update_tags(self.user, ['my new tag!'])

            job = self._create_job('delete_study', {'study': 1})
            private_task(job.id)

            self.assertEqual(job.status, 'success')
            with self.assertRaises(QiitaDBUnknownIDError):
                Study(1)
Ejemplo n.º 7
0
def check_access(study_id, user_id):
    """Checks if user given has access to the study given

    Parameters
    ----------
    study_id : int
        ID of the study to check access to
    user_id : str
        ID of the user to check access for

    Returns
    -------
    dict
        Empty dict if access allowed, else a dict in the form
        {'status': 'error',
         'message': reason for error}

    """
    try:
        study = Study(int(study_id))
    except QiitaDBUnknownIDError:
        return {'status': 'error',
                'message': 'Study does not exist'}
    if not study.has_access(User(user_id)):
        return {'status': 'error',
                'message': 'User does not have access to study'}
    return {}
Ejemplo n.º 8
0
    def test_build_study_info_new_study(self):
        info = {
            'timeseries_type_id': 1,
            'lab_person_id': None,
            'principal_investigator_id': 3,
            'metadata_complete': False,
            'mixs_compliant': True,
            'study_description': 'desc',
            'study_alias': 'alias',
            'study_abstract': 'abstract'
        }
        user = User('*****@*****.**')

        Study.create(user, 'test_study_1', efo=[1], info=info)
        obs = _build_study_info(user)
        self.exp.append({
            'study_id': 2,
            'status': 'sandbox',
            'study_abstract': 'abstract',
            'metadata_complete': False,
            'study_title': 'test_study_1',
            'num_raw_data': 0,
            'number_samples_collected': 0,
            'shared': '',
            'pmid': '',
            'publication_doi': '',
            'pi':
            '<a target="_blank" href="mailto:[email protected]">PIDude</a>',
            'proc_data_info': []
        })
        self.assertEqual(obs, self.exp)
Ejemplo n.º 9
0
    def test_build_study_info_new_study(self):
        info = {
            'timeseries_type_id': 1,
            'lab_person_id': None,
            'principal_investigator_id': 3,
            'metadata_complete': False,
            'mixs_compliant': True,
            'study_description': 'desc',
            'study_alias': 'alias',
            'study_abstract': 'abstract'}
        user = User('*****@*****.**')

        Study.create(user, 'test_study_1', efo=[1], info=info)
        obs = _build_study_info(user)
        self.exp.append({
            'study_id': 2,
            'status': 'sandbox',
            'study_abstract': 'abstract',
            'metadata_complete': False,
            'study_title': 'test_study_1',
            'num_raw_data': 0,
            'number_samples_collected': 0,
            'shared': '',
            'pmid': '',
            'publication_doi': '',
            'pi':
                '<a target="_blank" href="mailto:[email protected]">PIDude</a>',
            'proc_data_info': []})
        self.assertEqual(obs, self.exp)
Ejemplo n.º 10
0
def study_get_req(study_id, user_id):
    """Returns information available for the given study

    Parameters
    ----------
    study_id : int
        Study id to get prep template info for
    user_id : str
        User requesting the info

    Returns
    -------
    dict
        Data types information in the form
        {'status': status,
         'message': message,
         'info': dict of objects
        status can be success, warning, or error depending on result
        message has the warnings or errors
        info contains study information seperated by data type, in the form
        {col_name: value, ...} with value being a string, int, or list of
        strings or ints
    """
    access_error = check_access(study_id, user_id)
    if access_error:
        return access_error
    # Can only pass ids over API, so need to instantiate object
    study = Study(study_id)
    study_info = study.info
    # Add needed info that is not part of the initial info pull
    study_info['publications'] = study.publications
    study_info['study_id'] = study.id
    study_info['study_title'] = study.title
    study_info['shared_with'] = [s.id for s in study.shared_with]
    study_info['status'] = study.status
    study_info['ebi_study_accession'] = study.ebi_study_accession
    study_info['ebi_submission_status'] = study.ebi_submission_status

    # Clean up StudyPerson objects to string for display
    pi = study_info['principal_investigator']
    study_info['principal_investigator'] = {
        'name': pi.name,
        'email': pi.email,
        'affiliation': pi.affiliation}

    lab_person = study_info['lab_person']
    if lab_person:
        study_info['lab_person'] = {
            'name': lab_person.name,
            'email': lab_person.email,
            'affiliation': lab_person.affiliation}

    samples = study.sample_template
    study_info['num_samples'] = 0 if samples is None else len(list(samples))
    study_info['owner'] = study.owner.id

    return {'status': 'success',
            'message': '',
            'study_info': study_info,
            'editable': study.can_edit(User(user_id))}
Ejemplo n.º 11
0
    def test_build_study_info_new_study(self):
        ProcessedData(1).status = 'public'
        info = {
            'timeseries_type_id': 1,
            'portal_type_id': 1,
            'lab_person_id': None,
            'principal_investigator_id': 3,
            'metadata_complete': False,
            'mixs_compliant': True,
            'study_description': 'desc',
            'study_alias': 'alias',
            'study_abstract': 'abstract'}
        user = User('*****@*****.**')

        Study.create(user, 'test_study_1', efo=[1], info=info)
        obs = _build_study_info(user)
        self.exp.append({
            'status': 'sandbox',
            'checkbox': "<input type='checkbox' value='2' />",
            'abstract': 'abstract',
            'meta_complete': "<span class='glyphicon glyphicon-remove'>"
            "</span>",
            'title': '<a href=\'#\' data-toggle=\'modal\' data-target=\'#study'
            '-abstract-modal\' onclick=\'fillAbstract("studies-table"'
            ', 1)\'><span class=\'glyphicon glyphicon-file\' aria-hidden=\''
            'true\'></span></a> | <a href=\'/study/description/2\' id=\''
            'study1-title\'>test_study_1</a>',
            'num_raw_data': 0, 'id': 2, 'num_samples': '0',
            'shared': "<span id='shared_html_2'></span><br/><a class='btn "
            "btn-primary btn-xs' data-toggle='modal' data-target='#share-study"
            "-modal-view' onclick='modify_sharing(2);'>Modify</a>",
            'pmid': '', 'pi':
            '<a target="_blank" href="mailto:[email protected]">PIDude</a>'})
        self.assertEqual(obs, self.exp)
Ejemplo n.º 12
0
def check_access(study_id, user_id):
    """Checks if user given has access to the study given

    Parameters
    ----------
    study_id : int
        ID of the study to check access to
    user_id : str
        ID of the user to check access for

    Returns
    -------
    dict
        Empty dict if access allowed, else a dict in the form
        {'status': 'error',
         'message': reason for error}

    """
    try:
        study = Study(int(study_id))
    except QiitaDBUnknownIDError:
        return {'status': 'error', 'message': 'Study does not exist'}
    if not study.has_access(User(user_id)):
        return {
            'status': 'error',
            'message': 'User does not have access to study'
        }
    return {}
Ejemplo n.º 13
0
    def get(self, arguments):
        study_id = int(self.get_argument('study_id'))

        # this block is tricky because you can either pass the sample or the
        # prep template and if none is passed then we will let an exception
        # be raised because template will not be declared for the logic below
        if self.get_argument('prep_template', None):
            template = PrepTemplate(int(self.get_argument('prep_template')))
        if self.get_argument('sample_template', None):
            template = None
            tid = int(self.get_argument('sample_template'))
            try:
                template = SampleTemplate(tid)
            except QiitaDBUnknownIDError:
                raise HTTPError(404, "SampleTemplate %d does not exist" % tid)

        study = Study(template.study_id)

        # check whether or not the user has access to the requested information
        if not study.has_access(User(self.current_user)):
            raise HTTPError(403, "You do not have access to access this "
                                 "information.")

        df = dataframe_from_template(template)
        stats = stats_from_df(df)

        self.render('metadata_summary.html', user=self.current_user,
                    study_title=study.title, stats=stats,
                    study_id=study_id)
Ejemplo n.º 14
0
    def test_delete_study_empty_study(self):
        info = {
            "timeseries_type_id": '1',
            "metadata_complete": 'true',
            "mixs_compliant": 'true',
            "number_samples_collected": 25,
            "number_samples_promised": 28,
            "study_alias": "FCM",
            "study_description": "Microbiome of people who eat nothing but "
            "fried chicken",
            "study_abstract": "Exploring how a high fat diet changes the "
            "gut microbiome",
            "emp_person_id": StudyPerson(2),
            "principal_investigator_id": StudyPerson(3),
            "lab_person_id": StudyPerson(1)
        }
        new_study = Study.create(User('*****@*****.**'),
                                 "Fried Chicken Microbiome %s" % time(), info)
        job = self._create_job('delete_study', {'study': new_study.id})
        private_task(job.id)
        self.assertEqual(job.status, 'success')

        # making sure the study doesn't exist
        with self.assertRaises(QiitaDBUnknownIDError):
            Study(new_study.id)
Ejemplo n.º 15
0
def _build_study_info(studytype, user=None):
    """builds list of namedtuples for study listings"""
    if studytype == "private":
        studylist = user.user_studies
    elif studytype == "shared":
        studylist = user.shared_studies
    elif studytype == "public":
        studylist = Study.get_by_status('public')
    else:
        raise IncompetentQiitaDeveloperError("Must use private, shared, "
                                             "or public!")

    StudyTuple = namedtuple(
        'StudyInfo', 'id title meta_complete '
        'num_samples_collected shared num_raw_data pi '
        'pmids owner status')

    infolist = []
    for s_id in studylist:
        study = Study(s_id)
        status = study.status
        # Just passing the email address as the name here, since
        # name is not a required field in qiita.qiita_user
        owner = study_person_linkifier((study.owner, study.owner))
        info = study.info
        PI = StudyPerson(info['principal_investigator_id'])
        PI = study_person_linkifier((PI.email, PI.name))
        pmids = ", ".join([pubmed_linkifier([pmid]) for pmid in study.pmids])
        shared = _get_shared_links_for_study(study)
        infolist.append(
            StudyTuple(study.id, study.title, info["metadata_complete"],
                       info["number_samples_collected"], shared,
                       len(study.raw_data()), PI, pmids, owner, status))
    return infolist
Ejemplo n.º 16
0
    def delete_study(self, study, user, callback):
        """Delete study

        Parameters
        ----------
        study : Study
            The current study object
        user : User
            The current user object
        callback : function
            The callback function to call with the results once the processing
            is done and it fails
        """
        study_id = study.id
        study_title = study.title

        try:
            Study.delete(study_id)

            # redirecting to list but also passing messages
            # we need to change the request.method to GET
            self.request.method = 'GET'
            ListStudiesHandler(self.application, self.request)._execute(
                [t(self.request) for t in self.application.transforms],
                message=('Study "%s" has been deleted' % study_title),
                msg_level='success')
        except Exception as e:
            msg = "Couldn't remove study %d: %s" % (study_id, str(e))
            msg_level = "danger"

            callback((msg, msg_level, 'study_information_tab', None, None))
Ejemplo n.º 17
0
    def test_artifact_post_req(self):
        # Create new prep template to attach artifact to
        pt = npt.assert_warns(
            QiitaDBWarning, PrepTemplate.create,
            pd.DataFrame({'new_col': {'1.SKD6.640190': 1}}), Study(1), '16S')
        self._files_to_remove.extend([fp for _, fp in pt.get_filepaths()])

        filepaths = {'raw_forward_seqs': 'uploaded_file.txt',
                     'raw_barcodes': 'update.txt'}
        obs = artifact_post_req(
            '*****@*****.**', filepaths, 'FASTQ', 'New Test Artifact', pt.id)
        exp = {'status': 'success',
               'message': ''}
        self.assertEqual(obs, exp)
        wait_for_prep_information_job(pt.id)

        # Test importing an artifact
        # Create new prep template to attach artifact to
        pt = npt.assert_warns(
            QiitaDBWarning, PrepTemplate.create,
            pd.DataFrame({'new_col': {'1.SKD6.640190': 1}}), Study(1), '16S')
        self._files_to_remove.extend([fp for _, fp in pt.get_filepaths()])

        obs = artifact_post_req(
            '*****@*****.**', {}, 'Demultiplexed', 'New Test Artifact 2',
            pt.id, 3)
        exp = {'status': 'success',
               'message': ''}
        self.assertEqual(obs, exp)

        wait_for_prep_information_job(pt.id)
        # Instantiate the artifact to make sure it was made and
        # to clean the environment
        a = Artifact(pt.artifact.id)
        self._files_to_remove.extend([fp for _, fp, _ in a.filepaths])
Ejemplo n.º 18
0
    def test_build_study_info_new_study(self):
        info = {
            'timeseries_type_id': 1,
            'portal_type_id': 1,
            'lab_person_id': None,
            'principal_investigator_id': 3,
            'metadata_complete': False,
            'mixs_compliant': True,
            'study_description': 'desc',
            'study_alias': 'alias',
            'study_abstract': 'abstract'}
        user = User('*****@*****.**')

        Study.create(user, 'test_study_1', efo=[1], info=info)

        obs = _build_study_info('private', user)

        StudyTuple = namedtuple('StudyInfo', 'id title meta_complete '
                                'num_samples_collected shared num_raw_data pi '
                                'pmids owner status')
        exp = [
            StudyTuple(
                id=2,
                title='test_study_1',
                meta_complete=False, num_samples_collected=None,
                shared='',
                num_raw_data=0,
                pi='<a target="_blank" href="mailto:[email protected]">'
                   'PIDude</a>',
                pmids='',
                owner='<a target="_blank" href="mailto:[email protected]">'
                      '[email protected]</a>',
                status='sandbox')]
        self.assertEqual(obs, exp)
Ejemplo n.º 19
0
    def setUp(self):
        fd, self.seqs_fp = mkstemp(suffix='_seqs.fastq')
        close(fd)
        fd, self.barcodes_fp = mkstemp(suffix='_barcodes.fastq')
        close(fd)
        self.filetype = 2
        self.filepaths = [(self.seqs_fp, 1), (self.barcodes_fp, 2)]
        self.studies = [Study(1)]
        _, self.db_test_raw_dir = get_mountpoint('raw_data')[0]

        with open(self.seqs_fp, "w") as f:
            f.write("\n")
        with open(self.barcodes_fp, "w") as f:
            f.write("\n")
        self._clean_up_files = []

        # Create a new study
        info = {
            "timeseries_type_id": 1,
            "metadata_complete": True,
            "mixs_compliant": True,
            "number_samples_collected": 25,
            "number_samples_promised": 28,
            "portal_type_id": 3,
            "study_alias": "FCM",
            "study_description": "Microbiome of people who eat nothing but "
                                 "fried chicken",
            "study_abstract": "Exploring how a high fat diet changes the "
                              "gut microbiome",
            "emp_person_id": StudyPerson(2),
            "principal_investigator_id": StudyPerson(3),
            "lab_person_id": StudyPerson(1)
        }
        Study.create(User("*****@*****.**"), "Test study 2", [1], info)
Ejemplo n.º 20
0
    def test_build_study_info_empty_study(self):
        info = {
            'timeseries_type_id': 1,
            'lab_person_id': None,
            'principal_investigator_id': 3,
            'metadata_complete': False,
            'mixs_compliant': True,
            'study_description': 'desc',
            'study_alias': 'alias',
            'study_abstract': 'abstract'}
        Study.create(User('*****@*****.**'), "My study", efo=[1], info=info)
        obs = _build_study_info(User('*****@*****.**'), 'user')

        self.exp.append({
            'metadata_complete': False,
            'ebi_submission_status':
            'not submitted',
            'shared': [],
            'publication_pid': [],
            'pi': ('*****@*****.**', 'PIDude'),
            'status': 'sandbox',
            'proc_data_info': [],
            'publication_doi': [],
            'study_abstract': 'abstract',
            'study_id': 2,
            'ebi_study_accession': None,
            'study_title': 'My study',
            'number_samples_collected': 0})

        self.assertItemsEqual(obs, self.exp)

        # Now testing that admin also sees this study
        obs = _build_study_info(User('*****@*****.**'), 'user')
        self.assertEqual(obs, self.exp)
Ejemplo n.º 21
0
def sample_template_checks(study_id, user, check_exists=False):
    """Performs different checks and raises errors if any of the checks fail

    Parameters
    ----------
    study_id : int
        The study id
    user : qiita_db.user.User
        The user trying to access the study
    check_exists : bool, optional
        If true, check if the sample template exists

    Raises
    ------
    HTTPError
        404 if the study does not exist
        403 if the user does not have access to the study
        404 if check_exists == True and the sample template doesn't exist
    """
    try:
        study = Study(int(study_id))
    except QiitaDBUnknownIDError:
        raise HTTPError(404, reason='Study does not exist')
    if not study.has_access(user):
        raise HTTPError(403, reason='User does not have access to study')

    # Check if the sample template exists
    if check_exists and not SampleTemplate.exists(study_id):
        raise HTTPError(404, reason="Study %s doesn't have sample information"
                        % study_id)
Ejemplo n.º 22
0
    def test_get_accessible_filepath_ids(self):
        self._set_processed_data_private()

        # shared has access to all study files and analysis files

        obs = get_accessible_filepath_ids(User('*****@*****.**'))
        self.assertEqual(obs, set([1, 2, 5, 6, 7, 11, 12, 13, 14, 15, 16, 17,
                                   18, 19, 20]))

        # Now shared should not have access to the study files
        self._unshare_studies()
        obs = get_accessible_filepath_ids(User('*****@*****.**'))
        self.assertEqual(obs, set([12, 13, 14, 15]))

        # Now shared should not have access to any files
        self._unshare_analyses()
        obs = get_accessible_filepath_ids(User('*****@*****.**'))
        self.assertEqual(obs, set())

        # Now shared has access to public study files
        self._set_processed_data_public()
        obs = get_accessible_filepath_ids(User('*****@*****.**'))
        self.assertEqual(obs, set([1, 2, 5, 6, 7, 11, 16, 19, 20]))

        # Test that it doesn't break: if the SampleTemplate hasn't been added
        exp = set([1, 2, 5, 6, 7, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20])
        obs = get_accessible_filepath_ids(User('*****@*****.**'))
        self.assertEqual(obs, exp)

        info = {
            "timeseries_type_id": 1,
            "metadata_complete": True,
            "mixs_compliant": True,
            "number_samples_collected": 4,
            "number_samples_promised": 4,
            "portal_type_id": 3,
            "study_alias": "TestStudy",
            "study_description": "Description of a test study",
            "study_abstract": "No abstract right now...",
            "emp_person_id": 1,
            "principal_investigator_id": 1,
            "lab_person_id": 1
        }
        Study.create(User('*****@*****.**'), "Test study", [1], info)
        obs = get_accessible_filepath_ids(User('*****@*****.**'))
        self.assertEqual(obs, exp)

        # test in case there is a prep template that failed
        self.conn_handler.execute(
            "INSERT INTO qiita.prep_template (data_type_id, raw_data_id) "
            "VALUES (2,1)")
        obs = get_accessible_filepath_ids(User('*****@*****.**'))
        self.assertEqual(obs, exp)

        # admin should have access to everything
        count = self.conn_handler.execute_fetchone("SELECT count(*) FROM "
                                                   "qiita.filepath")[0]
        exp = set(range(1, count + 1))
        obs = get_accessible_filepath_ids(User('*****@*****.**'))
        self.assertEqual(obs, exp)
Ejemplo n.º 23
0
def _build_study_info(studytype, user=None):
    """builds list of namedtuples for study listings"""
    if studytype == "private":
        studylist = user.user_studies
    elif studytype == "shared":
        studylist = user.shared_studies
    elif studytype == "public":
        studylist = Study.get_by_status('public')
    else:
        raise IncompetentQiitaDeveloperError("Must use private, shared, "
                                             "or public!")

    StudyTuple = namedtuple('StudyInfo', 'id title meta_complete '
                            'num_samples_collected shared num_raw_data pi '
                            'pmids owner status')

    infolist = []
    for s_id in studylist:
        study = Study(s_id)
        status = study.status
        # Just passing the email address as the name here, since
        # name is not a required field in qiita.qiita_user
        owner = study_person_linkifier((study.owner, study.owner))
        info = study.info
        PI = StudyPerson(info['principal_investigator_id'])
        PI = study_person_linkifier((PI.email, PI.name))
        pmids = ", ".join([pubmed_linkifier([pmid])
                           for pmid in study.pmids])
        shared = _get_shared_links_for_study(study)
        infolist.append(StudyTuple(study.id, study.title,
                                   info["metadata_complete"],
                                   info["number_samples_collected"],
                                   shared, len(study.raw_data()),
                                   PI, pmids, owner, status))
    return infolist
Ejemplo n.º 24
0
    def test_build_study_info_empty_study(self):
        info = {
            'timeseries_type_id': 1,
            'lab_person_id': None,
            'principal_investigator_id': 3,
            'metadata_complete': False,
            'mixs_compliant': True,
            'study_description': 'desc',
            'study_alias': 'alias',
            'study_abstract': 'abstract'
        }
        Study.create(User('*****@*****.**'), "My study", efo=[1], info=info)
        obs = _build_study_info(User('*****@*****.**'), 'user')

        self.exp.append({
            'metadata_complete': False,
            'ebi_submission_status': 'not submitted',
            'shared': [],
            'pmid': [],
            'pi': ('*****@*****.**', 'PIDude'),
            'status': 'private',
            'proc_data_info': [],
            'publication_doi': [],
            'study_abstract': 'abstract',
            'study_id': 2,
            'ebi_study_accession': None,
            'study_title': 'My study',
            'number_samples_collected': 0
        })
        self.assertItemsEqual(obs, self.exp)
Ejemplo n.º 25
0
def study_delete_req(study_id, user_id):
    """Delete a given study

    Parameters
    ----------
    study_id : int
        Study id to delete
    user_id : str
        User requesting the deletion

    Returns
    -------
    dict
        Status of deletion, in the format
        {status: status,
         message: message}
    """
    access_error = check_access(study_id, user_id)
    if access_error:
        return access_error

    status = 'success'
    try:
        Study.delete(int(study_id))
        msg = ''
    except Exception as e:
        status = 'error'
        msg = 'Unable to delete study: %s' % str(e)
    return {'status': status, 'message': msg}
Ejemplo n.º 26
0
def study_delete_req(study_id, user_id):
    """Delete a given study

    Parameters
    ----------
    study_id : int
        Study id to delete
    user_id : str
        User requesting the deletion

    Returns
    -------
    dict
        Status of deletion, in the format
        {status: status,
         message: message}
    """
    access_error = check_access(study_id, user_id)
    if access_error:
        return access_error

    status = 'success'
    try:
        Study.delete(int(study_id))
        msg = ''
    except Exception as e:
        status = 'error'
        msg = 'Unable to delete study: %s' % str(e)
    return {
        'status': status,
        'message': msg
    }
Ejemplo n.º 27
0
    def test_remove_portal(self):
        Portal.create("NEWPORTAL", "SOMEDESC")
        # Select some samples on a default analysis
        qiita_config.portal = "NEWPORTAL"
        a = Analysis(User("*****@*****.**").default_analysis)
        a.add_samples({1: ['1.SKB8.640193', '1.SKD5.640186']})

        Portal.delete("NEWPORTAL")
        obs = self.conn_handler.execute_fetchall(
            "SELECT * FROM qiita.portal_type")
        exp = [[1, 'QIITA', 'QIITA portal. Access to all data stored '
                'in database.'],
               [2, 'EMP', 'EMP portal']]
        self.assertItemsEqual(obs, exp)

        obs = self.conn_handler.execute_fetchall(
            "SELECT * FROM qiita.analysis_portal")
        exp = [[1, 1], [2, 1], [3, 1], [4, 1], [5, 1], [6, 1], [7, 2], [8, 2],
               [9, 2], [10, 2]]
        self.assertItemsEqual(obs, exp)

        with self.assertRaises(QiitaDBLookupError):
            Portal.delete("NOEXISTPORTAL")
        with self.assertRaises(QiitaDBError):
            Portal.delete("QIITA")

        Portal.create("NEWPORTAL2", "SOMEDESC")
        # Add analysis to this new portal and make sure error raised
        qiita_config.portal = "NEWPORTAL2"
        Analysis.create(User("*****@*****.**"), "newportal analysis", "desc")
        qiita_config.portal = "QIITA"
        with self.assertRaises(QiitaDBError):
            Portal.delete("NEWPORTAL2")

        # Add study to this new portal and make sure error raised
        info = {
            "timeseries_type_id": 1,
            "metadata_complete": True,
            "mixs_compliant": True,
            "number_samples_collected": 25,
            "number_samples_promised": 28,
            "study_alias": "FCM",
            "study_description": "Microbiome of people who eat nothing but "
                                 "fried chicken",
            "study_abstract": "Exploring how a high fat diet changes the "
                              "gut microbiome",
            "emp_person_id": StudyPerson(2),
            "principal_investigator_id": StudyPerson(3),
            "lab_person_id": StudyPerson(1)
        }
        Portal.create("NEWPORTAL3", "SOMEDESC")
        qiita_config.portal = "NEWPORTAL3"
        Study.create(User('*****@*****.**'), "Fried chicken microbiome",
                     [1], info)
        qiita_config.portal = "QIITA"
        with self.assertRaises(QiitaDBError):
            Portal.delete("NEWPORTAL3")
Ejemplo n.º 28
0
def _build_study_info(user, search_type, study_proc=None, proc_samples=None):
    """Builds list of dicts for studies table, with all HTML formatted

    Parameters
    ----------
    user : User object
        logged in user
    search_type : choice, ['user', 'public']
        what kind of search to perform
    study_proc : dict of lists, optional
        Dictionary keyed on study_id that lists all processed data associated
        with that study. Required if proc_samples given.
    proc_samples : dict of lists, optional
        Dictionary keyed on proc_data_id that lists all samples associated with
        that processed data. Required if study_proc given.

    Returns
    -------
    infolist: list of dict of lists and dicts
        study and processed data info for JSON serialiation for datatables
        Each dict in the list is a single study, and contains the text

    Notes
    -----
    Both study_proc and proc_samples must be passed, or neither passed.
    """
    build_samples = False
    # Logic check to make sure both needed parts passed
    if study_proc is not None and proc_samples is None:
        raise IncompetentQiitaDeveloperError(
            'Must pass proc_samples when study_proc given')
    elif proc_samples is not None and study_proc is None:
        raise IncompetentQiitaDeveloperError(
            'Must pass study_proc when proc_samples given')
    elif study_proc is None:
        build_samples = True

    # get list of studies for table
    if search_type == 'user':
        user_study_set = user.user_studies.union(user.shared_studies)
        if user.level == 'admin':
            user_study_set = (user_study_set |
                              Study.get_by_status('sandbox') |
                              Study.get_by_status('private'))
        study_set = user_study_set - Study.get_by_status('public')
    elif search_type == 'public':
        study_set = Study.get_by_status('public')
    else:
        raise ValueError('Not a valid search type')
    if study_proc is not None:
        study_set = study_set.intersection(study_proc)
    if not study_set:
        # No studies left so no need to continue
        return []

    return generate_study_list([s.id for s in study_set], build_samples,
                               public_only=(search_type == 'public'))
Ejemplo n.º 29
0
def _build_study_info(user, search_type, study_proc=None, proc_samples=None):
    """Builds list of dicts for studies table, with all HTML formatted

    Parameters
    ----------
    user : User object
        logged in user
    search_type : choice, ['user', 'public']
        what kind of search to perform
    study_proc : dict of lists, optional
        Dictionary keyed on study_id that lists all processed data associated
        with that study. Required if proc_samples given.
    proc_samples : dict of lists, optional
        Dictionary keyed on proc_data_id that lists all samples associated with
        that processed data. Required if study_proc given.

    Returns
    -------
    infolist: list of dict of lists and dicts
        study and processed data info for JSON serialiation for datatables
        Each dict in the list is a single study, and contains the text

    Notes
    -----
    Both study_proc and proc_samples must be passed, or neither passed.
    """
    build_samples = False
    # Logic check to make sure both needed parts passed
    if study_proc is not None and proc_samples is None:
        raise IncompetentQiitaDeveloperError(
            'Must pass proc_samples when study_proc given')
    elif proc_samples is not None and study_proc is None:
        raise IncompetentQiitaDeveloperError(
            'Must pass study_proc when proc_samples given')
    elif study_proc is None:
        build_samples = True

    # get list of studies for table
    if search_type == 'user':
        user_study_set = user.user_studies.union(user.shared_studies)
        if user.level == 'admin':
            user_study_set = (user_study_set |
                              Study.get_by_status('sandbox') |
                              Study.get_by_status('private'))
        study_set = user_study_set - Study.get_by_status('public')
    elif search_type == 'public':
        study_set = Study.get_by_status('public')
    else:
        raise ValueError('Not a valid search type')
    if study_proc is not None:
        study_set = study_set.intersection(study_proc)
    if not study_set:
        # No studies left so no need to continue
        return []

    return generate_study_list([s.id for s in study_set], build_samples,
                               public_only=(search_type == 'public'))
Ejemplo n.º 30
0
    def get(self):
        data = self.get_argument("data", None)
        study_id = self.get_argument("study_id", None)
        data_type = self.get_argument("data_type", None)
        dtypes = get_data_types().keys()

        if data is None or study_id is None or data not in ('raw', 'biom'):
            raise HTTPError(422,
                            reason='You need to specify both data (the '
                            'data type you want to download - raw/biom) and '
                            'study_id')
        elif data_type is not None and data_type not in dtypes:
            raise HTTPError(422,
                            reason='Not a valid data_type. Valid types '
                            'are: %s' % ', '.join(dtypes))
        else:
            study_id = int(study_id)
            try:
                study = Study(study_id)
            except QiitaDBUnknownIDError:
                raise HTTPError(422, reason='Study does not exist')
            else:
                public_raw_download = study.public_raw_download
                if study.status != 'public':
                    raise HTTPError(422,
                                    reason='Study is not public. If this '
                                    'is a mistake contact: '
                                    '*****@*****.**')
                elif data == 'raw' and not public_raw_download:
                    raise HTTPError(422,
                                    reason='No raw data access. If this '
                                    'is a mistake contact: '
                                    '*****@*****.**')
                else:
                    to_download = []
                    for a in study.artifacts(
                            dtype=data_type,
                            artifact_type='BIOM' if data == 'biom' else None):
                        if a.visibility != 'public':
                            continue
                        to_download.extend(self._list_artifact_files_nginx(a))

                    if not to_download:
                        raise HTTPError(422,
                                        reason='Nothing to download. If '
                                        'this is a mistake contact: '
                                        '*****@*****.**')
                    else:
                        self._write_nginx_file_list(to_download)

                        zip_fn = 'study_%d_%s_%s.zip' % (
                            study_id, data,
                            datetime.now().strftime('%m%d%y-%H%M%S'))

                        self._set_nginx_headers(zip_fn)
        self.finish()
Ejemplo n.º 31
0
 def get(self):
     self.write(self.render_string('waiting.html'))
     self.flush()
     u = User(self.current_user)
     user_studies = [Study(s_id) for s_id in u.private_studies]
     share_dict = {s.id: s.shared_with for s in user_studies}
     shared_studies = [Study(s_id) for s_id in u.shared_studies]
     self.render('private_studies.html', user=self.current_user,
                 user_studies=user_studies, shared_studies=shared_studies,
                 share_dict=share_dict)
Ejemplo n.º 32
0
 def test_get_edit_utf8(self):
     """Make sure the page loads when utf8 characters are present"""
     study = Study(1)
     study.title = "TEST_ø"
     study.alias = "TEST_ø"
     study.description = "TEST_ø"
     study.abstract = "TEST_ø"
     response = self.get('/study/edit/1')
     self.assertEqual(response.code, 200)
     self.assertNotEqual(str(response.body), "")
Ejemplo n.º 33
0
    def test_get_accessible_filepath_ids(self):
        self._set_studies_private()

        # shared has access to all study files and analysis files

        obs = get_accessible_filepath_ids(User('*****@*****.**'))
        self.assertEqual(obs,
                         set([1, 2, 5, 6, 7, 11, 12, 13, 14, 15, 16, 17, 18]))

        # Now shared should not have access to the study files
        self._unshare_studies()
        obs = get_accessible_filepath_ids(User('*****@*****.**'))
        self.assertEqual(obs, set([12, 13, 14, 15]))

        # Now shared should not have access to any files
        self._unshare_analyses()
        obs = get_accessible_filepath_ids(User('*****@*****.**'))
        self.assertEqual(obs, set())

        # Test that it doesn't break: if the SampleTemplate hasn't been added
        exp = set([1, 2, 5, 6, 7, 11, 12, 13, 14, 15, 16, 17, 18])
        obs = get_accessible_filepath_ids(User('*****@*****.**'))
        self.assertEqual(obs, exp)

        info = {
            "timeseries_type_id": 1,
            "metadata_complete": True,
            "mixs_compliant": True,
            "number_samples_collected": 4,
            "number_samples_promised": 4,
            "portal_type_id": 3,
            "study_alias": "TestStudy",
            "study_description": "Description of a test study",
            "study_abstract": "No abstract right now...",
            "emp_person_id": 1,
            "principal_investigator_id": 1,
            "lab_person_id": 1
        }
        Study.create(User('*****@*****.**'), "Test study", [1], info)
        obs = get_accessible_filepath_ids(User('*****@*****.**'))
        self.assertEqual(obs, exp)

        # test in case there is a prep template that failed
        self.conn_handler.execute(
            "INSERT INTO qiita.prep_template (data_type_id, raw_data_id) "
            "VALUES (2,1)")
        obs = get_accessible_filepath_ids(User('*****@*****.**'))
        self.assertEqual(obs, exp)

        # admin should have access to everything
        count = self.conn_handler.execute_fetchone("SELECT count(*) FROM "
                                                   "qiita.filepath")[0]
        exp = set(range(1, count + 1))
        obs = get_accessible_filepath_ids(User('*****@*****.**'))
        self.assertEqual(obs, exp)
Ejemplo n.º 34
0
    def test_download_raw_data(self):
        # it's possible that one of the tests is deleting the raw data
        # so we will make sure that the files exists so this test passes
        study = Study(1)
        all_files = [x['fp'] for a in study.artifacts()
                     for x in a.filepaths]
        for fp in all_files:
            if not exists(fp):
                with open(fp, 'w') as f:
                    f.write('')
        response = self.get('/download_raw_data/1')
        self.assertEqual(response.code, 200)

        exp = (
            '2125826711 58 /protected/raw_data/1_s_G1_L001_sequences.fastq.gz '
            'raw_data/1_s_G1_L001_sequences.fastq.gz\n'
            '2125826711 58 /protected/raw_data/'
            '1_s_G1_L001_sequences_barcodes.fastq.gz '
            'raw_data/1_s_G1_L001_sequences_barcodes.fastq.gz\n'
            '- [0-9]* /protected/templates/1_prep_1_qiime_[0-9]*-[0-9]*.txt '
            'mapping_files/1_mapping_file.txt\n'
            '1756512010 1093210 /protected/BIOM/7/biom_table.biom '
            'BIOM/7/biom_table.biom\n'
            '- [0-9]* /protected/templates/1_prep_2_qiime_[0-9]*-[0-9]*.txt '
            'mapping_files/7_mapping_file.txt\n')
        self.assertRegex(response.body.decode('ascii'), exp)

        response = self.get('/download_study_bioms/200')
        self.assertEqual(response.code, 405)

        # changing user so we can test the failures
        BaseHandler.get_current_user = Mock(
            return_value=User("*****@*****.**"))
        response = self.get('/download_study_bioms/1')
        self.assertEqual(response.code, 405)

        # now, let's make sure that when artifacts are public AND the
        # public_raw_download any user can download the files
        study.public_raw_download = True
        BaseHandler.get_current_user = Mock(
            return_value=User("*****@*****.**"))
        response = self.get('/download_study_bioms/1')
        self.assertEqual(response.code, 405)
        # 7 is an uploaded biom, which should now be available but as it's a
        # biom, only the prep info file will be retrieved
        Artifact(7).visibility = 'public'
        BaseHandler.get_current_user = Mock(
            return_value=User("*****@*****.**"))
        response = self.get('/download_study_bioms/1')
        self.assertEqual(response.code, 200)
        exp = (
            '- [0-9]* /protected/templates/1_prep_2_qiime_[0-9]*-[0-9]*.txt '
            'mapping_files/7_mapping_file.txt\n')
        self.assertRegex(response.body.decode('ascii'), exp)
Ejemplo n.º 35
0
    def test_delete(self):
        title = "Fried chicken microbiome"
        study = Study.create(User('*****@*****.**'), title, [1], self.info)
        study.delete(study.id)
        self.assertFalse(study.exists(title))

        with self.assertRaises(QiitaDBError):
            Study.delete(1)

        with self.assertRaises(QiitaDBUnknownIDError):
            Study.delete(41)
Ejemplo n.º 36
0
    def test_download_raw_data(self):
        # it's possible that one of the tests is deleting the raw data
        # so we will make sure that the files exists so this test passes
        study = Study(1)
        all_files = [x['fp'] for a in study.artifacts()
                     for x in a.filepaths]
        for fp in all_files:
            if not exists(fp):
                with open(fp, 'w') as f:
                    f.write('')
        response = self.get('/download_raw_data/1')
        self.assertEqual(response.code, 200)

        exp = (
            '2125826711 58 /protected/raw_data/1_s_G1_L001_sequences.fastq.gz '
            'raw_data/1_s_G1_L001_sequences.fastq.gz\n'
            '2125826711 58 /protected/raw_data/'
            '1_s_G1_L001_sequences_barcodes.fastq.gz '
            'raw_data/1_s_G1_L001_sequences_barcodes.fastq.gz\n'
            '- [0-9]* /protected/templates/1_prep_1_qiime_[0-9]*-[0-9]*.txt '
            'mapping_files/1_mapping_file.txt\n'
            '1756512010 1093210 /protected/BIOM/7/biom_table.biom '
            'BIOM/7/biom_table.biom\n'
            '- [0-9]* /protected/templates/1_prep_2_qiime_[0-9]*-[0-9]*.txt '
            'mapping_files/7_mapping_file.txt\n')
        self.assertRegex(response.body.decode('ascii'), exp)

        response = self.get('/download_study_bioms/200')
        self.assertEqual(response.code, 405)

        # changing user so we can test the failures
        BaseHandler.get_current_user = Mock(
            return_value=User("*****@*****.**"))
        response = self.get('/download_study_bioms/1')
        self.assertEqual(response.code, 405)

        # now, let's make sure that when artifacts are public AND the
        # public_raw_download any user can download the files
        study.public_raw_download = True
        BaseHandler.get_current_user = Mock(
            return_value=User("*****@*****.**"))
        response = self.get('/download_study_bioms/1')
        self.assertEqual(response.code, 405)
        # 7 is an uploaded biom, which should now be available but as it's a
        # biom, only the prep info file will be retrieved
        Artifact(7).visibility = 'public'
        BaseHandler.get_current_user = Mock(
            return_value=User("*****@*****.**"))
        response = self.get('/download_study_bioms/1')
        self.assertEqual(response.code, 200)
        exp = (
            '- [0-9]* /protected/templates/1_prep_2_qiime_[0-9]*-[0-9]*.txt '
            'mapping_files/7_mapping_file.txt\n')
        self.assertRegex(response.body.decode('ascii'), exp)
Ejemplo n.º 37
0
    def test_artifact_post_req(self):
        # Create new prep template to attach artifact to
        pt = npt.assert_warns(QiitaDBWarning, PrepTemplate.create,
                              pd.DataFrame({'new_col': {
                                  '1.SKD6.640190': 1
                              }}), Study(1), '16S')
        self._files_to_remove.extend([fp for _, fp in pt.get_filepaths()])

        new_artifact_id = get_count('qiita.artifact') + 1
        filepaths = {
            'raw_forward_seqs': 'uploaded_file.txt',
            'raw_barcodes': 'update.txt'
        }
        obs = artifact_post_req('*****@*****.**', filepaths, 'FASTQ',
                                'New Test Artifact', pt.id)
        exp = {'status': 'success', 'message': ''}
        self.assertEqual(obs, exp)

        obs = r_client.get('prep_template_%d' % pt.id)
        self.assertIsNotNone(obs)
        redis_info = loads(r_client.get(loads(obs)['job_id']))
        while redis_info['status_msg'] == 'Running':
            sleep(0.05)
            redis_info = loads(r_client.get(loads(obs)['job_id']))

        # Instantiate the artifact to make sure it was made and
        # to clean the environment
        a = Artifact(new_artifact_id)
        self._files_to_remove.extend([fp for _, fp, _ in a.filepaths])

        # Test importing an artifact
        # Create new prep template to attach artifact to
        pt = npt.assert_warns(QiitaDBWarning, PrepTemplate.create,
                              pd.DataFrame({'new_col': {
                                  '1.SKD6.640190': 1
                              }}), Study(1), '16S')
        self._files_to_remove.extend([fp for _, fp in pt.get_filepaths()])

        new_artifact_id_2 = get_count('qiita.artifact') + 1
        obs = artifact_post_req('*****@*****.**', {}, 'FASTQ',
                                'New Test Artifact 2', pt.id, new_artifact_id)
        exp = {'status': 'success', 'message': ''}
        self.assertEqual(obs, exp)

        obs = r_client.get('prep_template_%d' % pt.id)
        self.assertIsNotNone(obs)
        redis_info = loads(r_client.get(loads(obs)['job_id']))
        while redis_info['status_msg'] == 'Running':
            sleep(0.05)
            redis_info = loads(r_client.get(loads(obs)['job_id']))
        # Instantiate the artifact to make sure it was made and
        # to clean the environment
        a = Artifact(new_artifact_id_2)
        self._files_to_remove.extend([fp for _, fp, _ in a.filepaths])
Ejemplo n.º 38
0
    def test_get_valid_one_arg(self):
        df = Study(1).sample_template.to_dataframe()
        df = df[['ph', 'country']]
        df = {idx: [row['country']] for idx, row in df.iterrows()}
        exp = {'header': ['country'], 'samples': df}

        response = self.get('/api/v1/study/1/samples/categories=country',
                            headers=self.headers)
        self.assertEqual(response.code, 200)
        obs = json_decode(response.body)
        self.assertEqual(obs, exp)
Ejemplo n.º 39
0
    def tearDown(self):
        for fp in self._clean_up_files:
            if exists(fp):
                remove(fp)

        study_id = self.new_study.id
        for pt in self.new_study.prep_templates():
            PrepTemplate.delete(pt.id)
        if SampleTemplate.exists(study_id):
            SampleTemplate.delete(study_id)
        Study.delete(study_id)
Ejemplo n.º 40
0
    def tearDown(self):
        for fp in self._clean_up_files:
            if exists(fp):
                remove(fp)

        study_id = self.new_study.id
        for pt in self.new_study.prep_templates():
            PrepTemplate.delete(pt.id)
        if SampleTemplate.exists(study_id):
            SampleTemplate.delete(study_id)
        Study.delete(study_id)
Ejemplo n.º 41
0
def get_raw_data_from_other_studies(user, study):
    """Retrieves a tuple of raw_data_id and the last study title for that
    raw_data
    """
    d = {}
    for sid in user.user_studies:
        if sid == study.id:
            continue
        for rdid in Study(sid).raw_data():
            d[int(rdid)] = Study(RawData(rdid).studies[-1]).title
    return d
Ejemplo n.º 42
0
    def test_get_valid_one_arg(self):
        df = Study(1).sample_template.to_dataframe()
        df = df[['ph', 'country']]
        df = {idx: [row['country']] for idx, row in df.iterrows()}
        exp = {'header': ['country'], 'samples': df}

        response = self.get('/api/v1/study/1/samples/categories=country',
                            headers=self.headers)
        self.assertEqual(response.code, 200)
        obs = json_decode(response.body)
        self.assertEqual(obs, exp)
Ejemplo n.º 43
0
    def get(self):
        user = self.current_user
        if user.level != 'admin':
            raise HTTPError(403, 'User %s is not admin' % self.current_user)

        parsed_studies = []
        for sid in Study.get_by_status('awaiting_approval'):
            study = Study(sid)
            parsed_studies.append((study.id, study.title, study.owner))

        self.render('admin_approval.html', study_info=parsed_studies)
Ejemplo n.º 44
0
def study_prep_get_req(study_id, user_id):
    """Gives a summary of each prep template attached to the study

    Parameters
    ----------
    study_id : int
        Study id to get prep template info for
    user_id : str
        User id requesting the prep templates

    Returns
    -------
    dict of list of dict
        prep template information seperated by data type, in the form
        {data_type: [{prep 1 info dict}, ....], ...}
    """
    access_error = check_access(study_id, user_id)
    if access_error:
        return access_error
    # Can only pass ids over API, so need to instantiate object
    study = Study(int(study_id))
    prep_info = defaultdict(list)
    editable = study.can_edit(User(user_id))
    for dtype in study.data_types:
        for prep in study.prep_templates(dtype):
            if prep.status != 'public' and not editable:
                continue
            start_artifact = prep.artifact
            info = {
                'name': 'PREP %d NAME' % prep.id,
                'id': prep.id,
                'status': prep.status,
            }
            if start_artifact is not None:
                youngest_artifact = prep.artifact.youngest_artifact
                info['start_artifact'] = start_artifact.artifact_type
                info['start_artifact_id'] = start_artifact.id
                info['youngest_artifact'] = '%s - %s' % (
                    youngest_artifact.name, youngest_artifact.artifact_type)
                info['ebi_experiment'] = bool(
                    [v for _, v in viewitems(prep.ebi_experiment_accessions)
                     if v is not None])
            else:
                info['start_artifact'] = None
                info['start_artifact_id'] = None
                info['youngest_artifact'] = None
                info['ebi_experiment'] = False

            prep_info[dtype].append(info)

    return {'status': 'success',
            'message': '',
            'info': prep_info}
Ejemplo n.º 45
0
def _get_accessible_raw_data(user):
    """Retrieves a tuple of raw_data_id and one study title for that
    raw_data
    """
    d = {}
    accessible_studies = user.user_studies.union(user.shared_studies)
    for sid in accessible_studies:
        study = Study(sid)
        study_title = study.title
        for rdid in study.raw_data():
            d[int(rdid)] = study_title
    return d
Ejemplo n.º 46
0
def study_tags_patch_request(user_id, study_id,
                             req_op, req_path, req_value=None, req_from=None):
    """Modifies an attribute of the artifact

    Parameters
    ----------
    user_id : int
        The id of the user performing the patch operation
    study_id : int
        The id of the study on which we will be performing the patch operation
    req_op : str
        The operation to perform on the study
    req_path : str
        The attribute to patch
    req_value : str, optional
        The value that needs to be modified
    req_from : str, optional
        The original path of the element

    Returns
    -------
    dict of {str, str}
        A dictionary with the following keys:
        - status: str, whether if the request is successful or not
        - message: str, if the request is unsuccessful, a human readable error
    """
    if req_op == 'replace':
        req_path = [v for v in req_path.split('/') if v]
        if len(req_path) != 1:
            return {'status': 'error',
                    'message': 'Incorrect path parameter'}

        attribute = req_path[0]

        # Check if the user actually has access to the study
        access_error = check_access(study_id, user_id)
        if access_error:
            return access_error
        study = Study(study_id)

        if attribute == 'tags':
            message = study.update_tags(User(user_id), req_value)
            return {'status': 'success',
                    'message': message}
        else:
            # We don't understand the attribute so return an error
            return {'status': 'error',
                    'message': 'Attribute "%s" not found. '
                               'Please, check the path parameter' % attribute}
    else:
        return {'status': 'error',
                'message': 'Operation "%s" not supported. '
                           'Current supported operations: replace' % req_op}
Ejemplo n.º 47
0
def study_tags_patch_request(user_id, study_id,
                             req_op, req_path, req_value=None, req_from=None):
    """Modifies an attribute of the artifact

    Parameters
    ----------
    user_id : int
        The id of the user performing the patch operation
    study_id : int
        The id of the study on which we will be performing the patch operation
    req_op : str
        The operation to perform on the study
    req_path : str
        The attribute to patch
    req_value : str, optional
        The value that needs to be modified
    req_from : str, optional
        The original path of the element

    Returns
    -------
    dict of {str, str}
        A dictionary with the following keys:
        - status: str, whether if the request is successful or not
        - message: str, if the request is unsuccessful, a human readable error
    """
    if req_op == 'replace':
        req_path = [v for v in req_path.split('/') if v]
        if len(req_path) != 1:
            return {'status': 'error',
                    'message': 'Incorrect path parameter'}

        attribute = req_path[0]

        # Check if the user actually has access to the study
        access_error = check_access(study_id, user_id)
        if access_error:
            return access_error
        study = Study(study_id)

        if attribute == 'tags':
            message = study.update_tags(User(user_id), req_value)
            return {'status': 'success',
                    'message': message}
        else:
            # We don't understand the attribute so return an error
            return {'status': 'error',
                    'message': 'Attribute "%s" not found. '
                               'Please, check the path parameter' % attribute}
    else:
        return {'status': 'error',
                'message': 'Operation "%s" not supported. '
                           'Current supported operations: replace' % req_op}
Ejemplo n.º 48
0
    def filter_by_processed_data(self, datatypes=None):
        """Filters results to what is available in each processed data

        Parameters
        ----------
        datatypes : list of str, optional
            Datatypes to selectively return. Default all datatypes available

        Returns
        -------
        study_proc_ids : dict of dicts of lists
            Processed data ids with samples for each study, in the format
            {study_id: {datatype: [proc_id, proc_id, ...], ...}, ...}
        proc_data_samples : dict of lists
            Samples available in each processed data id, in the format
            {proc_data_id: [samp_id1, samp_id2, ...], ...}
        samples_meta : dict of pandas DataFrames
            metadata for the found samples, keyed by study. Pandas indexed on
            sample_id, column headers are the metadata categories searched
            over
        """
        with TRN:
            if datatypes is not None:
                # convert to set for easy lookups
                datatypes = set(datatypes)
            study_proc_ids = {}
            proc_data_samples = {}
            samples_meta = {}
            headers = {c: val for c, val in enumerate(self.meta_headers)}
            for study_id, study_meta in viewitems(self.results):
                # add metadata to dataframe and dict
                # use from_dict because pandas doesn't like cursor objects
                samples_meta[study_id] = pd.DataFrame.from_dict(
                    {s[0]: s[1:] for s in study_meta}, orient='index')
                samples_meta[study_id].rename(columns=headers, inplace=True)
                # set up study-based data needed
                study = Study(study_id)
                study_sample_ids = {s[0] for s in study_meta}
                study_proc_ids[study_id] = defaultdict(list)
                for proc_data_id in study.processed_data():
                    proc_data = ProcessedData(proc_data_id)
                    datatype = proc_data.data_type()
                    # skip processed data if it doesn't fit the given datatypes
                    if datatypes is not None and datatype not in datatypes:
                        continue
                    filter_samps = proc_data.samples.intersection(
                        study_sample_ids)
                    if filter_samps:
                        proc_data_samples[proc_data_id] = sorted(filter_samps)
                        study_proc_ids[study_id][datatype].append(proc_data_id)

            return study_proc_ids, proc_data_samples, samples_meta
Ejemplo n.º 49
0
    def test_delete(self):
        title = "Fried chicken microbiome"
        # the study is assigned to investigation 1
        study = Study.create(User("*****@*****.**"), title, [1], self.info, Investigation(1))
        # sharing with other user
        study.share(User("*****@*****.**"))
        study.delete(study.id)
        self.assertFalse(study.exists(title))

        with self.assertRaises(QiitaDBError):
            Study.delete(1)

        with self.assertRaises(QiitaDBUnknownIDError):
            Study.delete(41)
Ejemplo n.º 50
0
    def get_info(self, portal="QIITA"):
        # Add the portals and, optionally, checkbox to the information
        studies = [s.id for s in Portal(portal).get_studies()]
        if not studies:
            return []

        study_info = Study.get_info(studies, info_cols=self.study_cols)
        info = []
        for s in study_info:
            # Make sure in correct order
            hold = dict(s)
            hold['portals'] = ', '.join(sorted(Study(s['study_id'])._portals))
            info.append(hold)
        return info
Ejemplo n.º 51
0
    def get(self):
        """Show the sample summary page"""
        study_id = int(self.get_argument('study_id'))
        email = self.current_user.id

        res = sample_template_meta_cats_get_req(study_id, email)
        if res['status'] == 'error':
            if 'does not exist' in res['message']:
                raise HTTPError(404, reason=res['message'])
            elif 'User does not have access to study' in res['message']:
                raise HTTPError(403, reason=res['message'])
            else:
                raise HTTPError(500, reason=res['message'])
        categories = res['categories']

        columns, rows = _build_sample_summary(study_id, email)

        _, alert_type, alert_msg = get_sample_template_processing_status(
            study_id)

        self.render('study_ajax/sample_prep_summary.html',
                    rows=rows,
                    columns=columns,
                    categories=categories,
                    study_id=study_id,
                    alert_type=alert_type,
                    alert_message=alert_msg,
                    user_can_edit=Study(study_id).can_edit(self.current_user))
Ejemplo n.º 52
0
    def get(self):
        stats = yield Task(self._get_stats)

        # Pull a random public study from the database
        public_studies = Study.get_by_status('public')
        study = choice(list(public_studies)) if public_studies else None

        if study is None:
            random_study_info = None
            random_study_title = None
            random_study_id = None
        else:
            random_study_info = study.info
            random_study_title = study.title
            random_study_id = study.id

        self.render('stats.html',
                    number_studies=stats['number_studies'],
                    number_of_samples=stats['number_of_samples'],
                    num_users=stats['num_users'],
                    lat_longs=eval(
                        stats['lat_longs']) if stats['lat_longs'] else [],
                    num_studies_ebi=stats['num_studies_ebi'],
                    num_samples_ebi=stats['num_samples_ebi'],
                    number_samples_ebi_prep=stats['number_samples_ebi_prep'],
                    img=stats['img'], time=stats['time'],
                    random_study_info=random_study_info,
                    random_study_title=random_study_title,
                    random_study_id=random_study_id)
Ejemplo n.º 53
0
    def _create_study(self, study_title):
        """Creates a new study

        Parameters
        ----------
        study_title: str
            The title of the new study

        Returns
        -------
        qiita_db.study.Study
            The newly created study
        """
        info = {
            "timeseries_type_id": 1,
            "metadata_complete": True,
            "mixs_compliant": True,
            "number_samples_collected": 25,
            "number_samples_promised": 28,
            "study_alias": "ALIAS",
            "study_description": "DESC",
            "study_abstract": "ABS",
            "principal_investigator_id": StudyPerson(3),
            "lab_person_id": StudyPerson(1)
        }
        return Study.create(User('*****@*****.**'), study_title, info)
Ejemplo n.º 54
0
    def setUp(self):
        super(NewArtifactHandlerTests, self).setUp()
        tmp_dir = join(get_mountpoint('uploads')[0][1], '1')

        # Create prep test file to point at
        fd, prep_fp = mkstemp(dir=tmp_dir, suffix='.txt')
        close(fd)
        with open(prep_fp, 'w') as f:
            f.write("""sample_name\tnew_col\n1.SKD6.640190\tnew_value\n""")
        self.prep = npt.assert_warns(
            QiitaDBWarning, PrepTemplate.create,
            pd.DataFrame({'new_col': {
                '1.SKD6.640190': 1
            }}), Study(1), "16S")

        fd, self.fwd_fp = mkstemp(dir=tmp_dir, suffix=".fastq")
        close(fd)
        with open(self.fwd_fp, 'w') as f:
            f.write("@seq\nTACGA\n+ABBBB\n")

        fd, self.barcodes_fp = mkstemp(dir=tmp_dir, suffix=".fastq")
        close(fd)
        with open(self.barcodes_fp, 'w') as f:
            f.write("@seq\nTACGA\n+ABBBB\n")

        self._files_to_remove = [prep_fp, self.fwd_fp, self.barcodes_fp]
Ejemplo n.º 55
0
    def test_patch_no_sample_template(self):
        info = {
            "timeseries_type_id": 1,
            "metadata_complete": True,
            "mixs_compliant": True,
            "study_alias": "FCM",
            "study_description": "DESC",
            "study_abstract": "ABS",
            "principal_investigator_id": StudyPerson(3),
            'first_contact': datetime(2015, 5, 19, 16, 10),
            'most_recent_contact': datetime(2015, 5, 19, 16, 11),
        }

        new_study = Study.create(User('*****@*****.**'),
                                 "Some New Study for test jr", info)

        body = {'sampleid1': {'category_a': 'value_a'},
                'sampleid2': {'category_b': 'value_b'}}

        exp = {'message': 'No sample information found'}
        response = self.patch('/api/v1/study/%d/samples' % new_study.id,
                              headers=self.headers, data=body, asjson=True)
        self.assertEqual(response.code, 404)
        obs = json_decode(response.body)
        self.assertEqual(obs, exp)
Ejemplo n.º 56
0
    def get(self):
        """Show the sample summary page"""
        study_id = self.get_argument('study_id')

        res = sample_template_meta_cats_get_req(int(study_id),
                                                self.current_user.id)

        if res['status'] == 'error':
            if 'does not exist' in res['message']:
                raise HTTPError(404, res['message'])
            elif 'User does not have access to study' in res['message']:
                raise HTTPError(403, res['message'])
            else:
                raise HTTPError(500, res['message'])

        meta_cats = res['categories']
        cols, samps_table = _build_sample_summary(study_id,
                                                  self.current_user.id)
        _, alert_type, alert_msg = get_sample_template_processing_status(
            study_id)
        self.render('study_ajax/sample_prep_summary.html',
                    table=samps_table,
                    cols=cols,
                    meta_available=meta_cats,
                    study_id=study_id,
                    alert_type=alert_type,
                    alert_message=alert_msg,
                    user_can_edit=Study(study_id).can_edit(self.current_user))
Ejemplo n.º 57
0
    def test_copy_artifact(self):
        # Failure test
        job = self._create_job('copy_artifact', {
            'artifact': 1,
            'prep_template': 1
        })

        private_task(job.id)
        self.assertEqual(job.status, 'error')
        self.assertIn("Prep template 1 already has an artifact associated",
                      job.log.msg)

        # Success test
        metadata_dict = {
            'SKB8.640193': {
                'center_name': 'ANL',
                'primer': 'GTGCCAGCMGCCGCGGTAA',
                'barcode': 'GTCCGCAAGTTA',
                'run_prefix': "s_G1_L001_sequences",
                'platform': 'Illumina',
                'instrument_model': 'Illumina MiSeq',
                'library_construction_protocol': 'AAAA',
                'experiment_design_description': 'BBBB'
            }
        }
        metadata = pd.DataFrame.from_dict(metadata_dict,
                                          orient='index',
                                          dtype=str)
        prep = PrepTemplate.create(metadata, Study(1), "16S")
        job = self._create_job('copy_artifact', {
            'artifact': 1,
            'prep_template': prep.id
        })
        private_task(job.id)
        self.assertEqual(job.status, 'success')
Ejemplo n.º 58
0
    def test_status_error(self):
        # Let's create a new study, so we can check that the error is raised
        # because the new study does not have access to the raw data
        info = {
            "timeseries_type_id": 1,
            "metadata_complete": True,
            "mixs_compliant": True,
            "number_samples_collected": 25,
            "number_samples_promised": 28,
            "portal_type_id": 3,
            "study_alias": "FCM",
            "study_description": "Microbiome of people who eat nothing but "
                                 "fried chicken",
            "study_abstract": "Exploring how a high fat diet changes the "
                              "gut microbiome",
            "emp_person_id": StudyPerson(2),
            "principal_investigator_id": StudyPerson(3),
            "lab_person_id": StudyPerson(1)
        }
        s = Study.create(User('*****@*****.**'), "Fried chicken microbiome",
                         [1], info)
        rd = RawData(1)

        with self.assertRaises(QiitaDBStatusError):
            rd.status(s)