Skip to content

Commit

Permalink
Fixed #9800 -- Allow "isPermaLink" attribute in <guid> element of an …
Browse files Browse the repository at this point in the history
…RSS item.

Thanks @rtnpro for the patch!
  • Loading branch information
charettes committed Feb 6, 2013
1 parent 2390fe3 commit 5449240
Show file tree
Hide file tree
Showing 6 changed files with 74 additions and 4 deletions.
2 changes: 2 additions & 0 deletions django/contrib/syndication/views.py
Expand Up @@ -184,6 +184,8 @@ def get_feed(self, obj, request):
link = link, link = link,
description = description, description = description,
unique_id = self.__get_dynamic_attr('item_guid', item, link), unique_id = self.__get_dynamic_attr('item_guid', item, link),
unique_id_is_permalink = self.__get_dynamic_attr(
'item_guid_is_permalink', item),
enclosure = enc, enclosure = enc,
pubdate = pubdate, pubdate = pubdate,
author_name = author_name, author_name = author_name,
Expand Down
11 changes: 8 additions & 3 deletions django/utils/feedgenerator.py
Expand Up @@ -113,8 +113,8 @@ def __init__(self, title, link, description, language=None, author_email=None,


def add_item(self, title, link, description, author_email=None, def add_item(self, title, link, description, author_email=None,
author_name=None, author_link=None, pubdate=None, comments=None, author_name=None, author_link=None, pubdate=None, comments=None,
unique_id=None, enclosure=None, categories=(), item_copyright=None, unique_id=None, unique_id_is_permalink=None, enclosure=None,
ttl=None, **kwargs): categories=(), item_copyright=None, ttl=None, **kwargs):
""" """
Adds an item to the feed. All args are expected to be Python Unicode Adds an item to the feed. All args are expected to be Python Unicode
objects except pubdate, which is a datetime.datetime object, and objects except pubdate, which is a datetime.datetime object, and
Expand All @@ -136,6 +136,7 @@ def add_item(self, title, link, description, author_email=None,
'pubdate': pubdate, 'pubdate': pubdate,
'comments': to_unicode(comments), 'comments': to_unicode(comments),
'unique_id': to_unicode(unique_id), 'unique_id': to_unicode(unique_id),
'unique_id_is_permalink': unique_id_is_permalink,
'enclosure': enclosure, 'enclosure': enclosure,
'categories': categories or (), 'categories': categories or (),
'item_copyright': to_unicode(item_copyright), 'item_copyright': to_unicode(item_copyright),
Expand Down Expand Up @@ -280,7 +281,11 @@ def add_item_elements(self, handler, item):
if item['comments'] is not None: if item['comments'] is not None:
handler.addQuickElement("comments", item['comments']) handler.addQuickElement("comments", item['comments'])
if item['unique_id'] is not None: if item['unique_id'] is not None:
handler.addQuickElement("guid", item['unique_id']) guid_attrs = {}
if isinstance(item.get('unique_id_is_permalink'), bool):
guid_attrs['isPermaLink'] = str(
item['unique_id_is_permalink']).lower()
handler.addQuickElement("guid", item['unique_id'], guid_attrs)
if item['ttl'] is not None: if item['ttl'] is not None:
handler.addQuickElement("ttl", item['ttl']) handler.addQuickElement("ttl", item['ttl'])


Expand Down
12 changes: 12 additions & 0 deletions docs/ref/contrib/syndication.txt
Expand Up @@ -624,6 +624,18 @@ This example illustrates all possible attributes and methods for a
Takes an item, as return by items(), and returns the item's ID. Takes an item, as return by items(), and returns the item's ID.
""" """


# ITEM_GUID_IS_PERMALINK -- The following method is optional. If
# provided, it sets the 'isPermaLink' attribute of an item's
# GUID element. This method is used only when 'item_guid' is
# specified.

def item_guid_is_permalink(self, obj):
"""
Takes an item, as returned by items(), and returns a boolean.
"""

item_guid_is_permalink = False # Hard coded value

# ITEM AUTHOR NAME -- One of the following three is optional. The # ITEM AUTHOR NAME -- One of the following three is optional. The
# framework looks for them in this order. # framework looks for them in this order.


Expand Down
13 changes: 13 additions & 0 deletions tests/regressiontests/syndication/feeds.py
Expand Up @@ -42,6 +42,19 @@ def item_pubdate(self, item):
item_copyright = 'Copyright (c) 2007, Sally Smith' item_copyright = 'Copyright (c) 2007, Sally Smith'




class TestRss2FeedWithGuidIsPermaLinkTrue(TestRss2Feed):
def item_guid_is_permalink(self, item):
return True


class TestRss2FeedWithGuidIsPermaLinkFalse(TestRss2Feed):
def item_guid(self, item):
return str(item.pk)

def item_guid_is_permalink(self, item):
return False


class TestRss091Feed(TestRss2Feed): class TestRss091Feed(TestRss2Feed):
feed_type = feedgenerator.RssUserland091Feed feed_type = feedgenerator.RssUserland091Feed


Expand Down
36 changes: 35 additions & 1 deletion tests/regressiontests/syndication/tests.py
Expand Up @@ -103,9 +103,43 @@ def test_rss2_feed(self):
'author': 'test@example.com (Sally Smith)', 'author': 'test@example.com (Sally Smith)',
}) })
self.assertCategories(items[0], ['python', 'testing']) self.assertCategories(items[0], ['python', 'testing'])

for item in items: for item in items:
self.assertChildNodes(item, ['title', 'link', 'description', 'guid', 'category', 'pubDate', 'author']) self.assertChildNodes(item, ['title', 'link', 'description', 'guid', 'category', 'pubDate', 'author'])
# Assert that <guid> does not have any 'isPermaLink' attribute
self.assertIsNone(item.getElementsByTagName(
'guid')[0].attributes.get('isPermaLink'))

def test_rss2_feed_guid_permalink_false(self):
"""
Test if the 'isPermaLink' attribute of <guid> element of an item
in the RSS feed is 'false'.
"""
response = self.client.get(
'/syndication/rss2/guid_ispermalink_false/')
doc = minidom.parseString(response.content)
chan = doc.getElementsByTagName(
'rss')[0].getElementsByTagName('channel')[0]
items = chan.getElementsByTagName('item')
for item in items:
self.assertEqual(
item.getElementsByTagName('guid')[0].attributes.get(
'isPermaLink').value, "false")

def test_rss2_feed_guid_permalink_true(self):
"""
Test if the 'isPermaLink' attribute of <guid> element of an item
in the RSS feed is 'true'.
"""
response = self.client.get(
'/syndication/rss2/guid_ispermalink_true/')
doc = minidom.parseString(response.content)
chan = doc.getElementsByTagName(
'rss')[0].getElementsByTagName('channel')[0]
items = chan.getElementsByTagName('item')
for item in items:
self.assertEqual(
item.getElementsByTagName('guid')[0].attributes.get(
'isPermaLink').value, "true")


def test_rss091_feed(self): def test_rss091_feed(self):
""" """
Expand Down
4 changes: 4 additions & 0 deletions tests/regressiontests/syndication/urls.py
Expand Up @@ -8,6 +8,10 @@
urlpatterns = patterns('django.contrib.syndication.views', urlpatterns = patterns('django.contrib.syndication.views',
(r'^syndication/complex/(?P<foo>.*)/$', feeds.ComplexFeed()), (r'^syndication/complex/(?P<foo>.*)/$', feeds.ComplexFeed()),
(r'^syndication/rss2/$', feeds.TestRss2Feed()), (r'^syndication/rss2/$', feeds.TestRss2Feed()),
(r'^syndication/rss2/guid_ispermalink_true/$',
feeds.TestRss2FeedWithGuidIsPermaLinkTrue()),
(r'^syndication/rss2/guid_ispermalink_false/$',
feeds.TestRss2FeedWithGuidIsPermaLinkFalse()),
(r'^syndication/rss091/$', feeds.TestRss091Feed()), (r'^syndication/rss091/$', feeds.TestRss091Feed()),
(r'^syndication/no_pubdate/$', feeds.TestNoPubdateFeed()), (r'^syndication/no_pubdate/$', feeds.TestNoPubdateFeed()),
(r'^syndication/atom/$', feeds.TestAtomFeed()), (r'^syndication/atom/$', feeds.TestAtomFeed()),
Expand Down

0 comments on commit 5449240

Please sign in to comment.