Example #1
0
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)
Example #2
0
def matchmaker_add(request, institute_id, case_name):
    """Add all affected individuals from a case to a MatchMaker server

    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)
    candidate_vars = request.form.getlist("selected_var")

    if len(candidate_vars) > 3:
        flash(
            "At the moment it is not possible to save to MatchMaker more than 3 candidate variants / genes",
            "warning",
        )
        return redirect(request.referrer)

    save_gender = "sex" in request.form
    features = (
        hpo_terms(case_obj)
        if "features" in request.form and case_obj.get("phenotype_terms")
        else []
    )
    disorders = omim_terms(store, case_obj) if "disorders" in request.form else []
    genes_only = request.form.get("genomicfeatures") == "genes"

    if not features and not candidate_vars:
        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)

    # create contact dictionary
    user_obj = store.user(current_user.email)
    contact_info = {
        "name": user_obj["name"],
        "href": "".join(["mailto:", user_obj["email"]]),
        "institution": "Scout software user, Science For Life Laboratory, Stockholm, Sweden",
    }

    submitted_info = {
        "contact": contact_info,
        "sex": save_gender,
        "features": features,
        "disorders": disorders,
        "genes_only": genes_only,
        "patient_id": [],
        "server_responses": [],
    }
    server_responses = []
    n_updated = 0
    for individual in case_obj.get("individuals"):
        if not individual["phenotype"] in [
            2,
            "affected",
        ]:  # include only affected individuals
            continue

        patient = {
            "contact": contact_info,
            "id": ".".join(
                [case_obj["_id"], individual.get("individual_id")]
            ),  # This is a required field form MME
            "label": ".".join([case_obj["display_name"], individual.get("display_name")]),
            "features": features,
            "disorders": disorders,
        }
        if save_gender:
            if individual["sex"] == "1":
                patient["sex"] = "MALE"
            else:
                patient["sex"] = "FEMALE"

        if candidate_vars:
            g_features = genomic_features(
                store, case_obj, individual.get("display_name"), candidate_vars, genes_only
            )
            patient["genomicFeatures"] = g_features
        resp = matchmaker.patient_submit(patient)
        submitted_info["server_responses"].append(
            {
                "patient": patient,
                "message": resp.get("message"),
                "status_code": resp.get("status_code"),
            }
        )
        if resp.get("status_code") != 200:
            flash(
                "an error occurred while adding patient to matchmaker: {}".format(resp),
                "warning",
            )
            continue
        flash(f"Patient {individual.get('display_name')} saved to MatchMaker", "success")
        n_updated += 1

    if n_updated > 0:
        store.case_mme_update(case_obj=case_obj, user_obj=user_obj, mme_subm_obj=submitted_info)

    return n_updated
def test_delete_user_mme_submitter(
    empty_mock_app, user_obj, case_obj, institute_obj, mme_submission, mme_patient
):
    """Test deleting a user that is a contact for a MatchMaker Exchange case"""

    runner = empty_mock_app.test_cli_runner()
    user_email = user_obj["email"]

    # GIVEN a user in the database
    store.user_collection.insert_one(user_obj)

    ## GIVEN a case with an affected individual saved in MatchMaker
    store.institute_collection.insert_one(institute_obj)
    case_obj["individuals"] = [
        {"phenotype": 2, "individual_id": "ADM1059A2", "display_name": "NA12882"}
    ]
    mme_submission["patients"] = [mme_patient]
    case_obj["mme_submission"] = mme_submission
    store.case_collection.insert_one(case_obj)

    ## GIVEN that user_obj is the MME patient's contact
    updated_case = store.case_mme_update(case_obj, user_obj, mme_submission)
    # Submission contact should contain user's email
    assert updated_case["mme_submission"]["subm_user"] == user_email
    # And one associated event should be found in database
    assert store.event_collection.find_one({"verb": "mme_add", "user_id": user_email})

    # WHEN using the CLI command to remove the user, then the function should ask to reassign MME case
    result = runner.invoke(cli, ["delete", "user", "-m", user_email], input="n")
    # AND user shouldn't be removed if answer is no
    assert "Aborted" in result.output
    assert store.user_collection.find_one({"email": user_email})

    # User should also not be removed if answer provided is yes, but new contact doesn't exist
    non_existent_user = "******"
    result = runner.invoke(
        cli, ["delete", "user", "-m", user_email], input="\n".join(["y", non_existent_user])
    )
    assert f"User with email '{non_existent_user}' was not found" in result.output
    assert store.user_collection.find_one({"email": user_email})

    # GIVEN another user with no right over the MME submission
    new_users_email = "*****@*****.**"
    result = runner.invoke(
        cli,
        [
            "load",
            "user",
            "-i",
            institute_obj["_id"],
            "-u",
            "Diana Prince",
            "-m",
            new_users_email,
        ],
    )
    assert result.exit_code == 0

    # THEN if this user is provided as a new MME contact the remove command should fail again
    result = runner.invoke(
        cli, ["delete", "user", "-m", user_email], input="\n".join(["y", new_users_email])
    )
    assert (
        f"Scout user with email '{new_users_email}' doesn't have a 'mme_submitter' role"
        in result.output
    )
    assert store.user_collection.find_one({"email": user_email})

    # GIVEN that the new user has a "mme_submitter" role
    store.user_collection.find_one_and_update(
        {"email": new_users_email}, {"$set": {"roles": ["mme_submitter"]}}
    )
    # THEN the new user can be used as a new MME patient's contact
    result = runner.invoke(
        cli, ["delete", "user", "-m", user_email], input="\n".join(["y", new_users_email])
    )
    assert result.exit_code == 0
    # AND the old user should be removed
    assert store.user_collection.find_one({"email": user_email}) is None
Example #4
0
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)