def matchmaker_delete(institute_id, case_name): """Remove a case from MatchMaker""" # check that only authorized users can delete patients from MME user_obj = store.user(current_user.email) if 'mme_submitter' not in user_obj['roles']: flash('unauthorized request', 'warning') return redirect(request.referrer) institute_obj, case_obj = institute_and_case(store, institute_id, case_name) # Required params for sending a delete request to MME: mme_base_url = current_app.config.get('MME_URL') mme_token = current_app.config.get('MME_TOKEN') if not mme_base_url or not mme_token: flash('An error occurred reading matchmaker connection parameters. Please check config file!', 'danger') return redirect(request.referrer) delete_result = controllers.mme_delete(case_obj, mme_base_url, mme_token) n_deleted = 0 category = 'warning' for resp in delete_result: if resp['status_code'] == 200: n_deleted += 1 else: flash(resp['message'], category) if n_deleted: category = 'success' # update case by removing mme submission # and create events for patients deletion from MME user_obj = store.user(current_user.email) store.case_mme_delete(case_obj=case_obj, user_obj=user_obj) flash('Number of patients deleted from Matchmaker: {} out of {}'.format(n_deleted, len(delete_result)), category) return redirect(request.referrer)
def assign(institute_id, case_name, user_id=None): """Assign and unassign a user from a case.""" institute_obj, case_obj = institute_and_case(store, institute_id, case_name) link = url_for('.case', institute_id=institute_id, case_name=case_name) if user_id: user_obj = store.user(user_id) else: user_obj = store.user(current_user.email) if request.form.get('action') == 'DELETE': store.unassign(institute_obj, case_obj, user_obj, link) else: store.assign(institute_obj, case_obj, user_obj, link) return redirect(request.referrer)
def assign(institute_id, case_name, user_id=None): """Assign and unassign a user from a case.""" institute_obj, case_obj = institute_and_case(store, institute_id, case_name) link = url_for('.case', institute_id=institute_id, case_name=case_name) if user_id: user_obj = store.user(user_id) else: user_obj = store.user(current_user.email) if request.form.get('action') == 'DELETE': store.unassign(institute_obj, case_obj, user_obj, link) else: store.assign(institute_obj, case_obj, user_obj, link) return redirect(request.referrer)
def assign(institute_id, case_name, user_id=None, inactivate=False): """Assign and unassign a user from a case.""" institute_obj, case_obj = institute_and_case(store, institute_id, case_name) link = url_for(".case", institute_id=institute_id, case_name=case_name) if user_id: user_obj = store.user(user_id) else: user_obj = store.user(current_user.email) if request.form.get("action") == "DELETE": store.unassign(institute_obj, case_obj, user_obj, link, inactivate) else: store.assign(institute_obj, case_obj, user_obj, link) return redirect(request.referrer)
def institutes(): """Display a list of all user institutes.""" institute_objs = user_institutes(store, current_user) institutes = [] for ins_obj in institute_objs: sanger_recipients = [] for user_mail in ins_obj.get("sanger_recipients", []): user_obj = store.user(user_mail) if not user_obj: continue sanger_recipients.append(user_obj["name"]) institutes.append({ "display_name": ins_obj["display_name"], "internal_id": ins_obj["_id"], "coverage_cutoff": ins_obj.get("coverage_cutoff", "None"), "sanger_recipients": sanger_recipients, "frequency_cutoff": ins_obj.get("frequency_cutoff", "None"), "phenotype_groups": ins_obj.get("phenotype_groups", PHENOTYPE_GROUPS), "case_count": sum(1 for i in store.cases(collaborator=ins_obj["_id"])), }) data = dict(institutes=institutes) return render_template("overview/institutes.html", **data)
def download_verified(): """Download all verified variants for user's cases""" user_obj = store.user(current_user.email) user_institutes = ( [inst["_id"] for inst in store.institutes()] if current_user.is_admin else user_obj.get("institutes") ) temp_excel_dir = os.path.join(variants_bp.static_folder, "verified_folder") os.makedirs(temp_excel_dir, exist_ok=True) if controllers.verified_excel_file(store, user_institutes, temp_excel_dir): data = zip_dir_to_obj(temp_excel_dir) # remove temp folder with excel files in it shutil.rmtree(temp_excel_dir) today = datetime.datetime.now().strftime("%Y-%m-%d") return send_file( data, mimetype="application/zip", as_attachment=True, download_name="_".join(["scout", "verified_variants", today]) + ".zip", cache_timeout=0, ) # remove temp folder with excel files in it shutil.rmtree(temp_excel_dir) flash("No verified variants could be exported for user's institutes", "warning") return redirect(request.referrer)
def institutes(): """Display a list of all user institutes.""" institute_objs = user_institutes(store, current_user) institutes = [] for ins_obj in institute_objs: sanger_recipients = [] for user_mail in ins_obj.get('sanger_recipients',[]): user_obj = store.user(user_mail) if not user_obj: continue sanger_recipients.append(user_obj['name']) institutes.append( { 'display_name': ins_obj['display_name'], 'internal_id': ins_obj['_id'], 'coverage_cutoff': ins_obj.get('coverage_cutoff', 'None'), 'sanger_recipients': sanger_recipients, 'frequency_cutoff': ins_obj.get('frequency_cutoff', 'None'), 'phenotype_groups': ins_obj.get('phenotype_groups', PHENOTYPE_GROUPS) } ) data = dict(institutes=institutes) return render_template( 'overview/institutes.html', **data)
def verify(institute_id, case_name, variant_id, variant_category, order): """Start procedure to validate variant using other techniques.""" institute_obj, case_obj = institute_and_case(store, institute_id, case_name) variant_obj = store.variant(variant_id) user_obj = store.user(current_user.email) comment = request.form.get('verification_comment') try: controllers.variant_verification( store=store, mail=mail, institute_obj=institute_obj, case_obj=case_obj, user_obj=user_obj, comment=comment, variant_obj=variant_obj, sender=current_app.config['MAIL_USERNAME'], variant_url=request.referrer, order=order, url_builder=url_for) except controllers.MissingVerificationRecipientError: flash('No verification recipients added to institute.', 'danger') return redirect(request.referrer)
def test_update_tracks_settings(app, user_obj, mocker, mock_redirect): """Test the endpoint that updates the IGV track preferences for a user""" mocker.patch("scout.server.blueprints.variant.views.redirect", return_value=mock_redirect) preferred_tracks = ["Genes", "ClinVar"] # GIVEN an initialized app with app.test_client() as client: # GIVEN that the user could be logged in resp = client.get(url_for("auto_login")) # GIVEN that the user wants to see only Genes and ClinVar SNVs tracks form_data = { "user_tracks": preferred_tracks, } # WHEN sending a POST request to the update resp = client.post( url_for( "variant.update_tracks_settings", ), data=form_data, ) # THEN the user object in the database should be updated with the right track info user_obj = store.user(email=user_obj["email"]) for track in preferred_tracks: assert track in preferred_tracks
def institutes(): """Display a list of all user institutes.""" institute_objs = user_institutes(store, current_user) institutes = [] for ins_obj in institute_objs: sanger_recipients = [] for user_mail in ins_obj.get('sanger_recipients', []): user_obj = store.user(user_mail) if not user_obj: continue sanger_recipients.append(user_obj['name']) institutes.append({ 'display_name': ins_obj['display_name'], 'internal_id': ins_obj['_id'], 'coverage_cutoff': ins_obj.get('coverage_cutoff', 'None'), 'sanger_recipients': sanger_recipients, 'frequency_cutoff': ins_obj.get('frequency_cutoff', 'None'), 'phenotype_groups': ins_obj.get('phenotype_groups', PHENOTYPE_GROUPS) }) data = dict(institutes=institutes) return render_template('overview/institutes.html', **data)
def matchmaker_matches(institute_id, case_name): """Show all MatchMaker matches for a given case""" # check that only authorized users can access MME patients matches user_obj = store.user(current_user.email) if 'mme_submitter' not in user_obj['roles']: flash('unauthorized request', 'warning') return redirect(request.referrer) # Required params for getting matches from MME server: mme_base_url = current_app.config.get('MME_URL') mme_token = current_app.config.get('MME_TOKEN') if not mme_base_url or not mme_token: flash( 'An error occurred reading matchmaker connection parameters. Please check config file!', 'danger') return redirect(request.referrer) institute_obj, case_obj = institute_and_case(store, institute_id, case_name) data = controllers.mme_matches(case_obj, institute_obj, mme_base_url, mme_token) if data and data.get('server_errors'): flash( 'MatchMaker server returned error:{}'.format( data['server_errors']), 'danger') return redirect(request.referrer) elif not data: data = {'institute': institute_obj, 'case': case_obj} return data
def phenotypes(institute_id, case_name, phenotype_id=None): """Handle phenotypes.""" institute_obj, case_obj = institute_and_case(store, institute_id, case_name) case_url = url_for('.case', institute_id=institute_id, case_name=case_name) is_group = request.args.get('is_group') == 'yes' user_obj = store.user(current_user.email) if phenotype_id: # DELETE a phenotype item/group from case store.remove_phenotype(institute_obj, case_obj, user_obj, case_url, phenotype_id, is_group=is_group) else: try: # add a new phenotype item/group to the case phenotype_term = request.form['hpo_term'] if phenotype_term.startswith('HP:') or len(phenotype_term) == 7: hpo_term = phenotype_term.split(' | ', 1)[0] store.add_phenotype(institute_obj, case_obj, user_obj, case_url, hpo_term=hpo_term, is_group=is_group) else: # assume omim id store.add_phenotype(institute_obj, case_obj, user_obj, case_url, omim_term=phenotype_term) except ValueError: return abort(400, ("unable to add phenotype: {}".format(phenotype_term))) return redirect(case_url)
def case_synopsis(institute_id, case_name): """Update (PUT) synopsis of a specific case.""" institute_obj, case_obj = institute_and_case(store, institute_id, case_name) user_obj = store.user(current_user.email) new_synopsis = request.form.get('synopsis') controllers.update_synopsis(store, institute_obj, case_obj, user_obj, new_synopsis) return redirect(request.referrer)
def institutes(): """Returns institutes info available for a user Returns: data(list): a list of institute dictionaries """ institute_objs = user_institutes(store, current_user) institutes = [] for ins_obj in institute_objs: sanger_recipients = [] for user_mail in ins_obj.get("sanger_recipients", []): user_obj = store.user(user_mail) if not user_obj: continue sanger_recipients.append(user_obj["name"]) institutes.append({ "display_name": ins_obj["display_name"], "internal_id": ins_obj["_id"], "coverage_cutoff": ins_obj.get("coverage_cutoff", "None"), "sanger_recipients": sanger_recipients, "frequency_cutoff": ins_obj.get("frequency_cutoff", "None"), "phenotype_groups": ins_obj.get("phenotype_groups", PHENOTYPE_GROUPS), "case_count": sum(1 for i in store.cases(collaborator=ins_obj["_id"])), }) return institutes
def events(institute_id, case_name, event_id=None): """Handle events.""" institute_obj, case_obj = institute_and_case(store, institute_id, case_name) link = request.form.get("link") content = request.form.get("content") variant_id = request.args.get("variant_id") user_obj = store.user(current_user.email) if event_id: # delete the event store.delete_event(event_id) else: if variant_id: # create a variant comment variant_obj = store.variant(variant_id) level = request.form.get("level", "specific") store.comment( institute_obj, case_obj, user_obj, link, variant=variant_obj, content=content, comment_level=level, ) else: # create a case comment store.comment(institute_obj, case_obj, user_obj, link, content=content) return redirect(request.referrer)
def reset_research(institute_id, case_name): institute_obj, case_obj = institute_and_case(store, institute_id, case_name) user_obj = store.user(current_user.email) link = url_for(".case", institute_id=institute_id, case_name=case_name) store.reset_research(institute_obj, case_obj, user_obj, link) return redirect(request.referrer)
def matchmaker_delete(request, institute_id, case_name): """Delete all affected samples for a case from MatchMaker Args: request(werkzeug.local.LocalProxy) institute_id(str): _id of an institute case_name(str): display name of a case """ # Check that general MME request requirements are fulfilled matchmaker_check_requirements(request) _, case_obj = institute_and_case(store, institute_id, case_name) # Delete each patient submitted for this case for patient in case_obj.get("mme_submission", {}).get("patients", []): # Send delete request to server and capture server's response patient_id = patient["id"] resp = matchmaker.patient_delete(patient_id) category = "warning" if resp["status_code"] == 200: category = "success" # update case by removing mme submission # and create events for patients deletion from MME user_obj = store.user(current_user.email) store.case_mme_delete(case_obj=case_obj, user_obj=user_obj) flash( f"Deleted patient '{patient_id}', case '{case_name}' from MatchMaker", "success", ) continue flash(f"An error occurred while deleting patient from MatchMaker", "danger")
def download_verified(): """Download all verified variants for user's cases""" user_obj = store.user(current_user.email) user_institutes = user_obj.get('institutes') temp_excel_dir = os.path.join(variants_bp.static_folder, 'verified_folder') os.makedirs(temp_excel_dir, exist_ok=True) written_files = controllers.verified_excel_file(store, user_institutes, temp_excel_dir) if written_files: today = datetime.datetime.now().strftime('%Y-%m-%d') # zip the files on the fly and serve the archive to the user data = io.BytesIO() with zipfile.ZipFile(data, mode='w') as z: for f_name in pathlib.Path(temp_excel_dir).iterdir(): zipfile.ZipFile z.write(f_name, os.path.basename(f_name)) data.seek(0) # remove temp folder with excel files in it shutil.rmtree(temp_excel_dir) return send_file(data, mimetype='application/zip', as_attachment=True, attachment_filename='_'.join( ['scout', 'verified_variants', today]) + '.zip') else: flash("No verified variants could be exported for user's institutes", 'warning') return redirect(request.referrer)
def matchmaker_match(institute_id, case_name, target): """Starts an internal match or a match against one or all MME external nodes""" institute_obj, case_obj = institute_and_case(store, institute_id, case_name) # check that only authorized users can run matches user_obj = store.user(current_user.email) if 'mme_submitter' not in user_obj['roles']: flash('unauthorized request', 'warning') return redirect(request.referrer) # Required params for sending an add request to MME: mme_base_url = current_app.config.get('MME_URL') mme_accepts = current_app.config.get('MME_ACCEPTS') mme_token = current_app.config.get('MME_TOKEN') nodes = current_app.mme_nodes if not mme_base_url or not mme_token or not mme_accepts: flash('An error occurred reading matchmaker connection parameters. Please check config file!', 'danger') return redirect(request.referrer) match_results = controllers.mme_match(case_obj, target, mme_base_url, mme_token, nodes, mme_accepts) ok_responses = 0 for match_results in match_results: match_results['status_code'] == 200 ok_responses +=1 if ok_responses: flash("Match request sent. Look for eventual matches in 'Matches' page.", 'info') else: flash('An error occurred while sending match request.', 'danger') return redirect(request.referrer)
def download_verified(): """Download all verified variants for user's cases""" user_obj = store.user(current_user.email) user_institutes = user_obj.get('institutes') temp_excel_dir = os.path.join(variants_bp.static_folder, 'verified_folder') os.makedirs(temp_excel_dir, exist_ok=True) written_files = controllers.verified_excel_file(store, user_institutes, temp_excel_dir) if written_files: today = datetime.datetime.now().strftime('%Y-%m-%d') # zip the files on the fly and serve the archive to the user data = io.BytesIO() with zipfile.ZipFile(data, mode='w') as z: for f_name in pathlib.Path(temp_excel_dir).iterdir(): zipfile.ZipFile z.write(f_name, os.path.basename(f_name)) data.seek(0) # remove temp folder with excel files in it shutil.rmtree(temp_excel_dir) return send_file( data, mimetype='application/zip', as_attachment=True, attachment_filename='_'.join(['scout', 'verified_variants', today])+'.zip' ) else: flash("No verified variants could be exported for user's institutes", 'warning') return redirect(request.referrer)
def case_synopsis(institute_id, case_name): """Update (PUT) synopsis of a specific case.""" institute_obj, case_obj = institute_and_case(store, institute_id, case_name) user_obj = store.user(current_user.email) new_synopsis = request.form.get('synopsis') controllers.update_synopsis(store, institute_obj, case_obj, user_obj, new_synopsis) return redirect(request.referrer)
def mark_causative(institute_id, case_name, variant_id, partial_causative=False): """Mark a variant as confirmed causative.""" institute_obj, case_obj = institute_and_case(store, institute_id, case_name) variant_obj = store.variant(variant_id) user_obj = store.user(current_user.email) link = url_for("variant.variant", institute_id=institute_id, case_name=case_name, variant_id=variant_id) if request.form["action"] == "ADD": if "partial_causative" in request.form: omim_terms = request.form.getlist("omim_select") hpo_terms = request.form.getlist("hpo_select") store.mark_partial_causative(institute_obj, case_obj, user_obj, link, variant_obj, omim_terms, hpo_terms) else: store.mark_causative(institute_obj, case_obj, user_obj, link, variant_obj) elif request.form["action"] == "DELETE": if partial_causative == "True": store.unmark_partial_causative(institute_obj, case_obj, user_obj, link, variant_obj) else: store.unmark_causative(institute_obj, case_obj, user_obj, link, variant_obj) # send the user back to the case that was marked as solved case_url = url_for(".case", institute_id=institute_id, case_name=case_name) return redirect(request.referrer)
def matchmaker_matches(institute_id, case_name): """Show all MatchMaker matches for a given case""" # check that only authorized users can access MME patients matches panel = 1 if request.method == "POST": panel = panel = request.form.get("pane_id") user_obj = store.user(current_user.email) if "mme_submitter" not in user_obj["roles"]: flash("unauthorized request", "warning") return redirect(request.referrer) # Required params for getting matches from MME server: mme_base_url = current_app.config.get("MME_URL") mme_token = current_app.config.get("MME_TOKEN") if not mme_base_url or not mme_token: flash( "An error occurred reading matchmaker connection parameters. Please check config file!", "danger", ) return redirect(request.referrer) institute_obj, case_obj = institute_and_case(store, institute_id, case_name) data = controllers.mme_matches(case_obj, institute_obj, mme_base_url, mme_token) data["panel"] = panel if data and data.get("server_errors"): flash( "MatchMaker server returned error:{}".format( data["server_errors"]), "danger", ) return redirect(request.referrer) elif not data: data = {"institute": institute_obj, "case": case_obj, "panel": panel} return data
def case_diagnosis(institute_id, case_name): """Add or remove a diagnosis for a case.""" institute_obj, case_obj = institute_and_case(store, institute_id, case_name) user_obj = store.user(current_user.email) link = url_for(".case", institute_id=institute_id, case_name=case_name) level = "phenotype" if "phenotype" in request.form else "gene" omim_id = request.form["omim_term"].split("|")[0] if not "OMIM:" in omim_id: # Could be an omim number provided by user omim_id = ":".join(["OMIM", omim_id]) # Make sure omim term exists in database: omim_obj = store.disease_term(omim_id.strip()) if not omim_obj: flash("Couldn't find any disease term with id: {}".format(omim_id), "warning") remove = True if request.args.get("remove") == "yes" else False store.diagnose( institute_obj, case_obj, user_obj, link, level=level, omim_id=omim_id, remove=remove, ) return redirect(request.referrer)
def case_diagnosis(institute_id, case_name): """Add or remove a diagnosis for a case.""" institute_obj, case_obj = institute_and_case(store, institute_id, case_name) user_obj = store.user(current_user.email) link = url_for(".case", institute_id=institute_id, case_name=case_name) omim_id = request.form["omim_term"].split("|")[0] omim_inds = request.form.getlist( "omim_inds") # Individual-level phenotypes if not "OMIM:" in omim_id: # Could be an omim number provided by user omim_id = ":".join(["OMIM", omim_id]) # Make sure omim term exists in database: omim_obj = store.disease_term(omim_id.strip()) if omim_obj is None: flash("Couldn't find any disease term with id: {}".format(omim_id), "warning") return redirect(request.referrer) remove = True if request.args.get("remove") == "yes" else False store.diagnose(institute_obj, case_obj, user_obj, link, omim_obj, omim_inds, remove) return redirect("#".join([link, "omim_assign"]))
def research(institute_id, case_name): """Open the research list for a case.""" institute_obj, case_obj = institute_and_case(store, institute_id, case_name) user_obj = store.user(current_user.email) link = url_for('.case', institute_id=institute_id, case_name=case_name) store.open_research(institute_obj, case_obj, user_obj, link) return redirect(request.referrer)
def matchmaker_check_requirements(request): """Make sure requirements are fulfilled before submitting any request to MatchMaker Exchange Args: request(werkzeug.local.LocalProxy) Returns: None, if requirements are fulfilled, otherwise redirects to previous page with error message """ # Make sure all MME connection parameters are available in scout instance if ( any( [ hasattr(matchmaker, "host"), hasattr(matchmaker, "accept"), hasattr(matchmaker, "token"), ] ) is None ): flash( "An error occurred reading matchmaker connection parameters. Please check config file!", "danger", ) return redirect(request.referrer) # Check that request comes from an authorized user (mme_submitter role) user_obj = store.user(current_user.email) if "mme_submitter" not in user_obj.get("roles", []): flash("unauthorized request", "warning") return redirect(request.referrer)
def call_rerunner(store, institute_id, case_name, metadata): """Call rerunner with updated pedigree metadata.""" # define the data to be passed payload = {"case_id": case_name, "sample_ids": [m["sample_id"] for m in metadata]} cnf = rerunner.connection_settings url = cnf.get("entrypoint") if not url: raise ValueError("Rerunner API entrypoint not configured") auth = HTTPBasicAuth(current_user.email, cnf.get("api_key")) LOG.info(f"Sending request -- {url}; params={payload}") resp = requests.post( url, params=payload, json=metadata, timeout=rerunner.timeout, headers={"Content-Type": "application/json"}, auth=auth, ) if resp.status_code == 200: LOG.info(f"Reanalysis was successfully started; case: {case_name}") # get institute, case and user objects for adding a notification of the rerun to the database institute_obj, case_obj = institute_and_case(store, institute_id, case_name) user_obj = store.user(current_user.email) link = url_for("cases.case", institute_id=institute_id, case_name=case_name) store.request_rerun(institute_obj, case_obj, user_obj, link) # notfiy the user of the rerun flash(f"Reanalysis was successfully started; case: {case_name}", "info") else: raise RerunnerError(f"{resp.reason}, {resp.status_code}")
def authorized(): oauth_response = None try: oauth_response = google.authorized_response() except OAuthException as error: current_app.logger.warn(oauth_response.message) flash("{} - try again!".format(oauth_response.message), 'warning') return redirect(url_for('public.index')) if oauth_response is None: flash("Access denied: reason={} error={}" .format(request.args.get['error_reason'], request.args['error_description']), 'danger') return abort(403) # add token to session, do it before validation to be able to fetch # additional data (like email) on the authenticated user session['google_token'] = (oauth_response['access_token'], '') # get additional user info with the access token google_user = google.get('userinfo') google_data = google_user.data user_obj = store.user(google_data['email']) if user_obj is None: flash('your email is not whitelisted, contact admin.', 'warning') return redirect(url_for('public.index')) user_obj['name'] = google_data['name'] user_obj['location'] = google_data['locale'] user_obj['accessed_at'] = datetime.now() store.update_user(user_obj) return perform_login(user_obj)
def phenotypes(institute_id, case_name, phenotype_id=None): """Handle phenotypes.""" institute_obj, case_obj = institute_and_case(store, institute_id, case_name) case_url = url_for('.case', institute_id=institute_id, case_name=case_name) is_group = request.args.get('is_group') == 'yes' user_obj = store.user(current_user.email) if phenotype_id: # DELETE a phenotype item/group from case store.remove_phenotype(institute_obj, case_obj, user_obj, case_url, phenotype_id, is_group=is_group) else: try: # add a new phenotype item/group to the case phenotype_term = request.form['hpo_term'] if phenotype_term.startswith('HP:') or len(phenotype_term) == 7: hpo_term = phenotype_term.split(' | ', 1)[0] store.add_phenotype(institute_obj, case_obj, user_obj, case_url, hpo_term=hpo_term, is_group=is_group) else: # assume omim id store.add_phenotype(institute_obj, case_obj, user_obj, case_url, omim_term=phenotype_term) except ValueError: return abort(400, ("unable to add phenotype: {}".format(phenotype_term))) return redirect(case_url)
def update_default_panels(store, current_user, institute_id, case_name, panel_ids): """Update default panels for a case.""" institute_obj, case_obj = institute_and_case(store, institute_id, case_name) user_obj = store.user(current_user.email) link = url_for("cases.case", institute_id=institute_id, case_name=case_name) panel_objs = [store.panel(panel_id) for panel_id in panel_ids] store.update_default_panels(institute_obj, case_obj, user_obj, link, panel_objs)
def add_case_group(store, current_user, institute_id, case_name, group=None): """Bind a case group in a selected a case, creating it in current institute if not given. Args: current_user (user)current user institute_id (str)institute id case_name (str)case display name group (str)case group id - converts to ObjectId Returns: updated_case (InsertOneResult) """ institute_obj, case_obj = institute_and_case(store, institute_id, case_name) link = url_for("cases.case", institute_id=institute_id, case_name=case_name) user_obj = store.user(current_user.email) if not group: group = store.init_case_group(institute_id) current_group_ids = set(case_obj.get("group", [])) current_group_ids.add(ObjectId(group)) updated_case = store.update_case_group_ids( institute_obj, case_obj, user_obj, link, list(current_group_ids) ) return updated_case
def research(institute_id, case_name): """Open the research list for a case.""" institute_obj, case_obj = institute_and_case(store, institute_id, case_name) user_obj = store.user(current_user.email) link = url_for('.case', institute_id=institute_id, case_name=case_name) store.open_research(institute_obj, case_obj, user_obj, link) return redirect(request.referrer)
def variant_update(institute_id, case_name, variant_id): """Update user-defined information about a variant: manual rank & ACMG.""" institute_obj, case_obj = institute_and_case(store, institute_id, case_name) variant_obj = store.variant(variant_id) user_obj = store.user(current_user.email) link = request.referrer manual_rank = request.form.get('manual_rank') if manual_rank: new_manual_rank = int(manual_rank) if manual_rank != '-1' else None store.update_manual_rank(institute_obj, case_obj, user_obj, link, variant_obj, new_manual_rank) if new_manual_rank: flash("updated variant tag: {}".format(new_manual_rank), 'info') else: flash("reset variant tag: {}".format(variant_obj['manual_rank']), 'info') elif request.form.get('acmg_classification'): new_acmg = request.form['acmg_classification'] acmg_classification = variant_obj.get('acmg_classification') if isinstance(acmg_classification, int) and (new_acmg == ACMG_MAP[acmg_classification]): new_acmg = None store.update_acmg(institute_obj, case_obj, user_obj, link, variant_obj, new_acmg) flash("updated ACMG classification: {}".format(new_acmg), 'info') return redirect(request.referrer)
def phenotypes_actions(institute_id, case_name): """Perform actions on multiple phenotypes.""" institute_obj, case_obj = institute_and_case(store, institute_id, case_name) case_url = url_for(".case", institute_id=institute_id, case_name=case_name) action = request.form["action"] hpo_ids = request.form.getlist("hpo_id") user_obj = store.user(current_user.email) if action == "PHENOMIZER": if len(hpo_ids) == 0: hpo_ids = [ term["phenotype_id"] for term in case_obj.get("phenotype_terms", []) ] username = current_app.config["PHENOMIZER_USERNAME"] password = current_app.config["PHENOMIZER_PASSWORD"] diseases = controllers.hpo_diseases(username, password, hpo_ids) if diseases: return render_template( "cases/diseases.html", diseases=diseases, institute=institute_obj, case=case_obj, ) if action == "DELETE": for hpo_id in hpo_ids: # DELETE a phenotype from the list store.remove_phenotype(institute_obj, case_obj, user_obj, case_url, hpo_id) if action == "ADDGENE": hgnc_ids = parse_raw_gene_ids(request.form.getlist("genes")) store.update_dynamic_gene_list(case_obj, hgnc_ids=list(hgnc_ids), add_only=True) if action == "GENES": hgnc_symbols = parse_raw_gene_symbols(request.form.getlist("genes")) store.update_dynamic_gene_list(case_obj, hgnc_symbols=list(hgnc_symbols)) if action == "GENERATE": if len(hpo_ids) == 0: hpo_ids = [ term["phenotype_id"] for term in case_obj.get("phenotype_terms", []) ] results = store.generate_hpo_gene_list(*hpo_ids) # determine how many HPO terms each gene must match hpo_count = int(request.form.get("min_match") or 1) hgnc_ids = [result[0] for result in results if result[1] >= hpo_count] store.update_dynamic_gene_list(case_obj, hgnc_ids=hgnc_ids, phenotype_ids=hpo_ids) return redirect("#".join([case_url, "phenotypes_panel"]))
def update_tracks_settings(): """Update custom track settings for a user according to form choices""" user_obj = store.user(email=current_user.email) selected_tracks = request.form.getlist("user_tracks") or [] # update user in database with custom tracks info user_obj["igv_tracks"] = selected_tracks store.update_user(user_obj) return redirect(request.referrer)
def mark_validation(institute_id, case_name, variant_id): """Mark a variant as sanger validated.""" institute_obj, case_obj = institute_and_case(store, institute_id, case_name) variant_obj = store.variant(variant_id) user_obj = store.user(current_user.email) validate_type = request.form['type'] or None link = url_for('variants.variant', institute_id=institute_id, case_name=case_name, variant_id=variant_id) store.validate(institute_obj, case_obj, user_obj, link, variant_obj, validate_type) return redirect(request.referrer or link)
def matchmaker_delete(institute_id, case_name): """Remove a case from MatchMaker""" # check that only authorized users can delete patients from MME user_obj = store.user(current_user.email) if "mme_submitter" not in user_obj["roles"]: flash("unauthorized request", "warning") return redirect(request.referrer) institute_obj, case_obj = institute_and_case(store, institute_id, case_name) # Required params for sending a delete request to MME: mme_base_url = current_app.config.get("MME_URL") mme_token = current_app.config.get("MME_TOKEN") if not mme_base_url or not mme_token: flash( "An error occurred reading matchmaker connection parameters. Please check config file!", "danger", ) return redirect(request.referrer) delete_result = controllers.mme_delete(case_obj, mme_base_url, mme_token) n_deleted = 0 category = "warning" for resp in delete_result: if resp["status_code"] == 200: n_deleted += 1 else: flash(resp["message"], category) if n_deleted: category = "success" # update case by removing mme submission # and create events for patients deletion from MME user_obj = store.user(current_user.email) store.case_mme_delete(case_obj=case_obj, user_obj=user_obj) flash( "Number of patients deleted from Matchmaker: {} out of {}".format( n_deleted, len(delete_result)), category, ) return redirect(request.referrer)
def mark_validation(institute_id, case_name, variant_id): """Mark a variant as sanger validated.""" institute_obj, case_obj = institute_and_case(store, institute_id, case_name) variant_obj = store.variant(variant_id) user_obj = store.user(current_user.email) validate_type = request.form['type'] or None link = url_for('variants.variant', institute_id=institute_id, case_name=case_name, variant_id=variant_id) store.validate(institute_obj, case_obj, user_obj, link, variant_obj, validate_type) return redirect(request.referrer or link)
def case_diagnosis(institute_id, case_name): """Add or remove a diagnosis for a case.""" institute_obj, case_obj = institute_and_case(store, institute_id, case_name) user_obj = store.user(current_user.email) link = url_for('.case', institute_id=institute_id, case_name=case_name) level = 'phenotype' if 'phenotype' in request.form else 'gene' omim_id = request.form['omim_id'] remove = True if request.args.get('remove') == 'yes' else False store.diagnose(institute_obj, case_obj, user_obj, link, level=level, omim_id=omim_id, remove=remove) return redirect(request.referrer)
def cohorts(institute_id, case_name): """Add/remove institute tags.""" institute_obj, case_obj = institute_and_case(store, institute_id, case_name) user_obj = store.user(current_user.email) link = url_for('.case', institute_id=institute_id, case_name=case_name) cohort_tag = request.form['cohort_tag'] if request.args.get('remove') == 'yes': store.remove_cohort(institute_obj, case_obj, user_obj, link, cohort_tag) else: store.add_cohort(institute_obj, case_obj, user_obj, link, cohort_tag) return redirect(request.referrer)
def pin_variant(institute_id, case_name, variant_id): """Pin and unpin variants to/from the list of suspects.""" institute_obj, case_obj = institute_and_case(store, institute_id, case_name) variant_obj = store.variant(variant_id) user_obj = store.user(current_user.email) link = url_for('variants.variant', institute_id=institute_id, case_name=case_name, variant_id=variant_id) if request.form['action'] == 'ADD': store.pin_variant(institute_obj, case_obj, user_obj, link, variant_obj) elif request.form['action'] == 'DELETE': store.unpin_variant(institute_obj, case_obj, user_obj, link, variant_obj) return redirect(request.referrer or link)
def variant_update(institute_id, case_name, variant_id): """Update user-defined information about a variant: manual rank & ACMG.""" institute_obj, case_obj = institute_and_case(store, institute_id, case_name) variant_obj = store.variant(variant_id) user_obj = store.user(current_user.email) link = request.referrer manual_rank = request.form.get('manual_rank') if manual_rank: new_manual_rank = int(manual_rank) if manual_rank != '-1' else None store.update_manual_rank(institute_obj, case_obj, user_obj, link, variant_obj, new_manual_rank) if new_manual_rank: flash("updated variant tag: {}".format(new_manual_rank), 'info') else: flash("reset variant tag: {}".format(variant_obj.get('manual_rank', 'NA')), 'info') elif request.form.get('acmg_classification'): new_acmg = request.form['acmg_classification'] acmg_classification = variant_obj.get('acmg_classification') if isinstance(acmg_classification, int) and (new_acmg == ACMG_MAP[acmg_classification]): new_acmg = None store.update_acmg(institute_obj, case_obj, user_obj, link, variant_obj, new_acmg) flash("updated ACMG classification: {}".format(new_acmg), 'info') new_dismiss = request.form.getlist('dismiss_variant') if request.form.getlist('dismiss_variant'): store.update_dismiss_variant(institute_obj, case_obj, user_obj, link, variant_obj, new_dismiss) if new_dismiss: flash("Dismissed variant: {}".format(new_dismiss), 'info') if variant_obj.get('dismiss_variant') and not new_dismiss: if 'dismiss' in request.form: store.update_dismiss_variant(institute_obj, case_obj, user_obj, link, variant_obj, new_dismiss) flash("Reset variant dismissal: {}".format(variant_obj.get('dismiss_variant')), 'info') else: log.debug("DO NOT reset variant dismissal: {}".format(variant_obj.get('dismiss_variant')), 'info') mosaic_tags = request.form.getlist('mosaic_tags') if mosaic_tags: store.update_mosaic_tags(institute_obj, case_obj, user_obj, link, variant_obj, mosaic_tags) if new_dismiss: flash("Added mosaic tags: {}".format(mosaic_tags), 'info') if variant_obj.get('mosaic_tags') and not mosaic_tags: if 'mosaic' in request.form: store.update_mosaic_tags(institute_obj, case_obj, user_obj, link, variant_obj, mosaic_tags) flash("Reset mosaic tags: {}".format(variant_obj.get('mosaic_tags')), 'info') return redirect(request.referrer)
def authorized(): oauth_response = None try: oauth_response = google.authorized_response() except OAuthException as error: current_app.logger.warn(oauth_response.message) flash("{} - try again!".format(oauth_response.message), 'warning') return redirect(url_for('public.index')) if oauth_response is None: flash("Access denied: reason={} error={}" .format(request.args.get['error_reason'], request.args['error_description']), 'danger') return abort(403) # add token to session, do it before validation to be able to fetch # additional data (like email) on the authenticated user session['google_token'] = (oauth_response['access_token'], '') # get additional user info with the access token google_user = google.get('userinfo') google_data = google_user.data user_obj = store.user(google_data['email']) # Try again with lower-cased email address if no match if user_obj is None: user_obj = store.user(google_data['email'].lower()) if user_obj is None: flash("email not whitelisted: {}".format(google_data['email']), 'warning') return redirect(url_for('public.index')) user_obj['name'] = google_data['name'] user_obj['location'] = google_data['locale'] user_obj['accessed_at'] = datetime.now() store.update_user(user_obj) return perform_login(user_obj)
def status(institute_id, case_name): """Update status of a specific case.""" institute_obj, case_obj = institute_and_case(store, institute_id, case_name) user_obj = store.user(current_user.email) status = request.form.get('status', case_obj['status']) link = url_for('.case', institute_id=institute_id, case_name=case_name) if status == 'archive': store.archive_case(institute_obj, case_obj, user_obj, status, link) else: store.update_status(institute_obj, case_obj, user_obj, status, link) return redirect(request.referrer)
def share(institute_id, case_name): """Share a case with a different institute.""" institute_obj, case_obj = institute_and_case(store, institute_id, case_name) user_obj = store.user(current_user.email) collaborator_id = request.form['collaborator'] revoke_access = 'revoke' in request.form link = url_for('.case', institute_id=institute_id, case_name=case_name) if revoke_access: store.unshare(institute_obj, case_obj, collaborator_id, user_obj, link) else: store.share(institute_obj, case_obj, collaborator_id, user_obj, link) return redirect(request.referrer)
def verify(institute_id, case_name, variant_id, variant_category, order): """Start procedure to validate variant using other techniques.""" institute_obj, case_obj = institute_and_case(store, institute_id, case_name) variant_obj = store.variant(variant_id) user_obj = store.user(current_user.email) comment = request.form.get('verification_comment') try: controllers.variant_verification(store=store, mail=mail, institute_obj=institute_obj, case_obj=case_obj, user_obj=user_obj, comment=comment, variant_obj=variant_obj, sender=current_app.config['MAIL_USERNAME'], variant_url=request.referrer, order=order, url_builder=url_for) except controllers.MissingVerificationRecipientError: flash('No verification recipients added to institute.', 'danger') return redirect(request.referrer)
def mark_causative(institute_id, case_name, variant_id): """Mark a variant as confirmed causative.""" institute_obj, case_obj = institute_and_case(store, institute_id, case_name) variant_obj = store.variant(variant_id) user_obj = store.user(current_user.email) link = url_for('variants.variant', institute_id=institute_id, case_name=case_name, variant_id=variant_id) if request.form['action'] == 'ADD': store.mark_causative(institute_obj, case_obj, user_obj, link, variant_obj) elif request.form['action'] == 'DELETE': store.unmark_causative(institute_obj, case_obj, user_obj, link, variant_obj) # send the user back to the case that was marked as solved case_url = url_for('.case', institute_id=institute_id, case_name=case_name) return redirect(case_url)
def login(): """Login a user if they have access.""" # store potential next param URL in the session if 'next' in request.args: session['next_url'] = request.args['next'] if current_app.config.get('GOOGLE'): callback_url = url_for('.authorized', _external=True) return google.authorize(callback=callback_url) user_email = request.args.get('email') user_obj = store.user(user_email) if user_obj is None: flash("email not whitelisted: {}".format(user_email), 'warning') return redirect(url_for('public.index')) return perform_login(user_obj)
def phenotypes_actions(institute_id, case_name): """Perform actions on multiple phenotypes.""" institute_obj, case_obj = institute_and_case(store, institute_id, case_name) case_url = url_for('.case', institute_id=institute_id, case_name=case_name) action = request.form['action'] hpo_ids = request.form.getlist('hpo_id') user_obj = store.user(current_user.email) if action == 'DELETE': for hpo_id in hpo_ids: # DELETE a phenotype from the list store.remove_phenotype(institute_obj, case_obj, user_obj, case_url, hpo_id) elif action == 'PHENOMIZER': if len(hpo_ids) == 0: hpo_ids = [term['phenotype_id'] for term in case_obj.get('phenotype_terms', [])] username = current_app.config['PHENOMIZER_USERNAME'] password = current_app.config['PHENOMIZER_PASSWORD'] diseases = controllers.hpo_diseases(username, password, hpo_ids) return render_template('cases/diseases.html', diseases=diseases, institute=institute_obj, case=case_obj) elif action == 'GENES': hgnc_symbols = set() for raw_symbols in request.form.getlist('genes'): # avoid empty lists if raw_symbols: hgnc_symbols.update(raw_symbol.split(' ', 1)[0] for raw_symbol in raw_symbols.split('|')) store.update_dynamic_gene_list(case_obj, hgnc_symbols=hgnc_symbols) elif action == 'GENERATE': if len(hpo_ids) == 0: hpo_ids = [term['phenotype_id'] for term in case_obj.get('phenotype_terms', [])] results = store.generate_hpo_gene_list(*hpo_ids) # determine how many HPO terms each gene must match hpo_count = int(request.form.get('min_match') or 1) hgnc_ids = [result[0] for result in results if result[1] >= hpo_count] store.update_dynamic_gene_list(case_obj, hgnc_ids=hgnc_ids, phenotype_ids=hpo_ids) return redirect(case_url)
def events(institute_id, case_name, event_id=None): """Handle events.""" institute_obj, case_obj = institute_and_case(store, institute_id, case_name) link = request.form.get('link') content = request.form.get('content') variant_id = request.args.get('variant_id') user_obj = store.user(current_user.email) if event_id: # delete the event store.delete_event(event_id) else: if variant_id: # create a variant comment variant_obj = store.variant(variant_id) level = request.form.get('level', 'specific') store.comment(institute_obj, case_obj, user_obj, link, variant=variant_obj, content=content, comment_level=level) else: # create a case comment store.comment(institute_obj, case_obj, user_obj, link, content=content) return redirect(request.referrer)
def matchmaker_matches(institute_id, case_name): """Show all MatchMaker matches for a given case""" # check that only authorized users can access MME patients matches user_obj = store.user(current_user.email) if 'mme_submitter' not in user_obj['roles']: flash('unauthorized request', 'warning') return redirect(request.referrer) # Required params for getting matches from MME server: mme_base_url = current_app.config.get('MME_URL') mme_token = current_app.config.get('MME_TOKEN') if not mme_base_url or not mme_token: flash('An error occurred reading matchmaker connection parameters. Please check config file!', 'danger') return redirect(request.referrer) institute_obj, case_obj = institute_and_case(store, institute_id, case_name) data = controllers.mme_matches(case_obj, institute_obj, mme_base_url, mme_token) if data and data.get('server_errors'): flash('MatchMaker server returned error:{}'.format(data['server_errors']), 'danger') return redirect(request.referrer) elif not data: data = { 'institute' : institute_obj, 'case' : case_obj } return data
def variants(institute_id, case_name): """Display a list of SNV variants.""" page = int(request.form.get('page', 1)) institute_obj, case_obj = institute_and_case(store, institute_id, case_name) variant_type = request.args.get('variant_type', 'clinical') # Update filter settings if Clinical Filter was requested default_panels = [] for panel in case_obj['panels']: if panel.get('is_default'): default_panels.append(panel['panel_name']) request.form.get('gene_panels') if bool(request.form.get('clinical_filter')): clinical_filter = MultiDict({ 'variant_type': 'clinical', 'region_annotations': ['exonic','splicing'], 'functional_annotations': SEVERE_SO_TERMS, 'clinsig': [4,5], 'clinsig_confident_always_returned': True, 'gnomad_frequency': str(institute_obj['frequency_cutoff']), 'variant_type': 'clinical', 'gene_panels': default_panels }) if(request.method == "POST"): if bool(request.form.get('clinical_filter')): form = FiltersForm(clinical_filter) form.csrf_token = request.args.get('csrf_token') else: form = FiltersForm(request.form) else: form = FiltersForm(request.args) # populate available panel choices available_panels = case_obj.get('panels', []) + [ {'panel_name': 'hpo', 'display_name': 'HPO'}] panel_choices = [(panel['panel_name'], panel['display_name']) for panel in available_panels] form.gene_panels.choices = panel_choices # upload gene panel if symbol file exists if (request.files): file = request.files[form.symbol_file.name] if request.files and file and file.filename != '': log.debug("Upload file request files: {0}".format(request.files.to_dict())) try: stream = io.StringIO(file.stream.read().decode('utf-8'), newline=None) except UnicodeDecodeError as error: flash("Only text files are supported!", 'warning') return redirect(request.referrer) hgnc_symbols_set = set(form.hgnc_symbols.data) log.debug("Symbols prior to upload: {0}".format(hgnc_symbols_set)) new_hgnc_symbols = controllers.upload_panel(store, institute_id, case_name, stream) hgnc_symbols_set.update(new_hgnc_symbols) form.hgnc_symbols.data = hgnc_symbols_set # reset gene panels form.gene_panels.data = '' # update status of case if vistited for the first time if case_obj['status'] == 'inactive' and not current_user.is_admin: flash('You just activated this case!', 'info') user_obj = store.user(current_user.email) case_link = url_for('cases.case', institute_id=institute_obj['_id'], case_name=case_obj['display_name']) store.update_status(institute_obj, case_obj, user_obj, 'active', case_link) # check if supplied gene symbols exist hgnc_symbols = [] non_clinical_symbols = [] not_found_symbols = [] not_found_ids = [] if (form.hgnc_symbols.data) and len(form.hgnc_symbols.data) > 0: is_clinical = form.data.get('variant_type', 'clinical') == 'clinical' clinical_symbols = store.clinical_symbols(case_obj) if is_clinical else None for hgnc_symbol in form.hgnc_symbols.data: if hgnc_symbol.isdigit(): hgnc_gene = store.hgnc_gene(int(hgnc_symbol)) if hgnc_gene is None: not_found_ids.append(hgnc_symbol) else: hgnc_symbols.append(hgnc_gene['hgnc_symbol']) elif store.hgnc_genes(hgnc_symbol).count() == 0: not_found_symbols.append(hgnc_symbol) elif is_clinical and (hgnc_symbol not in clinical_symbols): non_clinical_symbols.append(hgnc_symbol) else: hgnc_symbols.append(hgnc_symbol) if (not_found_ids): flash("HGNC id not found: {}".format(", ".join(not_found_ids)), 'warning') if (not_found_symbols): flash("HGNC symbol not found: {}".format(", ".join(not_found_symbols)), 'warning') if (non_clinical_symbols): flash("Gene not included in clinical list: {}".format(", ".join(non_clinical_symbols)), 'warning') form.hgnc_symbols.data = hgnc_symbols # handle HPO gene list separately if form.data['gene_panels'] == ['hpo']: hpo_symbols = list(set(term_obj['hgnc_symbol'] for term_obj in case_obj['dynamic_gene_list'])) form.hgnc_symbols.data = hpo_symbols variants_query = store.variants(case_obj['_id'], query=form.data) data = {} if request.form.get('export'): document_header = controllers.variants_export_header(case_obj) export_lines = [] if form.data['chrom'] == 'MT': # Return all MT variants export_lines = controllers.variant_export_lines(store, case_obj, variants_query) else: # Return max 500 variants export_lines = controllers.variant_export_lines(store, case_obj, variants_query.limit(500)) def generate(header, lines): yield header + '\n' for line in lines: yield line + '\n' headers = Headers() headers.add('Content-Disposition','attachment', filename=str(case_obj['display_name'])+'-filtered_variants.csv') # return a csv with the exported variants return Response(generate(",".join(document_header), export_lines), mimetype='text/csv', headers=headers) data = controllers.variants(store, institute_obj, case_obj, variants_query, page) return dict(institute=institute_obj, case=case_obj, form=form, severe_so_terms=SEVERE_SO_TERMS, page=page, **data)
def sv_variants(institute_id, case_name): """Display a list of structural variants.""" page = int(request.form.get('page', 1)) variant_type = request.args.get('variant_type', 'clinical') institute_obj, case_obj = institute_and_case(store, institute_id, case_name) form = SvFiltersForm(request.form) default_panels = [] for panel in case_obj['panels']: if panel['is_default']: default_panels.append(panel['panel_name']) request.form.get('gene_panels') if bool(request.form.get('clinical_filter')): clinical_filter = MultiDict({ 'variant_type': 'clinical', 'region_annotations': ['exonic','splicing'], 'functional_annotations': SEVERE_SO_TERMS, 'thousand_genomes_frequency': str(institute_obj['frequency_cutoff']), 'variant_type': 'clinical', 'clingen_ngi': 10, 'swegen': 10, 'size': 100, 'gene_panels': default_panels }) if(request.method == "POST"): if bool(request.form.get('clinical_filter')): form = SvFiltersForm(clinical_filter) form.csrf_token = request.args.get('csrf_token') else: form = SvFiltersForm(request.form) else: form = SvFiltersForm(request.args) available_panels = case_obj.get('panels', []) + [ {'panel_name': 'hpo', 'display_name': 'HPO'}] panel_choices = [(panel['panel_name'], panel['display_name']) for panel in available_panels] form.gene_panels.choices = panel_choices if form.data['gene_panels'] == ['hpo']: hpo_symbols = list(set(term_obj['hgnc_symbol'] for term_obj in case_obj['dynamic_gene_list'])) form.hgnc_symbols.data = hpo_symbols # update status of case if vistited for the first time if case_obj['status'] == 'inactive' and not current_user.is_admin: flash('You just activated this case!', 'info') user_obj = store.user(current_user.email) case_link = url_for('cases.case', institute_id=institute_obj['_id'], case_name=case_obj['display_name']) store.update_status(institute_obj, case_obj, user_obj, 'active', case_link) variants_query = store.variants(case_obj['_id'], category='sv', query=form.data) data = {} # if variants should be exported if request.form.get('export'): document_header = controllers.variants_export_header(case_obj) export_lines = [] # Return max 500 variants export_lines = controllers.variant_export_lines(store, case_obj, variants_query.limit(500)) def generate(header, lines): yield header + '\n' for line in lines: yield line + '\n' headers = Headers() headers.add('Content-Disposition','attachment', filename=str(case_obj['display_name'])+'-filtered_sv-variants.csv') return Response(generate(",".join(document_header), export_lines), mimetype='text/csv', headers=headers) # return a csv with the exported variants else: data = controllers.sv_variants(store, institute_obj, case_obj, variants_query, page) return dict(institute=institute_obj, case=case_obj, variant_type=variant_type, form=form, severe_so_terms=SEVERE_SO_TERMS, page=page, **data)
def matchmaker_add(institute_id, case_name): """Add or update a case in MatchMaker""" # check that only authorized users can add patients to MME user_obj = store.user(current_user.email) if 'mme_submitter' not in user_obj['roles']: flash('unauthorized request', 'warning') return redirect(request.referrer) institute_obj, case_obj = institute_and_case(store, institute_id, case_name) causatives = False features = False if case_obj.get('suspects') and len(case_obj.get('suspects'))>3: flash('At the moment it is not possible to save to MatchMaker more than 3 pinned variants', 'warning') return redirect(request.referrer) elif case_obj.get('suspects'): causatives = True if case_obj.get('phenotype_terms'): features = True mme_save_options = ['sex', 'features', 'disorders'] for index, item in enumerate(mme_save_options): if item in request.form: log.info('item {} is in request form'.format(item)) mme_save_options[index] = True else: mme_save_options[index] = False genomic_features = request.form.get('genomicfeatures') genes_only = True # upload to matchmaker only gene names if genomic_features == 'variants': genes_only = False # upload to matchmaker both variants and gene names # If there are no genomic features nor HPO terms to share for this case, abort if (not case_obj.get('suspects') and not mme_save_options[1]) or (causatives is False and features is False): flash('In order to upload a case to MatchMaker you need to pin a variant or at least assign a phenotype (HPO term)', 'danger') return redirect(request.referrer) user_obj = store.user(current_user.email) # Required params for sending an add request to MME: mme_base_url = current_app.config.get('MME_URL') mme_accepts = current_app.config.get('MME_ACCEPTS') mme_token = current_app.config.get('MME_TOKEN') if not mme_base_url or not mme_accepts or not mme_token: flash('An error occurred reading matchmaker connection parameters. Please check config file!', 'danger') return redirect(request.referrer) add_result = controllers.mme_add(store=store, user_obj=user_obj, case_obj=case_obj, add_gender=mme_save_options[0], add_features=mme_save_options[1], add_disorders=mme_save_options[2], genes_only=genes_only, mme_base_url = mme_base_url, mme_accepts=mme_accepts, mme_token=mme_token) # flash MME responses (one for each patient posted) n_succes_response = 0 n_inserted = 0 n_updated = 0 category = 'warning' for resp in add_result['server_responses']: message = resp.get('message') if resp.get('status_code') == 200: n_succes_response += 1 else: flash('an error occurred while adding patient to matchmaker: {}'.format(message), 'warning') if message == 'Patient was successfully updated.': n_updated +=1 elif message == 'Patient was successfully inserted into database.': n_inserted +=1 # if at least one patient was inserted or updated into matchmaker, save submission at the case level: if n_inserted or n_updated: category = 'success' store.case_mme_update(case_obj=case_obj, user_obj=user_obj, mme_subm_obj=add_result) flash('Number of new patients in matchmaker:{0}, number of updated records:{1}, number of failed requests:{2}'.format( n_inserted, n_updated, len(add_result.get('server_responses')) - n_succes_response), category) return redirect(request.referrer)
def load_user(user_email): """Returns the currently active user as an object.""" user_obj = store.user(user_email) user_inst = LoginUser(user_obj) if user_obj else None return user_inst