def sample_template_checks(study_id, user, check_exists=False): """Performs different checks and raises errors if any of the checks fail Parameters ---------- study_id : int The study id user : qiita_db.user.User The user trying to access the study check_exists : bool, optional If true, check if the sample template exists Raises ------ HTTPError 404 if the study does not exist 403 if the user does not have access to the study 404 if check_exists == True and the sample template doesn't exist """ try: study = Study(int(study_id)) except QiitaDBUnknownIDError: raise HTTPError(404, reason='Study does not exist') if not study.has_access(user): raise HTTPError(403, reason='User does not have access to study') # Check if the sample template exists if check_exists and not SampleTemplate.exists(study_id): raise HTTPError(404, reason="Study %s doesn't have sample information" % study_id)
def sample_template_checks(study_id, user, check_exists=False): """Performs different checks and raises errors if any of the checks fail Parameters ---------- study_id : int The study id user : qiita_db.user.User The user trying to access the study check_exists : bool, optional If true, check if the sample template exists Raises ------ HTTPError 404 if the study does not exist 403 if the user does not have access to the study 404 if check_exists == True and the sample template doesn't exist """ try: study = Study(int(study_id)) except QiitaDBUnknownIDError: raise HTTPError(404, reason='Study does not exist') if not study.has_access(user): raise HTTPError(403, reason='User does not have access to study') # Check if the sample template exists if check_exists and not SampleTemplate.exists(study_id): raise HTTPError(404, reason="Study %s doesn't have sample information" % study_id)
def sample_template_overview_handler_get_request(study_id, user): # Check if the current user has access to the sample template sample_template_checks(study_id, user) # Check if the sample template exists exists = SampleTemplate.exists(study_id) # The following information should always be provided: # The files that have been uploaded to the system and can be a # sample template file files = [ f for _, f in get_files_from_uploads_folders(study_id) if f.endswith(('txt', 'tsv')) ] # If there is a job associated with the sample information, the job id job = None job_info = r_client.get(SAMPLE_TEMPLATE_KEY_FORMAT % study_id) if job_info: job = loads(job_info)['job_id'] # Specific information if it exists or not: data_types = [] st_fp_id = None old_files = [] num_samples = 0 num_cols = 0 if exists: # If it exists we need to provide: # The id of the sample template file so the user can download it and # the list of old filepaths st = SampleTemplate(study_id) all_st_files = st.get_filepaths() # The current sample template file is the first one in the list # (pop(0)) and we are interested only in the id ([0]) st_fp_id = all_st_files.pop(0)[0] # For the old filepaths we are only interested in their basename old_files = [basename(fp) for _, fp in all_st_files] # The number of samples - this is a space efficient way of counting # the number of samples. Doing len(list(st.keys())) creates a list # that we are not using num_samples = sum(1 for _ in st.keys()) # The number of columns num_cols = len(st.categories()) else: # It doesn't exist, we also need to provide the data_types in case # the user uploads a QIIME mapping file data_types = sorted(data_types_get_req()['data_types']) return { 'exists': exists, 'uploaded_files': files, 'data_types': data_types, 'user_can_edit': Study(study_id).can_edit(user), 'job': job, 'download_id': st_fp_id, 'old_files': old_files, 'num_samples': num_samples, 'num_columns': num_cols }
def sample_template_overview_handler_get_request(study_id, user): # Check if the current user has access to the sample template sample_template_checks(study_id, user) # Check if the sample template exists exists = SampleTemplate.exists(study_id) # The following information should always be provided: # The files that have been uploaded to the system and can be a # sample template file files = [f for _, f, _ in get_files_from_uploads_folders(study_id) if f.endswith(('txt', 'tsv', 'xlsx'))] # If there is a job associated with the sample information, the job id job = None job_info = r_client.get(SAMPLE_TEMPLATE_KEY_FORMAT % study_id) if job_info: job = loads(job_info)['job_id'] # Specific information if it exists or not: data_types = [] st_fp_id = None old_files = [] num_samples = 0 num_cols = 0 if exists: # If it exists we need to provide: # The id of the sample template file so the user can download it and # the list of old filepaths st = SampleTemplate(study_id) all_st_files = st.get_filepaths() # The current sample template file is the first one in the list # (pop(0)) and we are interested only in the id ([0]) st_fp_id = all_st_files.pop(0)[0] # For the old filepaths we are only interested in their basename old_files = [basename(fp) for _, fp in all_st_files] # The number of samples - this is a space efficient way of counting # the number of samples. Doing len(list(st.keys())) creates a list # that we are not using num_samples = sum(1 for _ in st.keys()) # The number of columns num_cols = len(st.categories()) else: # It doesn't exist, we also need to provide the data_types in case # the user uploads a QIIME mapping file data_types = sorted(data_types_get_req()['data_types']) return {'exists': exists, 'uploaded_files': files, 'data_types': data_types, 'user_can_edit': Study(study_id).can_edit(user), 'job': job, 'download_id': st_fp_id, 'old_files': old_files, 'num_samples': num_samples, 'num_columns': num_cols}
def tearDown(self): for fp in self._clean_up_files: if exists(fp): remove(fp) study_id = self.new_study.id for pt in self.new_study.prep_templates(): PrepTemplate.delete(pt.id) if SampleTemplate.exists(study_id): SampleTemplate.delete(study_id) Study.delete(study_id)
def tearDown(self): for fp in self._clean_up_files: if exists(fp): remove(fp) study_id = self.new_study.id for pt in self.new_study.prep_templates(): PrepTemplate.delete(pt.id) if SampleTemplate.exists(study_id): SampleTemplate.delete(study_id) Study.delete(study_id)
def display_template(self, study, user, msg, msg_level, full_access, top_tab=None, sub_tab=None, prep_tab=None): """Simple function to avoid duplication of code""" study_status = study.status user_level = user.level sample_template_exists = SampleTemplate.exists(study.id) if sample_template_exists: st = SampleTemplate(study.id) missing_cols = st.check_restrictions( [SAMPLE_TEMPLATE_COLUMNS['qiita_main']]) allow_approval = len(missing_cols) == 0 approval_deny_msg = ( "Processed data approval request is disabled due to missing " "columns in the sample template: %s" % ', '.join(missing_cols)) else: allow_approval = False approval_deny_msg = "" # The general information of the study can be changed if the study is # not public or if the user is an admin, in which case they can always # modify the information of the study show_edit_btn = study_status != 'public' or user_level == 'admin' # Make the error message suitable for html msg = msg.replace('\n', "<br/>") self.render('study_description.html', message=msg, level=msg_level, study=study, study_title=study.title, study_alias=study.info['study_alias'], show_edit_btn=show_edit_btn, show_data_tabs=sample_template_exists, full_access=full_access, allow_approval=allow_approval, approval_deny_msg=approval_deny_msg, top_tab=top_tab, sub_tab=sub_tab, prep_tab=prep_tab)
def test_delete_sample_template(self): # Error case job = self._create_job('delete_sample_template', {'study': 1}) private_task(job.id) self.assertEqual(job.status, 'error') self.assertIn( "Sample template cannot be erased because there are " "prep templates associated", job.log.msg) # Success case info = { "timeseries_type_id": '1', "metadata_complete": 'true', "mixs_compliant": 'true', "number_samples_collected": 25, "number_samples_promised": 28, "study_alias": "TDST", "study_description": "Test delete sample template", "study_abstract": "Test delete sample template", "principal_investigator_id": StudyPerson(1) } study = Study.create(User('*****@*****.**'), "Delete Sample Template test", info) metadata = pd.DataFrame.from_dict( { 'Sample1': { 'physical_specimen_location': 'location1', 'physical_specimen_remaining': 'true', 'dna_extracted': 'true', 'sample_type': 'type1', 'collection_timestamp': '2014-05-29 12:24:15', 'host_subject_id': 'NotIdentified', 'Description': 'Test Sample 1', 'latitude': '42.42', 'longitude': '41.41', 'taxon_id': '9606', 'scientific_name': 'h**o sapiens' } }, orient='index', dtype=str) SampleTemplate.create(metadata, study) job = self._create_job('delete_sample_template', {'study': study.id}) private_task(job.id) self.assertEqual(job.status, 'success') self.assertFalse(SampleTemplate.exists(study.id))
def _check_sample_template_exists(samp_id): """Make sure a sample template exists in the system Parameters ---------- samp_id : int or str castable to int SampleTemplate id to check Returns ------- dict {'status': status, 'message': msg} """ if not SampleTemplate.exists(int(samp_id)): return {'status': 'error', 'message': 'Sample template %d does not exist' % int(samp_id) } return {'status': 'success', 'message': ''}
def _check_sample_template_exists(samp_id): """Make sure a sample template exists in the system Parameters ---------- samp_id : int or str castable to int SampleTemplate id to check Returns ------- dict {'status': status, 'message': msg} """ if not SampleTemplate.exists(int(samp_id)): return { 'status': 'error', 'message': 'Sample template %d does not exist' % int(samp_id) } return {'status': 'success', 'message': ''}
def display_template(self, study, user, msg, msg_level, full_access, top_tab=None, sub_tab=None, prep_tab=None): """Simple function to avoid duplication of code""" study_status = study.status user_level = user.level sample_template_exists = SampleTemplate.exists(study.id) if sample_template_exists: st = SampleTemplate(study.id) missing_cols = st.check_restrictions( [SAMPLE_TEMPLATE_COLUMNS['qiita_main']]) allow_approval = len(missing_cols) == 0 approval_deny_msg = ( "Processed data approval request is disabled due to missing " "columns in the sample template: %s" % ', '.join(missing_cols)) else: allow_approval = False approval_deny_msg = "" # The general information of the study can be changed if the study is # not public or if the user is an admin, in which case they can always # modify the information of the study show_edit_btn = study_status != 'public' or user_level == 'admin' # Make the error message suitable for html msg = msg.replace('\n', "<br/>") self.render('study_description.html', message=msg, level=msg_level, study=study, study_title=study.title, study_alias=study.info['study_alias'], show_edit_btn=show_edit_btn, show_data_tabs=sample_template_exists, full_access=full_access, allow_approval=allow_approval, approval_deny_msg=approval_deny_msg, top_tab=top_tab, sub_tab=sub_tab, prep_tab=prep_tab)
def test_delete_sample_template(self): # Error case job = self._create_job('delete_sample_template', {'study': 1}) private_task(job.id) self.assertEqual(job.status, 'error') self.assertIn("Sample template cannot be erased because there are " "prep templates associated", job.log.msg) # Success case info = {"timeseries_type_id": '1', "metadata_complete": 'true', "mixs_compliant": 'true', "number_samples_collected": 25, "number_samples_promised": 28, "study_alias": "TDST", "study_description": "Test delete sample template", "study_abstract": "Test delete sample template", "principal_investigator_id": StudyPerson(1)} study = Study.create(User('*****@*****.**'), "Delete Sample Template test", info) metadata = pd.DataFrame.from_dict( {'Sample1': {'physical_specimen_location': 'location1', 'physical_specimen_remaining': 'true', 'dna_extracted': 'true', 'sample_type': 'type1', 'collection_timestamp': '2014-05-29 12:24:15', 'host_subject_id': 'NotIdentified', 'Description': 'Test Sample 1', 'latitude': '42.42', 'longitude': '41.41', 'taxon_id': '9606', 'scientific_name': 'h**o sapiens'}}, orient='index', dtype=str) SampleTemplate.create(metadata, study) job = self._create_job('delete_sample_template', {'study': study.id}) private_task(job.id) self.assertEqual(job.status, 'success') self.assertFalse(SampleTemplate.exists(study.id))
def render(self, study): study_info = study.info id = study.id abstract = study_info['study_abstract'] description = study_info['study_description'] publications = [] for doi, pmid in study.publications: if doi is not None: publications.append(doi_linkifier([doi])) if pmid is not None: publications.append(pubmed_linkifier([pmid])) publications = ", ".join(publications) princ_inv = StudyPerson(study_info['principal_investigator_id']) pi_link = study_person_linkifier((princ_inv.email, princ_inv.name)) number_samples_promised = study_info['number_samples_promised'] number_samples_collected = study_info['number_samples_collected'] metadata_complete = study_info['metadata_complete'] data_types = sorted(viewitems(get_data_types()), key=itemgetter(1)) # Retrieve the files from the uploads folder, so the user can choose # the sample template of the study. Filter them to only include the # ones that ends with 'txt' or 'tsv'. files = [ f for _, f in get_files_from_uploads_folders(str(study.id)) if f.endswith(('txt', 'tsv')) ] # If the sample template exists, retrieve all its filepaths if SampleTemplate.exists(study.id): sample_templates = SampleTemplate(study.id).get_filepaths() else: # If the sample template does not exist, just pass an empty list sample_templates = [] # Check if the request came from a local source is_local_request = is_localhost(self.request.headers['host']) # The user can choose the sample template only if the study is # sandboxed or the current user is an admin show_select_sample = (study.status == 'sandbox' or self.current_user.level == 'admin') # EBI information ebi_status = study.ebi_submission_status ebi_accession = study.ebi_study_accession if ebi_accession: ebi_accession = (EBI_LINKIFIER.format(ebi_accession)) return self.render_string( "study_description_templates/study_information_tab.html", abstract=abstract, description=description, id=id, publications=publications, principal_investigator=pi_link, number_samples_promised=number_samples_promised, number_samples_collected=number_samples_collected, metadata_complete=metadata_complete, show_select_sample=show_select_sample, files=files, study_id=study.id, sample_templates=sample_templates, is_local_request=is_local_request, data_types=data_types, ebi_status=ebi_status, ebi_accession=ebi_accession)
def render(self, study): study_info = study.info id = study.id abstract = study_info['study_abstract'] description = study_info['study_description'] publications = [] for doi, pmid in study.publications: if doi is not None: publications.append(doi_linkifier([doi])) if pmid is not None: publications.append(pubmed_linkifier([pmid])) publications = ", ".join(publications) princ_inv = StudyPerson(study_info['principal_investigator_id']) pi_link = study_person_linkifier((princ_inv.email, princ_inv.name)) number_samples_promised = study_info['number_samples_promised'] number_samples_collected = study_info['number_samples_collected'] metadata_complete = study_info['metadata_complete'] data_types = sorted(viewitems(get_data_types()), key=itemgetter(1)) # Retrieve the files from the uploads folder, so the user can choose # the sample template of the study. Filter them to only include the # ones that ends with 'txt' or 'tsv'. files = [f for _, f in get_files_from_uploads_folders(str(study.id)) if f.endswith(('txt', 'tsv'))] # If the sample template exists, retrieve all its filepaths if SampleTemplate.exists(study.id): sample_templates = SampleTemplate(study.id).get_filepaths() else: # If the sample template does not exist, just pass an empty list sample_templates = [] # Check if the request came from a local source is_local_request = is_localhost(self.request.headers['host']) # The user can choose the sample template only if the study is # sandboxed or the current user is an admin show_select_sample = ( study.status == 'sandbox' or self.current_user.level == 'admin') # Ebi information ebi_status = study.ebi_submission_status ebi_accession = study.ebi_study_accession if ebi_accession: ebi_accession = (EBI_LINKIFIER.format(ebi_accession)) return self.render_string( "study_description_templates/study_information_tab.html", abstract=abstract, description=description, id=id, publications=publications, principal_investigator=pi_link, number_samples_promised=number_samples_promised, number_samples_collected=number_samples_collected, metadata_complete=metadata_complete, show_select_sample=show_select_sample, files=files, study_id=study.id, sample_templates=sample_templates, is_local_request=is_local_request, data_types=data_types, ebi_status=ebi_status, ebi_accession=ebi_accession)