def update_sample_association(account_id, source_id, sample_id, body, token_info): _validate_account_access(token_info, account_id) # TODO: API layer doesn't understand that BadRequest can be thrown, # but that looks to be the right result if sample_site bad. # Need to update the api layer if we want to specify 400s. # (Or we leave api as is and say 400's can always be thrown if your # request is bad) with Transaction() as t: sample_repo = SampleRepo(t) source_repo = SourceRepo(t) source = source_repo.get_source(account_id, source_id) if source is None: return jsonify(code=404, message="No such source"), 404 needs_sample_site = source.source_type in [ Source.SOURCE_TYPE_HUMAN, Source.SOURCE_TYPE_ANIMAL ] precludes_sample_site = source.source_type == \ Source.SOURCE_TYPE_ENVIRONMENT sample_site_present = "sample_site" in body and \ body["sample_site"] is not None if needs_sample_site and not sample_site_present: # Human/Animal sources require sample_site to be set raise BadRequest("human/animal samples require sample_site") if precludes_sample_site and sample_site_present: raise BadRequest("environmental samples cannot specify " "sample_site") sample_datetime = body['sample_datetime'] try: sample_datetime = fromisotime(sample_datetime) except ValueError: raise BadRequest("Invalid sample_datetime") curdate = datetime.now(sample_datetime.tzinfo) lower_limit = curdate + relativedelta(years=-10) upper_limit = curdate + relativedelta(months=+1) if sample_datetime < lower_limit or sample_datetime > upper_limit: raise BadRequest('Invalid sample date') # sample_site will not be present if its environmental. this will # default to None if the key is not present sample_site = body.get('sample_site') sample_info = SampleInfo(sample_id, sample_datetime, sample_site, body["sample_notes"]) is_admin = token_grants_admin_access(token_info) sample_repo.update_info(account_id, source_id, sample_info, override_locked=is_admin) final_sample = sample_repo.get_sample(account_id, source_id, sample_id) t.commit() return jsonify(final_sample), 200
def read_sample_association(account_id, source_id, sample_id, token_info): _validate_account_access(token_info, account_id) with Transaction() as t: sample_repo = SampleRepo(t) sample = sample_repo.get_sample(account_id, source_id, sample_id) if sample is None: return jsonify(code=404, message="Sample not found"), 404 return jsonify(sample.to_api()), 200
def dissociate_answered_survey_from_sample(self, account_id, source_id, sample_id, survey_id): sample_repo = SampleRepo(self._transaction) if not self._acct_source_owns_survey(account_id, source_id, survey_id): raise werkzeug.exceptions.NotFound("No survey ID: %s" % survey_id) s = sample_repo.get_sample(account_id, source_id, sample_id) if s is None: raise werkzeug.exceptions.NotFound("No sample ID: %s" % sample_id) with self._transaction.cursor() as cur: cur.execute( "DELETE FROM source_barcodes_surveys " "WHERE " "barcode = %s AND " "survey_id = %s", (s.barcode, survey_id)) # Also delete from vioscreen, myfoodrepo and polyphenol registries cur.execute( "UPDATE vioscreen_registry " "SET deleted=true " "WHERE " "account_id = %s AND " "source_id = %s AND " "sample_id = %s AND " "vio_id = %s", (account_id, source_id, sample_id, survey_id)) cur.execute( "UPDATE myfoodrepo_registry " "SET deleted=true " "WHERE " "account_id = %s AND " "source_id = %s AND " "myfoodrepo_id = %s", (account_id, source_id, survey_id)) try: uuid.UUID(survey_id) cur.execute( "UPDATE polyphenol_ffq_registry " "SET deleted = true " "WHERE " "account_id = %s AND " "source_id = %s AND " "polyphenol_ffq_id = %s", (account_id, source_id, survey_id)) except ValueError: # Note: we don't care about the error, just means it's not # the Polyphenol FFQ pass
def associate_answered_survey_with_sample(self, account_id, source_id, sample_id, survey_id): sample_repo = SampleRepo(self._transaction) if not self._acct_owns_survey(account_id, survey_id): raise werkzeug.exceptions.NotFound("No survey ID: %s" % survey_id) s = sample_repo.get_sample(account_id, source_id, sample_id) if s is None: raise werkzeug.exceptions.NotFound("No sample ID: %s" % sample_id) with self._transaction.cursor() as cur: cur.execute("INSERT INTO source_barcodes_surveys " "(barcode, survey_id) " "VALUES(%s, %s)", (s.barcode, survey_id))
def dissociate_answered_survey_from_sample(self, account_id, source_id, sample_id, survey_id): sample_repo = SampleRepo(self._transaction) if not self._acct_source_owns_survey(account_id, source_id, survey_id): raise werkzeug.exceptions.NotFound("No survey ID: %s" % survey_id) s = sample_repo.get_sample(account_id, source_id, sample_id) if s is None: raise werkzeug.exceptions.NotFound("No sample ID: %s" % sample_id) with self._transaction.cursor() as cur: cur.execute( "DELETE FROM source_barcodes_surveys " "WHERE " "barcode = %s AND " "survey_id = %s", (s.barcode, survey_id))
def list_answered_surveys_by_sample(self, account_id, source_id, sample_id): sample_repo = SampleRepo(self._transaction) # Note: Retrieving sample in this way validates permissions. sample = sample_repo.get_sample(account_id, source_id, sample_id) if sample is None: raise werkzeug.exceptions.NotFound("No sample ID: %s" % sample.id) with self._transaction.cursor() as cur: cur.execute( "SELECT " "survey_id " "FROM " "ag_kit_barcodes " "LEFT JOIN source_barcodes_surveys " "USING (barcode)" "WHERE " "ag_kit_barcode_id = %s", (sample_id, )) rows = cur.fetchall() answered_surveys = [r[0] for r in rows if r[0] is not None] return answered_surveys
def read_sample_association(account_id, source_id, sample_id, token_info): _validate_account_access(token_info, account_id) with Transaction() as t: sample_repo = SampleRepo(t) sample = sample_repo.get_sample(account_id, source_id, sample_id) if sample is None: return jsonify(code=404, message="Sample not found"), 404 qiita_body = {'sample_ids': ["10317." + str(sample.barcode)]} try: qiita_data = qclient.post('/api/v1/study/10317/samples/status', json=qiita_body) accession_urls = [] for barcode_info in qiita_data: experiment_accession = barcode_info.get("ebi_experiment_accession") if experiment_accession is None: continue accession_urls.append("https://www.ebi.ac.uk/ena/browser/view/" + experiment_accession + "?show=reads") sample.set_accession_urls(accession_urls) except NotFoundError: # I guess qiita doesn't know about this barcode, # so probably no ebi accession info pass except BadRequestError: # How do I log these to gunicorn?? app.logger.warning("Couldn't communicate with qiita", exc_info=True) except ForbiddenError: # How do I log these to gunicorn?? app.logger.warning("Couldn't communicate with qiita", exc_info=True) except RuntimeError: # How do I log these to gunicorn?? app.logger.warning("Couldn't communicate with qiita", exc_info=True) raise return jsonify(sample.to_api()),
def associate_answered_survey_with_sample(self, account_id, source_id, sample_id, survey_id): sample_repo = SampleRepo(self._transaction) if not self._acct_owns_survey(account_id, survey_id): raise werkzeug.exceptions.NotFound("No survey ID: %s" % survey_id) s = sample_repo.get_sample(account_id, source_id, sample_id) if s is None: raise werkzeug.exceptions.NotFound("No sample ID: %s" % sample_id) # Switching to insert if not exists semantics since vioscreen IDs will # be associated with samples prior to being filled out. with self._transaction.cursor() as cur: cur.execute( "SELECT * FROM source_barcodes_surveys " "WHERE barcode=%s AND survey_id=%s", (s.barcode, survey_id)) if cur.fetchone() is None: cur.execute( "INSERT INTO source_barcodes_surveys " "(barcode, survey_id) " "VALUES(%s, %s)", (s.barcode, survey_id))