Example #1
0
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()
Example #2
0
def test_status_defaults():
    status = AtomFeedStatus()
    assert_is_none(status.last_polled_at)
    assert_equal(status.last_page, 'recent')