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, True) r_client.set(redis_key, dumps({'job_id': job.id, 'is_qiita_job': True})) job.submit() return {'job': job.id}
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)))
def study_delete_req(study_id, user_id): """Delete a given study Parameters ---------- study_id : int Study id to delete user_id : str User requesting the deletion Returns ------- dict Status of deletion, in the format {status: status, message: message} """ access_error = check_access(study_id, user_id) if access_error: return access_error qiita_plugin = Software.from_name_and_version('Qiita', 'alpha') cmd = qiita_plugin.get_command('delete_study') params = Parameters.load(cmd, values_dict={'study': study_id}) job = ProcessingJob.create(User(user_id), params, True) # Store the job id attaching it to the sample template id r_client.set(STUDY_KEY_FORMAT % study_id, dumps({'job_id': job.id})) job.submit() return {'status': 'success', 'message': ''}
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 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()
def _get_private_software(self): # skipping the internal Qiita plugin and only selecting private # commands private_software = [s for s in Software.iter() if s.name != 'Qiita' and s.type == 'private'] return private_software
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)
def _create_job(self, cmd_name, values_dict): self.user = User('*****@*****.**') qiita_plugin = Software.from_name_and_version('Qiita', 'alpha') cmd = qiita_plugin.get_command(cmd_name) params = Parameters.load(cmd, values_dict=values_dict) job = ProcessingJob.create(self.user, params, True) job._set_status('queued') return job
def get(self): # active True will only show active software active = True user = self.current_user if user is not None and user.level in {'admin', 'dev'}: active = False software = Software.iter(active=active) self.render("software.html", software=software)
def sample_template_handler_post_request(study_id, user, filepath, data_type=None): """Creates a new sample template Parameters ---------- study_id: int The study to add the sample information user: qiita_db.user import User The user performing the request filepath: str The path to the sample template file data_type: str, optional If filepath is a QIIME mapping file, the data type of the prep information file Returns ------- dict of {'job': str} job: the id of the job adding the sample information to the study Raises ------ HTTPError 404 if the filepath doesn't exist """ # Check if the current user has access to the study sample_template_checks(study_id, user) # Check if the file exists fp_rsp = check_fp(study_id, filepath) if fp_rsp['status'] != 'success': raise HTTPError(404, 'Filepath not found') filepath = fp_rsp['file'] is_mapping_file = looks_like_qiime_mapping_file(filepath) if is_mapping_file and not data_type: raise HTTPError( 400, 'Please, choose a data type if uploading a ' 'QIIME mapping file') qiita_plugin = Software.from_name_and_version('Qiita', 'alpha') cmd = qiita_plugin.get_command('create_sample_template') params = Parameters.load(cmd, values_dict={ 'fp': filepath, 'study_id': study_id, 'is_mapping_file': is_mapping_file, 'data_type': data_type }) job = ProcessingJob.create(user, params, True) r_client.set(SAMPLE_TEMPLATE_KEY_FORMAT % study_id, dumps({'job_id': job.id})) job.submit() return {'job': job.id}
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 qiita_plugin = Software.from_name_and_version('Qiita', 'alpha') cmd = qiita_plugin.get_command('update_sample_template') params = Parameters.load(cmd, values_dict={ 'study': int(study_id), 'template_fp': fp_rsp }) job = ProcessingJob.create(User(user_id), params) # 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})) job.submit() return {'status': status, 'message': msg, 'file': sample_template}
def sample_template_handler_post_request(study_id, user, filepath, data_type=None, direct_upload=False): """Creates a new sample template Parameters ---------- study_id: int The study to add the sample information user: qiita_db.user import User The user performing the request filepath: str The path to the sample template file data_type: str, optional If filepath is a QIIME mapping file, the data type of the prep information file direct_upload: boolean, optional If filepath is a direct upload; if False we need to process the filepath as part of the study upload folder Returns ------- dict of {'job': str} job: the id of the job adding the sample information to the study Raises ------ HTTPError 404 if the filepath doesn't exist """ # Check if the current user has access to the study sample_template_checks(study_id, user) # Check if the file exists if not direct_upload: fp_rsp = check_fp(study_id, filepath) if fp_rsp['status'] != 'success': raise HTTPError(404, reason='Filepath not found') filepath = fp_rsp['file'] is_mapping_file = looks_like_qiime_mapping_file(filepath) if is_mapping_file and not data_type: raise HTTPError(400, reason='Please, choose a data type if uploading ' 'a QIIME mapping file') qiita_plugin = Software.from_name_and_version('Qiita', 'alpha') cmd = qiita_plugin.get_command('create_sample_template') params = Parameters.load( cmd, values_dict={'fp': filepath, 'study_id': study_id, 'is_mapping_file': is_mapping_file, 'data_type': data_type}) job = ProcessingJob.create(user, params, True) r_client.set(SAMPLE_TEMPLATE_KEY_FORMAT % study_id, dumps({'job_id': job.id})) job.submit() return {'job': job.id}
def post(self, study_id): method = self.get_argument('remote-request-type') url = self.get_argument('inputURL') ssh_key = self.request.files['ssh-key'][0]['body'] status = 'success' message = '' try: study = Study(int(study_id)) except QiitaDBUnknownIDError: raise HTTPError(404, reason="Study %s does not exist" % study_id) check_access(self.current_user, study, no_public=True, raise_error=True) _, upload_folder = get_mountpoint("uploads")[0] upload_folder = join(upload_folder, study_id) ssh_key_fp = join(upload_folder, '.key.txt') create_nested_path(upload_folder) with open(ssh_key_fp, 'wb') as f: f.write(ssh_key) chmod(ssh_key_fp, 0o600) qiita_plugin = Software.from_name_and_version('Qiita', 'alpha') if method == 'list': cmd = qiita_plugin.get_command('list_remote_files') params = Parameters.load(cmd, values_dict={ 'url': url, 'private_key': ssh_key_fp, 'study_id': study_id }) elif method == 'transfer': cmd = qiita_plugin.get_command('download_remote_files') params = Parameters.load(cmd, values_dict={ 'url': url, 'private_key': ssh_key_fp, 'destination': upload_folder }) else: status = 'error' message = 'Not a valid method' if status == 'success': job = ProcessingJob.create(self.current_user, params, True) job.submit() r_client.set(UPLOAD_STUDY_FORMAT % study_id, dumps({'job_id': job.id})) self.write({'status': status, 'message': message})
def post(self): analysis_id = int(self.get_argument('analysis_id')) user = self.current_user check_analysis_access(user, Analysis(analysis_id)) qiita_plugin = Software.from_name_and_version('Qiita', 'alpha') cmd = qiita_plugin.get_command('delete_analysis') params = Parameters.load(cmd, values_dict={'analysis_id': analysis_id}) job = ProcessingJob.create(user, params, True) # Store the job id attaching it to the sample template id r_client.set('analysis_delete_%d' % analysis_id, dumps({'job_id': job.id})) job.submit() self.redirect("%s/analysis/list/" % (qiita_config.portal_dir))
def post(self, study_id): method = self.get_argument('remote-request-type') url = self.get_argument('inputURL') ssh_key = self.request.files['ssh-key'][0]['body'] status = 'success' message = '' try: study = Study(int(study_id)) except QiitaDBUnknownIDError: raise HTTPError(404, reason="Study %s does not exist" % study_id) check_access( self.current_user, study, no_public=True, raise_error=True) _, upload_folder = get_mountpoint("uploads")[0] upload_folder = join(upload_folder, study_id) ssh_key_fp = join(upload_folder, '.key.txt') create_nested_path(upload_folder) with open(ssh_key_fp, 'w') as f: f.write(ssh_key) qiita_plugin = Software.from_name_and_version('Qiita', 'alpha') if method == 'list': cmd = qiita_plugin.get_command('list_remote_files') params = Parameters.load(cmd, values_dict={ 'url': url, 'private_key': ssh_key_fp, 'study_id': study_id}) elif method == 'transfer': cmd = qiita_plugin.get_command('download_remote_files') params = Parameters.load(cmd, values_dict={ 'url': url, 'private_key': ssh_key_fp, 'destination': upload_folder}) else: status = 'error' message = 'Not a valid method' if status == 'success': job = ProcessingJob.create(self.current_user, params, True) job.submit() r_client.set( UPLOAD_STUDY_FORMAT % study_id, dumps({'job_id': job.id})) self.write({'status': status, 'message': message})
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 qiita_plugin = Software.from_name_and_version('Qiita', 'alpha') cmd = qiita_plugin.get_command('delete_sample_template') params = Parameters.load(cmd, values_dict={'study': int(study_id)}) job = ProcessingJob.create(User(user_id), params) # 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})) job.submit() return {'status': 'success', 'message': ''}
def sample_template_handler_delete_request(study_id, user): """Deletes the sample template Parameters ---------- study_id: int The study to delete the sample information user: qiita_db.user The user performing the request Returns ------- dict of {'job': str} job: the id of the job deleting the sample information to the study Raises ------ HTTPError 404 If the sample template doesn't exist """ # Check if the current user has access to the study and if the sample # template exists sample_template_checks(study_id, user, check_exists=True) qiita_plugin = Software.from_name_and_version('Qiita', 'alpha') cmd = qiita_plugin.get_command('delete_sample_template') params = Parameters.load(cmd, values_dict={'study': int(study_id)}) job = ProcessingJob.create(user, params, True) # Store the job if deleteing the sample template r_client.set(SAMPLE_TEMPLATE_KEY_FORMAT % study_id, dumps({'job_id': job.id})) job.submit() return {'job': job.id}
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_template_id = int(prep_template_id) prep = PrepTemplate(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 user = User(user_id) if artifact_id: # if the artifact id has been provided, import the artifact qiita_plugin = Software.from_name_and_version('Qiita', 'alpha') cmd = qiita_plugin.get_command('copy_artifact') params = Parameters.load(cmd, values_dict={'artifact': artifact_id, 'prep_template': prep.id}) job = ProcessingJob.create(user, params, True) 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} if ftype not in cleaned_filepaths: cleaned_filepaths[ftype] = [] cleaned_filepaths[ftype].append(full_fp) # 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."} # This try/except will catch the case when the plugins are not # activated so there is no Validate for the given artifact_type try: command = Command.get_validator(artifact_type) except QiitaDBError as e: return {'status': 'error', 'message': str(e)} job = ProcessingJob.create( user, Parameters.load(command, values_dict={ 'template': prep_template_id, 'files': dumps(cleaned_filepaths), 'artifact_type': artifact_type, 'name': name, 'analysis': None, }), True) # Submit the job job.submit() r_client.set(PREP_TEMPLATE_KEY_FORMAT % prep.id, dumps({'job_id': job.id, 'is_qiita_job': True})) return {'status': 'success', 'message': ''}
def sample_template_handler_patch_request(user, req_op, req_path, req_value=None, req_from=None, direct_upload=False): """Patches the sample template Parameters ---------- user: qiita_db.user.User The user performing the request req_op : str The operation to perform on the sample template req_path : str The path to the attribute to patch req_value : str, optional The new value req_from : str, optional The original path of the element direct_upload : boolean, optional If the file being uploaded comes from a direct upload (True) Returns ------- Raises ------ HTTPError 400 If the path parameter doens't follow the expected format 400 If the given operation is not supported """ req_path = [v for v in req_path.split('/') if v] # At this point we know the path should be at least length 2 if len(req_path) < 2: raise HTTPError(400, reason='Incorrect path parameter') study_id = int(req_path[0]) # Check if the current user has access to the study and if the sample # template exists sample_template_checks(study_id, user, check_exists=True) if req_op == 'remove': # Path format # column: study_id/columns/column_name # sample: study_id/samples/sample_id if len(req_path) != 3: raise HTTPError(400, reason='Incorrect path parameter') attribute = req_path[1] attr_id = req_path[2] qiita_plugin = Software.from_name_and_version('Qiita', 'alpha') cmd = qiita_plugin.get_command('delete_sample_or_column') params = Parameters.load(cmd, values_dict={ 'obj_class': 'SampleTemplate', 'obj_id': study_id, 'sample_or_col': attribute, 'name': attr_id }) job = ProcessingJob.create(user, params, True) # 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})) job.submit() return {'job': job.id} elif req_op == 'replace': # WARNING: Although the patch operation is a replace, is not a full # true replace. A replace is in theory equivalent to a remove + add. # In this case, the replace operation doesn't necessarily removes # anything (e.g. when only new columns/samples are being added to the) # sample information. # Path format: study_id/data # Forcing to specify data for extensibility. In the future we may want # to use this function to replace other elements of the sample # information if len(req_path) != 2: raise HTTPError(400, reason='Incorrect path parameter') attribute = req_path[1] if attribute == 'data': # Update the sample information if req_value is None: raise HTTPError(400, reason="Value is required when updating " "sample information") if direct_upload: # We can assume that the file exist as it was generated by # the system filepath = req_value if not exists(filepath): reason = ('Upload file not found (%s), please report to ' '*****@*****.**' % filepath) raise HTTPError(404, reason=reason) else: # Check if the file exists fp_rsp = check_fp(study_id, req_value) if fp_rsp['status'] != 'success': raise HTTPError(404, reason='Filepath not found') filepath = fp_rsp['file'] qiita_plugin = Software.from_name_and_version('Qiita', 'alpha') cmd = qiita_plugin.get_command('update_sample_template') params = Parameters.load(cmd, values_dict={ 'study': study_id, 'template_fp': filepath }) job = ProcessingJob.create(user, params, True) # 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})) job.submit() return {'job': job.id} else: raise HTTPError(404, reason='Attribute %s not found' % attribute) else: raise HTTPError(400, reason='Operation %s not supported. Current ' 'supported operations: remove, replace' % req_op)
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_template_id = int(prep_template_id) prep = PrepTemplate(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 user = User(user_id) if artifact_id: # if the artifact id has been provided, import the artifact qiita_plugin = Software.from_name_and_version('Qiita', 'alpha') cmd = qiita_plugin.get_command('copy_artifact') params = Parameters.load(cmd, values_dict={ 'artifact': artifact_id, 'prep_template': prep.id }) job = ProcessingJob.create(user, params, True) else: uploads_path = get_mountpoint('uploads')[0][1] path_builder = partial(join, uploads_path, str(study_id)) cleaned_filepaths = {} for ftype, file_list in filepaths.items(): # 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 } if ftype not in cleaned_filepaths: cleaned_filepaths[ftype] = [] cleaned_filepaths[ftype].append(full_fp) # 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." } # This try/except will catch the case when the plugins are not # activated so there is no Validate for the given artifact_type try: command = Command.get_validator(artifact_type) except QiitaDBError as e: return {'status': 'error', 'message': str(e)} job = ProcessingJob.create( user, Parameters.load(command, values_dict={ 'template': prep_template_id, 'files': dumps(cleaned_filepaths), 'artifact_type': artifact_type, 'name': name, 'analysis': None, }), True) # Submit the job job.submit() r_client.set(PREP_TEMPLATE_KEY_FORMAT % prep.id, dumps({ 'job_id': job.id, 'is_qiita_job': True })) return {'status': 'success', 'message': ''}
def get(self): self.check_access() software = Software.iter(False) self.render("software.html", software=software)
from qiita_db.sql_connection import TRN from biom.util import biom_open from os import rename from collections import defaultdict # this is necessary to overcome this issue # https://github.com/biocore/biom-format/issues/761 def collapse_f(table, axis): return table.sum(axis=axis) studies = Study.get_by_status('private').union( Study.get_by_status('public')).union(Study.get_by_status('sandbox')) sft = Software.from_name_and_version('deblur', '1.0.3') # [0] deblur only has 1 command cmd = sft.commands[0] artifacts = [a for s in studies for a in s.artifacts() if a.processing_parameters is not None and a.processing_parameters.command == cmd] sql = "UPDATE qiita.filepath SET checksum = %s WHERE filepath_id = %s" for a in artifacts: # putting all this in a transaction in case something fails it does # it nicely with TRN: ftps = {ft: (fid, fp) for fid, fp, ft in a.filepaths if ft in ['biom', 'preprocessed_fasta']}
def sample_template_handler_patch_request(user, req_op, req_path, req_value=None, req_from=None): """Patches the sample template Parameters ---------- user: qiita_db.user.User The user performing the request req_op : str The operation to perform on the sample template req_path : str The path to the attribute to patch req_value : str, optional The new value req_from : str, optional The original path of the element Returns ------- Raises ------ HTTPError 400 If the path parameter doens't follow the expected format 400 If the given operation is not supported """ req_path = [v for v in req_path.split('/') if v] # At this point we know the path should be at least length 2 if len(req_path) < 2: raise HTTPError(400, reason='Incorrect path parameter') study_id = int(req_path[0]) # Check if the current user has access to the study and if the sample # template exists sample_template_checks(study_id, user, check_exists=True) if req_op == 'remove': # Path format # column: study_id/columns/column_name # sample: study_id/samples/sample_id if len(req_path) != 3: raise HTTPError(400, reason='Incorrect path parameter') attribute = req_path[1] attr_id = req_path[2] qiita_plugin = Software.from_name_and_version('Qiita', 'alpha') cmd = qiita_plugin.get_command('delete_sample_or_column') params = Parameters.load( cmd, values_dict={'obj_class': 'SampleTemplate', 'obj_id': study_id, 'sample_or_col': attribute, 'name': attr_id}) job = ProcessingJob.create(user, params, True) # 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})) job.submit() return {'job': job.id} elif req_op == 'replace': # WARNING: Although the patch operation is a replace, is not a full # true replace. A replace is in theory equivalent to a remove + add. # In this case, the replace operation doesn't necessarily removes # anything (e.g. when only new columns/samples are being added to the) # sample information. # Path format: study_id/data # Forcing to specify data for extensibility. In the future we may want # to use this function to replace other elements of the sample # information if len(req_path) != 2: raise HTTPError(400, reason='Incorrect path parameter') attribute = req_path[1] if attribute == 'data': # Update the sample information if req_value is None: raise HTTPError(400, reason="Value is required when updating " "sample information") # Check if the file exists fp_rsp = check_fp(study_id, req_value) if fp_rsp['status'] != 'success': raise HTTPError(404, reason='Filepath not found') filepath = fp_rsp['file'] qiita_plugin = Software.from_name_and_version('Qiita', 'alpha') cmd = qiita_plugin.get_command('update_sample_template') params = Parameters.load( cmd, values_dict={'study': study_id, 'template_fp': filepath}) job = ProcessingJob.create(user, params, True) # 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})) job.submit() return {'job': job.id} else: raise HTTPError(404, reason='Attribute %s not found' % attribute) else: raise HTTPError(400, reason='Operation %s not supported. Current ' 'supported operations: remove, replace' % req_op)
VALUES (%s, 'name', 'string', 'False', 'dflt_name'), (%s, 'provenance', 'string', 'False', NULL) """ TRN.add(sql, [c_id, c_id]) # Add the outputs to the command if outputs: sql = """INSERT INTO qiita.command_output (name, command_id, artifact_type_id) VALUES (%s, %s, %s)""" sql_args = [[pname, c_id, convert_to_id(at, 'artifact_type')] for pname, at in outputs.items()] TRN.add(sql, sql_args, many=True) TRN.execute() return Command(c_id) with TRN: # Retrieve the Qiita plugin qiita_plugin = Software.from_name_and_version('Qiita', 'alpha') # Create the INSDC download command parameters = { 'download_source': ['choice:["EBI-ENA", "SRA"]', 'EBI-ENA'], 'accession': ["string", 'None'], } create_command(qiita_plugin, "INSDC_download", "Downloads an accession from a given INSDC", parameters)
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, 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 - row_id: str, the row_id that we tried to delete """ 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'] qiita_plugin = Software.from_name_and_version('Qiita', 'alpha') cmd = qiita_plugin.get_command('update_prep_template') params = Parameters.load( cmd, values_dict={'prep_template': prep_id, 'template_fp': fp}) job = ProcessingJob.create(User(user_id), params, True) r_client.set(PREP_TEMPLATE_KEY_FORMAT % prep_id, dumps({'job_id': job.id})) job.submit() elif attribute == 'name': prep.name = req_value.strip() 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/row_id/{columns|samples}/name if len(req_path) != 4: return {'status': 'error', 'message': 'Incorrect path parameter'} prep_id = int(req_path[0]) row_id = req_path[1] attribute = req_path[2] attr_id = req_path[3] # 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 qiita_plugin = Software.from_name_and_version('Qiita', 'alpha') cmd = qiita_plugin.get_command('delete_sample_or_column') params = Parameters.load( cmd, values_dict={'obj_class': 'PrepTemplate', 'obj_id': prep_id, 'sample_or_col': attribute, 'name': attr_id}) job = ProcessingJob.create(User(user_id), params, True) # 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})) job.submit() return {'status': 'success', 'message': '', 'row_id': row_id} else: return {'status': 'error', 'message': 'Operation "%s" not supported. ' 'Current supported operations: replace, remove' % req_op, 'row_id': '0'}
# Nov 28, 2017 (only in py file) # Adding a new command into Qiita/Alpha: delete_analysis from qiita_db.software import Software, Command from qiita_db.sql_connection import TRN # Create the delete study command Command.create(Software.from_name_and_version('Qiita', 'alpha'), 'delete_analysis', 'Deletes a full analysis', {'analysis_id': ['integer', None]}) # Make sure that all validate commands have the "analysis" parameter with TRN: # Get all validate commands that are missing the analysis parameter sql = """SELECT command_id FROM qiita.software_command sc WHERE name = 'Validate' AND NOT ( SELECT EXISTS(SELECT * FROM qiita.command_parameter WHERE parameter_name = 'analysis' AND command_id = sc.command_id));""" TRN.add(sql) sql = """INSERT INTO qiita.command_parameter (command_id, parameter_name, parameter_type, required, default_value, name_order, check_biom_merge) VALUES (6, 'analysis', 'analysis', false, NULL, NULL, false)""" sql_params = [[cmd_id, 'analysis', 'analysis', False, None, None, False] for cmd_id in TRN.execute_fetchflatten()] TRN.add(sql, sql_params, many=True) TRN.execute()
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] # format # column: study_id/row_id/columns/column_name # sample: study_id/row_id/samples/sample_id if len(req_path) != 4: return {'status': 'error', 'message': 'Incorrect path parameter'} st_id = req_path[0] row_id = req_path[1] attribute = req_path[2] attr_id = req_path[3] # 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 qiita_plugin = Software.from_name_and_version('Qiita', 'alpha') cmd = qiita_plugin.get_command('delete_sample_or_column') params = Parameters.load(cmd, values_dict={ 'obj_class': 'SampleTemplate', 'obj_id': int(st_id), 'sample_or_col': attribute, 'name': attr_id }) job = ProcessingJob.create(User(user_id), params) # 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})) job.submit() return {'status': 'success', 'message': '', 'row_id': row_id} else: return { 'status': 'error', 'message': 'Operation "%s" not supported. ' 'Current supported operations: remove' % req_op, 'row_id': 0 }
# The status is error. The key message stores the error # message. We need to create a new job and mark it as # failed with the given error message params = Parameters.load(cmd, values_dict=values_dict) job = ProcessingJob.create(user, params) job._set_error(info['message']) payload = {'job_id': job.id} r_client.set(key, dumps(payload)) else: # The key doesn't contain any information. Delete the key r_client.delete(key) with TRN: # Retrieve the Qiita plugin qiita_plugin = Software.from_name_and_version('Qiita', 'alpha') # Create the submit command for VAMPS command parameters = {'artifact': ['integer', None]} create_command(qiita_plugin, "submit_to_VAMPS", "submits an artifact to VAMPS", parameters) # Create the copy artifact command parameters = {'artifact': ['integer', None], 'prep_template': ['prep_template', None]} create_command(qiita_plugin, "copy_artifact", "Creates a copy of an artifact", parameters) # Create the submit command for EBI command parameters = {'artifact': ['integer', None], 'submission_type': ['choice:["ADD", "MODIFY"]', 'ADD']}
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 """ study_id = int(study_id) access_error = check_access(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 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 } qiita_plugin = Software.from_name_and_version('Qiita', 'alpha') cmd = qiita_plugin.get_command('create_sample_template') params = Parameters.load(cmd, values_dict={ 'fp': fp_rsp, 'study_id': study_id, 'is_mapping_file': is_mapping_file, 'data_type': data_type }) job = ProcessingJob.create(User(user_id), params) r_client.set(SAMPLE_TEMPLATE_KEY_FORMAT % study_id, dumps({'job_id': job.id})) # Store the job id attaching it to the sample template id job.submit() return {'status': 'success', 'message': '', 'file': sample_template}