Skip to content

Commit

Permalink
Make the W3C validator happy with our RSS feed
Browse files Browse the repository at this point in the history
  • Loading branch information
seanh committed Sep 9, 2015
1 parent c096a5e commit ce61a3f
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 75 deletions.
64 changes: 33 additions & 31 deletions h/feeds/render.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,6 @@
from h.feeds import rss


def _render(request, feed_from_annotations_func, template, **kwargs):
"""Render the given arguments to an Atom or RSS response."""
def annotation_url(annotation):
"""Return the HTML permalink URL for the given annotation."""
return request.resource_url(request.root, "a", annotation["id"])

def annotation_api_url(annotation):
"""Return the JSON API URL for the given annotation."""
return request.resource_url(request.root, "api", "annotations",
annotation["id"])

feed = feed_from_annotations_func(
annotation_url=annotation_url, annotation_api_url=annotation_api_url,
**kwargs)

return renderers.render_to_response(
template, {"feed": feed}, request=request)


def render_atom(request, annotations, atom_url, html_url, title, subtitle):
"""Return a rendered Atom feed of the given annotations.
Expand All @@ -45,20 +26,34 @@ def render_atom(request, annotations, atom_url, html_url, title, subtitle):
"""
request.response.content_type = "application/atom+xml"
return _render(request=request,
feed_from_annotations_func=atom.feed_from_annotations,
template='h:templates/atom.xml.jinja2',
annotations=annotations,
atom_url=atom_url, html_url=html_url,
title=title, subtitle=subtitle)

def annotation_url(annotation):
"""Return the HTML permalink URL for the given annotation."""
return request.resource_url(request.root, "a", annotation["id"])

def render_rss(request, annotations, html_url, title, description):
def annotation_api_url(annotation):
"""Return the JSON API URL for the given annotation."""
return request.resource_url(request.root, "api", "annotations",
annotation["id"])

feed = atom.feed_from_annotations(
annotations=annotations, atom_url=atom_url,
annotation_url=annotation_url, annotation_api_url=annotation_api_url,
html_url=html_url, title=title, subtitle=subtitle)

return renderers.render_to_response(
'h:templates/atom.xml.jinja2', {"feed": feed}, request=request)


def render_rss(request, annotations, rss_url, html_url, title, description):
"""Return a rendered RSS feed of the given annotations.
:param annotations: The list of annotations to render as the feed's items
:type annotations: list of dicts
:param rss_url: The URL that this RSS feed will be served at
:type rss_url: string
:param html_url: The URL of the HTML page that this RSS feed is a feed of
:type html_url: string
Expand All @@ -72,8 +67,15 @@ def render_rss(request, annotations, html_url, title, description):
"""
request.response.content_type = "application/rss+xml"
return _render(request=request,
feed_from_annotations_func=rss.feed_from_annotations,
template='h:templates/rss.xml.jinja2',
annotations=annotations,
html_url=html_url, title=title, description=description)

def annotation_url(annotation):
"""Return the HTML permalink URL for the given annotation."""
return request.resource_url(request.root, "a", annotation["id"])

feed = rss.feed_from_annotations(
annotations=annotations, annotation_url=annotation_url,
rss_url=rss_url, html_url=html_url, title=title,
description=description)

return renderers.render_to_response(
'h:templates/rss.xml.jinja2', {"feed": feed}, request=request)
16 changes: 7 additions & 9 deletions h/feeds/rss.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def _pubDate_string_from_annotation(annotation):
'%a, %d %b %Y %H:%M:%S %Z')


def _feed_item_from_annotation(annotation, annotation_url, annotation_api_url):
def _feed_item_from_annotation(annotation, annotation_url):
"""Return an RSS feed item for the given annotation.
:returns: A logical representation of the RSS feed item as a dict,
Expand All @@ -33,20 +33,18 @@ def _feed_item_from_annotation(annotation, annotation_url, annotation_api_url):
:rtype: dict
"""
links = [annotation_url(annotation), annotation_api_url(annotation)]
links.extend(annotation.target_links)
return {
"title": annotation.title,
"description": annotation.description,
"pubDate": _pubDate_string_from_annotation(annotation),
"guid": h.feeds.util.tag_uri_for_annotation(
annotation, annotation_url),
"links": links,
"link": annotation_url(annotation)
}


def feed_from_annotations(annotations, annotation_url, annotation_api_url,
html_url, title, description):
def feed_from_annotations(annotations, annotation_url, rss_url, html_url,
title, description):
"""Return an RSS feed for the given list of annotations.
:returns: A logical representation of an RSS feed as a Python dict
Expand All @@ -57,13 +55,13 @@ def feed_from_annotations(annotations, annotation_url, annotation_api_url,
"""
feed = {
'title': title,
'link': html_url,
'rss_url': rss_url,
'html_url': html_url,
'description': description,
# This is called entries not items so as not to clash with the dict's
# standard .items() method.
'entries': [
_feed_item_from_annotation(annotation, annotation_url,
annotation_api_url)
_feed_item_from_annotation(annotation, annotation_url)
for annotation in annotations]
}

Expand Down
32 changes: 3 additions & 29 deletions h/feeds/test/rss_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,33 +35,7 @@ def test_feed_from_annotations_html_links():
[factories.Annotation()], annotation_url, mock.Mock(), '', '', '')

item = feed['entries'][0]
assert annotation_url.return_value in item['links']


def test_feed_from_annotations_json_links():
"""Items should include links to the annotations' JSON API URLs."""
annotation_api_url = mock.Mock()

feed = rss.feed_from_annotations(
[factories.Annotation()], _annotation_url(), annotation_api_url,
'', '', '')

item = feed['entries'][0]
assert annotation_api_url.return_value in item['links']


def test_feed_from_annotations_target_links():
"""Items should include links to each of the annotation's targets."""
with mock.patch("h.test.factories.api_models.Annotation.target_links",
new_callable=mock.PropertyMock) as mock_target_links:
mock_target_links.return_value = ['link1', 'link2']

feed = rss.feed_from_annotations(
[factories.Annotation()], _annotation_url(), mock.Mock(), '', '', '')

item = feed['entries'][0]
for link in mock_target_links.return_value:
assert link in item['links']
assert item['link'] == annotation_url.return_value


def test_feed_from_annotations_item_titles():
Expand Down Expand Up @@ -105,12 +79,12 @@ def test_feed_from_annotations_title():


def test_feed_from_annotations_link():
"""The feed should use the given html_url for its link field."""
"""The feed should use the given html_url for its html_url field."""
feed = rss.feed_from_annotations(
[], _annotation_url(), mock.Mock(), 'http://Hypothes.is/stream', '',
'')

assert feed['link'] == 'http://Hypothes.is/stream'
assert feed['html_url'] == 'http://Hypothes.is/stream'


def test_feed_from_annotations_description():
Expand Down
1 change: 1 addition & 0 deletions h/feeds/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ def stream_rss(request):
"""An RSS feed of the /stream page."""
return feeds.render_rss(
request=request, annotations=_annotations(request),
rss_url=request.route_url("stream_rss"),
html_url=request.route_url("stream"),
title=request.registry.settings.get("h.feed.title") or _(
"Hypothesis Stream"),
Expand Down
11 changes: 5 additions & 6 deletions h/templates/rss.xml.jinja2
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ render the feed to RSS XML.
-#}
<?xml version="1.0"?>
<rss version="2.0">
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>{{ feed.title }}</title>
<link>{{ feed.link }}</link>
<link>{{ feed.html_url }}</link>
<atom:link href="{{ feed.rss_url }}" rel="self" type="application/rss+xml" />
<description>{{ feed.description }}</description>
<pubDate>{{ feed.pubDate }}</pubDate>
<docs>http://blogs.law.harvard.edu/tech/rss</docs>
Expand All @@ -19,10 +20,8 @@ render the feed to RSS XML.
<title>{{ item.title }}</title>
<description>{{ item.description|safe }}</description>
<pubDate>{{ item.pubDate }}</pubDate>
<guid isPermalink="true">{{ item.guid }}</guid>
{% for link in item.links %}
<link>{{ link }}</link>
{% endfor %}
<guid isPermaLink="true">{{ item.guid }}</guid>
<link>{{ item.link }}</link>
</item>
{% endfor %}
</channel>
Expand Down

0 comments on commit ce61a3f

Please sign in to comment.