Esempio n. 1
0
def check_access_interaction_and_resource_type(resource_type, intn_type, rr):
    """ usage is deny = check_access_interaction_and_resource_type()

    :param
    resource_type: resource
    intn_type: interaction type
    rr: ResourceRouter


    """
    try:
        rt = SupportedResourceType.objects.get(resourceType=resource_type,
                                               fhir_source=rr)
        # force comparison to lower case to make case insensitive check
        if intn_type.lower() not in map(str.lower,
                                        rt.get_supported_interaction_types()):
            msg = 'The interaction: %s is not permitted on %s FHIR ' \
                  'resources on this FHIR sever.' % (intn_type,
                                                     resource_type)
            logger_debug.debug(msg="%s:%s" % ("403", msg))
            return kickout_403(msg)
    except SupportedResourceType.DoesNotExist:
        msg = '%s is not a supported resource ' \
              'type on this FHIR server.' % resource_type
        logger_debug.debug(msg="%s:%s" % ("404", msg))
        return kickout_404(msg)

    return False
Esempio n. 2
0
def check_access_interaction_and_resource_type(resource_type, interaction_type):
    try:
        rt = SupportedResourceType.objects.get(resource_name=resource_type)
        if interaction_type not in rt.get_supported_interaction_types():
            msg = 'The interaction {} is not permitted on {} FHIR resources on this FHIR sever.'.format(
                interaction_type, resource_type
            )
            return kickout_403(msg)
    except SupportedResourceType.DoesNotExist:
        msg = '{} is not a supported resource type on this FHIR server.'.format(resource_type)
        return kickout_404(msg)
    return False
def check_access_interaction_and_resource_type(resource_type, intn_type):
    """ usage is deny = check_access_interaction_and_resource_type()

     """
    try:
        rt = SupportedResourceType.objects.get(resource_name=resource_type)
        # force comparison to lower case to make case insensitive check
        if intn_type.lower() not in map(str.lower,
                                        rt.get_supported_interaction_types()):
            msg = 'The interaction: %s is not permitted on %s FHIR ' \
                  'resources on this FHIR sever.' % (intn_type,
                                                     resource_type)
            return kickout_403(msg)
    except SupportedResourceType.DoesNotExist:
        msg = '%s is not a supported resource ' \
              'type on this FHIR server.' % resource_type
        return kickout_404(msg)

    return False
Esempio n. 4
0
def create(request, resource_type):
    """
    Create FHIR Interaction
    Example client use in curl:
    curl -H 'Content-Type: application/json' --data @test.json http://127.0.0.1:8000/fhir/Practitioner

    We need to deal with possible multiple resourceType or filter by
    FHIRServer from Crosswalk
    """
    # TODO: Filter by FHIRServer
    interaction_type = 'create'
    # re-route to hello if no resource type is given:
    if not resource_type:
        return hello(request)

    try:
        rt = SupportedResourceType.objects.get(resourceType=resource_type)
        if interaction_type not in rt.get_supported_interaction_types(
        ) and request.method == 'GET':
            # GET means that this is a search so re-route
            return search(request, resource_type)

        elif interaction_type not in rt.get_supported_interaction_types():
            msg = 'The interaction %s is not permitted on %s FHIR resources on this FHIR sever.' % (
                interaction_type,
                resource_type,
            )
            return kickout_403(msg)

    except SupportedResourceType.DoesNotExist:
        msg = '%s is not a supported resource type on this FHIR server.' % (
            resource_type)
        return kickout_404(msg)

    # Catch all for GETs to re-direct to search if CREATE permission is valid
    if request.method == 'GET':
        return search(request, resource_type)

    if request.method == 'POST':
        # Check if request body is JSON ------------------------
        try:
            j = json.loads(request.body.decode('utf-8'),
                           object_pairs_hook=OrderedDict)
            if not isinstance(j, dict):
                kickout_400(
                    'The request body did not contain a JSON object i.e. {}.')
        except:
            return kickout_400("The request body did not contain valid JSON.")

        # if j.has_key('id'): # throws error if id not in OrderedDict
        if 'id' in j:
            return kickout_400(
                "Create cannot have an id. Perhaps you meant to perform an update?"
            )

        # Check json_schema is valid
        try:
            json_schema = json.loads(rt.json_schema,
                                     object_pairs_hook=OrderedDict)
        except:
            return kickout_500(
                'The JSON Schema on the server did not contain valid JSON.')

        # Check jsonschema
        if json_schema:
            try:
                validate(j, json_schema)
            except ValidationError:
                msg = 'JSON Schema Conformance Error. %s' % (str(
                    sys.exc_info()[1][0]))
                return kickout_400(msg)

        # write_to_mongo - TBD
        response = OrderedDict()
        response['id'] = str(uuid.uuid4())

        meta = OrderedDict()

        if j.get('meta').get('versionId'):
            meta['versionId'] = j.get('meta').get('versionId')
        else:
            meta['versionId'] = 1

        if j.get('meta').get('lastUpdated'):
            meta['lastUpdated'] = j.get('meta').get('lastUpdated')
        else:
            meta['lastUpdated'] = '%sZ' % (
                datetime.datetime.utcnow().isoformat())

        meta['id'] = response['id']
        response['meta'] = meta

        hr = HttpResponse(json.dumps(response, indent=4),
                          status=201,
                          content_type='application/json')
        hr['Location'] = '%s/%s/%s/_history/%s' % (
            'http://127.0.0.1:8000/fhir',
            resource_type,
            meta['id'],
            meta['versionId'],
        )
        return hr

    # This is something other than GET or POST (i.e. a  GET)
    if request.method not in ('GET', 'POST'):
        od = OrderedDict()
        od['request_method'] = request.method
        od['interaction_type'] = 'create'
        od['resource_type'] = resource_type
        od['note'] = 'Perform an HTTP POST to this URL with the JSON resource as the request body.'

        return HttpResponse(json.dumps(od, indent=4),
                            content_type='application/json')
Esempio n. 5
0
def read_search(request,
                interaction_type,
                resource_type,
                id=None,
                vid=None,
                *args,
                **kwargs):
    """
    Read from remote FHIR Server

    :param request:
    :param interaction_type:
    :param resource_type:
    :param id:
    :param vid:
    :param args:
    :param kwargs:
    :return:

    # Example client use in curl:
    # curl  -X GET http://127.0.0.1:8000/fhir/Practitioner/1234?_format=json


    """

    logger.debug('\n========================\n'
                 'INTERACTION_TYPE: %s' % interaction_type)

    # Get the users crosswalk
    cx = get_crosswalk(request.user)

    # cx will be the crosswalk record or None
    rr = get_resourcerouter(cx)

    # Check if this interaction type and resource type combo is allowed.
    deny = check_access_interaction_and_resource_type(resource_type,
                                                      interaction_type, rr)
    if deny:
        # if not allowed, return a 4xx error.
        return deny

    srtc = check_rt_controls(resource_type, rr)
    # We get back a Supported ResourceType Control record or None
    # with earlier if deny step we should have a valid srtc.

    if srtc.secure_access and request.user.is_anonymous():
        return kickout_403('Error 403: %s Resource access is controlled.'
                           ' Login is required:'
                           '%s' % (resource_type, request.user.is_anonymous()))
        # logger.debug('srtc: %s' % srtc)

    if (cx is None and srtc is not None):
        # There is a srtc record so we need to check override_search
        if srtc.override_search:
            # If user is not in Crosswalk and srtc has search_override = True
            # We need to prevent search to avoid data leakage.
            return kickout_403('Error 403: %s Resource is access controlled.'
                               ' No records are linked to user:'******'%s' % (resource_type, request.user))

    ################################################
    #
    # Now we should have sorted out all the bounces
    # Now to structure the call to the back-end
    #
    ################################################

    # construct the server address, path and release
    # Get the crosswalk.fhir_source = ResourceRouter

    # Build url from rr.server_address + rr.server_path + rr.server_release

    target_url = rr.fhir_url

    # add resource_type + '/'
    target_url += srtc.resourceType

    target_url += "/"

    # Analyze the _format parameter
    # Sve the display _format

    input_parameters = request.GET

    # requested_format = 'json' | 'xml' | 'html'
    requested_format = save_request_format(input_parameters)

    format_mode = eval_format_type(requested_format)

    # prepare the back-end _format setting
    back_end_format = set_fhir_format(format_mode)

    # remove the oauth parameters
    payload = strip_oauth(request.GET)

    # Get payload with oauth parameters removed
    # Add the format for back-end
    payload['_format'] = back_end_format

    # remove the srtc.search_block parameters
    payload = block_params(payload, srtc)

    # print("id:%s" % str(id))
    # move resource_id to _id=resource_id
    id_dict = set_resource_id(srtc, id, cx.fhir_id)
    # id_dict['query_mode'] = 'search' | 'read'
    # id_dict['url_id'] = '' | id
    # id_dict['_id'] = id  | ''
    # id_dict['patient'] = patient_id | ''

    # resource_id = id_dict['url_id']

    # Add the srtc.search_add parameters
    # added_params = add_params(srtc,
    #                           patient_id=id_dict['patient'],
    #                           key=id_dict['url_id'])

    # print("Added Params:%s" % added_params)

    params_list = search_add_to_list(srtc.search_add)

    # print("Params_List:%s" % params_list)

    payload = payload_additions(payload, params_list)

    # print('id_dict:%s' % id_dict)
    # print("what have we got?:%s" % id_dict)
    if id_dict['_id']:
        # add rt_id into the search parameters
        if id_dict['_id'] is not None:
            payload['_id'] = id_dict['_id']

    if resource_type.lower() == 'patient':
        # print("Working resource:%s" % resource_type)
        payload['_id'] = id_dict['patient']
        if payload['patient']:
            del payload['patient']

    for pyld_k, pyld_v in payload.items():
        if pyld_v is None:
            pass
        elif '%PATIENT%' in pyld_v:
            # replace %PATIENT% with cx.fhir_id

            payload = payload_var_replace(payload,
                                          pyld_k,
                                          new_value=id_dict['patient'],
                                          old_value='%PATIENT%')
    # print("post futzing:%s" % id_dict)
    # add the _format setting
    payload['_format'] = back_end_format

    # Make the request_call
    r = request_get_with_parms(request,
                               target_url,
                               json.loads(json.dumps(payload)),
                               cx,
                               reverse_lazy('home'),
                               timeout=settings.REQUEST_CALL_TIMEOUT)

    ################################################
    #
    # Now we process the response from the back-end
    #
    ################################################

    # if 'status_code' in r:
    #     r_status_code = r.status_code
    # else:
    #     r_status_code = 500

    rewrite_list = build_rewrite_list(cx)
    host_path = get_host_url(request, resource_type)[:-1]

    try:
        text_in = r.text
    except:
        text_in = ""

    text_out = post_process_request(request, back_end_format, host_path,
                                    text_in, rewrite_list)

    if resource_type.lower() == 'patient':
        display_key = id_dict['patient']
    else:
        display_key = id
    od = build_output_dict(request, OrderedDict(), resource_type, display_key,
                           vid, interaction_type, requested_format, text_out)

    ################################################
    #
    # Now display the result
    #
    ################################################
    ikey = ''
    try:
        ikey = find_ikey(r.text)
    except:
        ikey = ''

    if ikey is not '':

        save_url = get_target_url(target_url, resource_type)
        # print("Store target_url:%s but only: %s" % (target_url,save_url))
        content = {
            'fhir_to': save_url,
            'rwrt_list': rewrite_list,
            'res_type': resource_type,
            'intn_type': interaction_type,
            'key': display_key,
            'vid': vid,
            'resource_router': rr.id
        }
        sesn_var = write_session(request, ikey, content, skey=SESSION_KEY)
        if sesn_var:
            logger.debug("Problem writing session variables."
                         " Returned %s" % sesn_var)

    if format_mode == 'xml':
        # logger.debug('We got xml back in od')
        return HttpResponse(r.text,
                            content_type='application/%s' % requested_format)
        # return HttpResponse(tostring(dict_to_xml('content', od)),
        #                     content_type='application/%s' % requested_format)

    elif format_mode == 'json':
        # logger.debug('We got json back in od')
        return HttpResponse(pretty_json(od['bundle']),
                            content_type='application/%s' % requested_format)

    query_string = build_querystring(request.GET.copy())
    if "xml" in requested_format:
        # logger.debug("Sending text_out for display: %s" % text_out[0:100])
        div_text = get_div_from_xml(text_out)
        # print("DIV TEXT returned:[%s]%s" % (type(div_text), div_text))
        return render(
            request, 'bluebutton/default_xml.html', {
                'output': text_out,
                'content': {
                    'parameters': query_string,
                    'resource_type': resource_type,
                    'request_method': "GET",
                    'interaction_type': interaction_type,
                    'div_texts': [
                        div_text,
                    ],
                    'source': cx.fhir_source.name
                }
            })

    else:
        text_out = pretty_json(od['bundle'])
        div_text = get_div_from_json(od['bundle'])

    # logger.debug('We got a different format:%s' % requested_format)
    return render(
        request, 'bluebutton/default.html', {
            'output': text_out,
            'content': {
                'parameters': query_string,
                'resource_type': resource_type,
                'request_method': "GET",
                'interaction_type': interaction_type,
                'div_texts': div_text,
                'source': cx.fhir_source.name
            }
        })
Esempio n. 6
0
def generic_read(request,
                 interaction_type,
                 resource_type,
                 id=None,
                 vid=None,
                 *args,
                 **kwargs):
    """
    Read from remote FHIR Server

    :param request:
    :param interaction_type:
    :param resource_type:
    :param id:
    :param vid:
    :param args:
    :param kwargs:
    :return:

    # Example client use in curl:
    # curl  -X GET http://127.0.0.1:8000/fhir/Practitioner/1234

    Process flow:

    Is it a valid request?

    Get the target server info

    Get the request modifiers

    Construct the call

    Make the call

    Check result for errors

    Deliver the formatted result


    """
    # DONE: Fix to allow url_id in url for non-key resources.
    # eg. Patient is key resource so replace url if override_url_id is True
    # if override_url_id is not set allow url_id to be applied and check
    # if search_override is True.
    # interaction_type = 'read' or '_history' or 'vread' or 'search'
    logger.debug('\n========================\n'
                 'INTERACTION_TYPE: %s' % interaction_type)

    # Get the users crosswalk
    cx = get_crosswalk(request.user)

    # cx will be the crosswalk record or None
    rr = get_resourcerouter(cx)

    # Check if this interaction type and resource type combo is allowed.
    deny = check_access_interaction_and_resource_type(resource_type,
                                                      interaction_type, rr)
    if deny:
        # if not allowed, return a 4xx error.
        return deny

    srtc = check_rt_controls(resource_type, rr)
    # We get back a Supported ResourceType Control record or None
    # with earlier if deny step we should have a valid srtc.

    if srtc.secure_access and request.user.is_anonymous():
        return kickout_403('Error 403: %s Resource access is controlled.'
                           ' Login is required:'
                           '%s' % (resource_type, request.user.is_anonymous()))
    # logger.debug('srtc: %s' % srtc)

    if cx is None:
        logger.debug('Crosswalk for %s does not exist' % request.user)

    if (cx is None and srtc is not None):
        # There is a srtc record so we need to check override_search
        if srtc.override_search:
            # If user is not in Crosswalk and srtc has search_override = True
            # We need to prevent search to avoid data leakage.
            return kickout_403('Error 403: %s Resource is access controlled.'
                               ' No records are linked to user:'******'%s' % (resource_type, request.user))

    # Need to check if user is logged in.
    # request.user.is_anonymous()
    #
    # if request.user.is_anonymous():

    # Request.user = user
    # interaction_type = read | _history | vread
    # resource_type = 'Patient | Practitioner | ExplanationOfBenefit ...'
    # id = fhir_id (potentially masked)
    # vid = Version Id

    # Check the resource_type to see if it has a url
    # Check the resource_type to see if masking is required
    # Get the FHIR_Server (from crosswalk via request.user)
    # if masked get the fhir_id from crosswalk
    # if search_override strip search items (search_block)
    # if search_override add search keys

    fhir_url = ''
    # change source of default_url to ResourceRouter

    default_path = get_default_path(srtc.resource_name, cx=cx)
    # get the default path for resource with ending "/"
    # You need to add resource_type + "/" for full url

    if srtc:
        # logger.debug('SRTC:%s' % srtc)

        fhir_url = default_path + resource_type + '/'

        if srtc.override_url_id:
            fhir_url += cx.fhir_id + "/"

        # logger.debug('fhir_url:%s' % fhir_url)
    else:
        logger.debug('CX:%s' % cx)
        if cx:
            fhir_url = cx.get_fhir_resource_url(resource_type)
        else:
            # logger.debug('FHIRServer:%s' % FhirServerUrl())
            fhir_url = FhirServerUrl() + resource_type + '/'

    # #### SEARCH

    if interaction_type == 'search':
        key = None
    else:
        key = masked_id(resource_type, cx, srtc, id, slash=False)

        print("\nMasked_id-key:%s from r_id:%s "
              "and cx-fhir_id:%s\n" % (key, id, cx.fhir_id))

        # add key to fhir_url unless already in place.
        fhir_url = add_key_to_fhir_url(fhir_url, key)

    logger.debug('FHIR URL with key:%s' % fhir_url)

    ###########################

    # Now we get to process the API Call.

    # Internal handling format is json
    # Remove the oauth elements from the GET
    pass_params = strip_oauth(request.GET)

    # Let's store the inbound requested format
    # We need to simplify the format call to the backend
    # so that we get data we can manipulate
    requested_format = request_format(pass_params)

    # now we simplify the format/_format request for the back-end
    pass_params = strip_format_for_back_end(pass_params)
    if "_format" in pass_params:
        back_end_format = pass_params['_format']
    else:
        back_end_format = "json"

    # #### SEARCH

    if interaction_type == 'search':
        if cx is not None:
            # logger.debug("cx.fhir_id=%s" % cx.fhir_id)
            if cx.fhir_id.__contains__('/'):
                id = cx.fhir_id.split('/')[1]
            else:
                id = cx.fhir_id
            # logger.debug("Patient Id:%s" % r_id)

    if resource_type.lower() == "patient":
        key = cx.fhir_id
    else:
        key = id

    pass_params = build_params(pass_params, srtc, key, patient_id=cx.fhir_id)

    # Add the call type ( READ = nothing, VREAD, _HISTORY)
    # Before we add an identifier key
    pass_to = fhir_call_type(interaction_type, fhir_url, vid)

    logger.debug('\nHere is the URL to send, %s now add '
                 'GET parameters %s' % (pass_to, pass_params))

    if pass_params is not '':
        pass_to += pass_params

    logger.debug("\nMaking request:%s" % pass_to)

    ###############################################
    ###############################################
    # Now make the call to the backend API

    if interaction_type == "search":
        r = request_call(request,
                         pass_to,
                         cx,
                         reverse_lazy('home'),
                         timeout=settings.REQUEST_CALL_TIMEOUT)
    else:
        r = request_call(request, pass_to, cx, reverse_lazy('home'))

    # BACK FROM THE CALL TO BACKEND
    ###############################################
    ###############################################

    # logger.debug("r returned: %s" % r)

    # Check for Error here
    try:
        error_check = r.text
        logger.debug("We got r.text back:%s" % r.text[:200] + "...")
    except:
        error_check = "HttpResponse status_code=502"
        logger.debug("Something went wrong with call to %s" % pass_to)
    logger.debug("Checking for errors:%s" % error_check[:200] + "...")
    if 'status_code' in error_check:
        # logger.debug("We have a status code to check: %s" % r)
        if r.status_code in ERROR_CODE_LIST:
            logger.debug("\nError Status Code:%s" % r.status_code)
            return error_status(r, r.status_code)
    elif 'status_code=302' in error_check:
        return error_status(r, 302)
    elif 'status_code=502' in error_check:
        return error_status(r, 502)
    else:
        logger.debug("Status Code:%s " "in:%s" % (r.status_code, r))

    # We should have a 200 - good record to deal with
    # We can occasionaly get a 200 with a Connection Error. eg. Timeout
    try:
        if "ConnectionError" in r.text:
            logger.debug("Error:%s" % r.text)
            return error_status(r, 502)
    except:
        pass

    text_out = ''
    # if 'text' in r:
    #     logger.debug('r:%s' % r.text)
    #     logger_debug.debug('r:%s' % r.text)
    # else:
    #     logger.debug("r not returning text:%s" % r)
    #     logger_debug.debug("r not returning text:%s" % r)
    #     logger.debug("r.json: %s" % json.dumps(r.json))

    # logger.debug('Rewrite List:%s' % rewrite_url_list)

    host_path = get_host_url(request, resource_type)[:-1]
    # logger.debug('host path:%s' % host_path)

    # Add default FHIR Server URL to re-write
    rewrite_url_list = build_rewrite_list(cx)
    # print("Starting Rewrite_list:%s" % rewrite_url_list)

    # ct_detail = get_content_type(r)
    # logger.debug('Content-Type:%s \n work with %s' % (ct_detail,
    #                                                   back_end_format))

    try:
        text_in = r.text
    except:
        text_in = ""

    text_out = post_process_request(request, back_end_format, host_path,
                                    text_in, rewrite_url_list)

    od = build_output_dict(request, OrderedDict(), resource_type, key, vid,
                           interaction_type, requested_format, text_out)

    # write session variables if _getpages was found
    ikey = ''
    try:
        ikey = find_ikey(r.text)
    except:
        ikey = ''

    if ikey is not '':

        save_url = get_target_url(fhir_url, resource_type)
        # print("Store fhir_url:%s but only: %s" % (fhir_url,save_url))
        content = {
            'fhir_to': save_url,
            'rwrt_list': rewrite_url_list,
            'res_type': resource_type,
            'intn_type': interaction_type,
            'key': key,
            'vid': vid,
            'resource_router': rr.id
        }
        sesn_var = write_session(request, ikey, content, skey=SESSION_KEY)
        if sesn_var:
            logger.debug("Problem writing session variables."
                         " Returned %s" % sesn_var)
    if requested_format == 'xml':
        # logger.debug('We got xml back in od')
        return HttpResponse(r.text,
                            content_type='application/%s' % requested_format)
        # return HttpResponse(tostring(dict_to_xml('content', od)),
        #                     content_type='application/%s' % requested_format)

    elif requested_format == 'json':
        # logger.debug('We got json back in od')
        return HttpResponse(pretty_json(od['bundle']),
                            content_type='application/%s' % requested_format)

    query_string = build_querystring(request.GET.copy())
    if "xml" in requested_format:
        # logger.debug("Sending text_out for display: %s" % text_out[0:100])
        div_text = get_div_from_xml(text_out)
        # print("DIV TEXT returned:[%s]%s" % (type(div_text), div_text))
        return render(
            request, 'bluebutton/default_xml.html', {
                'output': text_out,
                'content': {
                    'parameters': query_string,
                    'resource_type': resource_type,
                    'request_method': "GET",
                    'interaction_type': interaction_type,
                    'div_texts': [
                        div_text,
                    ],
                    'source': cx.fhir_source.name
                }
            })

    else:
        text_out = pretty_json(od['bundle'])
        div_text = get_div_from_json(od['bundle'])

    # logger.debug('We got a different format:%s' % requested_format)
    return render(
        request, 'bluebutton/default.html', {
            'output': text_out,
            'content': {
                'parameters': query_string,
                'resource_type': resource_type,
                'request_method': "GET",
                'interaction_type': interaction_type,
                'div_texts': div_text,
                'source': cx.fhir_source.name
            }
        })
def create(request, resource_type):
    """
    Create FHIR Interaction
    Example client use in curl:
    curl -H 'Content-Type: application/json' --data @test.json http://127.0.0.1:8000/fhir/Practitioner
    """
    interaction_type = 'create'
    # re-route to hello if no resource type is given:
    if not resource_type:
        return hello(request)

    try:
        rt = SupportedResourceType.objects.get(resource_name=resource_type)
        if interaction_type not in rt.get_supported_interaction_types() and request.method == 'GET':
            # GET means that this is a search so re-route
            return search(request, resource_type)

        elif interaction_type not in rt.get_supported_interaction_types():
            msg = 'The interaction %s is not permitted on %s FHIR resources on this FHIR sever.' % (
                interaction_type,
                resource_type,
            )
            return kickout_403(msg)

    except SupportedResourceType.DoesNotExist:
        msg = '%s is not a supported resource type on this FHIR server.' % (resource_type)
        return kickout_404(msg)

    # Catch all for GETs to re-direct to search if CREATE permission is valid
    if request.method == 'GET':
        return search(request, resource_type)

    if request.method == 'POST':
        # Check if request body is JSON ------------------------
        try:
            j = json.loads(request.body.decode('utf-8'), object_pairs_hook=OrderedDict)
            if not isinstance(j, dict):
                kickout_400('The request body did not contain a JSON object i.e. {}.')
        except:
            return kickout_400("The request body did not contain valid JSON.")

        # if j.has_key('id'): # throws error if id not in OrderedDict
        if 'id' in j:
            return kickout_400("Create cannot have an id. Perhaps you meant to perform an update?")

        # Check json_schema is valid
        try:
            json_schema = json.loads(rt.json_schema, object_pairs_hook=OrderedDict)
        except:
            return kickout_500('The JSON Schema on the server did not contain valid JSON.')

        # Check jsonschema
        if json_schema:
            try:
                validate(j, json_schema)
            except ValidationError:
                msg = 'JSON Schema Conformance Error. %s' % (str(sys.exc_info()[1][0]))
                return kickout_400(msg)

        # write_to_mongo - TBD
        response = OrderedDict()
        response['id'] = str(uuid.uuid4())

        meta = OrderedDict()

        if j.get('meta').get('versionId'):
            meta['versionId'] = j.get('meta').get('versionId')
        else:
            meta['versionId'] = 1

        if j.get('meta').get('lastUpdated'):
            meta['lastUpdated'] = j.get('meta').get('lastUpdated')
        else:
            meta['lastUpdated'] = '%sZ' % (datetime.datetime.utcnow().isoformat())

        meta['id'] = response['id']
        response['meta'] = meta

        hr = HttpResponse(json.dumps(response, indent=4), status=201,
                          content_type='application/json')
        hr['Location'] = '%s/%s/%s/_history/%s' % (
            'http://127.0.0.1:8000/fhir',
            resource_type,
            meta['id'],
            meta['versionId'],
        )
        return hr

    # This is something other than GET or POST (i.e. a  GET)
    if request.method not in ('GET', 'POST'):
        od = OrderedDict()
        od['request_method'] = request.method
        od['interaction_type'] = 'create'
        od['resource_type'] = resource_type
        od['note'] = 'Perform an HTTP POST to this URL with the JSON resource as the request body.'

        return HttpResponse(json.dumps(od, indent=4),
                            content_type='application/json')
Esempio n. 8
0
def generic_read(request,
                 interaction_type,
                 resource_type,
                 r_id=None,
                 vid=None,
                 *args,
                 **kwargs):
    """
    Read from remote FHIR Server

    :param request:
    :param interaction_type:
    :param resource_type:
    :param id:
    :param vid:
    :param args:
    :param kwargs:
    :return:

    # Example client use in curl:
    # curl  -X GET http://127.0.0.1:8000/fhir/Practitioner/1234

    """
    # interaction_type = 'read' or '_history' or 'vread' or 'search'
    logger.debug('interaction_type: %s' % interaction_type)

    # Check if this interaction type and resource type combo is allowed.
    deny = check_access_interaction_and_resource_type(resource_type,
                                                      interaction_type)
    if deny:
        # if not allowed, return a 4xx error.
        return deny

    srtc = check_rt_controls(resource_type)
    # We get back a Supported ResourceType Control record or None
    # with earlier if deny step we should have a valid srtc.

    default_path = get_default_path(srtc.resource_name)
    # get the default path for resource with ending "/"
    # You need to add resource_type + "/" for full url

    logger.debug('srtc: %s' % srtc)

    try:
        cx = Crosswalk.objects.get(user=request.user)
    except Crosswalk.DoesNotExist:
        cx = None
        # logger.debug('Crosswalk for %s does not exist' % request.user)

    if (cx is None and srtc is not None):
        # There is a srtc record so we need to check override_search
        if srtc.override_search:
            # If user is not in Crosswalk and srtc has search_override = True
            # We need to prevent search to avoid data leakage.
            return kickout_403('Error 403: %s Resource is access controlled.'
                               ' No records are linked to user:'******'%s' % (resource_type, request.user))

    # Request.user = user
    # interaction_type = read | _history | vread
    # resource_type = 'Patient | Practitioner | ExplanationOfBenefit ...'
    # id = fhir_id (potentially masked)
    # vid = Version Id

    # Check the resource_type to see if it has a url
    # Check the resource_type to see if masking is required
    # Get the FHIR_Server (from crosswalk via request.user)
    # if masked get the fhir_id from crosswalk
    # if search_override strip search items (search_block)
    # if search_override add search keys

    fhir_url = ''
    # change source of default_url to ResourceRouter

    # Add default FHIR Server URL to re-write

    rewrite_url_list = settings.FHIR_SERVER_CONF['REWRITE_FROM']
    # print("Starting Rewrite_list:%s" % rewrite_url_list)

    if srtc:
        logger.debug('SRTC:%s' % srtc)

        fhir_url = default_path + resource_type + '/'
        # Add to the rewrite_url list
        rewrite_url_list.append(default_path)

    else:
        logger.debug('CX:%s' % cx)
        if cx:
            fhir_url = cx.get_fhir_resource_url(resource_type)
            rewrite_url_list.append(fhir_url.replace(resource_type + '/', ''))
        else:
            # logger.debug('FHIRServer:%s' % FhirServerUrl())
            fhir_url = FhirServerUrl() + resource_type + '/'

    if FhirServerUrl()[:-1] not in rewrite_url_list:
        rewrite_url_list.append(FhirServerUrl()[:-1])

    logger.debug('FHIR URL:%s' % fhir_url)
    logger.debug('Rewrite List:%s' % rewrite_url_list)

    if interaction_type == 'search':
        key = None
    else:
        key = masked_id(resource_type, cx, srtc, r_id, slash=False)
        if fhir_url.endswith(resource_type + '/'):
            # we need to make sure we don't specify resource_type twice in URL
            if key.startswith(resource_type + '/'):
                key = key.replace(resource_type + '/', '')

        fhir_url += key + '/'

    logger.debug('FHIR URL with key:%s' % fhir_url)

    ###########################

    # Now we get to process the API Call.

    # Internal handling format is json
    # Remove the oauth elements from the GET
    pass_params = strip_oauth(request.GET)

    if interaction_type == 'search':
        if cx is not None:
            logger.debug("cx.fhir_id=%s" % cx.fhir_id)
            r_id = cx.fhir_id.split('/')[1]
            logger.debug("Patient Id:%s" % r_id)

    if resource_type == "Patient":
        key = r_id

    pass_params = build_params(pass_params,
                               srtc,
                               # key,
                               r_id,
                               )

    if interaction_type == 'vread':
        pass_to = fhir_url + '_history' + '/' + vid
    elif interaction_type == '_history':
        pass_to = fhir_url + '_history'
    else:  # interaction_type == 'read':
        pass_to = fhir_url

    logger.debug('Here is the URL to send, %s now add '
                 'GET parameters %s' % (pass_to, pass_params))

    if pass_params is not '':
        pass_to += pass_params

    logger.debug("Making request:%s" % pass_to)
    # Now make the call to the backend API
    r = request_call(request, pass_to, reverse_lazy('api:v1:home'))

    text_out = ''
    if 'text' in r:
        logger.debug('r:%s' % r.text)
    else:
        logger.debug("r not returning text:%s" % r)

    # logger.debug('Rewrite List:%s' % rewrite_url_list)

    host_path = get_host_url(request, resource_type)[:-1]
    logger.debug('host path:%s' % host_path)

    # get 'xml' 'json' or ''
    fmt = get_search_param_format(pass_params)

    text_out = post_process_request(request,
                                    fmt,
                                    host_path,
                                    r.text,
                                    rewrite_url_list)

    od = build_output_dict(request,
                           OrderedDict(),
                           resource_type,
                           key,
                           vid,
                           interaction_type,
                           fmt,
                           text_out)

    # write session variables if _getpages was found
    ikey = find_ikey(r.text)
    if ikey is not '':

        save_url = get_target_url(fhir_url, resource_type)
        # print("Store fhir_url:%s but only: %s" % (fhir_url,save_url))
        content = {
            'fhir_to': save_url,
            'rwrt_list': rewrite_url_list,
            'res_type': resource_type,
            'intn_type': interaction_type,
            'key': key,
            'vid': vid
        }
        sesn_var = write_session(request, ikey, content, skey=SESSION_KEY)
        if sesn_var:
            logger.debug("Problem writing session variables."
                         " Returned %s" % sesn_var)
    if fmt == 'xml':
        # logger.debug('We got xml back in od')
        return HttpResponse(r.text, content_type='application/%s' % fmt)
        # return HttpResponse( tostring(dict_to_xml('content', od)),
        #                      content_type='application/%s' % fmt)
    elif fmt == 'json':
        # logger.debug('We got json back in od')
        return HttpResponse(pretty_json(od),
                            content_type='application/%s' % fmt)

    # logger.debug('We got a different format:%s' % fmt)
    return render(
        request,
        'bluebutton/default.html',
        {'content': pretty_json(od), 'output': od},
    )