def post(self): """Returns list of pending requests from the database""" if request.method == "POST": response_json = request.get_json() password = response_json["password"] if ApiManagerUtils.check_admin_pass(password): table = Requests() values = [] try: rows = table.query.filter_by().all() except SQLAlchemyError: return BARUtils.error_exit("Internal server error"), 500 [ values.append({ "first_name": row.first_name, "last_name": row.last_name, "email": row.email, "telephone": row.telephone, "contact_type": row.contact_type, "notes": row.notes, }) for row in rows ] return BARUtils.success_exit(values) else: return BARUtils.error_exit("Forbidden"), 403
def post(self): """Takes a CSV file containing expression data and inserts the data into the database""" if request.method == "POST": if "file" not in request.files: return BARUtils.error_exit("No file attached"), 400 file = request.files["file"] if file: filename = secure_filename(file.filename) key = request.headers.get("X-Api-Key") file.save(os.path.join(DATA_FOLDER, key, filename)) if SummarizationGeneExpressionUtils.decrement_uses(key): inputs = (""" { "csvUpload.insertDataScript": "./insertData.py", "csvUpload.id": """ + key + """, "csvUpload.csv": """ + os.path.join(DATA_FOLDER, key, filename) + """, } """) path = os.path.join(SUMMARIZATION_FILES_PATH, "csvUpload.wdl") files = { "workflowSource": ("csvUpload.wdl", open(path, "rb")), "workflowInputs": ("rpkm_inputs.json", inputs), } requests.post(CROMWELL_URL + "/api/workflows/v1", files=files) return BARUtils.success_exit(key) else: return BARUtils.error_exit("Invalid API key")
def post(self): """This end point returns gene expression data for a single gene and multiple samples.""" json_data = request.get_json() # Validate json try: json_data = RNASeqSchema().load(json_data) except ValidationError as err: return BARUtils.error_exit(err.messages), 400 species = json_data['species'] database = json_data['database'] gene_id = json_data['gene_id'] sample_ids = json_data['sample_ids'] results = RNASeqUtils.get_data(species, database, gene_id, sample_ids) if results['success']: # Return results if there are data if len(results['data']) > 0: return BARUtils.success_exit(results['data']) else: return BARUtils.error_exit( 'There are no data found for the given gene') else: return BARUtils.error_exit(results['error']), results['error_code']
def post(self): """Saves the given file if the user has a valid API key """ if request.method == 'POST': api_key = request.headers.get('x-api-key') if api_key is None: return BARUtils.error_exit('Invalid API key'), 403 elif SummarizationGeneExpressionUtils.decrement_uses(api_key): now = datetime.now() dt_string = now.strftime("%d-%m-%Y_%H-%M-%S") if 'file' in request.files: file = request.files['file'] extension = '' if file.content_type == 'text/xml': extension = '.xml' elif file.content_type == 'image/svg+xml': extension = '.svg' else: return BARUtils.error_exit('Invalid file type'), 400 filename = os.path.join(DATA_FOLDER, api_key, dt_string + extension) file.save(filename) return BARUtils.success_exit(True) else: return BARUtils.error_exit('No file attached'), 400 else: return BARUtils.error_exit('Invalid API key')
def get(self, table_id, sample, gene): """Returns the value for a given gene and sample. If no sample is given returns all values for that gene""" if not BARUtils.is_arabidopsis_gene_valid(gene): return BARUtils.success_exit("Invalid gene ID"), 400 else: key = request.headers.get("X-Api-Key") if SummarizationGeneExpressionUtils.decrement_uses(key): con = db.get_engine(bind="summarization") tbl = SummarizationGeneExpressionUtils.get_table_object( table_id) if sample == "": values = {} try: rows = con.execute( tbl.select(tbl.c.Value).where(tbl.c.Gene == gene)) except SQLAlchemyError: return BARUtils.error_exit( "Internal server error"), 500 for row in rows: values.update({str(row.Sample): float(row.Value)}) else: values = [] try: rows = con.execute( tbl.select(tbl.c.Value).where( tbl.c.Sample == sample).where( tbl.c.Gene == gene)) except SQLAlchemyError: return BARUtils.error_exit( "Internal server error"), 500 [values.append(row.Value) for row in rows] return BARUtils.success_exit(values) else: return BARUtils.error_exit("Invalid API key")
def get(self, species='', gene_id=''): """This end point provides gene alias given a gene ID.""" aliases = [] # Escape input species = escape(species) gene_id = escape(gene_id) if species == 'arabidopsis': if BARUtils.is_arabidopsis_gene_valid(gene_id): try: rows = AgiAlias.query.filter_by(agi=gene_id).all() except OperationalError: return BARUtils.error_exit( 'An internal error has occurred'), 500 [aliases.append(row.alias) for row in rows] else: return BARUtils.error_exit('Invalid gene id'), 400 else: return BARUtils.error_exit('No data for the given species') # Return results if there are data if len(aliases) > 0: return BARUtils.success_exit(aliases) else: return BARUtils.error_exit( 'There are no data found for the given gene')
def post(self): """Takes a CSV file containing expression data and inserts the data into the database """ if request.method == 'POST': if 'file' not in request.files: return BARUtils.error_exit('No file attached'), 400 file = request.files['file'] if file: filename = secure_filename(file.filename) key = request.headers.get('X-Api-Key') file.save(os.path.join(DATA_FOLDER + '/' + key + '/', filename)) if SummarizationGeneExpressionUtils.decrement_uses(key): inputs = """ { 'csvUpload.insertDataScript': './insertData.py', 'csvUpload.id': """ + key + """, 'csvUpload.csv': """ + os.path.join( DATA_FOLDER, key, filename) + """, } """ path = os.path.join(SUMMARIZATION_FILES_PATH, 'csvUpload.wdl') files = { 'workflowSource': ('csvUpload.wdl', open(path, 'rb')), 'workflowInputs': ('rpkm_inputs.json', inputs) } requests.post(CROMWELL_URL + '/api/workflows/v1', files=files) return BARUtils.success_exit(key) else: return BARUtils.error_exit('Invalid API key')
def post(self): """Returns list of pending requests from the database """ if request.method == 'POST': response_json = request.get_json() password = response_json['password'] if ApiManagerUtils.check_admin_pass(password): table = Requests() values = [] try: rows = table.query.filter_by().all() except SQLAlchemyError: return BARUtils.error_exit('Internal server error'), 500 [ values.append({ 'first_name': row.first_name, 'last_name': row.last_name, 'email': row.email, 'telephone': row.telephone, 'contact_type': row.contact_type, 'notes': row.notes }) for row in rows ] return BARUtils.success_exit(values) else: return BARUtils.error_exit('Forbidden'), 403
def get(self, gene_id=''): """ Endpoint returns annotated SNP poplar data in order of (to match A th API format): AA pos (zero-indexed), sample id, 'missense_variant','MODERATE', 'MISSENSE', codon/DNA base change, AA change (DH), pro length, gene ID, 'protein_coding', 'CODING', transcript id, biotype values with single quotes are fixed """ results_json = [] # Escape input gene_id = escape(gene_id) if BARUtils.is_poplar_gene_valid(gene_id) is False: return BARUtils.error_exit('Invalid gene id'), 400 try: rows = db.session.query(ProteinReference, SnpsToProtein, SnpsReference). \ select_from(ProteinReference). \ join(SnpsToProtein). \ join(SnpsReference). \ filter(ProteinReference.gene_identifier == gene_id).all() # BAR A Th API format is chr, AA pos (zero-indexed), sample id, 'missense_variant', # 'MODERATE', 'MISSENSE', codon/DNA base change, AA change (DH), # pro length, gene ID, 'protein_coding', 'CODING', transcript id, biotype for protein, snpsjoin, snpstbl in rows: itm_lst = [ snpstbl.chromosome, # snpstbl.chromosomal_loci, snpsjoin.aa_pos - 1, # zero index-ed snpstbl.sample_id, 'missense_variant', 'MODERATE', 'MISSENSE', str(snpsjoin.transcript_pos) + snpsjoin.ref_DNA + '>' + snpsjoin.alt_DNA, snpsjoin.ref_aa + snpsjoin.alt_aa, None, re.sub(r".\d$", '', protein.gene_identifier), 'protein_coding', 'CODING', protein.gene_identifier, None, ] results_json.append(itm_lst) except OperationalError: return BARUtils.error_exit('An internal error has occurred'), 500 # Return results if there are data if len(results_json) > 0: return BARUtils.success_exit(results_json) else: return BARUtils.error_exit( 'There are no data found for the given gene')
def get(self, table_id=""): """Returns the list of genes in the table with the given ID""" key = request.headers.get("x-api-key") if SummarizationGeneExpressionUtils.decrement_uses(key): con = db.get_engine(bind="summarization") tbl = SummarizationGeneExpressionUtils.get_table_object(table_id) values = [] try: rows = con.execute(db.select([tbl.c.Gene]).distinct()) except SQLAlchemyError: return BARUtils.error_exit("Internal server error"), 500 [values.append(row.Gene) for row in rows] return BARUtils.success_exit(values) else: return BARUtils.error_exit("Invalid API key")
def post(self): """Takes a Google Drive folder ID (containing BAM files) and submits them to the Cromwell server for summarization """ if request.method == 'POST': json = request.get_json() key = request.headers.get('X-Api-Key') if SummarizationGeneExpressionUtils.decrement_uses(key): inputs = """ { 'geneSummarization.gtf': './data/Araport11_GFF3_genes_transposons.201606.gtf', 'geneSummarization.summarizeGenesScript': './summarize_genes.R', 'geneSummarization.downloadFilesScript': './downloadDriveFiles.py', 'geneSummarization.insertDataScript': './insertData.py', 'geneSummarization.credentials': './data/credentials.json', 'geneSummarization.token': './data/token.pickle', 'geneSummarization.aliases': './data/aliases.txt', 'geneSummarization.folderId': """ + json[ 'folderId'] + """, 'geneSummarization.id': """ + key + """ } """ # Create DB # Send request to Cromwell path = os.path.join(SUMMARIZATION_FILES_PATH, 'rpkm.wdl') files = { 'workflowSource': ('rpkm.wdl', open(path, 'rb')), 'workflowInputs': ('rpkm_inputs.json', inputs) } requests.post(CROMWELL_URL + '/api/workflows/v1', files=files) # Return ID for future accessing return BARUtils.success_exit(key), 200 else: return BARUtils.error_exit('Invalid API key')
def get(self, table_id=''): """Drops the table with the given ID """ if request.remote_addr != '127.0.0.1': return BARUtils.error_exit('Forbidden'), 403 tbl = SummarizationGeneExpressionUtils.get_table_object(table_id) tbl.drop()
def get(self, gene_id=""): """This end point retrieves publications from ThaleMine given an AGI ID""" gene_id = escape(gene_id) # Is data valid if not BARUtils.is_arabidopsis_gene_valid(gene_id): return BARUtils.error_exit("Invalid gene id"), 400 query = ( '<query name="" model="genomic" view="Gene.publications.firstAuthor Gene.publications.issue ' "Gene.publications.journal Gene.publications.pages Gene.publications.pubMedId Gene.publications.title " 'Gene.publications.volume Gene.publications.year" longDescription="" ' 'sortOrder="Gene.publications.firstAuthor asc"><constraint path="Gene.primaryIdentifier" op="=" value="{' '}"/></query> ') query = query.format(gene_id) # Now query the web service payload = {"format": "json", "query": query} resp = requests.post( "https://bar.utoronto.ca/thalemine/service/query/results", data=payload, headers=request_headers, ) return resp.json()
def post(self): if request.method == 'POST': response_json = request.get_json() df = pandas.DataFrame.from_records([response_json]) con = db.get_engine(bind='summarization') try: reqs = Requests() users = Users() row_req = reqs.query.filter_by(email=df.email[0]).first() row_users = users.query.filter_by(email=df.email[0]).first() if row_req is None and row_users is None: df.to_sql('requests', con, if_exists='append', index=False) else: return BARUtils.error_exit('E-mail already in use'), 409 except SQLAlchemyError: return BARUtils.error_exit('Internal server error'), 500
def get(self, species='', database='', gene_id=''): """This end point returns RNA-Seq gene expression data""" # Variables species = escape(species) database = escape(database) gene_id = escape(gene_id) results = RNASeqUtils.get_data(species, database, gene_id) if results['success']: # Return results if there are data if len(results['data']) > 0: return BARUtils.success_exit(results['data']) else: return BARUtils.error_exit( 'There are no data found for the given gene') else: return BARUtils.error_exit(results['error']), results['error_code']
def post(self): """Verify if an API key provided by the user exists in the database""" if request.method == "POST": tbl = Users() json = request.get_json() key = json["key"] try: row = tbl.query.filter_by(api_key=key).first() except SQLAlchemyError: return BARUtils.error_exit("Internal server error"), 500 if row is None: return BARUtils.error_exit("API key not found"), 404 else: if row.uses_left > 0: return BARUtils.success_exit(True) else: return BARUtils.error_exit("API key expired"), 401
def get(self, species="", database="", gene_id=""): """This end point returns RNA-Seq gene expression data""" # Variables species = escape(species) database = escape(database) gene_id = escape(gene_id) results = RNASeqUtils.get_data(species, database, gene_id) if results["success"]: # Return results if there are data if len(results["data"]) > 0: return BARUtils.success_exit(results["data"]) else: return BARUtils.error_exit( "There are no data found for the given gene") else: return BARUtils.error_exit(results["error"]), results["error_code"]
def get(self, file_id): """Returns a specific file stored in the user's folder""" if request.method == "GET": api_key = request.headers.get("x-api-key") filename = os.path.join(DATA_FOLDER, api_key, file_id) if os.path.isfile(filename): return send_file(filename) else: return BARUtils.error_exit("File not found"), 404
def post(self): """Delete a request from the database""" if request.method == "POST": response_json = request.get_json() password = response_json["password"] if ApiManagerUtils.check_admin_pass(password): response_json = request.get_json() table = Requests() try: el = table.query.filter_by( email=response_json["email"]).one() except SQLAlchemyError: return BARUtils.error_exit("Internal server error"), 500 db.session.delete(el) db.session.commit() # table.query.filter_by(email=response_json['email']).delete() return BARUtils.success_exit(True) else: return BARUtils.error_exit("Forbidden"), 403
def get(self, fixed_pdb='', moving_pdb=''): """This end point returns the superimposition of the moving PDB onto moving PDB in PDB format""" fixed_pdb = escape(fixed_pdb) moving_pdb = escape(moving_pdb) arabidopsis_pdb_path = '/var/www/html/eplant_legacy/java/Phyre2-Models/Phyre2_' poplar_pdb_path = '/var/www/html/eplant_poplar/pdb/' phenix_pdb_link = 'https://bar.utoronto.ca/phenix-pdbs/' phenix_pdb_path = '/var/www/html/phenix-pdbs/' # Check if genes ids are valid if BARUtils.is_arabidopsis_gene_valid(fixed_pdb): fixed_pdb_path = arabidopsis_pdb_path + fixed_pdb.upper() + '.pdb' elif BARUtils.is_poplar_gene_valid(fixed_pdb): fixed_pdb_path = poplar_pdb_path + BARUtils.format_poplar( fixed_pdb) + '.pdb' else: return BARUtils.error_exit('Invalid fixed pdb gene id'), 400 if BARUtils.is_arabidopsis_gene_valid(moving_pdb): moving_pdb_path = arabidopsis_pdb_path + moving_pdb.upper( ) + '.pdb' elif BARUtils.is_poplar_gene_valid(moving_pdb): moving_pdb_path = poplar_pdb_path + BARUtils.format_poplar( moving_pdb) + '.pdb' else: return BARUtils.error_exit('Invalid moving pdb gene id'), 400 # Check if model already exists phenix_file_name = fixed_pdb.upper() + "-" + moving_pdb.upper( ) + "-phenix.pdb" response = requests.get(phenix_pdb_link + phenix_file_name) # If not, generate the model if response.status_code != 200: subprocess.run([ 'phenix.superpose_pdbs', 'file_name=' + phenix_pdb_path + phenix_file_name, fixed_pdb_path, moving_pdb_path ]) return redirect(phenix_pdb_link + phenix_file_name)
def get(self, species='', gene_id=''): """This end point provides gene isoforms given a gene ID. Only genes/isoforms with pdb structures are returned""" gene_isoforms = [] # Escape input species = escape(species) gene_id = escape(gene_id) if species == 'arabidopsis': if BARUtils.is_arabidopsis_gene_valid(gene_id): try: rows = isoforms.query.filter_by(gene=gene_id).all() except OperationalError: return BARUtils.error_exit( 'An internal error has occurred'), 500 [gene_isoforms.append(row.isoform) for row in rows] # Found isoforms if len(gene_isoforms) > 0: return BARUtils.success_exit(gene_isoforms) else: return BARUtils.error_exit('Invalid gene id'), 400 elif species == 'poplar': if BARUtils.is_poplar_gene_valid(gene_id): # Path is the location of poplar pdb file if os.environ.get('BAR'): path = '/DATA/ePlants_Data/eplant_poplar/protein_structures/' else: path = os.getcwd( ) + '/data/gene_information/gene_isoforms/' path += gene_id + '.pdb' if os.path.exists(path) and os.path.isfile(path): return BARUtils.success_exit(gene_id) else: return BARUtils.error_exit('Invalid gene id'), 400 else: return BARUtils.error_exit('No data for the given species') return BARUtils.error_exit( 'There are no data found for the given gene')
def get(self, table_id=""): """Returns the list of samples in the table with the given ID""" con = db.get_engine(bind="summarization") tbl = SummarizationGeneExpressionUtils.get_table_object(table_id) values = [] try: rows = con.execute(db.select([tbl.c.Sample]).distinct()) except SQLAlchemyError: return BARUtils.error_exit("Internal server error"), 500 [values.append(row.Sample) for row in rows] return BARUtils.success_exit(values)
def post(self): """This function adds a CSV's data to the database. This is only called by the Cromwell server after receiving the user's file.""" if request.remote_addr != "127.0.0.1": return BARUtils.error_exit("Forbidden"), 403 if request.method == "POST": key = request.headers.get("X-Api-Key") if SummarizationGeneExpressionUtils.decrement_uses(key): csv = request.get_json()["csv"] db_id = request.get_json()["uid"] df = pandas.read_csv(csv) db_id = db_id.split(".")[0] df = df.melt(id_vars=["Gene"], var_name="Sample", value_name="Value") db_id = db_id.split("/")[len(db_id.split("/")) - 1] con = db.get_engine(bind="summarization") df.to_sql(db_id, con, if_exists="append", index=True) return BARUtils.success_exit("Success") else: return BARUtils.error_exit("Invalid API key")
def post(self): """This function adds a CSV's data to the database. This is only called by the Cromwell server after receiving the user's file. """ if request.remote_addr != '127.0.0.1': return BARUtils.error_exit('Forbidden'), 403 if request.method == 'POST': key = request.headers.get('X-Api-Key') if SummarizationGeneExpressionUtils.decrement_uses(key): csv = request.get_json()['csv'] db_id = request.get_json()['uid'] df = pandas.read_csv(csv) db_id = db_id.split('.')[0] df = df.melt(id_vars=['Gene'], var_name='Sample', value_name='Value') db_id = db_id.split('/')[len(db_id.split('/')) - 1] con = db.get_engine(bind='summarization') df.to_sql(db_id, con, if_exists='append', index=True) return BARUtils.success_exit('Success') else: return BARUtils.error_exit('Invalid API key')
def get(self, species="", gene_id=""): """ Endpoint returns sequence for a given gene of a particular species Response JSON designed to be like current PHP one: https://bar.utoronto.ca/webservices/bar_araport/get_protein_sequence_by_identifier.php?locus=AT1G01010.1 Species Supported: - Tomato (ITAG3.2) - e.g. Solyc00g005445.1.1 """ species = escape(species.lower()) gene_id = escape(gene_id.capitalize()) if species == "tomato": if BARUtils.is_tomato_gene_valid(gene_id, True): try: rows = Tomato32SequenceInfo.query.filter_by( gene_id=gene_id).all() if len(rows) == 0: return ( BARUtils.error_exit( "There are no data found for the given gene"), 400, ) else: return { "status": "success", "result": [{ "length": len(rows[0].full_seq) - 1, "gene_id": rows[0].gene_id, "sequence": rows[0].full_seq, }] } except OperationalError: return BARUtils.error_exit( "An internal error has occurred"), 500 else: return BARUtils.error_exit("Invalid gene id"), 400 else: return BARUtils.error_exit("Invalid species"), 400
def get(self, table_id="", user_string=""): """Returns all genes that contain a given string as part of their name""" con = db.get_engine(bind="summarization") tbl = SummarizationGeneExpressionUtils.get_table_object(table_id) values = [] try: rows = con.execute( db.select([tbl.c.Gene]).where( tbl.c.Gene.contains(user_string)).distinct()) except SQLAlchemyError: return BARUtils.error_exit("Internal server error"), 500 [values.append(row.Gene) for row in rows] return BARUtils.success_exit(values)
def post(self): if request.method == "POST": response_json = request.get_json() df = pandas.DataFrame.from_records([response_json]) con = db.get_engine(bind="summarization") try: reqs = Requests() users = Users() row_req = reqs.query.filter_by(email=df.email[0]).first() row_users = users.query.filter_by(email=df.email[0]).first() if row_req is None and row_users is None: df.to_sql("requests", con, if_exists="append", index=False) if ApiManagerUtils.send_email(): return BARUtils.success_exit("Data added, email sent") else: return BARUtils.success_exit( "Data added, email failed") else: return BARUtils.error_exit("E-mail already in use"), 409 except SQLAlchemyError: return BARUtils.error_exit("Internal server error"), 500
def post(self): """Approve a request from the database and add it to the Users table """ if request.method == 'POST': response_json = request.get_json() email = response_json['email'] password = response_json['password'] if ApiManagerUtils.check_admin_pass(password): table = Requests() values = [] try: rows = table.query.filter_by(email=email).all() except SQLAlchemyError: return BARUtils.error_exit('Internal server error'), 500 key = uuid.uuid4().hex [ values.append({ 'first_name': row.first_name, 'last_name': row.last_name, 'email': row.email, 'telephone': row.telephone, 'contact_type': row.contact_type, 'date_added': datetime.now(), 'status': 'user', 'api_key': key, 'uses_left': 25 }) for row in rows ] df = pandas.DataFrame.from_records([values[0]]) con = db.get_engine(bind='summarization') try: df.to_sql('users', con, if_exists='append', index=False) el = table.query.filter_by(email=email).one() db.session.delete(el) except SQLAlchemyError: return BARUtils.error_exit('Internal server error'), 500 return BARUtils.success_exit(key) else: return BARUtils.error_exit('Forbidden'), 403
def post(self): """Approve a request from the database and add it to the Users table""" if request.method == "POST": response_json = request.get_json() email = response_json["email"] password = response_json["password"] if ApiManagerUtils.check_admin_pass(password): table = Requests() values = [] try: rows = table.query.filter_by(email=email).all() except SQLAlchemyError: return BARUtils.error_exit("Internal server error"), 500 key = uuid.uuid4().hex [ values.append({ "first_name": row.first_name, "last_name": row.last_name, "email": row.email, "telephone": row.telephone, "contact_type": row.contact_type, "date_added": datetime.now(), "status": "user", "api_key": key, "uses_left": 25, }) for row in rows ] df = pandas.DataFrame.from_records([values[0]]) con = db.get_engine(bind="summarization") try: df.to_sql("users", con, if_exists="append", index=False) el = table.query.filter_by(email=email).one() db.session.delete(el) except SQLAlchemyError: return BARUtils.error_exit("Internal server error"), 500 return BARUtils.success_exit(key) else: return BARUtils.error_exit("Forbidden"), 403
def get(self, gene_id='', top_n=''): """This end point is a proxy for ATTED-II api version 4. This is used by ThaleMine. This end point is currently not cached. """ gene_id = escape(gene_id) top_n = escape(top_n) # Is data valid if not BARUtils.is_arabidopsis_gene_valid(gene_id): return BARUtils.error_exit('Invalid gene id'), 400 if not BARUtils.is_integer(top_n): return BARUtils.error_exit('Invalid count'), 400 # Now query the web service payload = {'gene': gene_id, 'topN': top_n} resp = requests.get('https://atted.jp/cgi-bin/api4.cgi', params=payload, headers=request_headers) # I think the remote API always returns status 200, so skip status checking return resp.json()