Beispiel #1
0
def mme_match_proxy(request):
    """
    -This is a proxy URL for backend MME server as per MME spec.
    -Looks for matches for the given individual ONLY in the local MME DB.
    -Expects a single patient (as per MME spec) in the POST

    Args:
        None, all data in POST under key "patient_data"
    Returns:
        Status code and results (as per MME spec), returns raw results from MME Server
    NOTES:
    1. login is not required, since AUTH is handled by MME server, hence missing
    decorator @login_required

    """
    query_patient_data = ''
    for line in request.readlines():
        query_patient_data = query_patient_data + ' ' + line
    response = proxy_request(request,
                             MME_LOCAL_MATCH_URL,
                             data=query_patient_data)
    if response.status_code == 200:
        try:
            _generate_notification_for_incoming_match(response, request,
                                                      query_patient_data)
        except Exception:
            logger.error(
                'Unable to create notification for incoming MME match request')
    return response
Beispiel #2
0
def _handle_phenotips_save_request(request, patient_id):
    """Update the seqr SQL database record for this patient with the just-saved phenotype data."""

    url = '/rest/patients/%s' % patient_id

    cookie_header = request.META.get('HTTP_COOKIE')
    http_headers = {'Cookie': cookie_header} if cookie_header else {}
    response = proxy_request(request, url, headers=http_headers, method='GET', scheme='http', host=settings.PHENOTIPS_SERVER)
    if response.status_code != 200:
        logger.error("ERROR: unable to retrieve patient json. %s %s %s" % (
            url, response.status_code, response.reason_phrase))
        return

    patient_json = json.loads(response.content)

    try:
        if patient_json.get('external_id'):
            # prefer to use the external id for legacy reasons: some projects shared phenotips
            # records by sharing the phenotips internal id, so in rare cases, the
            # Individual.objects.get(phenotips_patient_id=...) may match multiple Individual records
            individual = Individual.objects.get(phenotips_eid=patient_json['external_id'])
        else:
            individual = Individual.objects.get(phenotips_patient_id=patient_json['id'])

    except ObjectDoesNotExist as e:
        logger.error("ERROR: PhenoTips patient id %s not found in seqr Individuals." % patient_json['id'])
        return

    _update_individual_phenotips_data(individual, patient_json)
Beispiel #3
0
def phenotips_edit_handler(request, project_guid, patient_id):
    """Request the PhenoTips Edit page for the given patient_id, and forwards PhenoTips' response to the client.

    Args:
        request: Django HTTP request object
        project_guid (string): project GUID for the seqr project containing this individual
        patient_id (string): PhenoTips internal patient id
    """

    # query string forwarding needed for PedigreeEditor button
    query_string = request.META["QUERY_STRING"]
    url = "/bin/edit/data/{patient_id}?{query_string}".format(
        patient_id=patient_id, query_string=query_string)

    project = Project.objects.get(guid=project_guid)

    check_permissions(project, request.user, CAN_EDIT)

    auth_tuple = _get_phenotips_username_and_password(
        request.user, project, permissions_level=CAN_EDIT)

    return proxy_request(request,
                         url,
                         headers={},
                         auth_tuple=auth_tuple,
                         host=settings.PHENOTIPS_SERVER)
Beispiel #4
0
def mme_match_proxy(request):
    """
    -This is a proxy URL for backend MME server as per MME spec.
    -Looks for matches for the given individual ONLY in the local MME DB.
    -Expects a single patient (as per MME spec) in the POST

    Args:
        None, all data in POST under key "patient_data"
    Returns:
        Status code and results (as per MME spec), returns raw results from MME Server
    NOTES:
    1. login is not required, since AUTH is handled by MME server, hence missing
    decorator @login_required

    """
    query_patient_data = ''
    for line in request.readlines():
        query_patient_data = query_patient_data + ' ' + line
    response = proxy_request(request, MME_LOCAL_MATCH_URL, data=query_patient_data)
    if response.status_code == 200:
        try:
            _generate_notification_for_incoming_match(response, request, query_patient_data)
        except Exception:
            logger.error('Unable to create slack notification for incoming MME match request')
    return response
Beispiel #5
0
def _phenotips_view_handler(request,
                            project_guid,
                            individual_guid,
                            url_template,
                            permission_level=CAN_VIEW):
    """Requests the PhenoTips PDF for the given patient_id, and forwards PhenoTips' response to the client.

    Args:
        request: Django HTTP request object
        project_guid (string): project GUID for the seqr project containing this individual
        individual_guid (string): individual GUID for the seqr individual corresponding to the desired patient
    """

    project = Project.objects.get(guid=project_guid)
    check_permissions(project, request.user, CAN_VIEW)

    individual = Individual.objects.get(guid=individual_guid)
    _create_patient_if_missing(project, individual)
    _set_phenotips_patient_id_if_missing(project, individual)

    # query string forwarding needed for PedigreeEditor button
    query_string = request.META["QUERY_STRING"]
    url = url_template.format(patient_id=individual.phenotips_patient_id,
                              query_string=query_string)

    auth_tuple = _get_phenotips_username_and_password(
        request.user, project, permissions_level=permission_level)

    return proxy_request(request,
                         url,
                         headers={},
                         auth_tuple=auth_tuple,
                         host=settings.PHENOTIPS_SERVER)
Beispiel #6
0
def fetch_igv_track(request, project_guid, igv_track_path):

    get_project_and_check_permissions(project_guid, request.user)

    logger.info("Proxy Request: %s %s" % (request.method, igv_track_path))

    is_cram = igv_track_path.split('?')[0].endswith('.cram')
    if is_cram:
        absolute_path = "/alignments?reference=igvjs/static/data/public/Homo_sapiens_assembly38.fasta&file=igvjs/static/data/readviz-mounts/{0}&options={1}&region={2}".format(
            igv_track_path, request.GET.get('options', ''),
            request.GET.get('region', ''))
        request_kwargs = {
            'host': settings.READ_VIZ_CRAM_PATH,
            'scheme': 'http',
            'filter_request_headers': True,
            'stream': True
        }
    else:
        absolute_path = os.path.join(settings.READ_VIZ_BAM_PATH,
                                     igv_track_path)
        request_kwargs = {
            'auth_tuple': ('xbrowse-bams', 'xbrowse-bams'),
            'verify': False
        }

    return proxy_request(request, absolute_path, **request_kwargs)
Beispiel #7
0
def proxy_to_phenotips(request):
    """This django view accepts GET and POST requests and forwards them to PhenoTips"""

    url = request.get_full_path()
    if any([k for k in DO_NOT_PROXY_URL_KEYWORDS if k.lower() in url.lower()]):
        logger.warn("Blocked proxy url: " + str(url))
        return HttpResponse(status=204)
    logger.info("Proxying url: " + str(url))

    # Some PhenoTips endpoints that use HTTP redirects lose the phenotips JSESSION auth cookie
    # along the way, and don't proxy correctly. Using a Session object as below to store the cookies
    # provides a work-around.
    phenotips_session = requests.Session()
    for key, value in request.COOKIES.items():
        phenotips_session.cookies.set(key, value)

    http_response = proxy_request(request,
                                  url,
                                  data=request.body,
                                  session=phenotips_session,
                                  host=settings.PHENOTIPS_SERVER,
                                  filter_request_headers=True)

    # if this is the 'Quick Save' request, also save a copy of phenotips data in the seqr SQL db.
    match = re.match(PHENOTIPS_QUICK_SAVE_URL_REGEX, url)
    if match:
        _handle_phenotips_save_request(request, patient_id=match.group(1))

    return http_response
Beispiel #8
0
def _handle_phenotips_save_request(request, patient_id):
    """Update the seqr SQL database record for this patient with the just-saved phenotype data."""

    url = '/rest/patients/%s' % patient_id

    cookie_header = request.META.get('HTTP_COOKIE')
    http_headers = {'Cookie': cookie_header} if cookie_header else {}
    response = proxy_request(request, url, headers=http_headers, method='GET', scheme='http', host=PHENOTIPS_SERVER)
    if response.status_code != 200:
        logger.error("ERROR: unable to retrieve patient json. %s %s %s" % (
            url, response.status_code, response.reason_phrase))
        return

    patient_json = json.loads(response.content)

    try:
        if patient_json.get('external_id'):
            # prefer to use the external id for legacy reasons: some projects shared phenotips
            # records by sharing the phenotips internal id, so in rare cases, the
            # Individual.objects.get(phenotips_patient_id=...) may match multiple Individual records
            individual = Individual.objects.get(phenotips_eid=patient_json['external_id'])
        else:
            individual = Individual.objects.get(phenotips_patient_id=patient_json['id'])

    except ObjectDoesNotExist as e:
        logger.error("ERROR: PhenoTips patient id %s not found in seqr Individuals." % patient_json['id'])
        return

    _update_individual_phenotips_data(individual, patient_json)
Beispiel #9
0
def proxy_to_phenotips(request):
    """This django view accepts GET and POST requests and forwards them to PhenoTips"""

    url = request.get_full_path()
    if any([k for k in DO_NOT_PROXY_URL_KEYWORDS if k.lower() in url.lower()]):
        logger.warn("Blocked proxy url: " + str(url))
        return HttpResponse(status=204)
    logger.info("Proxying url: " + str(url))

    # Some PhenoTips endpoints that use HTTP redirects lose the phenotips JSESSION auth cookie
    # along the way, and don't proxy correctly. Using a Session object as below to store the cookies
    # provides a work-around.
    phenotips_session = requests.Session()
    for key, value in request.COOKIES.items():
        phenotips_session.cookies.set(key, value)

    http_response = proxy_request(request, url, data=request.body, session=phenotips_session,
                                  host=settings.PHENOTIPS_SERVER, filter_request_headers=True)

    # if this is the 'Quick Save' request, also save a copy of phenotips data in the seqr SQL db.
    match = re.match(PHENOTIPS_QUICK_SAVE_URL_REGEX, url)
    if match:
        _handle_phenotips_save_request(request, patient_id=match.group(1))

    return http_response
Beispiel #10
0
def _make_api_call(method,
                   url,
                   http_headers={},
                   data=None,
                   auth_tuple=None,
                   expected_status_code=200,
                   parse_json_resonse=True,
                   verbose=False):
    """Utility method for making an API call and then parsing & returning the json response.

    Args:
        method (string): 'GET' or 'POST'
        url (string): url path, starting with '/' (eg. '/bin/edit/data/P0000001')
        data (string): request body - used for POST, PUT, and other such requests.
        auth_tuple (tuple): ("username", "password") pair
        expected_status_code (int or list): expected server response code
        parse_json_resonse (bool): whether to parse and return the json response
        verbose (bool): whether to print details about the request & response
    Returns:
        json object or None if response content is empty
    """

    try:
        response = proxy_request(None,
                                 url,
                                 headers=http_headers,
                                 method=method,
                                 scheme='http',
                                 data=data,
                                 auth_tuple=auth_tuple,
                                 host=settings.PHENOTIPS_SERVER,
                                 verbose=verbose)
    except requests.exceptions.RequestException as e:
        raise PhenotipsException(e.message)
    if (isinstance(expected_status_code, int)
            and response.status_code != expected_status_code) or (
                isinstance(expected_status_code, list)
                and response.status_code not in expected_status_code):
        raise PhenotipsException(
            "Unable to retrieve %s. response code = %s: %s" %
            (url, response.status_code, response.reason_phrase))

    if parse_json_resonse:
        if not response.content:
            return {}

        try:
            return json.loads(response.content)
        except ValueError as e:
            logger.error(
                "Unable to parse PhenoTips response for %s request to %s" %
                (method, url))
            raise PhenotipsException("Unable to parse response for %s:\n%s" %
                                     (url, e))
    else:
        return dict(response.items())
Beispiel #11
0
def proxy_to_kibana(request):
    try:

        return proxy_request(request, host=KIBANA_SERVER, url=request.get_full_path(), data=request.body, stream=True)
        # use stream=True because kibana returns gziped responses, and this prevents the requests module from
        # automatically unziping them
    except ConnectionError as e:
        logger.error(e)

        return HttpResponse("Error: Unable to connect to Kibana")
Beispiel #12
0
def proxy_to_kibana(request):
    try:

        return proxy_request(request, host=KIBANA_SERVER, url=request.get_full_path(), data=request.body, stream=True)
        # use stream=True because kibana returns gziped responses, and this prevents the requests module from
        # automatically unziping them
    except ConnectionError as e:
        logger.error(e)

        return HttpResponse("Error: Unable to connect to Kibana")
Beispiel #13
0
def proxy_to_igv(igv_track_path, params, request=None, **request_kwargs):
    is_cram = igv_track_path.split('?')[0].endswith('.cram')
    if is_cram:
        absolute_path = "/alignments?reference=igvjs/static/data/public/Homo_sapiens_assembly38.fasta&file=igvjs/static/data/readviz-mounts/{0}&options={1}&region={2}".format(
            igv_track_path, params.get('options', ''), params.get('region', ''))
        request_kwargs.update({'host': settings.READ_VIZ_CRAM_PATH, 'stream': True})
    else:
        absolute_path = os.path.join(settings.READ_VIZ_BAM_PATH, igv_track_path)
        request_kwargs.update({'auth_tuple': ('xbrowse-bams', 'xbrowse-bams'), 'verify': False})

    return proxy_request(request, absolute_path, **request_kwargs)
Beispiel #14
0
def mme_metrics_proxy(request):
    """
    -This is a proxy URL for backend MME server as per MME spec.
    -Proxies public metrics endpoint

    Args:
        None, all data in POST under key "patient_data"
    Returns:
        Metric JSON from matchbox
    NOTES:
    1. seqr login IS NOT required, since AUTH via toke in POST is handled by MME server, hence no
    decorator @login_required. This is a PUBLIC endpoint

    """
    return proxy_request(request, MME_MATCHBOX_PUBLIC_METRICS_URL)
Beispiel #15
0
def mme_metrics_proxy(request):
    """
    -This is a proxy URL for backend MME server as per MME spec.
    -Proxies public metrics endpoint

    Args:
        None, all data in POST under key "patient_data"
    Returns:
        Metric JSON from matchbox
    NOTES:
    1. seqr login IS NOT required, since AUTH via toke in POST is handled by MME server, hence no
    decorator @login_required. This is a PUBLIC endpoint

    """
    return proxy_request(request, MME_MATCHBOX_PUBLIC_METRICS_URL)
Beispiel #16
0
def _make_api_call(
        method,
        url,
        http_headers={},
        data=None,
        auth_tuple=None,
        expected_status_code=200,
        parse_json_resonse=True,
        verbose=False):
    """Utility method for making an API call and then parsing & returning the json response.

    Args:
        method (string): 'GET' or 'POST'
        url (string): url path, starting with '/' (eg. '/bin/edit/data/P0000001')
        data (string): request body - used for POST, PUT, and other such requests.
        auth_tuple (tuple): ("username", "password") pair
        expected_status_code (int or list): expected server response code
        parse_json_resonse (bool): whether to parse and return the json response
        verbose (bool): whether to print details about the request & response
    Returns:
        json object or None if response content is empty
    """

    try:
        response = proxy_request(None, url, headers=http_headers, method=method, scheme='http', data=data,
                                 auth_tuple=auth_tuple, host=settings.PHENOTIPS_SERVER, verbose=verbose)
    except requests.exceptions.RequestException as e:
        raise PhenotipsException(e.message)
    if (isinstance(expected_status_code, int) and response.status_code != expected_status_code) or (
        isinstance(expected_status_code, list) and response.status_code not in expected_status_code):
        raise PhenotipsException("Unable to retrieve %s. response code = %s: %s" % (
            url, response.status_code, response.reason_phrase))

    if parse_json_resonse:
        if not response.content:
            return {}

        try:
            return json.loads(response.content)
        except ValueError as e:
            logger.error("Unable to parse PhenoTips response for %s request to %s" % (method, url))
            raise PhenotipsException("Unable to parse response for %s:\n%s" % (url, e))
    else:
        return dict(response.items())
Beispiel #17
0
def proxy_to_igv(igv_track_path, params, request=None, **request_kwargs):
    is_cram = igv_track_path.split('?')[0].endswith('.cram')
    if is_cram:
        absolute_path = "/alignments?reference=igvjs/static/data/public/Homo_sapiens_assembly38.fasta&file=igvjs/static/data/readviz-mounts/{0}&options={1}&region={2}".format(
            igv_track_path, params.get('options', ''),
            params.get('region', ''))
        request_kwargs.update({
            'host': settings.READ_VIZ_CRAM_PATH,
            'stream': True
        })
    else:
        absolute_path = os.path.join(settings.READ_VIZ_BAM_PATH,
                                     igv_track_path)
        request_kwargs.update({
            'auth_tuple': ('xbrowse-bams', 'xbrowse-bams'),
            'verify': False
        })

    return proxy_request(request, absolute_path, **request_kwargs)
Beispiel #18
0
def phenotips_pdf_handler(request, project_guid, patient_id):
    """Requests the PhenoTips PDF for the given patient_id, and forwards PhenoTips' response to the client.

    Args:
        request: Django HTTP request object
        project_guid (string): project GUID for the seqr project containing this individual
        patient_id (string): PhenoTips internal patient id
    """

    url = "/bin/export/data/{patient_id}?format=pdf&pdfcover=0&pdftoc=0&pdftemplate=PhenoTips.PatientSheetCode".format(
        patient_id=patient_id)
    project = Project.objects.get(guid=project_guid)

    check_permissions(project, request.user, CAN_VIEW)

    auth_tuple = _get_phenotips_username_and_password(
        request.user, project, permissions_level=CAN_VIEW)

    return proxy_request(request,
                         url,
                         headers={},
                         auth_tuple=auth_tuple,
                         host=settings.PHENOTIPS_SERVER)
Beispiel #19
0
def _phenotips_view_handler(request, project_guid, individual_guid, url_template, permission_level=CAN_VIEW):
    """Requests the PhenoTips PDF for the given patient_id, and forwards PhenoTips' response to the client.

    Args:
        request: Django HTTP request object
        project_guid (string): project GUID for the seqr project containing this individual
        individual_guid (string): individual GUID for the seqr individual corresponding to the desired patient
    """

    project = Project.objects.get(guid=project_guid)
    check_permissions(project, request.user, CAN_VIEW)

    individual = Individual.objects.get(guid=individual_guid)
    _create_patient_if_missing(project, individual)
    _set_phenotips_patient_id_if_missing(project, individual)

    # query string forwarding needed for PedigreeEditor button
    query_string = request.META["QUERY_STRING"]
    url = url_template.format(patient_id=individual.phenotips_patient_id, query_string=query_string)

    auth_tuple = _get_phenotips_username_and_password(request.user, project, permissions_level=permission_level)

    return proxy_request(request, url, headers={}, auth_tuple=auth_tuple, host=settings.PHENOTIPS_SERVER)
Beispiel #20
0
def mme_metrics_proxy(request):
    return proxy_request(request,
                         MME_MATCHBOX_METRICS_URL,
                         headers=MME_HEADERS)
Beispiel #21
0
def mme_metrics_proxy(request):
    return proxy_request(request, MME_MATCHBOX_METRICS_URL, headers=MME_HEADERS)