def generate_identifier(requests, identifier_type): """ Calls the idgen module's generateIdentifier endpoint Identifier source ID is determined from `identifier_type`. If `identifier_type` doesn't have an identifier source, return None. If the identifier source doesn't return an identifier, return None. If anything goes wrong ... return None. Partners in Health have written basic auth support for the idgen module, but it is not yet widely used. Until then, requests must use a session that has been authenticated with the HTML login page. """ identifier = None source_id = None # Create a new Requests session to log in using an HTML login page. # See `authenticate_session()` for details. with Requests( domain_name=requests.domain_name, base_url=requests.base_url, verify=requests.verify, auth_manager=requests.auth_manager, notify_addresses=requests.notify_addresses, payload_id=requests.payload_id, logger=requests.logger, ) as requests_session: authenticate_session(requests_session) try: source_id = get_identifier_source_id(requests_session, identifier_type) except OpenmrsHtmlUiChanged as err: requests.notify_exception('Unexpected OpenMRS HTML UI', details=str(err)) if source_id: # Example request: http://www.example.com/openmrs/module/idgen/generateIdentifier.form?source=1 response = requests_session.get( '/module/idgen/generateIdentifier.form', params={'source': source_id}) try: if not (200 <= response.status_code < 300 and response.content): raise OpenmrsException() try: # Example response: {"identifiers": ["CHR203007"]} identifier = response.json()['identifiers'][0] except (ValueError, IndexError, KeyError): raise OpenmrsException() except OpenmrsException: requests.notify_exception( 'OpenMRS idgen module returned an unexpected response', details= (f'OpenMRS idgen module at "{response.url}" ' f'returned an unexpected response {response.status_code}: \r\n' f'{response.content}')) return identifier
def generate_identifier(requests, identifier_type): """ Calls the idgen module's generateIdentifier endpoint Identifier source ID is determined from `identifier_type`. If `identifier_type` doesn't have an identifier source, return None. If the identifier source doesn't return an identifier, return None. If anything goes wrong ... return None. The idgen module is not a REST API. It does not use API authentication. The user has to be logged in using the HTML login page, and the resulting authenticated session used for sending requests. """ identifier = None source_id = None with Requests(domain_name=requests.domain_name, base_url=requests.base_url, username=requests.username, password=requests.password, verify=requests.verify) as requests_session: authenticate_session(requests_session) try: source_id = get_identifier_source_id(requests_session, identifier_type) except OpenmrsHtmlUiChanged as err: notify_exception( request=None, message='Unexpected OpenMRS HTML UI', details=str(err), ) if source_id: # Example request: http://www.example.com/openmrs/module/idgen/generateIdentifier.form?source=1 response = requests_session.get( '/module/idgen/generateIdentifier.form', params={'source': source_id}) try: if not (200 <= response.status_code < 300 and response.content): raise OpenmrsException() try: # Example response: {"identifiers": ["CHR203007"]} identifier = response.json()['identifiers'][0] except (ValueError, IndexError, KeyError): raise OpenmrsException() except OpenmrsException: notify_exception( request=None, message= 'OpenMRS idgen module returned an unexpected response', details= 'OpenMRS idgen module at "{}" returned an unexpected response {}: "{}"' .format(response.url, response.status_code, response.content)) return identifier
def import_encounter(repeater, encounter_uuid): try: encounter = get_encounter(repeater, encounter_uuid) except (RequestException, ValueError) as err: raise OpenmrsException( _(f'{repeater.domain}: {repeater}: Error fetching Encounter ' f'"{encounter_uuid}": {err}')) from err case_blocks = [] patient_case_id, default_owner_id, patient_case_block = get_case_id_owner_id_case_block( repeater, encounter['patientUuid'], ) if not patient_case_id: # No patient to create or update. Ignore this encounter. return if patient_case_block: case_blocks.append(patient_case_block) case_block_kwargs, more_case_blocks = get_case_block_kwargs_from_encounter( repeater, encounter, patient_case_id, default_owner_id, ) case_blocks.extend(more_case_blocks) if has_case_updates(case_block_kwargs) or case_blocks: update_case(repeater, patient_case_id, case_block_kwargs, case_blocks)
def import_encounter(repeater, encounter_uuid): try: encounter = get_encounter(repeater, encounter_uuid) except (RequestException, ValueError) as err: raise OpenmrsException( _(f'{repeater.domain}: {repeater}: Error fetching Encounter ' f'"{encounter_uuid}": {err}')) from err case_block_kwargs = {"update": {}, "index": {}} case_blocks = [] # NOTE: Atom Feed integration requires Patient UUID to be external_id case = get_case(repeater, encounter['patientUuid']) if case: case_id = case.case_id default_owner_id = case.owner_id else: case_block = create_case(repeater, encounter['patientUuid']) case_blocks.append(case_block) case_id = case_block.case_id default_owner_id = case_block.owner_id case_type = repeater.white_listed_case_types[0] more_kwargs, more_case_blocks = get_case_block_kwargs_from_observations( encounter['observations'], repeater.observation_mappings, case_id, case_type, default_owner_id, ) deep_update(case_block_kwargs, more_kwargs) case_blocks.extend(more_case_blocks) if 'bahmniDiagnoses' in encounter: more_kwargs, more_case_blocks = get_case_block_kwargs_from_bahmni_diagnoses( encounter['bahmniDiagnoses'], repeater.diagnosis_mappings, case_id, case_type, default_owner_id, ) deep_update(case_block_kwargs, more_kwargs) case_blocks.extend(more_case_blocks) # O/ ... ... ... start snip # TODO: Remove this after deploy, once existing configs have # been moved to repeater.bahmni_diagnoses more_kwargs, more_case_blocks = get_case_block_kwargs_from_bahmni_diagnoses( encounter['bahmniDiagnoses'], repeater.observation_mappings, case_id, case_type, default_owner_id, ) deep_update(case_block_kwargs, more_kwargs) case_blocks.extend(more_case_blocks) # O\ ˙˙˙ ˙˙˙ ˙˙˙ end snip if has_case_updates(case_block_kwargs) or case_blocks: update_case(repeater, case_id, case_block_kwargs, case_blocks)
def update_patient(repeater, patient_uuid): """ Fetch patient from OpenMRS, submit case update for all mapped case properties. .. NOTE:: OpenMRS UUID must be saved to "external_id" case property """ if len(repeater.white_listed_case_types) != 1: raise ConfigurationError( _(f'{repeater.domain}: {repeater}: Error in settings: Unable to update ' f'patients from OpenMRS unless only one case type is specified.') ) case_type = repeater.white_listed_case_types[0] try: patient = get_patient_by_uuid(repeater.requests, patient_uuid) except (RequestException, ValueError) as err: raise OpenmrsException( _(f'{repeater.domain}: {repeater}: Error fetching Patient ' f'{patient_uuid!r}: {err}')) from err case, error = importer_util.lookup_case( EXTERNAL_ID, patient_uuid, repeater.domain, case_type=case_type, ) if error == LookupErrors.NotFound: if not repeater.openmrs_config.case_config.import_creates_cases: # We can't create cases via the Atom feed, just update them. # Nothing to do here. return default_owner: Optional[CommCareUser] = repeater.first_user case_block = get_addpatient_caseblock(case_type, default_owner, patient, repeater) elif error == LookupErrors.MultipleResults: # Multiple cases have been matched to the same patient. # Could be caused by: # * The cases were given the same identifier value. It could # be user error, or case config assumed identifier was # unique but it wasn't. # * PatientFinder matched badly. # * Race condition where a patient was previously added to # both CommCare and OpenMRS. raise DuplicateCaseMatch( _(f'{repeater.domain}: {repeater}: More than one case found ' f'matching unique OpenMRS UUID. case external_id: "{patient_uuid}"' )) else: case_block = get_updatepatient_caseblock(case, patient, repeater) if case_block: submit_case_blocks( [case_block.as_text()], repeater.domain, xmlns=XMLNS_OPENMRS, device_id=OPENMRS_ATOM_FEED_DEVICE_ID + repeater.get_id, )
def generate_identifier(requests, identifier_type): """ Calls the idgen module's generateIdentifier endpoint Identifier source ID is determined from `identifier_type`. If `identifier_type` doesn't have an identifier source, return None. If the identifier source doesn't return an identifier, return None. If anything goes wrong ... return None. """ try: source_id = get_identifier_source_id(requests, identifier_type) except OpenmrsHtmlUiChanged as err: notify_exception( request=None, message='Unexpected OpenMRS HTML UI', details=str(err), ) return None if source_id: # Example request: http://www.example.com/openmrs/module/idgen/generateIdentifier.form?source=1 response = requests.get('/module/idgen/generateIdentifier.form', {'source': source_id}) try: if not (200 <= response.status_code < 300 and response.content): raise OpenmrsException() try: # Example response: {"identifiers": ["CHR203007"]} return response.json()['identifiers'][0] except (ValueError, IndexError, KeyError): raise OpenmrsException() except OpenmrsException: notify_exception( request=None, message='OpenMRS idgen module returned an unexpected response', details= 'OpenMRS idgen module at "{}" returned an unexpected response {}: "{}"' .format(response.url, response.status_code, response.content)) return None
def get_feed_xml(requests, feed_name, page: str): assert feed_name in ATOM_FEED_NAMES feed_url = f'/ws/atomfeed/{feed_name}/{page}' resp = requests.get(feed_url) if resp.status_code == 500: if 'AtomFeedRuntimeException: feed does not exist' in resp.text: exception = OpenmrsFeedRuntimeException( f'Domain "{requests.domain_name}": Page does not exist in Atom ' f'feed "{resp.url}". Resetting Atom feed status.') requests.notify_exception( str(exception), _("This can happen if the IP address of a Repeater is changed " "to point to a different server, or if a server has been " "rebuilt. It can signal more severe consequences, like " "attempts to synchronize CommCare cases with OpenMRS " "patients that can no longer be found.")) raise exception if ('AtomFeedRuntimeException: feedId must not be null and must be ' 'greater than 0') in resp.text: exception = OpenmrsFeedRuntimeException( f'Domain "{requests.domain_name}": Page "{page}" is not valid ' f'in Atom feed "{resp.url}". Resetting Atom feed status.') requests.notify_exception( str(exception), _('It is unclear how Atom feed pagination can lead to page ' '"{}". Follow up with OpenMRS system ' 'administrator.').format(page)) raise exception # Use OpenmrsException instead of OpenmrsFeedRuntimeException so # that we don't reset the Atom feed if we don't know what the # problem is. exception = OpenmrsException( f'Domain "{requests.domain_name}": Unrecognized error in Atom ' f'feed "{resp.url}".') requests.notify_exception(str(exception), _('Response text: \n{}').format(resp.text)) raise exception try: root = etree.fromstring(resp.content) except etree.XMLSyntaxError as err: requests.notify_exception( str(err), _('There is an XML syntax error in the OpenMRS Atom feed at ' f'"{resp.url}".')) raise OpenmrsFeedSyntaxError() from err return root