def get_feed_updates(repeater, feed_name): """ Iterates over a paginated atom feed, yields patients updated since repeater.patients_last_polled_at, and updates the repeater. """ def has_new_entries_since(last_polled_at, element, xpath='./atom:updated'): return not last_polled_at or get_timestamp(element, xpath) > last_polled_at assert feed_name in ATOM_FEED_NAMES atom_feed_status = repeater.atom_feed_status.get(feed_name, AtomFeedStatus()) last_polled_at = atom_feed_status['last_polled_at'] page = atom_feed_status['last_page'] get_uuid = get_patient_uuid if feed_name == ATOM_FEED_NAME_PATIENT else get_encounter_uuid # The OpenMRS Atom feeds' timestamps are timezone-aware. So when we # compare timestamps in has_new_entries_since(), this timestamp # must also be timezone-aware. repeater.patients_last_polled_at is # set to a UTC timestamp (datetime.utcnow()), but the timezone gets # dropped because it is stored as a jsonobject DateTimeProperty. # This sets it as a UTC timestamp again: last_polled_at = pytz.utc.localize( last_polled_at) if last_polled_at else None try: while True: feed_xml = get_feed_xml(repeater.requests, feed_name, page) if has_new_entries_since(last_polled_at, feed_xml): for entry in feed_xml.xpath( './atom:entry', namespaces={'atom': 'http://www.w3.org/2005/Atom'}): if has_new_entries_since(last_polled_at, entry, './atom:published'): yield get_uuid(entry) next_page = feed_xml.xpath( './atom:link[@rel="next-archive"]', namespaces={'atom': 'http://www.w3.org/2005/Atom'}) if next_page: href = next_page[0].get('href') page = href.split('/')[-1] else: if not page: this_page = feed_xml.xpath( './atom:link[@rel="via"]', namespaces={'atom': 'http://www.w3.org/2005/Atom'}) href = this_page[0].get('href') page = href.split('/')[-1] break except (RequestException, HTTPError): # Don't update repeater if OpenMRS is offline return except OpenmrsFeedDoesNotExist: repeater.atom_feed_status[feed_name] = AtomFeedStatus() repeater.save() else: repeater.atom_feed_status[feed_name] = AtomFeedStatus( last_polled_at=datetime.utcnow(), last_page=page, ) repeater.save()
def test_status_defaults(): status = AtomFeedStatus() assert_is_none(status.last_polled_at) assert_equal(status.last_page, 'recent')