##// END OF EJS Templates
feeds: replace webhelpers.feedgenerator with simple mako templating for rendering RSS/Atom XML...
Mads Kiilerich -
r7899:6c9e8aa9 default
parent child Browse files
Show More
@@ -22,38 +22,131 b' Shared code for providing RSS and ATOM f'
22 import datetime
22 import datetime
23 import re
23 import re
24
24
25 from webhelpers import feedgenerator
25 import mako.template
26
26
27
27
28 language = 'en-us'
28 language = 'en-us'
29 ttl = "5"
29 ttl = "5"
30
30
31
32 # From ``django.utils.feedgenerator`` via webhelpers.feedgenerator
33 def rfc2822_date(date):
34 # We do this ourselves to be timezone aware, email.Utils is not tz aware.
35 if getattr(date, "tzinfo", False):
36 time_str = date.strftime('%a, %d %b %Y %H:%M:%S ')
37 offset = date.tzinfo.utcoffset(date)
38 timezone = (offset.days * 24 * 60) + (offset.seconds / 60)
39 hour, minute = divmod(timezone, 60)
40 return time_str + "%+03d%02d" % (hour, minute)
41 else:
42 return date.strftime('%a, %d %b %Y %H:%M:%S -0000')
43
44 # From ``django.utils.feedgenerator`` via webhelpers.feedgenerator
45 def rfc3339_date(date):
46 if getattr(date, "tzinfo", False):
47 time_str = date.strftime('%Y-%m-%dT%H:%M:%S')
48 offset = date.tzinfo.utcoffset(date)
49 timezone = (offset.days * 24 * 60) + (offset.seconds / 60)
50 hour, minute = divmod(timezone, 60)
51 return time_str + "%+03d:%02d" % (hour, minute)
52 else:
53 return date.strftime('%Y-%m-%dT%H:%M:%SZ')
54
55 # From ``django.utils.feedgenerator`` via webhelpers.feedgenerator
56 def get_tag_uri(url, date):
57 "Creates a TagURI. See http://diveintomark.org/archives/2004/05/28/howto-atom-id"
58 tag = re.sub('^http://', '', url)
59 if date is not None:
60 tag = re.sub('/', ',%s:/' % date.strftime('%Y-%m-%d'), tag, 1)
61 tag = re.sub('#', '/', tag)
62 return u'tag:' + tag
63
64
65 class Attributes(object):
66 """Simple namespace for attribute dict access in mako and elsewhere"""
67 def __init__(self, a_dict):
68 self.__dict__ = a_dict
69
70
31 class _Feeder(object):
71 class _Feeder(object):
32
72
33 content_type = None
73 content_type = None
34 feed_factory = None # a webhelpers.feedgenerator
74 template = None # subclass must provide a mako.template.Template
35
75
36 @classmethod
76 @classmethod
37 def render(cls, header, entries):
77 def render(cls, header, entries):
38 feed = cls.feed_factory(
78 try:
79 latest_pubdate = max(
80 pubdate for pubdate in (e.get('pubdate') for e in entries)
81 if pubdate
82 )
83 except ValueError: # max() arg is an empty sequence ... or worse
84 latest_pubdate = datetime.datetime.now()
85
86 return cls.template.render(
39 language=language,
87 language=language,
40 ttl=ttl, # rss only
88 ttl=ttl, # rss only
89 latest_pubdate=latest_pubdate,
90 rfc2822_date=rfc2822_date, # for RSS
91 rfc3339_date=rfc3339_date, # for Atom
92 get_tag_uri=get_tag_uri,
93 entries=[Attributes(e) for e in entries],
41 **header
94 **header
42 )
95 )
43 for e in entries:
44 feed.add_item(**e)
45 return feed.writeString('utf-8')
46
96
47
97
48 class AtomFeed(_Feeder):
98 class AtomFeed(_Feeder):
49
99
50 content_type = 'application/atom+xml'
100 content_type = 'application/atom+xml'
51
101
52 feed_factory = feedgenerator.Atom1Feed
102 template = mako.template.Template('''\
103 <?xml version="1.0" encoding="utf-8"?>
104 <feed xmlns="http://www.w3.org/2005/Atom" xml:lang="${language}">
105 <title>${title}</title>
106 <link href="${link}" rel="alternate"></link>
107 <id>${link}</id>
108 <updated>${rfc3339_date(latest_pubdate)}</updated>
109 % for entry in entries:
110 <entry>
111 <title>${entry.title}</title>
112 <link href="${entry.link}" rel="alternate"></link>
113 <updated>${rfc3339_date(entry.pubdate)}</updated>
114 <published>${rfc3339_date(entry.pubdate)}</published>
115 <author>
116 <name>${entry.author_name}</name>
117 <email>${entry.author_email}</email>
118 </author>
119 <id>${get_tag_uri(entry.link, entry.pubdate)}</id>
120 <summary type="html">${entry.description}</summary>
121 </entry>
122 % endfor
123 </feed>
124 ''', default_filters=['x'], output_encoding='utf-8', encoding_errors='replace')
53
125
54
126
55 class RssFeed(_Feeder):
127 class RssFeed(_Feeder):
56
128
57 content_type = 'application/rss+xml'
129 content_type = 'application/rss+xml'
58
130
59 feed_factory = feedgenerator.Rss201rev2Feed
131 template = mako.template.Template('''\
132 <?xml version="1.0" encoding="utf-8"?>
133 <rss version="2.0">
134 <channel>
135 <title>${title}</title>
136 <link>${link}</link>
137 <description>${description}</description>
138 <language>${language}</language>
139 <lastBuildDate>${rfc2822_date(latest_pubdate)}</lastBuildDate>
140 <ttl>${ttl}</ttl>
141 % for entry in entries:
142 <item>
143 <title>${entry.title}</title>
144 <link>${entry.link}</link>
145 <description>${entry.description}</description>
146 <author>${entry.author_email} (${entry.author_name})</author>
147 <pubDate>${rfc2822_date(entry.pubdate)}</pubDate>
148 </item>
149 % endfor
150 </channel>
151 </rss>
152 ''', default_filters=['x'], output_encoding='utf-8', encoding_errors='replace')
General Comments 0
You need to be logged in to leave comments. Login now