Esempio n. 1
0
    def delete(self, request, questionnaire_id, format=None):
        """
        Deletes A FHIR Questionnaire for the passed ID
        """
        # Use the FHIR client lib to validate our resource.
        questionnaire_request = BundleEntryRequest(
            {
                "url": f"Questionnaire/{questionnaire_id}",
                "method": "DELETE",
            }
        )
        questionnaire_entry = BundleEntry()
        questionnaire_entry.request = questionnaire_request

        # Validate it.
        bundle = Bundle()
        bundle.entry = [questionnaire_entry]
        bundle.type = "transaction"

        try:
            # Create the organization
            response = requests.post(PPM.fhir_url(), json=bundle.as_json())
            logger.debug("Response: {}".format(response.status_code))
            response.raise_for_status()

            return response.json()

        except Exception as e:
            logger.exception(
                "API/Questionnaire: Delete Questionnaire error: {}".format(e),
                exc_info=True,
                extra={
                    "request": request,
                },
            )
Esempio n. 2
0
 def _create_bundle_response(entries):
     bundle = Bundle()
     bundle.type = 'searchset'
     bundle.entry = []
     bundle.total = len(entries)
     for item in entries:
         entry = BundleEntry()
         entry.fullUrl = '{}{}'.format(request.base_url, item.id.value)
         entry.resource = item
         bundle.entry.append(entry)
     return bundle
Esempio n. 3
0
    def questionnaire_transaction(cls, questionnaire, questionnaire_id=None):
        """
        Accepts a Questionnaire object and builds the transaction to be used
        to perform the needed operation in FHIR. Operations can be POST or PUT,
        depending on if an ID is passed. If the object does not need to be created
        or updated, the operation will return as a success with an empty response
        object.

        :param questionnaire: The Questionnaire object to be persisted
        :type questionnaire: dict
        :param questionnaire_id: The ID to use for new Questionnaire, defaults to None
        :type questionnaire_id: str, optional
        :return: The response if the resource was created, None if no operation needed
        :rtype: dict
        """
        # Check for a version matching the created one
        version = questionnaire["version"]
        query = {"identifier": f"{FHIR.qualtrics_survey_version_identifier_system}|{version}"}
        if questionnaire_id:
            query["_id"] = questionnaire_id

        questionnaires = FHIR._query_resources("Questionnaire", query)
        if questionnaires:

            # No need to recreate it
            logger.debug(f"PPM/Qualtrics: Questionnaire already exists for survey version {version}")
            return None

        # Use the FHIR client lib to validate our resource.
        questionnaire = Questionnaire(questionnaire)
        questionnaire_request = BundleEntryRequest(
            {
                "url": f"Questionnaire/{questionnaire_id}" if questionnaire_id else "Questionnaire",
                "method": "PUT" if questionnaire_id else "POST",
            }
        )
        questionnaire_entry = BundleEntry()
        questionnaire_entry.resource = questionnaire
        questionnaire_entry.request = questionnaire_request

        # Validate it.
        bundle = Bundle()
        bundle.entry = [questionnaire_entry]
        bundle.type = "transaction"

        # Create the organization
        response = requests.post(PPM.fhir_url(), json=bundle.as_json())
        logger.debug("PPM/Qualtrics: FHIR Response: {}".format(response.status_code))
        response.raise_for_status()

        return response.json()
Esempio n. 4
0
    def _query_resources(queries=[]):

        # Build the transaction
        transaction = {
            'resourceType': 'Bundle',
            'type': 'transaction',
            'entry': []
        }

        # Get the questionnaire
        for query in queries:
            transaction['entry'].append(
                {'request': {
                    'url': query,
                    'method': 'GET'
                }})

        # Query for a response

        # Execute the search
        response = requests.post(settings.FHIR_URL,
                                 headers={'content-type': 'application/json'},
                                 json=transaction)
        response.raise_for_status()

        # Build the objects
        bundle = Bundle(response.json())

        return bundle
Esempio n. 5
0
    def import_collection(self, filepath, options):
        """Iterate over a collection bundle and dispatch to the importers for the various resource types"""
        verbosity = options['verbosity']
        strict = options['strict']

        logger.info(f'Importing {filepath}')
        with open(filepath, 'r') as handle:
            fhirjs = json.load(handle)
            bundle = Bundle(fhirjs, strict=strict)

            for entry in fhirjs[
                    "entry"]:  # TODO: Is there something more elegant than mucking through a JSON structure?
                res = entry[
                    "resource"]  # TODO: Is there something more elegant than mucking through a JSON structure?
                res_type = res["resourceType"]

                # OC: Creating spans from the tracer of the execution context will divide the overall execution into small, measurable chunks
                tracer = execution_context.get_opencensus_tracer()
                with tracer.span(name=f'Import {res_type}'):
                    logger.debug(f'Resource: {res}')

                    if res_type == "Patient":
                        self.import_patient(res, options)

                    if res_type == "Condition":
                        self.import_condition(res, options)

                    if res_type == "Observation":
                        self.import_observation(res, options)
Esempio n. 6
0
    def parse_response(self, response: Dict) -> None:
        """
        Parse the response from the FHIR server to which we have sent our
        task. The response looks something like this:

        .. code-block:: json

            {
              "resourceType": "Bundle",
              "id": "cae48957-e7e6-4649-97f8-0a882076ad0a",
              "type": "transaction-response",
              "link": [
                {
                  "relation": "self",
                  "url": "http://localhost:8080/fhir"
                }
              ],
              "entry": [
                {
                  "response": {
                    "status": "200 OK",
                    "location": "Patient/1/_history/1",
                    "etag": "1"
                  }
                },
                {
                  "response": {
                    "status": "200 OK",
                    "location": "Questionnaire/26/_history/1",
                    "etag": "1"
                  }
                },
                {
                  "response": {
                    "status": "201 Created",
                    "location": "QuestionnaireResponse/42/_history/1",
                    "etag": "1",
                    "lastModified": "2021-05-24T09:30:11.098+00:00"
                  }
                }
              ]
            }

        The server's reply contains a Bundle
        (https://www.hl7.org/fhir/bundle.html), which is a container for
        resources. Here, the bundle contains entry objects
        (https://www.hl7.org/fhir/bundle-definitions.html#Bundle.entry).

        """
        bundle = Bundle(jsondict=response)

        if bundle.entry is not None:
            self._save_exported_entries(bundle)
Esempio n. 7
0
    def patch(request, questionnaire_id, format=None):
        """
        Uses FHIR+json patch to update a resource
        """

        # Base 64 encode the patch
        parameters = Parameters(request.data)
        questionnaire_request = BundleEntryRequest(
            {
                "url": f"Questionnaire/{questionnaire_id}",
                "method": "PATCH",
            }
        )
        questionnaire_entry = BundleEntry()
        questionnaire_entry.resource = parameters
        questionnaire_entry.request = questionnaire_request

        # Validate it.
        bundle = Bundle()
        bundle.entry = [questionnaire_entry]
        bundle.type = "transaction"

        try:
            # Create the organization
            response = requests.post(PPM.fhir_url(), json=bundle.as_json())
            logger.debug("Response: {}".format(response.status_code))
            response.raise_for_status()

            return response.json()

        except Exception as e:
            logger.exception(
                "API/Questionnaire: Delete Questionnaire error: {}".format(e),
                exc_info=True,
                extra={
                    "request": request,
                },
            )
Esempio n. 8
0
def get_patients():
    query = FHIRSearch(resource_type=Patient)
    patient_bundle = query.perform(smart.server)
    patients = extract_resources(patient_bundle.entry)
    next_page_url = get_next_url(patient_bundle.link)

    while next_page_url is not None:
        response = smart.server.request_json(next_page_url)
        next_page_bund = Bundle(response)
        next_page_resources = extract_resources(next_page_bund.entry)
        patients.extend(next_page_resources)

        next_page_url = get_next_url(next_page_bund.link)

    return patients
Esempio n. 9
0
    def _bundle(resources):

        # Build the bundle
        bundle = Bundle()
        bundle.type = 'transaction'
        bundle.entry = []

        for resource in resources:

            # Build the entry request
            bundle_entry_request = BundleEntryRequest()
            bundle_entry_request.method = 'POST'
            bundle_entry_request.url = resource.resource_type

            # Add it to the entry
            bundle_entry = BundleEntry()
            bundle_entry.resource = resource
            bundle_entry.fullUrl = resource.id
            bundle_entry.request = bundle_entry_request

            # Add it
            bundle.entry.append(bundle_entry)

        return bundle
Esempio n. 10
0
    def get_patient(patient_email):

        # Build the transaction
        transaction = {
            'resourceType': 'Bundle',
            'type': 'transaction',
            'entry': []
        }

        # Add the request for the patient
        transaction['entry'].append({
            'request': {
                'url':
                'Patient?identifier=http://schema.org/email|{}'.format(
                    quote(patient_email)),
                'method':
                'GET'
            }
        })

        # Query for a response

        # Execute the search
        response = requests.post(settings.FHIR_URL,
                                 headers={'content-type': 'application/json'},
                                 json=transaction)
        response.raise_for_status()

        # Build the objects
        bundle = Bundle(response.json())

        # Check for the Patient
        if not bundle.entry[0].resource.entry or bundle.entry[
                0].resource.entry[0].resource.resource_type != 'Patient':
            logger.error("Patient could not be fetched",
                         exc_info=True,
                         extra={
                             'patient': FHIR._obfuscate_email(patient_email),
                         })
            raise FHIR.PatientDoesNotExist()

        # Instantiate it
        patient = bundle.entry[0].resource.entry[0].resource

        return patient
Esempio n. 11
0
def create_bundle(query, paginate=True):
    # Initialize searchset bundle
    b = Bundle()
    b.type = 'searchset'

    # Handle _summary arg
    # TODO: Refactor into separate function or decorator
    summary = request.args.get('_summary')
    if summary:
        if summary == 'count':
            b.total = len(query.all())
            return b
    # TODO: Handle summary = True and summary = Text and summary = Data
    # Apply pagination if desired and set links
    if paginate:
        p, per_page = paginate_query(query=query)
        b = set_bundle_page_links(bundle=b, pagination=p, per_page=per_page)
        records = p.items
        b.total = p.total
    # Otherwise, execute query as-is
    else:
        records = query.all()
        b.total = len(records)

    # Loop through results to generate bundle entries
    for r in records:
        try:
            # Try creating a search entry for the bundle
            e = create_bundle_search_entry(obj=r)
            # If entry can be made (e.g. if object has working fhir attribute) append to bundle
            try:
                b.entry.append(e)
            except AttributeError:
                b.entry = [e]
        # Silently ignore items returned in the query that can't be turned into bundle entries
        except TypeError:
            # TODO: Improve error handling or feedback on this function for items that fail to be created
            pass

    # TODO: Add OperationOutcome to bundle attribute
    return b
def make_bundle(value: str, sp_unique: bool = False) -> Bundle:
    system = "https://some_system"
    jd = {
        "type":
        "transaction",
        "entry": [
            BundleEntry(
                jsondict={
                    "request":
                    BundleEntryRequest(
                        jsondict={
                            "method": "POST",
                            "url": "Questionnaire",
                            "ifNoneExist": f"identifier={system}|{value}",
                        }).as_json(),
                    "resource":
                    Questionnaire(
                        jsondict={
                            "name":
                            "some_questionnaire_name",
                            "status":
                            "active",
                            "identifier": [
                                Identifier(jsondict={
                                    "system": system,
                                    "value": value
                                }).as_json()
                            ],
                        }).as_json(),
                }).as_json()
        ],
    }
    # Note: the .as_json() conversions are necessary.
    if sp_unique:
        raise NotImplementedError(
            "sp_unique method not implemented; see "
            "https://github.com/hapifhir/hapi-fhir/issues/3141")
    return Bundle(jsondict=jd)
Esempio n. 13
0
    def get_resources(questionnaire_id, patient_email, dry=False):

        # Build the transaction
        transaction = {
            'resourceType': 'Bundle',
            'type': 'transaction',
            'entry': []
        }

        # Get the questionnaire
        transaction['entry'].append({
            'request': {
                'url': 'Questionnaire?_id={}'.format(questionnaire_id),
                'method': 'GET'
            }
        })

        # Add the request for the patient
        transaction['entry'].append({
            'request': {
                'url':
                'Patient?identifier=http://schema.org/email|{}'.format(
                    quote(patient_email)),
                'method':
                'GET'
            }
        })

        # Query for a response

        # Execute the search
        response = requests.post(settings.FHIR_URL,
                                 headers={'content-type': 'application/json'},
                                 json=transaction)
        response.raise_for_status()

        # Build the objects
        bundle = Bundle(response.json())

        # Check for the questionnaire
        if not bundle.entry[0].resource.entry or bundle.entry[
                0].resource.entry[0].resource.resource_type != 'Questionnaire':
            logger.error("Questionnaire could not be fetched",
                         exc_info=True,
                         extra={
                             'questionnaires': questionnaire_id,
                         })
            raise FHIR.QuestionnaireDoesNotExist()

        # Instantiate it
        questionnaire = bundle.entry[0].resource.entry[0].resource

        # Check for the patient
        if not dry:
            if not bundle.entry[1].resource.entry or bundle.entry[
                    1].resource.entry[0].resource.resource_type != 'Patient':
                logger.error("Patient could not be fetched",
                             exc_info=True,
                             extra={
                                 'patient':
                                 FHIR._obfuscate_email(patient_email),
                                 'questionnaires': questionnaire_id,
                                 'bundle': bundle.as_json(),
                             })
                raise FHIR.PatientDoesNotExist()

            # Get it
            patient = bundle.entry[1].resource.entry[0].resource
        else:
            # In dry mode, use a fake patient
            patient = FHIR.get_demo_patient(patient_email)

        return questionnaire, patient