Ejemplo n.º 1
0
    def test_status_change(self):
        new_status = 'new status'

        r_client.set(self.test_id, json.dumps(self.test_job_info))

        obs = _status_change(self.test_id, new_status)
        self.assertEqual(obs, self.test_job_info['status'])
Ejemplo n.º 2
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': ''}
Ejemplo n.º 3
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}))
Ejemplo n.º 4
0
    def test_status_change(self):
        new_status = 'new status'

        r_client.set(self.test_id, json.dumps(self.test_job_info))

        obs = _status_change(self.test_id, new_status)
        self.assertEqual(obs, self.test_job_info['status'])
Ejemplo n.º 5
0
def sample_template_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 == 'remove':
        req_path = [v for v in req_path.split('/') if v]

        if len(req_path) != 3:
            return {'status': 'error', 'message': 'Incorrect path parameter'}

        st_id = req_path[0]
        attribute = req_path[1]
        attr_id = req_path[2]

        # Check if the user actually has access to the template
        st = SampleTemplate(st_id)
        access_error = check_access(st.study_id, user_id)
        if access_error:
            return access_error

        # Offload the deletion of the sample or column to the cluster
        job_id = safe_submit(user_id, delete_sample_or_column, SampleTemplate,
                             int(st_id), attribute, attr_id)
        # Store the job id attaching it to the sample template id
        r_client.set(SAMPLE_TEMPLATE_KEY_FORMAT % st_id,
                     dumps({'job_id': job_id}))

        return {'status': 'success', 'message': ''}

    else:
        return {
            'status':
            'error',
            'message':
            'Operation "%s" not supported. '
            'Current supported operations: remove' % req_op
        }
Ejemplo n.º 6
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': ''}
Ejemplo n.º 7
0
def sample_template_delete_req(study_id, user_id):
    """Deletes the sample template attached to the study

    Parameters
    ----------
    study_id : int
        The current study object id
    user_id : str
        The current user object id

    Returns
    -------
    dict
        results dictonary in the format
        {'status': status,
         'message': msg}

    status can be success, warning, or error depending on result
    message has the warnings or errors
    """
    exists = _check_sample_template_exists(int(study_id))
    if exists['status'] != 'success':
        return exists
    access_error = check_access(int(study_id), user_id)
    if access_error:
        return access_error

    # Offload the deletion of the sample template to the cluster
    job_id = safe_submit(user_id, delete_sample_template, int(study_id))
    # Store the job id attaching it to the sample template id
    r_client.set(SAMPLE_TEMPLATE_KEY_FORMAT % study_id,
                 dumps({'job_id': job_id}))

    return {'status': 'success', 'message': ''}
Ejemplo n.º 8
0
def create_info(name, info_type, url=None, parent=None, id=None,
                context=ctx_default, store=False):
    """Return a group object"""
    id = str(uuid4()) if id is None else id
    pubsub = _pubsub_key(id)

    info = {'id': id,
            'type': info_type,
            'pubsub': pubsub,
            'url': url,
            'parent': parent,
            'context': context,
            'name': name,
            'status': 'Queued' if info_type == 'job' else None,
            'date_start': None,
            'date_end': None,
            'date_created': str(datetime.now()),
            'result': None}

    if store:
        r_client.set(id, json_encode(info))

        if parent is not None:
            r_client.sadd(_children_key(parent), id)

    return info
Ejemplo n.º 9
0
    def _deposit_payload(redis_deets, payload):
        """Drop messages into redis

        This is being defined inline as we need to use it multiple times, and
        for an undiagnosed reason, having this function call it as a first
        class function does not work.
        """
        from json import dumps
        from moi import r_client

        job_id = redis_deets['job_id']
        pubsub = redis_deets['pubsub']
        messages = redis_deets['messages']

        serialized = dumps(payload)

        # First, we need to push the message on to the messages queue which is
        # in place in the event of a race-condition where a websocket client
        # may not be already listening to the pubsub.
        r_client.rpush(messages, serialized)

        # Next, in support of our "normal" and desired means of communicating,
        # we "publish" our payload. Anyone listening on the pubsub will see
        # this and fire an event (e.g., WebSocketHandler.callback)
        r_client.publish(pubsub, serialized)

        # Finally, we dump the payload keyed by job ID so that subsequent
        # handlers who are not listening on the channel can examine the results
        r_client.set(job_id, serialized, ex=86400 * 7)  # expire at 1 week
Ejemplo n.º 10
0
def get_sample_template_processing_status(st_id):
    job_info = r_client.get(SAMPLE_TEMPLATE_KEY_FORMAT % st_id)
    if job_info:
        job_info = loads(job_info)
        job_id = job_info['job_id']
        if job_id:
            redis_info = loads(r_client.get(job_id))
            processing = redis_info['status_msg'] == 'Running'
            if processing:
                alert_type = 'info'
                alert_msg = 'This sample template is currently being processed'
            elif redis_info['status_msg'] == 'Success':
                alert_type = redis_info['return']['status']
                alert_msg = redis_info['return']['message'].replace('\n',
                                                                    '</br>')
                payload = {'job_id': None,
                           'status': alert_type,
                           'message': alert_msg}
                r_client.set(SAMPLE_TEMPLATE_KEY_FORMAT % st_id,
                             dumps(payload))
            else:
                alert_type = redis_info['return']['status']
                alert_msg = redis_info['return']['message'].replace('\n',
                                                                    '</br>')
        else:
            processing = False
            alert_type = job_info['status']
            alert_msg = job_info['message'].replace('\n', '</br>')
    else:
        processing = False
        alert_type = ''
        alert_msg = ''

    return processing, alert_type, alert_msg
Ejemplo n.º 11
0
    def _deposit_payload(redis_deets, payload):
        """Drop messages into redis

        This is being defined inline as we need to use it multiple times, and
        for an undiagnosed reason, having this function call it as a first
        class function does not work.
        """
        from json import dumps
        from moi import r_client

        job_id = redis_deets['job_id']
        pubsub = redis_deets['pubsub']
        messages = redis_deets['messages']

        serialized = dumps(payload)

        # First, we need to push the message on to the messages queue which is
        # in place in the event of a race-condition where a websocket client
        # may not be already listening to the pubsub.
        r_client.rpush(messages, serialized)

        # Next, in support of our "normal" and desired means of communicating,
        # we "publish" our payload. Anyone listening on the pubsub will see
        # this and fire an event (e.g., WebSocketHandler.callback)
        r_client.publish(pubsub, serialized)

        # Finally, we dump the payload keyed by job ID so that subsequent
        # handlers who are not listening on the channel can examine the results
        r_client.set(job_id, serialized, ex=86400 * 7)  # expire at 1 week
Ejemplo n.º 12
0
def create_info(name,
                info_type,
                url=None,
                parent=None,
                id=None,
                context=ctx_default,
                store=False):
    """Return a group object"""
    id = str(uuid4()) if id is None else id
    pubsub = _pubsub_key(id)

    info = {
        'id': id,
        'type': info_type,
        'pubsub': pubsub,
        'url': url,
        'parent': parent,
        'context': context,
        'name': name,
        'status': 'Queued' if info_type == 'job' else None,
        'date_start': None,
        'date_end': None,
        'date_created': str(datetime.now()),
        'result': None
    }

    if store:
        r_client.set(id, json_encode(info))

        if parent is not None:
            r_client.sadd(_children_key(parent), id)

    return info
Ejemplo n.º 13
0
def sample_template_delete_req(study_id, user_id):
    """Deletes the sample template attached to the study

    Parameters
    ----------
    study_id : int
        The current study object id
    user_id : str
        The current user object id

    Returns
    -------
    dict
        results dictonary in the format
        {'status': status,
         'message': msg}

    status can be success, warning, or error depending on result
    message has the warnings or errors
    """
    exists = _check_sample_template_exists(int(study_id))
    if exists['status'] != 'success':
        return exists
    access_error = check_access(int(study_id), user_id)
    if access_error:
        return access_error

    # Offload the deletion of the sample template to the cluster
    job_id = safe_submit(user_id, delete_sample_template, int(study_id))
    # Store the job id attaching it to the sample template id
    r_client.set(SAMPLE_TEMPLATE_KEY_FORMAT % study_id,
                 dumps({'job_id': job_id}))

    return {'status': 'success', 'message': ''}
Ejemplo n.º 14
0
def sample_template_post_req(study_id, user_id, data_type,
                             sample_template):
    """Creates the sample template from the given file

    Parameters
    ----------
    study_id : int
        The current study object id
    user_id : str
        The current user object id
    data_type : str
        Data type for the sample template
    sample_template : str
        filename to use for creation

    Returns
    -------
    dict
        results dictonary in the format
        {'status': status,
         'message': msg,
         'file': sample_template}

    status can be success, warning, or error depending on result
    message has the warnings or errors
    file has the file name
    """
    access_error = check_access(int(study_id), user_id)
    if access_error:
        return access_error
    fp_rsp = check_fp(study_id, sample_template)
    if fp_rsp['status'] != 'success':
        # Unknown filepath, so return the error message
        return fp_rsp
    fp_rsp = fp_rsp['file']

    # Define here the message and message level in case of success
    msg = ''
    status = 'success'
    is_mapping_file = looks_like_qiime_mapping_file(fp_rsp)
    if is_mapping_file and not data_type:
        return {'status': 'error',
                'message': 'Please, choose a data type if uploading a '
                           'QIIME mapping file',
                'file': sample_template}

    study = Study(int(study_id))

    # Offload the creation of the sample template to the cluster
    job_id = safe_submit(user_id, create_sample_template, fp_rsp, study,
                         is_mapping_file, data_type)
    # Store the job id attaching it to the sample template id
    r_client.set(SAMPLE_TEMPLATE_KEY_FORMAT % study.id,
                 dumps({'job_id': job_id}))

    return {'status': status,
            'message': msg,
            'file': sample_template}
Ejemplo n.º 15
0
def sample_template_post_req(study_id, user_id, data_type, sample_template):
    """Creates the sample template from the given file

    Parameters
    ----------
    study_id : int
        The current study object id
    user_id : str
        The current user object id
    data_type : str
        Data type for the sample template
    sample_template : str
        filename to use for creation

    Returns
    -------
    dict
        results dictonary in the format
        {'status': status,
         'message': msg,
         'file': sample_template}

    status can be success, warning, or error depending on result
    message has the warnings or errors
    file has the file name
    """
    access_error = check_access(int(study_id), user_id)
    if access_error:
        return access_error
    fp_rsp = check_fp(study_id, sample_template)
    if fp_rsp['status'] != 'success':
        # Unknown filepath, so return the error message
        return fp_rsp
    fp_rsp = fp_rsp['file']

    # Define here the message and message level in case of success
    msg = ''
    status = 'success'
    is_mapping_file = looks_like_qiime_mapping_file(fp_rsp)
    if is_mapping_file and not data_type:
        return {
            'status': 'error',
            'message': 'Please, choose a data type if uploading a '
            'QIIME mapping file',
            'file': sample_template
        }

    study = Study(int(study_id))

    # Offload the creation of the sample template to the cluster
    job_id = safe_submit(user_id, create_sample_template, fp_rsp, study,
                         is_mapping_file, data_type)
    # Store the job id attaching it to the sample template id
    r_client.set(SAMPLE_TEMPLATE_KEY_FORMAT % study.id,
                 dumps({'job_id': job_id}))

    return {'status': status, 'message': msg, 'file': sample_template}
Ejemplo n.º 16
0
    def test_status_change(self):
        new_status = 'new status'

        r_client.set(self.test_id, json.dumps(self.test_job_info))

        # _status_change will return the old status
        obs = _status_change(self.test_id, new_status)
        self.assertEqual(obs, self.test_job_info['status'])

        obs = json.loads(r_client.get(self.test_id))
        self.assertEqual(obs['status'], new_status)
Ejemplo n.º 17
0
def sample_template_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 == 'remove':
        req_path = [v for v in req_path.split('/') if v]

        if len(req_path) != 3:
            return {'status': 'error',
                    'message': 'Incorrect path parameter'}

        st_id = req_path[0]
        attribute = req_path[1]
        attr_id = req_path[2]

        # Check if the user actually has access to the template
        st = SampleTemplate(st_id)
        access_error = check_access(st.study_id, user_id)
        if access_error:
            return access_error

        # Offload the deletion of the sample or column to the cluster
        job_id = safe_submit(user_id, delete_sample_or_column, SampleTemplate,
                             int(st_id), attribute, attr_id)
        # Store the job id attaching it to the sample template id
        r_client.set(SAMPLE_TEMPLATE_KEY_FORMAT % st_id,
                     dumps({'job_id': job_id}))

        return {'status': 'success', 'message': ''}

    else:
        return {'status': 'error',
                'message': 'Operation "%s" not supported. '
                           'Current supported operations: remove' % req_op}
Ejemplo n.º 18
0
    def test_status_change(self):
        new_status = 'new status'

        r_client.set(self.test_id, json.dumps(self.test_job_info))

        # _status_change will return the old status
        obs = _status_change(self.test_id, new_status)
        self.assertEqual(obs, self.test_job_info['status'])

        obs = json.loads(r_client.get(self.test_id))
        self.assertEqual(obs['status'], new_status)
Ejemplo n.º 19
0
 def setUp(self):
     r_client.hset('user-id-map', 'testing', 'testing')
     r_client.sadd('testing:children', 'a')
     r_client.sadd('testing:children', 'b')
     r_client.sadd('testing:children', 'c')
     r_client.set('a', '{"type": "job", "id": "a", "name": "a"}')
     r_client.set('b', '{"type": "job", "id": "b", "name": "b"}')
     r_client.set('c', '{"type": "job", "id": "c", "name": "c"}')
     r_client.set('d', '{"type": "job", "id": "d", "name": "other job"}')
     r_client.set('e', '{"type": "job", "id": "e", "name": "other job e"}')
     self.obj = Group('testing')
Ejemplo n.º 20
0
 def setUp(self):
     r_client.hset('user-id-map', 'testing', 'testing')
     r_client.sadd('testing:children', 'a')
     r_client.sadd('testing:children', 'b')
     r_client.sadd('testing:children', 'c')
     r_client.set('a', '{"type": "job", "id": "a", "name": "a"}')
     r_client.set('b', '{"type": "job", "id": "b", "name": "b"}')
     r_client.set('c', '{"type": "job", "id": "c", "name": "c"}')
     r_client.set('d', '{"type": "job", "id": "d", "name": "other job"}')
     r_client.set('e', '{"type": "job", "id": "e", "name": "other job e"}')
     self.obj = Group('testing')
     self.to_delete = ['testing', 'testing:jobs', 'testing:children',
                       'user-id-map', 'a', 'b', 'c', 'd', 'e']
Ejemplo n.º 21
0
def sample_template_put_req(study_id, user_id, sample_template):
    """Updates a sample template using the given file

    Parameters
    ----------
    study_id : int
        The current study object id
    user_id : str
        The current user object id
    sample_template : str
        filename to use for updating

    Returns
    -------
    dict
        results dictonary in the format
        {'status': status,
         'message': msg,
         'file': sample_template}

    status can be success, warning, or error depending on result
    message has the warnings or errors
    file has the file name
    """
    exists = _check_sample_template_exists(int(study_id))
    if exists['status'] != 'success':
        return exists
    access_error = check_access(int(study_id), user_id)
    if access_error:
        return access_error

    fp_rsp = check_fp(study_id, sample_template)
    if fp_rsp['status'] != 'success':
        # Unknown filepath, so return the error message
        return fp_rsp
    fp_rsp = fp_rsp['file']

    msg = ''
    status = 'success'

    # Offload the update of the sample template to the cluster
    job_id = safe_submit(user_id, update_sample_template, int(study_id),
                         fp_rsp)
    # Store the job id attaching it to the sample template id
    r_client.set(SAMPLE_TEMPLATE_KEY_FORMAT % study_id,
                 dumps({'job_id': job_id}))

    return {'status': status,
            'message': msg,
            'file': sample_template}
Ejemplo n.º 22
0
    def post(self):
        if r_client.get('maintenance') is not None:
            raise HTTPError(503, "Site is down for maintenance")

        username = self.get_argument("username", "").strip().lower()
        passwd = self.get_argument("password", "")
        nextpage = self.get_argument("next", None)
        if nextpage is None:
            if "auth/" not in self.request.headers['Referer']:
                nextpage = self.request.headers['Referer']
            else:
                nextpage = "%s/" % qiita_config.portal_dir

        msg = ""
        # check the user level
        try:
            if User(username).level == "unverified":
                # email not verified so dont log in
                msg = ("Email not verified. Please check your email and click "
                       "the verify link. You may need to check your spam "
                       "folder to find the email.<br/>If a verification email"
                       " has not arrived in 15 minutes, please email <a href='"
                       "mailto:[email protected]'>[email protected]</a>")
        except QiitaDBUnknownIDError:
            msg = "Unknown user"
        except RuntimeError:
            # means DB not available, so set maintenance mode and failover
            r_client.set(
                "maintenance", "Database connection unavailable, "
                "please try again later.")
            self.redirect("%s/" % qiita_config.portal_dir)
            return

        # Check the login information
        login = None
        try:
            login = User.login(username, passwd)
        except IncorrectEmailError:
            msg = "Unknown user"
        except IncorrectPasswordError:
            msg = "Incorrect password"
        except UnverifiedEmailError:
            msg = "You have not verified your email address"

        if login:
            # everything good so log in
            self.set_current_user(username)
            self.redirect(nextpage)
        else:
            self.render("index.html", message=msg, level='danger')
Ejemplo n.º 23
0
def _submit(ctx, parent_id, name, url, func, *args, **kwargs):
    """Submit a function to a cluster

    Parameters
    ----------
    parent_id : str
        The ID of the group that the job is a part of.
    name : str
        The name of the job
    url : str
        The handler that can take the results (e.g., /beta_diversity/)
    func : function
        The function to execute. Any returns from this function will be
        serialized and deposited into Redis using the uuid for a key. This
        function should raise if the method fails.
    args : tuple or None
        Any args for ``func``
    kwargs : dict or None
        Any kwargs for ``func``

    Returns
    -------
    tuple, (str, str, AsyncResult)
        The job ID, parent ID and the IPython's AsyncResult object of the job
    """
    parent_info = r_client.get(parent_id)
    if parent_info is None:
        parent_info = create_info('unnamed', 'group', id=parent_id)
        parent_id = parent_info['id']
        r_client.set(parent_id, json.dumps(parent_info))

    parent_pubsub_key = parent_id + ':pubsub'

    job_info = create_info(name,
                           'job',
                           url=url,
                           parent=parent_id,
                           context=ctx.name,
                           store=True)
    job_info['status'] = 'Queued'
    job_id = job_info['id']

    with r_client.pipeline() as pipe:
        pipe.set(job_id, json.dumps(job_info))
        pipe.publish(parent_pubsub_key, json.dumps({'add': [job_id]}))
        pipe.execute()

    ar = ctx.bv.apply_async(_redis_wrap, job_info, func, *args, **kwargs)
    return job_id, parent_id, ar
Ejemplo n.º 24
0
    def post(self):
        if r_client.get('maintenance') is not None:
            raise HTTPError(503, "Site is down for maintenance")

        username = self.get_argument("username", "").strip().lower()
        passwd = self.get_argument("password", "")
        nextpage = self.get_argument("next", None)
        if nextpage is None:
            if "auth/" not in self.request.headers['Referer']:
                nextpage = self.request.headers['Referer']
            else:
                nextpage = "%s/" % qiita_config.portal_dir

        msg = ""
        # check the user level
        try:
            if User(username).level == "unverified":
                # email not verified so dont log in
                msg = ("Email not verified. Please check your email and click "
                       "the verify link. You may need to check your spam "
                       "folder to find the email.<br/>If a verification email"
                       " has not arrived in 15 minutes, please email <a href='"
                       "mailto:[email protected]'>[email protected]</a>")
        except QiitaDBUnknownIDError:
            msg = "Unknown user"
        except RuntimeError:
            # means DB not available, so set maintenance mode and failover
            r_client.set("maintenance", "Database connection unavailable, "
                         "please try again later.")
            self.redirect("%s/" % qiita_config.portal_dir)
            return

        # Check the login information
        login = None
        try:
            login = User.login(username, passwd)
        except IncorrectEmailError:
            msg = "Unknown user"
        except IncorrectPasswordError:
            msg = "Incorrect password"
        except UnverifiedEmailError:
            msg = "You have not verified your email address"

        if login:
            # everything good so log in
            self.set_current_user(username)
            self.redirect(nextpage)
        else:
            self.render("index.html", message=msg, level='danger')
Ejemplo n.º 25
0
def sample_template_put_req(study_id, user_id, sample_template):
    """Updates a sample template using the given file

    Parameters
    ----------
    study_id : int
        The current study object id
    user_id : str
        The current user object id
    sample_template : str
        filename to use for updating

    Returns
    -------
    dict
        results dictonary in the format
        {'status': status,
         'message': msg,
         'file': sample_template}

    status can be success, warning, or error depending on result
    message has the warnings or errors
    file has the file name
    """
    exists = _check_sample_template_exists(int(study_id))
    if exists['status'] != 'success':
        return exists
    access_error = check_access(int(study_id), user_id)
    if access_error:
        return access_error

    fp_rsp = check_fp(study_id, sample_template)
    if fp_rsp['status'] != 'success':
        # Unknown filepath, so return the error message
        return fp_rsp
    fp_rsp = fp_rsp['file']

    msg = ''
    status = 'success'

    # Offload the update of the sample template to the cluster
    job_id = safe_submit(user_id, update_sample_template, int(study_id),
                         fp_rsp)
    # Store the job id attaching it to the sample template id
    r_client.set(SAMPLE_TEMPLATE_KEY_FORMAT % study_id,
                 dumps({'job_id': job_id}))

    return {'status': status, 'message': msg, 'file': sample_template}
Ejemplo n.º 26
0
    def test_redis_wrap(self):
        def foo(a, b, **kwargs):
            return a + b

        r_client.set(self.test_job_info['id'], json.dumps(self.test_job_info))
        obs_ret = _redis_wrap(self.test_job_info, foo, 1, 2)

        sleep(1)
        obs = json.loads(r_client.get(self.test_job_info['id']))
        self.assertEqual(obs['result'], 3)
        self.assertEqual(obs_ret, obs['result'])
        self.assertEqual(obs['status'], 'Success')
        self.assertNotEqual(obs['date_start'], None)
        self.assertNotEqual(obs['date_end'], None)

        r_client.set(self.test_job_info['id'], json.dumps(self.test_job_info))
Ejemplo n.º 27
0
    def test_redis_wrap(self):
        def foo(a, b, **kwargs):
            return a+b

        r_client.set(self.test_job_info['id'], json.dumps(self.test_job_info))
        obs_ret = _redis_wrap(self.test_job_info, foo, 1, 2)

        sleep(1)
        obs = json.loads(r_client.get(self.test_job_info['id']))
        self.assertEqual(obs['result'], 3)
        self.assertEqual(obs_ret, obs['result'])
        self.assertEqual(obs['status'], 'Success')
        self.assertNotEqual(obs['date_start'], None)
        self.assertNotEqual(obs['date_end'], None)

        r_client.set(self.test_job_info['id'], json.dumps(self.test_job_info))
Ejemplo n.º 28
0
    def test_post_select_samples(self):
        # just making sure that the key is not set in redis
        r_client.delete('maintenance')
        response = self.get('/auth/reset/')
        self.assertEqual(response.code, 200)
        self.assertIn(('<label for="newpass2" class="col-sm-2 '
                       'control-label">Repeat New Password'
                       '</label>'), response.body)

        # not displaying due to maintenance
        r_client.set('maintenance', 'This is my error message')
        response = self.get('/auth/reset/')
        self.assertEqual(response.code, 200)
        self.assertNotIn(('<label for="newpass2" class="col-sm-2 '
                          'control-label">Repeat New Password'
                          '</label>'), response.body)
        r_client.delete('maintenance')
Ejemplo n.º 29
0
    def post(self):
        if r_client.get('maintenance') is not None:
            raise HTTPError(503, "Site is down for maintenance")

        username = self.get_argument("username", "").strip().lower()
        passwd = self.get_argument("password", "")
        nextpage = self.get_argument("next", None)
        if nextpage is None:
            if "auth/" not in self.request.headers['Referer']:
                nextpage = self.request.headers['Referer']
            else:
                nextpage = "/"

        msg = ""
        # check the user level
        try:
            if User(username).level == "unverified":
                # email not verified so dont log in
                msg = "Email not verified"
        except QiitaDBUnknownIDError:
            msg = "Unknown user"
        except RuntimeError:
            # means DB not available, so set maintenance mode and failover
            r_client.set(
                "maintenance", "Database connection unavailable, "
                "please try again later.")
            self.redirect("/")
            return

        # Check the login information
        login = None
        try:
            login = User.login(username, passwd)
        except IncorrectEmailError:
            msg = "Unknown user"
        except IncorrectPasswordError:
            msg = "Incorrect password"
        except UnverifiedEmailError:
            msg = "You have not verified your email address"

        if login:
            # everything good so log in
            self.set_current_user(username)
            self.redirect(nextpage)
        else:
            self.render("index.html", message=msg, level='danger')
Ejemplo n.º 30
0
    def test_post_select_samples(self):
        # just making sure that the key is not set in redis
        r_client.delete('maintenance')
        response = self.get('/auth/reset/')
        self.assertEqual(response.code, 200)
        self.assertIn(('<label for="newpass2" class="col-sm-2 '
                       'control-label">Repeat New Password'
                       '</label>'), response.body)

        # not displaying due to maintenance
        r_client.set('maintenance', 'This is my error message')
        response = self.get('/auth/reset/')
        self.assertEqual(response.code, 200)
        self.assertNotIn(('<label for="newpass2" class="col-sm-2 '
                          'control-label">Repeat New Password'
                          '</label>'), response.body)
        r_client.delete('maintenance')
Ejemplo n.º 31
0
    def test_post_select_samples(self):
        # just making sure that the key is not set in redis
        r_client.delete("maintenance")
        response = self.get("/auth/reset/")
        self.assertEqual(response.code, 200)
        self.assertTrue(
            ('<label for="newpass2" class="col-sm-10 ' 'control-label">Repeat New Password' "</label>") in response.body
        )

        # not displaying due to maintenance
        r_client.set("maintenance", "This is my error message")
        response = self.get("/auth/reset/")
        self.assertEqual(response.code, 200)
        self.assertFalse(
            ('<label for="newpass2" class="col-sm-10 ' 'control-label">Repeat New Password' "</label>") in response.body
        )
        r_client.delete("maintenance")
Ejemplo n.º 32
0
def _submit(ctx, parent_id, name, url, func, *args, **kwargs):
    """Submit a function to a cluster

    Parameters
    ----------
    parent_id : str
        The ID of the group that the job is a part of.
    name : str
        The name of the job
    url : str
        The handler that can take the results (e.g., /beta_diversity/)
    func : function
        The function to execute. Any returns from this function will be
        serialized and deposited into Redis using the uuid for a key. This
        function should raise if the method fails.
    args : tuple or None
        Any args for ``func``
    kwargs : dict or None
        Any kwargs for ``func``

    Returns
    -------
    tuple, (str, str, AsyncResult)
        The job ID, parent ID and the IPython's AsyncResult object of the job
    """
    parent_info = r_client.get(parent_id)
    if parent_info is None:
        parent_info = create_info('unnamed', 'group', id=parent_id)
        parent_id = parent_info['id']
        r_client.set(parent_id, json.dumps(parent_info))

    parent_pubsub_key = parent_id + ':pubsub'

    job_info = create_info(name, 'job', url=url, parent=parent_id,
                           context=ctx.name, store=True)
    job_info['status'] = 'Queued'
    job_id = job_info['id']

    with r_client.pipeline() as pipe:
        pipe.set(job_id, json.dumps(job_info))
        pipe.publish(parent_pubsub_key, json.dumps({'add': [job_id]}))
        pipe.execute()

    ar = ctx.bv.apply_async(_redis_wrap, job_info, func, *args, **kwargs)
    return job_id, parent_id, ar
Ejemplo n.º 33
0
    def post(self):
        if r_client.get('maintenance') is not None:
            raise HTTPError(503, "Site is down for maintenance")

        username = self.get_argument("username", "").strip().lower()
        passwd = self.get_argument("password", "")
        nextpage = self.get_argument("next", None)
        if nextpage is None:
            if "auth/" not in self.request.headers['Referer']:
                nextpage = self.request.headers['Referer']
            else:
                nextpage = "/"

        msg = ""
        # check the user level
        try:
            if User(username).level == "unverified":
                # email not verified so dont log in
                msg = "Email not verified"
        except QiitaDBUnknownIDError:
            msg = "Unknown user"
        except RuntimeError:
            # means DB not available, so set maintenance mode and failover
            r_client.set("maintenance", "Database connection unavailable, "
                         "please try again later.")
            self.redirect("/")
            return

        # Check the login information
        login = None
        try:
            login = User.login(username, passwd)
        except IncorrectEmailError:
            msg = "Unknown user"
        except IncorrectPasswordError:
            msg = "Incorrect password"
        except UnverifiedEmailError:
            msg = "You have not verified your email address"

        if login:
            # everything good so log in
            self.set_current_user(username)
            self.redirect(nextpage)
        else:
            self.render("index.html", message=msg, level='danger')
Ejemplo n.º 34
0
def get_sample_template_processing_status(st_id):
    job_info = r_client.get(SAMPLE_TEMPLATE_KEY_FORMAT % st_id)
    if job_info:
        job_info = loads(job_info)
        job_id = job_info['job_id']
        if job_id:
            redis_info = r_client.get(job_id)
            if redis_info:
                redis_info = loads(redis_info)
                processing = redis_info['status_msg'] == 'Running'
                if processing:
                    alert_type = 'info'
                    alert_msg = ('This sample template is currently being '
                                 'processed')
                elif redis_info['status_msg'] == 'Success':
                    alert_type = redis_info['return']['status']
                    alert_msg = redis_info['return']['message'].replace(
                        '\n', '</br>')
                    payload = {
                        'job_id': None,
                        'status': alert_type,
                        'message': alert_msg
                    }
                    r_client.set(SAMPLE_TEMPLATE_KEY_FORMAT % st_id,
                                 dumps(payload))
                else:
                    alert_type = redis_info['return']['status']
                    alert_msg = redis_info['return']['message'].replace(
                        '\n', '</br>')
            else:
                processing = False
                alert_type = ''
                alert_msg = ''
        else:
            processing = False
            alert_type = job_info['status']
            alert_msg = job_info['message'].replace('\n', '</br>')
    else:
        processing = False
        alert_type = ''
        alert_msg = ''

    return processing, alert_type, alert_msg
Ejemplo n.º 35
0
    def test_redis_wrap(self):
        def foo(a, b, **kwargs):
            return a+b

        r_client.set(self.test_job_info['id'], json.dumps(self.test_job_info))
        _redis_wrap(self.test_job_info, foo, 1, 2)

        sleep(2)
        obs = json.loads(r_client.get(self.test_job_info['id']))
        self.assertEqual(obs['result'], 3)
        self.assertEqual(obs['status'], 'Success')
        self.assertNotEqual(obs['date_start'], None)
        self.assertNotEqual(obs['date_end'], None)

        r_client.set(self.test_job_info['id'], json.dumps(self.test_job_info))
        _redis_wrap(self.test_job_info, foo, 1, 2, 3)

        sleep(2)
        obs = json.loads(r_client.get(self.test_job_info['id']))
        self.assertEqual(obs['result'][0],
                         u'Traceback (most recent call last):\n')
        self.assertEqual(obs['status'], 'Failed')
        self.assertNotEqual(obs['date_start'], None)
        self.assertNotEqual(obs['date_end'], None)
Ejemplo n.º 36
0
    def test_redis_wrap(self):
        def foo(a, b, **kwargs):
            return a + b

        r_client.set(self.test_job_info['id'], json.dumps(self.test_job_info))
        _redis_wrap(self.test_job_info, foo, 1, 2)

        sleep(2)
        obs = json.loads(r_client.get(self.test_job_info['id']))
        self.assertEqual(obs['result'], 3)
        self.assertEqual(obs['status'], 'Success')
        self.assertNotEqual(obs['date_start'], None)
        self.assertNotEqual(obs['date_end'], None)

        r_client.set(self.test_job_info['id'], json.dumps(self.test_job_info))
        _redis_wrap(self.test_job_info, foo, 1, 2, 3)

        sleep(2)
        obs = json.loads(r_client.get(self.test_job_info['id']))
        self.assertEqual(obs['result'][0],
                         u'Traceback (most recent call last):\n')
        self.assertEqual(obs['status'], 'Failed')
        self.assertNotEqual(obs['date_start'], None)
        self.assertNotEqual(obs['date_end'], None)
Ejemplo n.º 37
0
 def test_traverse_complex(self):
     r_client.sadd('testing:children', 'd')
     r_client.sadd('d:children', 'd_a', 'd_b')
     r_client.set('d', '{"type": "group", "id": "d", "name": "d"}')
     r_client.set('d_a', '{"type": "job", "id": "d_a", "name": "d_a"}')
     r_client.set('d_b', '{"type": "job", "id": "d_b", "name": "d_b"}')
     self.to_delete.append('d:children')
     self.to_delete.append('d_a')
     self.to_delete.append('d_b')
     exp = {'a', 'b', 'c', 'd', 'd_a', 'd_b'}
     obs = {obj['id'] for obj in self.obj.traverse('testing')}
     self.assertEqual(obs, exp)
 def test_traverse_complex(self):
     r_client.sadd('testing:children', 'd')
     r_client.sadd('d:children', 'd_a', 'd_b')
     r_client.set('d', '{"type": "group", "id": "d", "name": "d"}')
     r_client.set('d_a', '{"type": "job", "id": "d_a", "name": "d_a"}')
     r_client.set('d_b', '{"type": "job", "id": "d_b", "name": "d_b"}')
     self.to_delete.append('d:children')
     self.to_delete.append('d_a')
     self.to_delete.append('d_b')
     exp = {'a', 'b', 'c', 'd', 'd_a', 'd_b'}
     obs = {obj['id'] for obj in self.obj.traverse('testing')}
     self.assertEqual(obs, exp)
Ejemplo n.º 39
0
    def test_analysis_description_handler_get_request(self):
        obs = analysis_description_handler_get_request(1, User('*****@*****.**'))
        exp = {
            'analysis_name': 'SomeAnalysis',
            'analysis_id': 1,
            'analysis_description': 'A test analysis',
            'alert_type': 'info',
            'alert_msg': ''
        }
        self.assertEqual(obs, exp)

        r_client.set('analysis_1', dumps({'job_id': 'job_id'}))
        r_client.set('job_id', dumps({'status_msg': 'running'}))
        obs = analysis_description_handler_get_request(1, User('*****@*****.**'))
        exp = {
            'analysis_name': 'SomeAnalysis',
            'analysis_id': 1,
            'analysis_description': 'A test analysis',
            'alert_type': 'info',
            'alert_msg': 'An artifact is being deleted from this analysis'
        }
        self.assertEqual(obs, exp)

        r_client.set(
            'job_id',
            dumps({
                'status_msg': 'Success',
                'return': {
                    'status': 'danger',
                    'message': 'Error deleting artifact'
                }
            }))
        obs = analysis_description_handler_get_request(1, User('*****@*****.**'))
        exp = {
            'analysis_name': 'SomeAnalysis',
            'analysis_id': 1,
            'analysis_description': 'A test analysis',
            'alert_type': 'danger',
            'alert_msg': 'Error deleting artifact'
        }
        self.assertEqual(obs, exp)
Ejemplo n.º 40
0
    def test_get_sample_template_processing_status(self):
        key = SAMPLE_TEMPLATE_KEY_FORMAT % 1

        obs_proc, obs_at, obs_am = get_sample_template_processing_status(1)
        self.assertFalse(obs_proc)
        self.assertEqual(obs_at, "")
        self.assertEqual(obs_am, "")

        # Without job id
        r_client.set(key, dumps({'job_id': None, 'status': "success",
                                 'message': ""}))
        obs_proc, obs_at, obs_am = get_sample_template_processing_status(1)
        self.assertFalse(obs_proc)
        self.assertEqual(obs_at, "success")
        self.assertEqual(obs_am, "")

        # With job id and processing
        r_client.set(key, dumps({'job_id': "test_job_id"}))
        r_client.set("test_job_id", dumps({'status_msg': 'Running'}))
        obs_proc, obs_at, obs_am = get_sample_template_processing_status(1)
        self.assertTrue(obs_proc)
        self.assertEqual(obs_at, "info")
        self.assertEqual(
            obs_am, "This sample template is currently being processed")

        # With job id and success
        r_client.set(key, dumps({'job_id': "test_job_id"}))
        r_client.set("test_job_id",
                     dumps({'status_msg': 'Success',
                            'return': {'status': 'success',
                                       'message': 'Some\nwarning'}}))
        obs_proc, obs_at, obs_am = get_sample_template_processing_status(1)
        self.assertFalse(obs_proc)
        self.assertEqual(obs_at, "success")
        self.assertEqual(obs_am, "Some</br>warning")
        obs = loads(r_client.get(key))
        self.assertEqual(obs, {'job_id': None, 'status': 'success',
                               'message': 'Some</br>warning'})

        # With job and not success
        r_client.set(key, dumps({'job_id': "test_job_id"}))
        r_client.set("test_job_id",
                     dumps({'status_msg': 'Failed',
                            'return': {'status': 'error',
                                       'message': 'Some\nerror'}}))
        obs_proc, obs_at, obs_am = get_sample_template_processing_status(1)
        self.assertFalse(obs_proc)
        self.assertEqual(obs_at, "error")
        self.assertEqual(obs_am, "Some</br>error")
Ejemplo n.º 41
0
def prep_template_ajax_get_req(user_id, prep_id):
    """Returns the prep tempalte information needed for the AJAX handler

    Parameters
    ----------
    user_id : str
        The user id
    prep_id : int
        The prep template id

    Returns
    -------
    dict of {str: object}
        A dictionary with the following keys:
        - status: str, whether the request is successful or not
        - message: str, if the request is unsuccessful, a human readable error
        - name: str, the name of the prep template
        - files: list of str, the files available to update the prep template
        - download_prep: int, the filepath_id of the prep file
        - download_qiime, int, the filepath_id of the qiime mapping file
        - num_samples: int, the number of samples present in the template
        - num_columns: int, the number of columns present in the template
        - investigation_type: str, the investigation type of the template
        - ontology: str, dict of {str, list of str} containing the information
        of the ENA ontology
        - artifact_attached: bool, whether the template has an artifact
        attached
        - study_id: int, the study id of the template
    """
    # Currently there is no name attribute, but it will be soon
    name = "Prep information %d" % prep_id
    pt = PrepTemplate(prep_id)

    job_info = r_client.get(PREP_TEMPLATE_KEY_FORMAT % prep_id)
    if job_info:
        job_info = loads(job_info)
        job_id = job_info['job_id']
        if job_id:
            redis_info = loads(r_client.get(job_id))
            processing = redis_info['status_msg'] == 'Running'
            if processing:
                alert_type = 'info'
                alert_msg = 'This prep template is currently being updated'
            elif redis_info['status_msg'] == 'Success':
                alert_type = redis_info['return']['status']
                alert_msg = redis_info['return']['message'].replace('\n',
                                                                    '</br>')
                payload = {'job_id': None,
                           'status': alert_type,
                           'message': alert_msg}
                r_client.set(PREP_TEMPLATE_KEY_FORMAT % prep_id,
                             dumps(payload))
            else:
                alert_type = redis_info['return']['status']
                alert_msg = redis_info['return']['message'].replace('\n',
                                                                    '</br>')
        else:
            processing = False
            alert_type = job_info['status']
            alert_msg = job_info['message'].replace('\n', '</br>')
    else:
        processing = False
        alert_type = ''
        alert_msg = ''

    artifact_attached = pt.artifact is not None
    study_id = pt.study_id
    files = [f for _, f in get_files_from_uploads_folders(study_id)
             if f.endswith(('.txt', '.tsv'))]

    # The call to list is needed because keys is an iterator
    num_samples = len(list(pt.keys()))
    num_columns = len(pt.categories())
    investigation_type = pt.investigation_type

    # Retrieve the information to download the prep template and QIIME
    # mapping file. See issue https://github.com/biocore/qiita/issues/1675
    download_prep = []
    download_qiime = []
    for fp_id, fp in pt.get_filepaths():
        if 'qiime' in basename(fp):
            download_qiime.append(fp_id)
        else:
            download_prep.append(fp_id)
    download_prep = download_prep[0]
    download_qiime = download_qiime[0]

    ontology = _get_ENA_ontology()

    editable = Study(study_id).can_edit(User(user_id)) and not processing

    return {'status': 'success',
            'message': '',
            'name': name,
            'files': files,
            'download_prep': download_prep,
            'download_qiime': download_qiime,
            'num_samples': num_samples,
            'num_columns': num_columns,
            'investigation_type': investigation_type,
            'ontology': ontology,
            'artifact_attached': artifact_attached,
            'study_id': study_id,
            'editable': editable,
            'data_type': pt.data_type(),
            'alert_type': alert_type,
            'is_submitted_to_ebi': pt.is_submitted_to_ebi,
            'alert_message': alert_msg}
Ejemplo n.º 42
0
def prep_template_patch_req(user_id, req_op, req_path, req_value=None,
                            req_from=None):
    """Modifies an attribute of the prep template

    Parameters
    ----------
    user_id : str
        The id of the user performing the patch operation
    req_op : str
        The operation to perform on the prep information
    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
    """
    req_path = [v for v in req_path.split('/') if v]
    if req_op == 'replace':
        # The structure of the path should be /prep_id/attribute_to_modify/
        # so if we don't have those 2 elements, we should return an error
        if len(req_path) != 2:
            return {'status': 'error',
                    'message': 'Incorrect path parameter'}
        prep_id = int(req_path[0])
        attribute = req_path[1]

        # Check if the user actually has access to the prep template
        prep = PrepTemplate(prep_id)
        access_error = check_access(prep.study_id, user_id)
        if access_error:
            return access_error

        status = 'success'
        msg = ''
        if attribute == 'investigation_type':
            prep.investigation_type = req_value
        elif attribute == 'data':
            fp = check_fp(prep.study_id, req_value)
            if fp['status'] != 'success':
                return fp
            fp = fp['file']
            job_id = safe_submit(user_id, update_prep_template, prep_id, fp)
            r_client.set(PREP_TEMPLATE_KEY_FORMAT % prep_id,
                         dumps({'job_id': job_id}))
        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}

        return {'status': status, 'message': msg}
    elif req_op == 'remove':
        # The structure of the path should be /prep_id/{columns|samples}/name
        if len(req_path) != 3:
            return {'status': 'error',
                    'message': 'Incorrect path parameter'}
        prep_id = int(req_path[0])
        attribute = req_path[1]
        attr_id = req_path[2]

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

        # Offload the deletion of the column to the cluster
        job_id = safe_submit(user_id, delete_sample_or_column, PrepTemplate,
                             prep_id, attribute, attr_id)
        # Store the job id attaching it to the sample template id
        r_client.set(PREP_TEMPLATE_KEY_FORMAT % prep_id,
                     dumps({'job_id': job_id}))
        return {'status': 'success', 'message': ''}
    else:
        return {'status': 'error',
                'message': 'Operation "%s" not supported. '
                           'Current supported operations: replace, remove'
                           % req_op}
Ejemplo n.º 43
0
    def test_get_sample_template_processing_status(self):
        key = SAMPLE_TEMPLATE_KEY_FORMAT % 1

        obs_proc, obs_at, obs_am = get_sample_template_processing_status(1)
        self.assertFalse(obs_proc)
        self.assertEqual(obs_at, "")
        self.assertEqual(obs_am, "")

        # Without job id
        r_client.set(key, dumps({"job_id": None, "status": "success", "message": ""}))
        obs_proc, obs_at, obs_am = get_sample_template_processing_status(1)
        self.assertFalse(obs_proc)
        self.assertEqual(obs_at, "success")
        self.assertEqual(obs_am, "")

        # With job id and processing
        r_client.set(key, dumps({"job_id": "test_job_id"}))
        r_client.set("test_job_id", dumps({"status_msg": "Running"}))
        obs_proc, obs_at, obs_am = get_sample_template_processing_status(1)
        self.assertTrue(obs_proc)
        self.assertEqual(obs_at, "info")
        self.assertEqual(obs_am, "This sample template is currently being processed")

        # With job id and success
        r_client.set(key, dumps({"job_id": "test_job_id"}))
        r_client.set(
            "test_job_id", dumps({"status_msg": "Success", "return": {"status": "success", "message": "Some\nwarning"}})
        )
        obs_proc, obs_at, obs_am = get_sample_template_processing_status(1)
        self.assertFalse(obs_proc)
        self.assertEqual(obs_at, "success")
        self.assertEqual(obs_am, "Some</br>warning")
        obs = loads(r_client.get(key))
        self.assertEqual(obs, {"job_id": None, "status": "success", "message": "Some</br>warning"})

        # With job and not success
        r_client.set(key, dumps({"job_id": "test_job_id"}))
        r_client.set(
            "test_job_id", dumps({"status_msg": "Failed", "return": {"status": "error", "message": "Some\nerror"}})
        )
        obs_proc, obs_at, obs_am = get_sample_template_processing_status(1)
        self.assertFalse(obs_proc)
        self.assertEqual(obs_at, "error")
        self.assertEqual(obs_am, "Some</br>error")

        # With job expired
        r_client.set(key, dumps({"job_id": "non_existent_job"}))
        obs_proc, obs_at, obs_am = get_sample_template_processing_status(1)
        self.assertFalse(obs_proc)
        self.assertEqual(obs_at, "")
        self.assertEqual(obs_am, "")
Ejemplo n.º 44
0
def sample_template_summary_get_req(samp_id, user_id):
    """Returns a summary of the sample template metadata columns

    Parameters
    ----------
    samp_id : int
        SampleTemplate id to get info for
    user_id : str
        User requesting the sample template info

    Returns
    -------
    dict
        Returns summary information in the form
        {'status': str,
         'message': str,
         'info': dict of {str: object}
        status can be success, warning, or error depending on result
        message has the warnings or errors
        info dictionary contains the keys as the metadata categories
        and the values are list of tuples. Each tuple is an observed value in
        the category and the number of times its seen.
        Format {num_samples: value,
                category: [(val1, count1), (val2, count2), ...], ...}
    """
    access_error = check_access(samp_id, user_id)
    if access_error:
        return access_error

    job_info = r_client.get(SAMPLE_TEMPLATE_KEY_FORMAT % samp_id)
    if job_info:
        job_info = loads(job_info)
        job_id = job_info['job_id']
        if job_id:
            redis_info = loads(r_client.get(job_id))
            processing = redis_info['status_msg'] == 'Running'
            if processing:
                alert_type = 'info'
                alert_msg = 'This sample template is currently being processed'
            elif redis_info['status_msg'] == 'Success':
                alert_type = redis_info['return']['status']
                alert_msg = redis_info['return']['message'].replace('\n',
                                                                    '</br>')
                payload = {'job_id': None,
                           'status': alert_type,
                           'message': alert_msg}
                r_client.set(SAMPLE_TEMPLATE_KEY_FORMAT % samp_id,
                             dumps(payload))
            else:
                alert_type = redis_info['return']['status']
                alert_msg = redis_info['return']['message'].replace('\n',
                                                                    '</br>')
        else:
            processing = False
            alert_type = job_info['status']
            alert_msg = job_info['message'].replace('\n', '</br>')
    else:
        processing = False
        alert_type = ''
        alert_msg = ''

    exists = _check_sample_template_exists(int(samp_id))
    if exists['status'] != 'success':
        return {'status': 'success',
                'message': '',
                'num_samples': 0,
                'num_columns': 0,
                'editable': not processing,
                'alert_type': alert_type,
                'alert_message': alert_msg,
                'stats': {}}

    template = SampleTemplate(int(samp_id))

    df = template.to_dataframe()

    editable = (Study(template.study_id).can_edit(User(user_id)) and not
                processing)

    out = {'status': 'success',
           'message': '',
           'num_samples': df.shape[0],
           'num_columns': df.shape[1],
           'editable': editable,
           'alert_type': alert_type,
           'alert_message': alert_msg,
           'stats': {}}

    # drop the samp_id column if it exists
    if 'study_id' in df.columns:
        df.drop('study_id', axis=1, inplace=True)
    for column in df.columns:
        counts = df[column].value_counts()
        out['stats'][str(column)] = [(str(key), counts[key])
                                     for key in natsorted(counts.index)]

    return out
Ejemplo n.º 45
0
def artifact_post_req(user_id,
                      filepaths,
                      artifact_type,
                      name,
                      prep_template_id,
                      artifact_id=None):
    """Creates the initial artifact for the prep template

    Parameters
    ----------
    user_id : str
        User adding the atrifact
    filepaths : dict of str
        Comma-separated list of files to attach to the artifact,
        keyed by file type
    artifact_type : str
        The type of the artifact
    name : str
        Name to give the artifact
    prep_template_id : int or str castable to int
        Prep template to attach the artifact to
    artifact_id : int or str castable to int, optional
        The id of the imported artifact

    Returns
    -------
    dict of objects
        A dictionary containing the new artifact ID
        {'status': status,
         'message': message,
         'artifact': id}
    """
    prep = PrepTemplate(int(prep_template_id))
    study_id = prep.study_id

    # First check if the user has access to the study
    access_error = check_access(study_id, user_id)
    if access_error:
        return access_error

    if artifact_id:
        # if the artifact id has been provided, import the artifact
        job_id = safe_submit(user_id, copy_raw_data, prep, artifact_id)
    else:
        uploads_path = get_mountpoint('uploads')[0][1]
        path_builder = partial(join, uploads_path, str(study_id))
        cleaned_filepaths = []
        for ftype, file_list in viewitems(filepaths):
            # JavaScript sends us this list as a comma-separated list
            for fp in file_list.split(','):
                # JavaScript will send this value as an empty string if the
                # list of files was empty. In such case, the split will
                # generate a single element containing the empty string. Check
                # for that case here and, if fp is not the empty string,
                # proceed to check if the file exists
                if fp:
                    # Check if filepath being passed exists for study
                    full_fp = path_builder(fp)
                    exists = check_fp(study_id, full_fp)
                    if exists['status'] != 'success':
                        return {
                            'status': 'error',
                            'message': 'File does not exist: %s' % fp
                        }
                    cleaned_filepaths.append((full_fp, ftype))

        # This should never happen, but it doesn't hurt to actually have
        # a explicit check, in case there is something odd with the JS
        if not cleaned_filepaths:
            return {
                'status': 'error',
                'message': "Can't create artifact, no files provided."
            }

        job_id = safe_submit(user_id,
                             create_raw_data,
                             artifact_type,
                             prep,
                             cleaned_filepaths,
                             name=name)

    r_client.set(PREP_TEMPLATE_KEY_FORMAT % prep.id, dumps({'job_id': job_id}))

    return {'status': 'success', 'message': ''}
Ejemplo n.º 46
0
def sample_template_summary_get_req(samp_id, user_id):
    """Returns a summary of the sample template metadata columns

    Parameters
    ----------
    samp_id : int
        SampleTemplate id to get info for
    user_id : str
        User requesting the sample template info

    Returns
    -------
    dict
        Returns summary information in the form
        {'status': str,
         'message': str,
         'info': dict of {str: object}
        status can be success, warning, or error depending on result
        message has the warnings or errors
        info dictionary contains the keys as the metadata categories
        and the values are list of tuples. Each tuple is an observed value in
        the category and the number of times its seen.
        Format {num_samples: value,
                category: [(val1, count1), (val2, count2), ...], ...}
    """
    access_error = check_access(samp_id, user_id)
    if access_error:
        return access_error

    job_info = r_client.get(SAMPLE_TEMPLATE_KEY_FORMAT % samp_id)
    if job_info:
        job_info = loads(job_info)
        job_id = job_info['job_id']
        if job_id:
            redis_info = loads(r_client.get(job_id))
            processing = redis_info['status_msg'] == 'Running'
            if processing:
                alert_type = 'info'
                alert_msg = 'This sample template is currently being processed'
            elif redis_info['status_msg'] == 'Success':
                alert_type = redis_info['return']['status']
                alert_msg = redis_info['return']['message'].replace(
                    '\n', '</br>')
                payload = {
                    'job_id': None,
                    'status': alert_type,
                    'message': alert_msg
                }
                r_client.set(SAMPLE_TEMPLATE_KEY_FORMAT % samp_id,
                             dumps(payload))
            else:
                alert_type = redis_info['return']['status']
                alert_msg = redis_info['return']['message'].replace(
                    '\n', '</br>')
        else:
            processing = False
            alert_type = job_info['status']
            alert_msg = job_info['message'].replace('\n', '</br>')
    else:
        processing = False
        alert_type = ''
        alert_msg = ''

    exists = _check_sample_template_exists(int(samp_id))
    if exists['status'] != 'success':
        return {
            'status': 'success',
            'message': '',
            'num_samples': 0,
            'num_columns': 0,
            'editable': not processing,
            'alert_type': alert_type,
            'alert_message': alert_msg,
            'stats': {}
        }

    template = SampleTemplate(int(samp_id))

    df = template.to_dataframe()

    editable = (Study(template.study_id).can_edit(User(user_id))
                and not processing)

    out = {
        'status': 'success',
        'message': '',
        'num_samples': df.shape[0],
        'num_columns': df.shape[1],
        'editable': editable,
        'alert_type': alert_type,
        'alert_message': alert_msg,
        'stats': {}
    }

    # drop the samp_id column if it exists
    if 'study_id' in df.columns:
        df.drop('study_id', axis=1, inplace=True)
    for column in df.columns:
        counts = df[column].value_counts()
        out['stats'][str(column)] = [(str(key), counts[key])
                                     for key in natsorted(counts.index)]

    return out
Ejemplo n.º 47
0
    def test_get_sample_template_processing_status(self):
        key = SAMPLE_TEMPLATE_KEY_FORMAT % 1

        obs_proc, obs_at, obs_am = get_sample_template_processing_status(1)
        self.assertFalse(obs_proc)
        self.assertEqual(obs_at, "")
        self.assertEqual(obs_am, "")

        # Without job id
        r_client.set(
            key, dumps({
                'job_id': None,
                'status': "success",
                'message': ""
            }))
        obs_proc, obs_at, obs_am = get_sample_template_processing_status(1)
        self.assertFalse(obs_proc)
        self.assertEqual(obs_at, "success")
        self.assertEqual(obs_am, "")

        # With job id and processing
        r_client.set(key, dumps({'job_id': "test_job_id"}))
        r_client.set("test_job_id", dumps({'status_msg': 'Running'}))
        obs_proc, obs_at, obs_am = get_sample_template_processing_status(1)
        self.assertTrue(obs_proc)
        self.assertEqual(obs_at, "info")
        self.assertEqual(obs_am,
                         "This sample template is currently being processed")

        # With job id and success
        r_client.set(key, dumps({'job_id': "test_job_id"}))
        r_client.set(
            "test_job_id",
            dumps({
                'status_msg': 'Success',
                'return': {
                    'status': 'success',
                    'message': 'Some\nwarning'
                }
            }))
        obs_proc, obs_at, obs_am = get_sample_template_processing_status(1)
        self.assertFalse(obs_proc)
        self.assertEqual(obs_at, "success")
        self.assertEqual(obs_am, "Some</br>warning")
        obs = loads(r_client.get(key))
        self.assertEqual(obs, {
            'job_id': None,
            'status': 'success',
            'message': 'Some</br>warning'
        })

        # With job and not success
        r_client.set(key, dumps({'job_id': "test_job_id"}))
        r_client.set(
            "test_job_id",
            dumps({
                'status_msg': 'Failed',
                'return': {
                    'status': 'error',
                    'message': 'Some\nerror'
                }
            }))
        obs_proc, obs_at, obs_am = get_sample_template_processing_status(1)
        self.assertFalse(obs_proc)
        self.assertEqual(obs_at, "error")
        self.assertEqual(obs_am, "Some</br>error")
Ejemplo n.º 48
0
def prep_template_ajax_get_req(user_id, prep_id):
    """Returns the prep tempalte information needed for the AJAX handler

    Parameters
    ----------
    user_id : str
        The user id
    prep_id : int
        The prep template id

    Returns
    -------
    dict of {str: object}
        A dictionary with the following keys:
        - status: str, whether the request is successful or not
        - message: str, if the request is unsuccessful, a human readable error
        - name: str, the name of the prep template
        - files: list of str, the files available to update the prep template
        - download_prep: int, the filepath_id of the prep file
        - download_qiime, int, the filepath_id of the qiime mapping file
        - num_samples: int, the number of samples present in the template
        - num_columns: int, the number of columns present in the template
        - investigation_type: str, the investigation type of the template
        - ontology: str, dict of {str, list of str} containing the information
        of the ENA ontology
        - artifact_attached: bool, whether the template has an artifact
        attached
        - study_id: int, the study id of the template
    """
    # Currently there is no name attribute, but it will be soon
    name = "Prep information %d" % prep_id
    pt = PrepTemplate(prep_id)

    job_info = r_client.get(PREP_TEMPLATE_KEY_FORMAT % prep_id)
    if job_info:
        job_info = loads(job_info)
        job_id = job_info['job_id']
        if job_id:
            if job_info['is_qiita_job']:
                job = ProcessingJob(job_id)
                processing = job.status in ('queued', 'running')
                success = job.status == 'success'
                alert_type = 'info' if processing or success else 'danger'
                alert_msg = (job.log.msg.replace('\n', '</br>')
                             if job.log is not None else "")
            else:
                redis_info = loads(r_client.get(job_id))
                processing = redis_info['status_msg'] == 'Running'
                success = redis_info['status_msg'] == 'Success'
                if redis_info['return'] is not None:
                    alert_type = redis_info['return']['status']
                    alert_msg = redis_info['return']['message'].replace(
                        '\n', '</br>')
                else:
                    alert_type = 'info'
                    alert_msg = ''

            if processing:
                alert_type = 'info'
                alert_msg = 'This prep template is currently being updated'
            elif success:
                payload = {'job_id': None,
                           'status': alert_type,
                           'message': alert_msg,
                           'is_qiita_job': job_info['is_qiita_job']}
                r_client.set(PREP_TEMPLATE_KEY_FORMAT % prep_id,
                             dumps(payload))
        else:
            processing = False
            alert_type = job_info['status']
            alert_msg = job_info['message'].replace('\n', '</br>')
    else:
        processing = False
        alert_type = ''
        alert_msg = ''

    artifact_attached = pt.artifact is not None
    study_id = pt.study_id
    files = [f for _, f in get_files_from_uploads_folders(study_id)
             if f.endswith(('.txt', '.tsv'))]

    # The call to list is needed because keys is an iterator
    num_samples = len(list(pt.keys()))
    num_columns = len(pt.categories())
    investigation_type = pt.investigation_type

    # Retrieve the information to download the prep template and QIIME
    # mapping file. See issue https://github.com/biocore/qiita/issues/1675
    download_prep = []
    download_qiime = []
    for fp_id, fp in pt.get_filepaths():
        if 'qiime' in basename(fp):
            download_qiime.append(fp_id)
        else:
            download_prep.append(fp_id)
    download_prep = download_prep[0]
    download_qiime = download_qiime[0]

    ontology = _get_ENA_ontology()

    editable = Study(study_id).can_edit(User(user_id)) and not processing

    return {'status': 'success',
            'message': '',
            'name': name,
            'files': files,
            'download_prep': download_prep,
            'download_qiime': download_qiime,
            'num_samples': num_samples,
            'num_columns': num_columns,
            'investigation_type': investigation_type,
            'ontology': ontology,
            'artifact_attached': artifact_attached,
            'study_id': study_id,
            'editable': editable,
            'data_type': pt.data_type(),
            'alert_type': alert_type,
            'is_submitted_to_ebi': pt.is_submitted_to_ebi,
            'alert_message': alert_msg}
Ejemplo n.º 49
0
def prep_template_patch_req(user_id, req_op, req_path, req_value=None,
                            req_from=None):
    """Modifies an attribute of the prep template

    Parameters
    ----------
    user_id : str
        The id of the user performing the patch operation
    req_op : str
        The operation to perform on the prep information
    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]
        # The structure of the path should be /prep_id/attribute_to_modify/
        # so if we don't have those 2 elements, we should return an error
        if len(req_path) != 2:
            return {'status': 'error',
                    'message': 'Incorrect path parameter'}
        prep_id = int(req_path[0])
        attribute = req_path[1]

        # Check if the user actually has access to the prep template
        prep = PrepTemplate(prep_id)
        access_error = check_access(prep.study_id, user_id)
        if access_error:
            return access_error

        status = 'success'
        msg = ''
        if attribute == 'investigation_type':
            prep.investigation_type = req_value
        elif attribute == 'data':
            fp = check_fp(prep.study_id, req_value)
            if fp['status'] != 'success':
                return fp
            fp = fp['file']
            job_id = safe_submit(user_id, update_prep_template, prep_id, fp)
            r_client.set(PREP_TEMPLATE_KEY_FORMAT % prep_id, job_id)
        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}

        return {'status': status, 'message': msg}
    else:
        return {'status': 'error',
                'message': 'Operation "%s" not supported. '
                           'Current supported operations: replace' % req_op}
Ejemplo n.º 50
0
def artifact_post_req(user_id, filepaths, artifact_type, name,
                      prep_template_id, artifact_id=None):
    """Creates the initial artifact for the prep template

    Parameters
    ----------
    user_id : str
        User adding the atrifact
    filepaths : dict of str
        Comma-separated list of files to attach to the artifact,
        keyed by file type
    artifact_type : str
        The type of the artifact
    name : str
        Name to give the artifact
    prep_template_id : int or str castable to int
        Prep template to attach the artifact to
    artifact_id : int or str castable to int, optional
        The id of the imported artifact

    Returns
    -------
    dict of objects
        A dictionary containing the new artifact ID
        {'status': status,
         'message': message,
         'artifact': id}
    """
    prep = PrepTemplate(int(prep_template_id))
    study_id = prep.study_id

    # First check if the user has access to the study
    access_error = check_access(study_id, user_id)
    if access_error:
        return access_error

    if artifact_id:
        # if the artifact id has been provided, import the artifact
        job_id = safe_submit(user_id, copy_raw_data, prep, artifact_id)
    else:
        uploads_path = get_mountpoint('uploads')[0][1]
        path_builder = partial(join, uploads_path, str(study_id))
        cleaned_filepaths = []
        for ftype, file_list in viewitems(filepaths):
            # JavaScript sends us this list as a comma-separated list
            for fp in file_list.split(','):
                # JavaScript will send this value as an empty string if the
                # list of files was empty. In such case, the split will
                # generate a single element containing the empty string. Check
                # for that case here and, if fp is not the empty string,
                # proceed to check if the file exists
                if fp:
                    # Check if filepath being passed exists for study
                    full_fp = path_builder(fp)
                    exists = check_fp(study_id, full_fp)
                    if exists['status'] != 'success':
                        return {'status': 'error',
                                'message': 'File does not exist: %s' % fp}
                    cleaned_filepaths.append((full_fp, ftype))

        # This should never happen, but it doesn't hurt to actually have
        # a explicit check, in case there is something odd with the JS
        if not cleaned_filepaths:
            return {'status': 'error',
                    'message': "Can't create artifact, no files provided."}

        job_id = safe_submit(user_id, create_raw_data, artifact_type, prep,
                             cleaned_filepaths, name=name)

    r_client.set(PREP_TEMPLATE_KEY_FORMAT % prep.id, dumps({'job_id': job_id}))

    return {'status': 'success',
            'message': ''}