Example #1
0
    def delete_processed_data(self, study, user, callback):
        """Delete the selected processed data

        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
        """
        pd_id = int(self.get_argument('processed_data_id'))

        try:
            Artifact.delete(pd_id)
            msg = ("Processed data %d has been deleted" % pd_id)
            msg_level = "success"
            pd_id = None
        except Exception as e:
            msg = ("Couldn't remove processed data %d: %s" % (pd_id, str(e)))
            msg_level = "danger"

        callback((msg, msg_level, 'processed_data_tab', pd_id, None))
    def approve_study(self, study, user, callback):
        """Approves the current study if and only if the current user is admin

        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
        """
        if _approve(user.level):
            pd_id = int(self.get_argument('pd_id'))
            pd = Artifact(pd_id)
            pd.visibility = 'private'
            _propagate_visibility(pd)
            msg = "Processed data approved"
            msg_level = "success"
        else:
            msg = ("The current user does not have permission to approve "
                   "the processed data")
            msg_level = "danger"
        callback((msg, msg_level, "processed_data_tab", pd_id, None))
Example #3
0
    def approve_study(self, study, user, callback):
        """Approves the current study if and only if the current user is admin

        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
        """
        if _approve(user.level):
            pd_id = int(self.get_argument('pd_id'))
            pd = Artifact(pd_id)
            pd.visibility = 'private'
            _propagate_visibility(pd)
            msg = "Processed data approved"
            msg_level = "success"
        else:
            msg = ("The current user does not have permission to approve "
                   "the processed data")
            msg_level = "danger"
        callback((msg, msg_level, "processed_data_tab", pd_id, None))
Example #4
0
    def setUp(self):
        uploads_path = get_mountpoint('uploads')[0][1]
        # Create prep test file to point at
        self.update_fp = join(uploads_path, '1', 'update.txt')
        with open(self.update_fp, 'w') as f:
            f.write("""sample_name\tnew_col\n1.SKD6.640190\tnew_value\n""")

        self._files_to_remove = [self.update_fp]
        self._files_to_remove = []

        # creating temporal files and artifact
        # NOTE: we don't need to remove the artifact created cause it's
        # used to test the delete functionality
        fd, fp = mkstemp(suffix='_seqs.fna')
        close(fd)
        with open(fp, 'w') as f:
            f.write(">1.sid_r4_0 M02034:17:000000000-A5U18:1:1101:15370:1394 "
                    "1:N:0:1 orig_bc=CATGAGCT new_bc=CATGAGCT bc_diffs=0\n"
                    "GTGTGCCAGCAGCCGCGGTAATACGTAGGG\n")
        # 4 Demultiplexed
        filepaths_processed = [(fp, 4)]
        # 1 for default parameters and input data
        exp_params = Parameters.from_default_params(DefaultParameters(1),
                                                    {'input_data': 1})
        self.artifact = Artifact.create(filepaths_processed, "Demultiplexed",
                                        parents=[Artifact(1)],
                                        processing_parameters=exp_params)
Example #5
0
    def delete_raw_data(self, study, user, callback):
        """Delete the selected raw data

        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
        """
        raw_data_id = int(self.get_argument('raw_data_id'))
        prep_template_id = int(self.get_argument('prep_template_id'))

        try:
            Artifact.delete(raw_data_id)
            msg = ("Raw data %d has been deleted from prep_template %d" %
                   (raw_data_id, prep_template_id))
            msg_level = "success"
        except Exception as e:
            msg = "Couldn't remove raw data %d: %s" % (raw_data_id, str(e))
            msg_level = "danger"

        callback((msg, msg_level, "prep_template_tab", prep_template_id, None))
Example #6
0
    def test_prep_template_graph_get_req(self):
        obs = prep_template_graph_get_req(1, '*****@*****.**')
        exp = {'edge_list': [(1, 3), (1, 2), (2, 4), (2, 5), (2, 6)],
               'node_labels': [(1, 'Raw data 1 - FASTQ'),
                               (2, 'Demultiplexed 1 - Demultiplexed'),
                               (3, 'Demultiplexed 2 - Demultiplexed'),
                               (4, 'BIOM - BIOM'),
                               (5, 'BIOM - BIOM'),
                               (6, 'BIOM - BIOM')],
               'status': 'success',
               'message': ''}
        self.assertItemsEqual(obs['edge_list'], exp['edge_list'])
        self.assertItemsEqual(obs['node_labels'], exp['node_labels'])
        self.assertEqual(obs['status'], exp['status'])
        self.assertEqual(obs['message'], exp['message'])

        Artifact(4).visibility = "public"
        obs = prep_template_graph_get_req(1, '*****@*****.**')
        exp = {'edge_list': [(1, 2), (2, 4)],
               'node_labels': [(1, 'Raw data 1 - FASTQ'),
                               (2, 'Demultiplexed 1 - Demultiplexed'),
                               (4, 'BIOM - BIOM')],
               'status': 'success',
               'message': ''}
        self.assertItemsEqual(obs['edge_list'], exp['edge_list'])
        self.assertItemsEqual(obs['node_labels'], exp['node_labels'])
        self.assertEqual(obs['status'], exp['status'])
        self.assertEqual(obs['message'], exp['message'])

        # Reset visibility of the artifacts
        for i in range(4, 0, -1):
            Artifact(i).visibility = "private"
Example #7
0
    def post(self, preprocessed_data_id):
        user = self.current_user
        # make sure user is admin and can therefore actually submit to VAMPS
        if user.level != 'admin':
            raise HTTPError(403, "User %s cannot submit to VAMPS!" %
                            user.id)
        msg = ''
        msg_level = 'success'

        plugin = Software.from_name_and_version('Qiita', 'alpha')
        cmd = plugin.get_command('submit_to_VAMPS')
        artifact = Artifact(preprocessed_data_id)

        # Check if the artifact is already being submitted to VAMPS
        is_being_submitted = any(
            [j.status in ('queued', 'running')
             for j in artifact.jobs(cmd=cmd)])

        if is_being_submitted == 'submitting':
            msg = "Cannot resubmit! Data is already being submitted"
            msg_level = 'danger'
            self.display_template(preprocessed_data_id, msg, msg_level)
        else:
            params = Parameters.load(
                cmd, values_dict={'artifact': preprocessed_data_id})
            job = ProcessingJob.create(user, params, True)
            job.submit()
            self.redirect('/study/description/%s' % artifact.study.study_id)
    def delete_raw_data(self, study, user, callback):
        """Delete the selected raw data

        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
        """
        raw_data_id = int(self.get_argument('raw_data_id'))
        prep_template_id = int(self.get_argument('prep_template_id'))

        try:
            Artifact.delete(raw_data_id)
            msg = ("Raw data %d has been deleted from prep_template %d"
                   % (raw_data_id, prep_template_id))
            msg_level = "success"
        except Exception as e:
            msg = "Couldn't remove raw data %d: %s" % (raw_data_id, str(e))
            msg_level = "danger"

        callback((msg, msg_level, "prep_template_tab", prep_template_id, None))
Example #9
0
    def post(self, preprocessed_data_id):
        user = self.current_user
        # make sure user is admin and can therefore actually submit to VAMPS
        if user.level != 'admin':
            raise HTTPError(403, "User %s cannot submit to VAMPS!" % user.id)
        msg = ''
        msg_level = 'success'

        plugin = Software.from_name_and_version('Qiita', 'alpha')
        cmd = plugin.get_command('submit_to_VAMPS')
        artifact = Artifact(preprocessed_data_id)

        # Check if the artifact is already being submitted to VAMPS
        is_being_submitted = any([
            j.status in ('queued', 'running') for j in artifact.jobs(cmd=cmd)
        ])

        if is_being_submitted == 'submitting':
            msg = "Cannot resubmit! Data is already being submitted"
            msg_level = 'danger'
            self.display_template(preprocessed_data_id, msg, msg_level)
        else:
            params = Parameters.load(
                cmd, values_dict={'artifact': preprocessed_data_id})
            job = ProcessingJob.create(user, params)
            job.submit()
            self.redirect('/study/description/%s' % artifact.study.study_id)
Example #10
0
    def post(self, preprocessed_data_id):
        # make sure user is admin and can therefore actually submit to VAMPS
        if self.current_user.level != "admin":
            raise HTTPError(403, "User %s cannot submit to VAMPS!" % self.current_user.id)
        msg = ""
        msg_level = "success"
        preprocessed_data = Artifact(preprocessed_data_id)
        state = preprocessed_data.submitted_to_vamps_status()

        demux = [path for _, path, ftype in preprocessed_data.get_filepaths() if ftype == "preprocessed_demux"]
        demux_length = len(demux)

        if state in ("submitting", "success"):
            msg = "Cannot resubmit! Current state is: %s" % state
            msg_level = "danger"
        elif demux_length != 1:
            msg = "The study doesn't have demux files or have too many" % state
            msg_level = "danger"
        else:
            channel = self.current_user.id
            job_id = submit(channel, submit_to_VAMPS, int(preprocessed_data_id))

            self.render(
                "compute_wait.html",
                job_id=job_id,
                title="VAMPS Submission",
                completion_redirect="/compute_complete/%s" % job_id,
            )
            return

        self.display_template(preprocessed_data_id, msg, msg_level)
Example #11
0
def artifact_get_prep_req(user_id, artifact_ids):
    """Returns all prep info sample ids for the given artifact_ids

    Parameters
    ----------
    user_id : str
        user making the request
    artifact_ids : list of int
        list of artifact ids

    Returns
    -------
    dict of objects
        A dictionary containing the artifact information
        {'status': status,
         'message': message,
         'data': {artifact_id: [prep info sample ids]}
    """
    samples = {}

    for aid in sorted(artifact_ids):
        artifact = Artifact(aid)
        access_error = check_access(artifact.study.id, user_id)
        if access_error:
            return access_error

        samples[aid] = list(
            chain(*[sorted(pt.keys()) for pt in Artifact(aid).prep_templates]))

    return {'status': 'success', 'msg': '', 'data': samples}
Example #12
0
    def post(self, preprocessed_data_id):
        # make sure user is admin and can therefore actually submit to VAMPS
        if self.current_user.level != 'admin':
            raise HTTPError(
                403, "User %s cannot submit to VAMPS!" % self.current_user.id)
        msg = ''
        msg_level = 'success'
        preprocessed_data = Artifact(preprocessed_data_id)
        state = preprocessed_data.submitted_to_vamps_status()

        demux = [
            path for _, path, ftype in preprocessed_data.get_filepaths()
            if ftype == 'preprocessed_demux'
        ]
        demux_length = len(demux)

        if state in ('submitting', 'success'):
            msg = "Cannot resubmit! Current state is: %s" % state
            msg_level = 'danger'
        elif demux_length != 1:
            msg = "The study doesn't have demux files or have too many" % state
            msg_level = 'danger'
        else:
            channel = self.current_user.id
            job_id = submit(channel, submit_to_VAMPS,
                            int(preprocessed_data_id))

            self.render('compute_wait.html',
                        job_id=job_id,
                        title='VAMPS Submission',
                        completion_redirect='/compute_complete/%s' % job_id)
            return

        self.display_template(preprocessed_data_id, msg, msg_level)
Example #13
0
def artifact_delete_req(artifact_id, user_id):
    """Deletes the artifact

    Parameters
    ----------
    artifact_id : int
        Artifact being acted on
    user_id : str
        The user requesting the action

    Returns
    -------
    dict
        Status of action, in the form {'status': status, 'message': msg}
        status: status of the action, either success or error
        message: Human readable message for status
    """
    pd = Artifact(int(artifact_id))
    access_error = check_access(pd.study.id, user_id)
    if access_error:
        return access_error
    try:
        Artifact.delete(int(artifact_id))
    except QiitaDBArtifactDeletionError as e:
        return {'status': 'error',
                'message': str(e)}
    return {'status': 'success',
            'message': ''}
    def delete_processed_data(self, study, user, callback):
        """Delete the selected processed data

        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
        """
        pd_id = int(self.get_argument('processed_data_id'))

        try:
            Artifact.delete(pd_id)
            msg = ("Processed data %d has been deleted" % pd_id)
            msg_level = "success"
            pd_id = None
        except Exception as e:
            msg = ("Couldn't remove processed data %d: %s" %
                   (pd_id, str(e)))
            msg_level = "danger"

        callback((msg, msg_level, 'processed_data_tab', pd_id, None))
Example #15
0
    def write_demux_files(self, prep_template, generate_hdf5=True):
        """Writes a demux test file to avoid duplication of code"""
        fna_fp = join(self.temp_dir, 'seqs.fna')
        demux_fp = join(self.temp_dir, 'demux.seqs')
        if generate_hdf5:
            with open(fna_fp, 'w') as f:
                f.write(FASTA_EXAMPLE)
            with File(demux_fp, "w") as f:
                to_hdf5(fna_fp, f)
        else:
            with open(demux_fp, 'w') as f:
                f.write('')

        if prep_template.artifact is None:
            ppd = Artifact.create([(demux_fp, 6)],
                                  "Demultiplexed",
                                  prep_template=prep_template)
        else:
            params = Parameters.from_default_params(
                DefaultParameters(1),
                {'input_data': prep_template.artifact.id})
            ppd = Artifact.create([(demux_fp, 6)],
                                  "Demultiplexed",
                                  parents=[prep_template.artifact],
                                  processing_parameters=params)
        return ppd
Example #16
0
def copy_raw_data(prep_template, artifact_id):
    """Creates a new raw data by copying from artifact_id

    Parameters
    ----------
    prep_template : qiita_db.metadata_template.prep_template.PrepTemplate
        The template to attach the artifact
    artifact_id : int
        The id of the artifact to duplicate

    Returns
    -------
    dict of {str: str}
        A dict of the form {'status': str, 'message': str}
    """
    from qiita_db.artifact import Artifact

    status = 'success'
    msg = ''

    try:
        Artifact.copy(Artifact(artifact_id), prep_template)
    except Exception as e:
        # We should hit this exception rarely (that's why it is an
        # exception)  since at this point we have done multiple checks.
        # However, it can occur in weird cases, so better let the GUI know
        # that this failed
        return {'status': 'danger',
                'message': "Error creating artifact: %s" % str(e)}

    return {'status': status, 'message': msg}
Example #17
0
    def test_check_artifact_access(self):
        # "Study" artifact
        a = Artifact(1)
        # The user has access
        u = User('*****@*****.**')
        check_artifact_access(u, a)

        # Admin has access to everything
        admin = User('*****@*****.**')
        check_artifact_access(admin, a)

        # Demo user doesn't have access
        demo_u = User('*****@*****.**')
        with self.assertRaises(HTTPError):
            check_artifact_access(demo_u, a)

        # "Analysis" artifact
        a = Artifact(8)
        a.visibility = 'private'
        check_artifact_access(u, a)
        check_artifact_access(admin, a)
        with self.assertRaises(HTTPError):
            check_artifact_access(demo_u, a)
        check_artifact_access(User('*****@*****.**'), a)
        a.visibility = 'public'
        check_artifact_access(demo_u, a)
Example #18
0
    def write_demux_files(self, prep_template, generate_hdf5=True):
        """Writes a demux test file to avoid duplication of code"""
        fna_fp = join(self.temp_dir, 'seqs.fna')
        demux_fp = join(self.temp_dir, 'demux.seqs')
        if generate_hdf5:
            with open(fna_fp, 'w') as f:
                f.write(FASTA_EXAMPLE)
            with File(demux_fp, "w") as f:
                to_hdf5(fna_fp, f)
        else:
            with open(demux_fp, 'w') as f:
                f.write('')

        if prep_template.artifact is None:
            ppd = Artifact.create(
                [(demux_fp, 6)], "Demultiplexed", prep_template=prep_template,
                can_be_submitted_to_ebi=True, can_be_submitted_to_vamps=True)
        else:
            params = Parameters.from_default_params(
                DefaultParameters(1),
                {'input_data': prep_template.artifact.id})
            ppd = Artifact.create(
                [(demux_fp, 6)], "Demultiplexed",
                parents=[prep_template.artifact], processing_parameters=params,
                can_be_submitted_to_ebi=True, can_be_submitted_to_vamps=True)
        return ppd
Example #19
0
 def test_patch_artifact_ajax_handler(self):
     a = Artifact(1)
     self.assertEqual(a.name, 'Raw data 1')
     arguments = {'op': 'replace', 'path': '/name/', 'value': 'NEW_NAME'}
     response = self.patch('/artifact/1/', data=arguments)
     self.assertEqual(response.code, 200)
     self.assertEqual(a.name, 'NEW_NAME')
     a.name = 'Raw data 1'
Example #20
0
 def test_patch_artifact_ajax_handler(self):
     a = Artifact(1)
     self.assertEqual(a.name, 'Raw data 1')
     arguments = {'op': 'replace', 'path': '/name/', 'value': 'NEW_NAME'}
     response = self.patch('/artifact/1/', data=arguments)
     self.assertEqual(response.code, 200)
     self.assertEqual(a.name, 'NEW_NAME')
     a.name = 'Raw data 1'
Example #21
0
    def test_download(self):
        # check success
        response = self.get('/download/1')
        self.assertEqual(response.code, 200)
        self.assertEqual(response.body.decode('ascii'), (
            "This installation of Qiita was not equipped with nginx, so it "
            "is incapable of serving files. The file you attempted to "
            "download is located at raw_data/1_s_G1_L001_sequences.fastq.gz"))
        self.assertEqual(
            response.headers['Content-Disposition'],
            "attachment; filename=1_1_s_G1_L001_sequences.fastq.gz")
        # other tests to validate the filename
        response = self.get('/download/2')
        self.assertEqual(
            response.headers['Content-Disposition'],
            "attachment; filename=1_1_s_G1_L001_sequences_barcodes.fastq.gz")
        response = self.get('/download/3')
        self.assertEqual(
            response.headers['Content-Disposition'],
            "attachment; filename=2_1_seqs.fna")
        response = self.get('/download/18')
        self.assertEqual(
            response.headers['Content-Disposition'],
            "attachment; filename=1_prep_1_19700101-000000.txt")
        response = self.get('/download/22')
        self.assertEqual(
            response.headers['Content-Disposition'],
            "attachment; filename=7_biom_table.biom")

        # failure
        response = self.get('/download/1000')
        self.assertEqual(response.code, 403)

        # directory
        a = Artifact(1)
        fd, fp = mkstemp(suffix='.html')
        close(fd)
        with open(fp, 'w') as f:
            f.write('\n')
        self._clean_up_files.append(fp)
        dirpath = mkdtemp()
        fd, fp2 = mkstemp(suffix='.txt', dir=dirpath)
        close(fd)
        with open(fp2, 'w') as f:
            f.write('\n')
        self._clean_up_files.append(dirpath)
        a.set_html_summary(fp, support_dir=dirpath)
        for x in a.filepaths:
            if x['fp_type'] == 'html_summary_dir':
                break
        response = self.get('/download/%d' % x['fp_id'])
        self.assertEqual(response.code, 200)

        fp_name = basename(fp2)
        dirname = basename(dirpath)
        self.assertEqual(response.body.decode('ascii'),
                         "- 1 /protected/FASTQ/1/%s/%s FASTQ/1/%s/%s\n" % (
                            dirname, fp_name, dirname, fp_name))
Example #22
0
    def test_download(self):
        # check success
        response = self.get('/download/1')
        self.assertEqual(response.code, 200)
        self.assertEqual(response.body.decode('ascii'), (
            "This installation of Qiita was not equipped with nginx, so it "
            "is incapable of serving files. The file you attempted to "
            "download is located at raw_data/1_s_G1_L001_sequences.fastq.gz"))
        self.assertEqual(
            response.headers['Content-Disposition'],
            "attachment; filename=1_1_s_G1_L001_sequences.fastq.gz")
        # other tests to validate the filename
        response = self.get('/download/2')
        self.assertEqual(
            response.headers['Content-Disposition'],
            "attachment; filename=1_1_s_G1_L001_sequences_barcodes.fastq.gz")
        response = self.get('/download/3')
        self.assertEqual(
            response.headers['Content-Disposition'],
            "attachment; filename=2_1_seqs.fna")
        response = self.get('/download/18')
        self.assertEqual(
            response.headers['Content-Disposition'],
            "attachment; filename=1_prep_1_19700101-000000.txt")
        response = self.get('/download/22')
        self.assertEqual(
            response.headers['Content-Disposition'],
            "attachment; filename=7_biom_table.biom")

        # failure
        response = self.get('/download/1000')
        self.assertEqual(response.code, 403)

        # directory
        a = Artifact(1)
        fd, fp = mkstemp(suffix='.html')
        close(fd)
        with open(fp, 'w') as f:
            f.write('\n')
        self._clean_up_files.append(fp)
        dirpath = mkdtemp()
        fd, fp2 = mkstemp(suffix='.txt', dir=dirpath)
        close(fd)
        with open(fp2, 'w') as f:
            f.write('\n')
        self._clean_up_files.append(dirpath)
        a.set_html_summary(fp, support_dir=dirpath)
        for x in a.filepaths:
            if x['fp_type'] == 'html_summary_dir':
                break
        response = self.get('/download/%d' % x['fp_id'])
        self.assertEqual(response.code, 200)

        fp_name = basename(fp2)
        dirname = basename(dirpath)
        self.assertEqual(response.body.decode('ascii'),
                         "- 1 /protected/FASTQ/1/%s/%s FASTQ/1/%s/%s\n" % (
                            dirname, fp_name, dirname, fp_name))
Example #23
0
def artifact_patch_request(user_id, req_op, req_path, req_value=None,
                           req_from=None):
    """Modifies an attribute of the artifact

    Parameters
    ----------
    user_id : str
        The id of the user performing the patch operation
    req_op : str
        The operation to perform on the artifact
    req_path : str
        The prep information and 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) != 2:
            return {'status': 'error',
                    'message': 'Incorrect path parameter'}

        artifact_id = req_path[0]
        attribute = req_path[1]

        # Check if the user actually has access to the artifact
        artifact = Artifact(artifact_id)
        access_error = check_access(artifact.study.id, user_id)
        if access_error:
            return access_error

        if not req_value:
            return {'status': 'error',
                    'message': 'A value is required'}

        if attribute == 'name':
            artifact.name = req_value
            return {'status': 'success',
                    '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}
Example #24
0
    def test_artifact_patch_request(self):
        a = Artifact(1)
        test_user = User('*****@*****.**')
        self.assertEqual(a.name, 'Raw data 1')

        artifact_patch_request(test_user, 1, 'replace', '/name/',
                               req_value='NEW_NAME')
        self.assertEqual(a.name, 'NEW_NAME')

        # Reset the name
        a.name = 'Raw data 1'

        # No access
        with self.assertRaises(QiitaHTTPError):
            artifact_patch_request(User('*****@*****.**'), 1, 'replace',
                                   '/name/', req_value='NEW_NAME')

        # Incorrect path parameter
        with self.assertRaises(QiitaHTTPError):
            artifact_patch_request(test_user, 1, 'replace',
                                   '/name/wrong/', req_value='NEW_NAME')

        # Missing value
        with self.assertRaises(QiitaHTTPError):
            artifact_patch_request(test_user, 1, 'replace', '/name/')

        # Wrong attribute
        with self.assertRaises(QiitaHTTPError):
            artifact_patch_request(test_user, 1, 'replace',
                                   '/wrong/', req_value='NEW_NAME')

        # Wrong operation
        with self.assertRaises(QiitaHTTPError):
            artifact_patch_request(test_user, 1, 'add', '/name/',
                                   req_value='NEW_NAME')

        # Changing visibility
        self.assertEqual(a.visibility, 'private')
        artifact_patch_request(test_user, 1, 'replace', '/visibility/',
                               req_value='sandbox')
        self.assertEqual(a.visibility, 'sandbox')

        # Admin can change to private
        artifact_patch_request(User('*****@*****.**'), 1, 'replace',
                               '/visibility/', req_value='private')
        self.assertEqual(a.visibility, 'private')

        # Test user can't change to private
        with self.assertRaises(QiitaHTTPError):
            artifact_patch_request(test_user, 1, 'replace', '/visibility/',
                                   req_value='private')

        # Unkown req value
        with self.assertRaises(QiitaHTTPError):
            artifact_patch_request(test_user, 1, 'replace', '/visibility/',
                                   req_value='wrong')
Example #25
0
def list_options_handler_get_req(command_id, artifact_id=None):
    """Returns the available default parameters set for the given command

    Parameters
    ----------
    command_id : int
        The command id
    artifact_id : int, optional
        The artifact id so to limit options based on how it has already been
        processed

    Returns
    -------
    dict of objects
        A dictionary containing the commands information
        {'status': str,
         'message': str,
         'options': list of dicts of {'id: str', 'name': str,
                                      'values': dict of {str: str}}}
    """
    def _helper_process_params(params):
        return dumps({k: str(v).lower()
                      for k, v in params.items()},
                     sort_keys=True)

    command = Command(command_id)
    rparamers = command.required_parameters.keys()
    eparams = []
    if artifact_id is not None:
        artifact = Artifact(artifact_id)
        for job in artifact.jobs(cmd=command):
            jstatus = job.status
            outputs = job.outputs if job.status == 'success' else None
            # this ignore any jobs that weren't successful or are in
            # construction, or the results have been deleted [outputs == {}]
            if jstatus not in {'success', 'in_construction'} or outputs == {}:
                continue
            params = job.parameters.values.copy()
            for k in rparamers:
                del params[k]
            eparams.append(_helper_process_params(params))

    options = [{
        'id': p.id,
        'name': p.name,
        'values': p.values
    } for p in command.default_parameter_sets
               if _helper_process_params(p.values) not in eparams]
    return {
        'status': 'success',
        'message': '',
        'options': options,
        'req_options': command.required_parameters,
        'opt_options': command.optional_parameters
    }
Example #26
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])
Example #27
0
def artifact_status_put_req(artifact_id, user_id, visibility):
    """Set the status of the artifact given

    Parameters
    ----------
    artifact_id : int
        Artifact being acted on
    user_id : str
        The user requesting the action
    visibility : {'sandbox', 'awaiting_approval', 'private', 'public'}
        What to change the visibility to

    Returns
    -------
    dict
        Status of action, in the form {'status': status, 'message': msg}
        status: status of the action, either success or error
        message: Human readable message for status
    """
    if visibility not in get_visibilities():
        return {'status': 'error',
                'message': 'Unknown visibility value: %s' % visibility}

    pd = Artifact(int(artifact_id))
    sid = pd.study.id
    access_error = check_access(sid, user_id)
    if access_error:
        return access_error
    user = User(str(user_id))
    status = 'success'
    msg = 'Artifact visibility changed to %s' % visibility
    # Set the approval to private if needs approval and admin
    if visibility == 'private':
        if not qiita_config.require_approval:
            pd.visibility = 'private'
        # Set the approval to private if approval not required
        elif user.level == 'admin':
            pd.visibility = 'private'
        # Trying to set approval without admin privileges
        else:
            status = 'error'
            msg = 'User does not have permissions to approve change'
    else:
        pd.visibility = visibility

    LogEntry.create('Warning', '%s changed artifact %s (study %d) to %s' % (
        user_id, artifact_id, sid, visibility))

    return {'status': status,
            'message': msg}
Example #28
0
    def test_get_artifact_summary_handler(self):
        a = Artifact(1)
        # Add a summary to the artifact
        fd, fp = mkstemp(suffix=".html")
        close(fd)
        with open(fp, 'w') as f:
            f.write('<b>HTML TEST - not important</b>\n')
        a = Artifact(1)
        a.set_html_summary(fp)
        self._files_to_remove.extend([fp, a.html_summary_fp[1]])

        summary = relpath(a.html_summary_fp[1], qiita_config.base_data_dir)
        response = self.get('/artifact/html_summary/%s' % summary)
        self.assertEqual(response.code, 200)
        self.assertEqual(response.body, '<b>HTML TEST - not important</b>\n')
Example #29
0
    def display_template(self, preprocessed_data_id, msg, msg_level):
        """Simple function to avoid duplication of code"""
        preprocessed_data_id = int(preprocessed_data_id)
        try:
            preprocessed_data = Artifact(preprocessed_data_id)
        except QiitaDBUnknownIDError:
            raise HTTPError(
                404, "Artifact %d does not exist!" % preprocessed_data_id)
        else:
            user = self.current_user
            if user.level != 'admin':
                raise HTTPError(
                    403, "No permissions of admin, "
                    "get/VAMPSSubmitHandler: %s!" % user.id)

        prep_template = PrepTemplate(preprocessed_data.prep_template)
        sample_template = SampleTemplate(preprocessed_data.study)
        study = Study(preprocessed_data.study)
        stats = [('Number of samples', len(prep_template)),
                 ('Number of metadata headers',
                  len(sample_template.categories()))]

        demux = [
            path for _, path, ftype in preprocessed_data.get_filepaths()
            if ftype == 'preprocessed_demux'
        ]
        demux_length = len(demux)

        if not demux_length:
            msg = ("Study does not appear to have demultiplexed "
                   "sequences associated")
            msg_level = 'danger'
        elif demux_length > 1:
            msg = ("Study appears to have multiple demultiplexed files!")
            msg_level = 'danger'
        elif demux_length == 1:
            demux_file = demux[0]
            demux_file_stats = demux_stats(demux_file)
            stats.append(('Number of sequences', demux_file_stats.n))
            msg_level = 'success'

        self.render('vamps_submission.html',
                    study_title=study.title,
                    stats=stats,
                    message=msg,
                    study_id=study.id,
                    level=msg_level,
                    preprocessed_data_id=preprocessed_data_id)
Example #30
0
    def get(self, analysis_id):
        analysis_id = int(analysis_id.split("/")[0])
        analysis = Analysis(analysis_id)
        check_analysis_access(self.current_user, analysis)

        jobres = defaultdict(list)
        for jobject in analysis.jobs:
            results = []
            for res in jobject.results:
                name = basename(res)
                if name.startswith('index'):
                    name = basename(dirname(res)).replace('_', ' ')
                results.append((res, name))
            jobres[jobject.datatype].append((jobject.command[0], results))

        dropped_samples = analysis.dropped_samples
        dropped = defaultdict(list)
        for proc_data_id, samples in viewitems(dropped_samples):
            if not samples:
                continue
            proc_data = Artifact(proc_data_id)
            data_type = proc_data.data_type
            dropped[data_type].append(
                (proc_data.study.title, len(samples), ', '.join(samples)))

        self.render("analysis_results.html",
                    analysis_id=analysis_id,
                    jobres=jobres,
                    aname=analysis.name,
                    dropped=dropped,
                    basefolder=get_db_files_base_dir())
Example #31
0
    def get(self):
        # Format sel_data to get study IDs for the processed data
        sel_data = defaultdict(dict)
        proc_data_info = {}
        sel_samps = self.current_user.default_analysis.samples
        for aid, samples in viewitems(sel_samps):
            a = Artifact(aid)
            sel_data[a.study][aid] = samples
            # Also get processed data info
            processing_parameters = a.processing_parameters
            if processing_parameters is None:
                params = None
                algorithm = None
            else:
                cmd = processing_parameters.command
                params = processing_parameters.values
                if 'reference' in params:
                    ref = Reference(params['reference'])
                    del params['reference']

                    params['reference_name'] = ref.name
                    params['reference_version'] = ref.version
                algorithm = '%s (%s)' % (cmd.software.name, cmd.name)

            proc_data_info[aid] = {
                'processed_date': str(a.timestamp),
                'algorithm': algorithm,
                'data_type': a.data_type,
                'params': params
            }

        self.render("analysis_selected.html", sel_data=sel_data,
                    proc_info=proc_data_info)
Example #32
0
    def post(self, study_id, prep_id):
        study = self.safe_get_study(study_id)
        if study is None:
            return

        prep_id = to_int(prep_id)
        try:
            p = PrepTemplate(prep_id)
        except QiitaDBUnknownIDError:
            self.fail('Preparation not found', 404)
            return

        if p.study_id != study.id:
            self.fail('Preparation ID not associated with the study', 409)
            return

        artifact_deets = json_decode(self.request.body)
        _, upload = get_mountpoint('uploads')[0]
        base = os.path.join(upload, study_id)
        filepaths = [(os.path.join(base, fp), fp_type)
                     for fp, fp_type in artifact_deets['filepaths']]

        try:
            art = Artifact.create(filepaths,
                                  artifact_deets['artifact_type'],
                                  artifact_deets['artifact_name'],
                                  p)
        except QiitaError as e:
            self.fail(str(e), 406)
            return

        self.write({'id': art.id})
        self.set_status(201)
        self.finish()
Example #33
0
def artifact_post_req(user, artifact_id):
    """Deletes the artifact

    Parameters
    ----------
    user : qiita_db.user.User
        The user requesting the action
    artifact_id : int
        Id of the artifact being deleted
    """
    artifact_id = int(artifact_id)
    artifact = Artifact(artifact_id)
    check_artifact_access(user, artifact)

    analysis = artifact.analysis

    if analysis:
        # Do something when deleting in the analysis part to keep track of it
        redis_key = "analysis_%s" % analysis.id
    else:
        pt_id = artifact.prep_templates[0].id
        redis_key = PREP_TEMPLATE_KEY_FORMAT % pt_id

    qiita_plugin = Software.from_name_and_version('Qiita', 'alpha')
    cmd = qiita_plugin.get_command('delete_artifact')
    params = Parameters.load(cmd, values_dict={'artifact': artifact_id})
    job = ProcessingJob.create(user, params)

    r_client.set(redis_key, dumps({'job_id': job.id, 'is_qiita_job': True}))

    job.submit()
Example #34
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])
Example #35
0
def process_artifact_handler_get_req(artifact_id):
    """Returns the information for the process artifact handler

    Parameters
    ----------
    artifact_id : int
        The artifact to be processed

    Returns
    -------
    dict of str
        A dictionary containing the artifact information
        {'status': str,
         'message': str,
         'name': str,
         'type': str}
    """
    artifact = Artifact(artifact_id)

    return {
        'status': 'success',
        'message': '',
        'name': artifact.name,
        'type': artifact.artifact_type,
        'study_id': artifact.study.id
    }
Example #36
0
    def post(self, preprocessed_data_id):
        user = self.current_user
        # make sure user is admin and can therefore actually submit to EBI
        if user.level != 'admin':
            raise HTTPError(403, reason="User %s cannot submit to EBI!" %
                            user.id)
        submission_type = self.get_argument('submission_type')

        if submission_type not in ['ADD', 'MODIFY']:
            raise HTTPError(403, reason="User: %s, %s is not a recognized "
                            "submission type" % (user.id, submission_type))

        study = Artifact(preprocessed_data_id).study
        state = study.ebi_submission_status
        if state == 'submitting':
            message = "Cannot resubmit! Current state is: %s" % state
            self.display_template(preprocessed_data_id, message, 'danger')
        else:
            qiita_plugin = Software.from_name_and_version('Qiita', 'alpha')
            cmd = qiita_plugin.get_command('submit_to_EBI')
            params = Parameters.load(
                cmd, values_dict={'artifact': preprocessed_data_id,
                                  'submission_type': submission_type})
            job = ProcessingJob.create(user, params, True)

            r_client.set('ebi_submission_%s' % preprocessed_data_id,
                         dumps({'job_id': job.id, 'is_qiita_job': True}))
            job.submit()

            level = 'success'
            message = 'EBI submission started. Job id: %s' % job.id

            self.redirect("%s/study/description/%d?level=%s&message=%s" % (
                qiita_config.portal_dir, study.id, level, url_escape(message)))
Example #37
0
    def get(self):
        # Format sel_data to get study IDs for the processed data
        sel_data = defaultdict(dict)
        proc_data_info = {}
        sel_samps = self.current_user.default_analysis.samples
        for pid, samps in viewitems(sel_samps):
            proc_data = Artifact(pid)
            sel_data[proc_data.study][pid] = samps
            # Also get processed data info
            parameters = proc_data.processing_parameters
            reference = Reference(parameters.values['reference'])

            proc_data_info[pid] = {
                'processed_date': str(proc_data.timestamp),
                'algorithm': parameters.command.name,
                'reference_name': reference.name,
                'reference_version': reference.version,
                'sequence_filepath': reference.sequence_fp,
                'taxonomy_filepath': reference.taxonomy_fp,
                'tree_filepath': reference.tree_fp,
                'data_type': proc_data.data_type
            }

        self.render("analysis_selected.html",
                    sel_data=sel_data,
                    proc_info=proc_data_info)
Example #38
0
    def setUp(self):
        uploads_path = get_mountpoint('uploads')[0][1]
        # Create prep test file to point at
        self.update_fp = join(uploads_path, '1', 'update.txt')
        with open(self.update_fp, 'w') as f:
            f.write("""sample_name\tnew_col\n1.SKD6.640190\tnew_value\n""")

        self._files_to_remove = [self.update_fp]
        self._files_to_remove = []

        # creating temporal files and artifact
        # NOTE: we don't need to remove the artifact created cause it's
        # used to test the delete functionality
        fd, fp = mkstemp(suffix='_seqs.fna')
        close(fd)
        with open(fp, 'w') as f:
            f.write(">1.sid_r4_0 M02034:17:000000000-A5U18:1:1101:15370:1394 "
                    "1:N:0:1 orig_bc=CATGAGCT new_bc=CATGAGCT bc_diffs=0\n"
                    "GTGTGCCAGCAGCCGCGGTAATACGTAGGG\n")
        # 4 Demultiplexed
        filepaths_processed = [(fp, 4)]
        # 1 for default parameters and input data
        exp_params = Parameters.from_default_params(DefaultParameters(1),
                                                    {'input_data': 1})
        self.artifact = Artifact.create(filepaths_processed, "Demultiplexed",
                                        parents=[Artifact(1)],
                                        processing_parameters=exp_params)
Example #39
0
    def post(self, preprocessed_data_id):
        user = self.current_user
        # make sure user is admin and can therefore actually submit to VAMPS
        if user.level != 'admin':
            raise HTTPError(403, "User %s cannot submit to VAMPS!" % user.id)
        msg = ''
        msg_level = 'success'
        study = Artifact(preprocessed_data_id).study
        study_id = study.id
        state = study.ebi_submission_status
        if state == 'submitting':
            msg = "Cannot resubmit! Current state is: %s" % state
            msg_level = 'danger'
        else:
            channel = user.id
            job_id = submit(channel, submit_to_VAMPS,
                            int(preprocessed_data_id))

            self.render(
                'compute_wait.html',
                job_id=job_id,
                title='VAMPS Submission',
                completion_redirect=('/study/description/%s?top_tab='
                                     'preprocessed_data_tab&sub_tab=%s' %
                                     (study_id, preprocessed_data_id)))
            return

        self.display_template(preprocessed_data_id, msg, msg_level)
Example #40
0
    def test_download(self):
        # check failures
        response = self.get('/public_artifact_download/')
        self.assertEqual(response.code, 422)
        self.assertEqual(response.reason, 'You need to specify an artifact id')

        response = self.get('/public_artifact_download/?artifact_id=10000')
        self.assertEqual(response.code, 404)
        self.assertEqual(response.reason, 'Artifact does not exist')

        response = self.get('/public_artifact_download/?artifact_id=3')
        self.assertEqual(response.code, 404)
        self.assertEqual(
            response.reason, 'Artifact is not public. If this is '
            'a mistake contact: [email protected]')

        # check success
        Artifact(5).visibility = 'public'
        response = self.get('/public_artifact_download/?artifact_id=5')
        self.assertEqual(response.code, 200)
        exp = ('- [0-9]* /protected/processed_data/'
               '1_study_1001_closed_reference_otu_table.biom '
               'processed_data/1_study_1001_closed_reference_otu_table.biom\n'
               '- [0-9]* /protected/templates/1_prep_1_[0-9]*-[0-9]*.txt '
               'mapping_files/5_mapping_file.txt')
        self.assertRegex(response.body.decode('ascii'), exp)
Example #41
0
    def get(self):
        artifact_id = self.get_argument("artifact_id", None)

        if artifact_id is None:
            raise HTTPError(422, reason='You need to specify an artifact id')
        else:
            try:
                artifact = Artifact(artifact_id)
            except QiitaDBUnknownIDError:
                raise HTTPError(404, reason='Artifact does not exist')
            else:
                if artifact.visibility != 'public':
                    raise HTTPError(404, reason='Artifact is not public. If '
                                    'this is a mistake contact: '
                                    '*****@*****.**')
                else:
                    to_download = self._list_artifact_files_nginx(artifact)
                    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 = 'artifact_%s_%s.zip' % (
                            artifact_id, datetime.now().strftime(
                                '%m%d%y-%H%M%S'))

                        self._set_nginx_headers(zip_fn)
        self.finish()
Example #42
0
def artifact_delete_req(artifact_id, user_id):
    """Deletes the artifact

    Parameters
    ----------
    artifact_id : int
        Artifact being acted on
    user_id : str
        The user requesting the action

    Returns
    -------
    dict
        Status of action, in the form {'status': status, 'message': msg}
        status: status of the action, either success or error
        message: Human readable message for status
    """
    pd = Artifact(int(artifact_id))
    pt_id = pd.prep_templates[0].id
    access_error = check_access(pd.study.id, user_id)
    if access_error:
        return access_error

    job_id = safe_submit(user_id, delete_artifact, artifact_id)
    r_client.set(PREP_TEMPLATE_KEY_FORMAT % pt_id, dumps({'job_id': job_id}))

    return {'status': 'success', 'message': ''}
Example #43
0
    def post(self, preprocessed_data_id):
        user = self.current_user
        # make sure user is admin and can therefore actually submit to EBI
        if user.level != 'admin':
            raise HTTPError(403, "User %s cannot submit to EBI!" %
                            user.id)
        submission_type = self.get_argument('submission_type')

        if submission_type not in ['ADD', 'MODIFY']:
            raise HTTPError(403, "User: %s, %s is not a recognized submission "
                            "type" % (user.id, submission_type))

        msg = ''
        msg_level = 'success'
        study = Artifact(preprocessed_data_id).study
        study_id = study.id
        state = study.ebi_submission_status
        if state == 'submitting':
            msg = "Cannot resubmit! Current state is: %s" % state
            msg_level = 'danger'
        else:
            channel = user.id
            job_id = submit(channel, submit_to_ebi, int(preprocessed_data_id),
                            submission_type)

            self.render('compute_wait.html',
                        job_id=job_id, title='EBI Submission',
                        completion_redirect=('/study/description/%s?top_tab='
                                             'preprocessed_data_tab&sub_tab=%s'
                                             % (study_id,
                                                preprocessed_data_id)))
            return

        self.display_template(preprocessed_data_id, msg, msg_level)
Example #44
0
def artifact_post_req(user, artifact_id):
    """Deletes the artifact

    Parameters
    ----------
    user : qiita_db.user.User
        The user requesting the action
    artifact_id : int
        Id of the artifact being deleted
    """
    artifact_id = int(artifact_id)
    artifact = Artifact(artifact_id)
    check_artifact_access(user, artifact)

    analysis = artifact.analysis

    if analysis:
        # Do something when deleting in the analysis part to keep track of it
        redis_key = "analysis_%s" % analysis.id
    else:
        pt_id = artifact.prep_templates[0].id
        redis_key = PREP_TEMPLATE_KEY_FORMAT % pt_id

    job_id = safe_submit(user.id, delete_artifact, artifact_id)
    r_client.set(redis_key, dumps({'job_id': job_id, 'is_qiita_job': False}))
Example #45
0
def artifact_status_put_req(artifact_id, user_id, visibility):
    """Set the status of the artifact given

    Parameters
    ----------
    artifact_id : int
        Artifact being acted on
    user_id : str
        The user requesting the action
    visibility : {'sandbox', 'awaiting_approval', 'private', 'public'}
        What to change the visibility to

    Returns
    -------
    dict
        Status of action, in the form {'status': status, 'message': msg}
        status: status of the action, either success or error
        message: Human readable message for status
    """
    if visibility not in get_visibilities():
        return {'status': 'error',
                'message': 'Unknown visiblity value: %s' % visibility}

    pd = Artifact(int(artifact_id))
    access_error = check_access(pd.study.id, user_id)
    if access_error:
        return access_error
    user = User(str(user_id))
    status = 'success'
    msg = 'Artifact visibility changed to %s' % visibility
    # Set the approval to private if needs approval and admin
    if visibility == 'private':
        if not qiita_config.require_approval:
            pd.visibility = 'private'
        # Set the approval to private if approval not required
        elif user.level == 'admin':
            pd.visibility = 'private'
        # Trying to set approval without admin privileges
        else:
            status = 'error'
            msg = 'User does not have permissions to approve change'
    else:
        pd.visibility = visibility

    return {'status': status,
            'message': msg}
Example #46
0
def artifact_summary_post_request(user_id, artifact_id):
    """Launches the HTML summary generation and returns the job information

    Parameters
    ----------
    user_id : str
        The user making the request
    artifact_id : int or str
        The artifact id

    Returns
    -------
    dict of objects
        A dictionary containing the artifact summary information
        {'status': str,
         'message': str,
         'job': list of [str, str, str]}
    """
    artifact_id = int(artifact_id)
    artifact = Artifact(artifact_id)

    access_error = check_access(artifact.study.id, user_id)
    if access_error:
        return access_error

    # Check if the summary is being generated or has been already generated
    command = Command.get_html_generator(artifact.artifact_type)
    jobs = artifact.jobs(cmd=command)
    jobs = [j for j in jobs if j.status in ['queued', 'running', 'success']]
    if jobs:
        # The HTML summary is either being generated or already generated.
        # Return the information of that job so we only generate the HTML
        # once
        job = jobs[0]
    else:
        # Create a new job to generate the HTML summary and return the newly
        # created job information
        job = ProcessingJob.create(
            User(user_id),
            Parameters.load(command, values_dict={'input_data': artifact_id}))
        job.submit()

    return {'status': 'success',
            'message': '',
            'job': [job.id, job.status, job.step]}
Example #47
0
    def display_template(self, preprocessed_data_id, msg, msg_level):
        """Simple function to avoid duplication of code"""
        preprocessed_data_id = int(preprocessed_data_id)
        try:
            preprocessed_data = Artifact(preprocessed_data_id)
        except QiitaDBUnknownIDError:
            raise HTTPError(404, "Artifact %d does not exist!" % preprocessed_data_id)
        else:
            user = self.current_user
            if user.level != "admin":
                raise HTTPError(403, "No permissions of admin, " "get/VAMPSSubmitHandler: %s!" % user.id)

        prep_template = PrepTemplate(preprocessed_data.prep_template)
        sample_template = SampleTemplate(preprocessed_data.study)
        study = Study(preprocessed_data.study)
        stats = [
            ("Number of samples", len(prep_template)),
            ("Number of metadata headers", len(sample_template.categories())),
        ]

        demux = [path for _, path, ftype in preprocessed_data.get_filepaths() if ftype == "preprocessed_demux"]
        demux_length = len(demux)

        if not demux_length:
            msg = "Study does not appear to have demultiplexed " "sequences associated"
            msg_level = "danger"
        elif demux_length > 1:
            msg = "Study appears to have multiple demultiplexed files!"
            msg_level = "danger"
        elif demux_length == 1:
            demux_file = demux[0]
            demux_file_stats = demux_stats(demux_file)
            stats.append(("Number of sequences", demux_file_stats.n))
            msg_level = "success"

        self.render(
            "vamps_submission.html",
            study_title=study.title,
            stats=stats,
            message=msg,
            study_id=study.id,
            level=msg_level,
            preprocessed_data_id=preprocessed_data_id,
        )
Example #48
0
def artifact_graph_get_req(artifact_id, direction, user_id):
    """Creates graphs of ancestor or descendant artifacts from given one

    Parameters
    ----------
    artifact_id : int
        Artifact ID to get graph for
    direction : {'ancestors', 'descendants'}
        What direction to get the graph in

    Returns
    -------
    dict of lists of tuples
        A dictionary containing the edge list representation of the graph,
        and the node labels. Formatted as:
        {'status': status,
         'message': message,
         'edge_list': [(0, 1), (0, 2)...],
         'node_labels': [(0, 'label0'), (1, 'label1'), ...]}

    Notes
    -----
    Nodes are identified by the corresponding Artifact ID.
    """
    access_error = check_access(Artifact(artifact_id).study.id, user_id)
    if access_error:
        return access_error

    if direction == 'descendants':
        G = Artifact(int(artifact_id)).descendants
    elif direction == 'ancestors':
        G = Artifact(int(artifact_id)).ancestors
    else:
        return {
            'status': 'error',
            'message': 'Unknown directon %s' % direction
        }

    node_labels = [(n.id, ' - '.join([n.name, n.artifact_type]))
                   for n in G.nodes()]
    return {'edge_list': [(n.id, m.id) for n, m in G.edges()],
            'node_labels': node_labels,
            'status': 'success',
            'message': ''}
Example #49
0
    def test_propagate_visibility(self):
        a = Artifact(4)
        a.visibility = 'public'
        _propagate_visibility(a)
        self.assertEqual(Artifact(1).visibility, 'public')
        self.assertEqual(Artifact(2).visibility, 'public')
        self.assertEqual(Artifact(4).visibility, 'public')

        a.visibility = 'private'
        _propagate_visibility(a)
        self.assertEqual(Artifact(1).visibility, 'private')
        self.assertEqual(Artifact(2).visibility, 'private')
        self.assertEqual(Artifact(4).visibility, 'private')

        a = Artifact(2)
        a.visibility = 'public'
        _propagate_visibility(a)
        self.assertEqual(Artifact(1).visibility, 'private')
        self.assertEqual(Artifact(2).visibility, 'private')
        self.assertEqual(Artifact(4).visibility, 'private')
    def request_approval(self, study, user, callback):
        """Changes the status of the current study to "awaiting_approval"

        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
        """
        pd_id = int(self.get_argument('pd_id'))
        pd = Artifact(pd_id)
        pd.visibility = 'awaiting_approval'
        _propagate_visibility(pd)
        msg = "Processed data sent to admin for approval"
        msg_level = "success"
        callback((msg, msg_level, "processed_data_tab", pd_id, None))
    def make_public(self, study, user, callback):
        """Makes the current study public

        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
        """
        pd_id = int(self.get_argument('pd_id'))
        pd = Artifact(pd_id)
        pd.visibility = 'public'
        _propagate_visibility(pd)
        msg = "Processed data set to public"
        msg_level = "success"
        callback((msg, msg_level, "processed_data_tab", pd_id, None))
    def make_sandbox(self, study, user, callback):
        """Reverts the current study to the 'sandbox' status

        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
        """
        pd_id = int(self.get_argument('pd_id'))
        pd = Artifact(pd_id)
        pd.visibility = 'sandbox'
        _propagate_visibility(pd)
        msg = "Processed data reverted to sandbox"
        msg_level = "success"
        callback((msg, msg_level, "processed_data_tab", pd_id, None))
Example #53
0
def artifact_summary_post_request(user, artifact_id):
    """Launches the HTML summary generation and returns the job information

    Parameters
    ----------
    user : qiita_db.user.User
        The user making the request
    artifact_id : int or str
        The artifact id

    Returns
    -------
    dict of objects
        A dictionary containing the job summary information
        {'job': [str, str, str]}
    """
    artifact_id = int(artifact_id)
    artifact = Artifact(artifact_id)

    check_artifact_access(user, artifact)

    # Check if the summary is being generated or has been already generated
    command = Command.get_html_generator(artifact.artifact_type)
    jobs = artifact.jobs(cmd=command)
    jobs = [j for j in jobs if j.status in ['queued', 'running', 'success']]
    if jobs:
        # The HTML summary is either being generated or already generated.
        # Return the information of that job so we only generate the HTML
        # once - Magic number 0 -> we are ensuring that there is only one
        # job generating the summary, so we can use the index 0 to access to
        # that job
        job = jobs[0]
    else:
        # Create a new job to generate the HTML summary and return the newly
        # created job information
        job = ProcessingJob.create(user, Parameters.load(
            command, values_dict={'input_data': artifact_id}), True)
        job.submit()

    return {'job': [job.id, job.status, job.step]}
    def get(self):
        user = self.current_user
        if user.level != 'admin':
            raise HTTPError(403, 'User %s is not admin' % self.current_user)

        studies = defaultdict(list)
        for artifact in Artifact.iter_by_visibility('awaiting_approval'):
            studies[artifact.study].append(artifact.id)
        parsed_studies = [(s.id, s.title, s.owner.email, pds)
                          for s, pds in viewitems(studies)]

        self.render('admin_approval.html',
                    study_info=parsed_studies)
Example #55
0
    def test_download(self):
        # check success
        response = self.get('/download/1')
        self.assertEqual(response.code, 200)
        self.assertEqual(response.body, (
            "This installation of Qiita was not equipped with nginx, so it "
            "is incapable of serving files. The file you attempted to "
            "download is located at raw_data/1_s_G1_L001_sequences.fastq.gz"))

        # failure
        response = self.get('/download/1000')
        self.assertEqual(response.code, 403)

        # directory
        a = Artifact(1)
        fd, fp = mkstemp(suffix='.html')
        close(fd)
        with open(fp, 'w') as f:
            f.write('\n')
        self._clean_up_files.append(fp)
        dirpath = mkdtemp()
        fd, fp2 = mkstemp(suffix='.txt', dir=dirpath)
        close(fd)
        with open(fp2, 'w') as f:
            f.write('\n')
        self._clean_up_files.append(dirpath)
        a.set_html_summary(fp, support_dir=dirpath)
        for fp_id, _, fp_type in a.filepaths:
            if fp_type == 'html_summary_dir':
                break
        response = self.get('/download/%d' % fp_id)
        self.assertEqual(response.code, 200)

        fp_name = basename(fp2)
        dirname = basename(dirpath)
        self.assertEqual(
            response.body, "- 1 /protected/FASTQ/1/%s/%s FASTQ/1/%s/%s\n"
                           % (dirname, fp_name, dirname, fp_name))
Example #56
0
def create_raw_data(artifact_type, prep_template, filepaths, name=None):
    """Creates a new raw data

    Needs to be dispachable because it moves large files

    Parameters
    ----------
    artifact_type: str
        The artifact type
    prep_template : qiita_db.metadata_template.prep_template.PrepTemplate
        The template to attach the artifact
    filepaths : list of (str, str)
        The list with filepaths and their filepath types
    name : str, optional
        The name of the new artifact

    Returns
    -------
    dict of {str: str}
        A dict of the form {'status': str, 'message': str}
    """
    from qiita_db.artifact import Artifact

    status = 'success'
    msg = ''
    try:
        Artifact.create(filepaths, artifact_type, name=name,
                        prep_template=prep_template)
    except Exception as e:
        # We should hit this exception rarely (that's why it is an
        # exception)  since at this point we have done multiple checks.
        # However, it can occur in weird cases, so better let the GUI know
        # that this failed
        return {'status': 'danger',
                'message': "Error creating artifact: %s" % str(e)}

    return {'status': status, 'message': msg}
Example #57
0
def delete_artifact(artifact_id):
    """Deletes an artifact from the system

    Parameters
    ----------
    artifact_id : int
        The artifact to delete

    Returns
    -------
    dict of {str: str}
        A dict of the form {'status': str, 'message': str}
    """
    from qiita_db.artifact import Artifact

    status = 'success'
    msg = ''
    try:
        Artifact.delete(artifact_id)
    except Exception as e:
        status = 'danger'
        msg = str(e)

    return {'status': status, 'message': msg}
Example #58
0
def artifact_types_get_req():
    """Gets artifact types and descriptions available

    Returns
    -------
    dict of objects
        {'status': status,
         'message': message,
         'types': [[str, str], ...]}
        types holds type and description of the artifact type, in the form
        [[artifact_type, description], ...]
    """
    return {'status': 'success',
            'message': '',
            'types': Artifact.types()}