commit d78b313afff4b31c52f9b500fc441cea400ef81c
parent e85797d6bb556cbf827118fc5ca46339dcb4d06f
Author: Dan Callaghan <djc@djc.id.au>
Date: Thu, 4 Dec 2008 18:24:59 +1000
atom
--HG--
rename : templates/multiple_atom.xml => templates/atom/BlogEntry.xml
rename : templates/multiple_atom.xml => templates/atom/ReadingLogEntry.xml
rename : templates/multiple_atom.xml => templates/atom/multiple.xml
Diffstat:
7 files changed, 124 insertions(+), 77 deletions(-)
diff --git a/app.py b/app.py
@@ -36,7 +36,7 @@ class Constance(object):
def __iter__(self):
try:
- resp = self.dispatch(self.req.path_info)
+ resp = self.dispatch()
except exc.HTTPException, e:
resp = e
return iter(resp(self.environ, self.start))
@@ -51,10 +51,13 @@ class Constance(object):
(r'/blog/([^/]+)/?$', 'blog_entry'),
(r'/blog/([^/]+)/comments/\+new$', 'add_post_comment')]
urls = [(re.compile(patt), method) for patt, method in urls]
- def dispatch(self, path_info):
- if path_info == '/':
- return self.index()
- path_info = urllib.unquote(path_info).decode(self.encoding)
+ def dispatch(self):
+ format = self.req.accept.best_match(['text/html', 'application/atom+xml']) # XXX don't hardcode
+
+ if self.req.path_info == '/':
+ return self.index(format)
+
+ path_info = urllib.unquote(self.req.path_info).decode(self.encoding)
for item_set in self.item_sets:
try:
result = item_set.get(path_info)
@@ -62,37 +65,51 @@ class Constance(object):
pass
else:
if hasattr(result, '__iter__'):
- return self.render_multiple(result)
+ return self.render_multiple(result, format)
else:
- return self.render_single(result)
+ return self.render_single(result, format)
# no matching URI found, so give a 404
raise exc.HTTPNotFound().exception
- def render_single(self, item):
- template = template_loader.load('html/single.xml')
- rendered = template.generate(
- config=self.config,
- item=item
- ).render('xhtml')
- return Response(rendered, content_type='text/html')
+ def render_single(self, item, format):
+ if format == 'text/html':
+ template = template_loader.load('html/single.xml')
+ rendered = template.generate(
+ config=self.config,
+ item=item
+ ).render('xhtml')
+ else:
+ raise exc.HTTPBadRequest('Unacceptable format for render_single %r' % format).exception
+ return Response(rendered, content_type=format)
- def render_multiple(self, items):
+ def render_multiple(self, items, format):
try:
offset = int(self.req.GET.get('offset', 0))
except ValueError:
raise exc.HTTPBadRequest('Invalid offset %r' % self.GET['offset']).exception
- template = template_loader.load('html/multiple.xml')
- rendered = template.generate(
- config=self.config,
- items=items,
- title=None,
- offset=offset
- ).render('xhtml')
- return Response(rendered, content_type='text/html')
+ if format == 'text/html':
+ template = template_loader.load('html/multiple.xml')
+ rendered = template.generate(
+ config=self.config,
+ items=items,
+ title=None,
+ offset=offset
+ ).render('xhtml')
+ elif format == 'application/atom+xml':
+ template = template_loader.load('atom/multiple.xml')
+ rendered = template.generate(
+ config=self.config,
+ items=items,
+ title=None,
+ self_url=self.req.path_url
+ ).render('xml')
+ else:
+ raise exc.HTTPBadRequest('Unacceptable format for render_multiple %r' % format).exception
+ return Response(rendered, content_type=format)
- def index(self):
+ def index(self, format):
items = chain(*self.item_sets)
- return self.render_multiple(items)
+ return self.render_multiple(items, format)
def tag_cloud(self):
tag_freqs = {}
diff --git a/itemtypes.py b/itemtypes.py
@@ -91,6 +91,9 @@ class BlogEntry(object):
if format == 'text/html':
template = template_loader.load('html/' + self.__class__.__name__ + '.xml')
return template.generate(item=self)
+ elif format == 'application/atom+xml':
+ template = template_loader.load('atom/' + self.__class__.__name__ + '.xml')
+ return template.generate(item=self)
else:
raise UnsupportedFormatError(format)
@@ -159,6 +162,9 @@ class ReadingLogEntry(object):
if format == 'text/html':
template = template_loader.load('html/' + self.__class__.__name__ + '.xml')
return template.generate(item=self)
+ elif format == 'application/atom+xml':
+ template = template_loader.load('atom/' + self.__class__.__name__ + '.xml')
+ return template.generate(item=self)
else:
raise UnsupportedFormatError(format)
diff --git a/templates/atom/BlogEntry.xml b/templates/atom/BlogEntry.xml
@@ -0,0 +1,27 @@
+<entry xmlns="http://www.w3.org/2005/Atom"
+ xmlns:py="http://genshi.edgewall.org/"
+ xmlns:xi="http://www.w3.org/2001/XInclude">
+
+<?python
+import blog
+from viewutils import markdown, tag_list, ATOM_TIME_FORMAT
+?>
+
+<id>${item.guid}</id>
+<published>${item.publication_date.strftime(ATOM_TIME_FORMAT)}</published>
+<updated>${item.modified_date.strftime(ATOM_TIME_FORMAT)}</updated>
+<!--author py:with="email = config.getunicode('global', 'email')">
+ <name>${config.getunicode('global', 'author')}</name>
+ <email py:if="email">${email}</email>
+</author-->
+<category py:for="tag in item.tags" scheme="/tags/" term="${tag}" /><!-- XXX app_uri -->
+<link rel="alternate" href="${item.uri_path}" /><!-- XXX app_uri -->
+<title type="text">${item.title}</title>
+<content type="xhtml" xml:base="${item.uri_path}"><!-- XXX app_uri -->
+ <div xmlns="http://www.w3.org/1999/xhtml">
+ <p py:if="item.tags">Tagged: ${tag_list('', item.tags)}</p><!-- XXX script_name -->
+ ${markdown(item.body)}
+ </div>
+</content>
+
+</entry>
diff --git a/templates/atom/ReadingLogEntry.xml b/templates/atom/ReadingLogEntry.xml
@@ -0,0 +1,26 @@
+<entry xmlns="http://www.w3.org/2005/Atom"
+ xmlns:py="http://genshi.edgewall.org/"
+ xmlns:xi="http://www.w3.org/2001/XInclude">
+
+<?python
+from viewutils import ATOM_TIME_FORMAT
+?>
+
+<id>${item.guid}</id>
+<published>${item.publication_date.strftime(ATOM_TIME_FORMAT)}</published>
+<updated>${item.modified_date.strftime(ATOM_TIME_FORMAT)}</updated>
+<!--author py:with="email = config.getunicode('global', 'email')">
+ <name>${config.getunicode('global', 'author')}</name>
+ <email py:if="email">${email}</email>
+</author-->
+<category py:for="tag in item.tags" scheme="/tags/" term="${tag}" /><!-- XXX app_uri -->
+<title type="text">${item.title} by ${item.author}</title>
+<summary py:if="item.rating" type="text">${item.rating} stars</summary>
+<content type="xhtml">
+ <div xmlns="http://www.w3.org/1999/xhtml">
+ <p><a href="${item.url}">${item.title}</a> by ${item.author}</p>
+ <p py:if="item.rating">${item.rating} stars</p>
+ </div>
+</content>
+
+</entry>
diff --git a/templates/atom/multiple.xml b/templates/atom/multiple.xml
@@ -0,0 +1,21 @@
+<feed xmlns="http://www.w3.org/2005/Atom"
+ xmlns:py="http://genshi.edgewall.org/"
+ xmlns:xi="http://www.w3.org/2001/XInclude">
+
+<?python
+from viewutils import ATOM_TIME_FORMAT
+sorted_items = sorted(items, key=lambda item: item.publication_date, reverse=True)[:config.getint('global', 'items_in_feed')]
+?>
+
+<id>${self_url}</id>
+<title type="text">${config.getunicode('global', 'name')}<py:if test="title"> (${title})</py:if></title>
+<link rel="self" type="application/atom+xml" href="${self_url}" />
+<link rel="alternate" href="${self_url}" />
+<generator>constance</generator>
+<updated py:if="sorted_items">${max(item.modified_date for item in sorted_items).strftime(ATOM_TIME_FORMAT)}</updated>
+
+<py:for each="item in sorted_items">
+ ${item.render('application/atom+xml')}
+</py:for>
+
+</feed>
diff --git a/templates/multiple_atom.xml b/templates/multiple_atom.xml
@@ -1,52 +0,0 @@
-<feed xmlns="http://www.w3.org/2005/Atom"
- xmlns:py="http://genshi.edgewall.org/"
- xmlns:xi="http://www.w3.org/2001/XInclude">
-
-<xi:include href="_fragments.xml" />
-
-<?python
-import blog
-from viewutils import markdown, tag_list
-ATOM_TIME_FORMAT = str('%Y-%m-%dT%H:%M:%S+10:00')
-?>
-
-<id>${self_url}?format=atom</id>
-<title type="text">${config.getunicode('global', 'name')}<py:if test="title"> (${title})</py:if></title>
-<link rel="self" type="application/atom+xml" href="${self_url}?format=atom" />
-<link rel="alternate" href="${self_url}" />
-<generator>constance</generator>
-<updated>${feed_updated.strftime(ATOM_TIME_FORMAT)}</updated>
-
-<entry py:for="entry in sorted_entries">
- <id>${entry.guid}</id>
- <published>${entry.publication_date.strftime(ATOM_TIME_FORMAT)}</published>
- <updated>${entry.modified_date.strftime(ATOM_TIME_FORMAT)}</updated>
- <author py:with="email = config.getunicode('global', 'email')">
- <name>${config.getunicode('global', 'author')}</name>
- <email py:if="email">${email}</email>
- </author>
- <category py:for="tag in entry.tags" scheme="${abs_uri('tags', '')}" term="${tag}" />
- <py:if test="isinstance(entry, blog.BlogEntry)">
- <link rel="alternate" href="${abs_uri('blog', entry.id)}" />
- <title type="text">${entry.title}</title>
- <content type="xhtml" xml:base="${abs_uri('blog', entry.id)}">
- <div xmlns="http://www.w3.org/1999/xhtml">
- <p py:if="entry.tags">Tagged: ${tag_list(environ.get('SCRIPT_NAME', ''), entry.tags)}</p>
- ${markdown(entry.body)}
- </div>
- </content>
- </py:if>
- <py:if test="isinstance(entry, blog.ReadingLogEntry)">
- <link rel="alternate" href="${abs_uri('reading', '')}#entry-${entry.id}" />
- <title type="text">${entry.title} by ${entry.author}</title>
- <summary py:if="entry.rating" type="text">${entry.rating} stars</summary>
- <content type="xhtml">
- <div xmlns="http://www.w3.org/1999/xhtml">
- <p><a href="${entry.url}">${entry.title}</a> by ${entry.author}</p>
- <p py:if="entry.rating">${entry.rating} stars</p>
- </div>
- </content>
- </py:if>
-</entry>
-
-</feed>
diff --git a/viewutils.py b/viewutils.py
@@ -21,6 +21,8 @@ def idify(s):
s = IDIFY_WHITESPACE_PATT.sub(u'-', s)
return u''.join(c for c in s if IDIFY_ACCEPT_PATT.match(c))
+ATOM_TIME_FORMAT = '%Y-%m-%dT%H:%M:%S+10:00'
+
def tag_list(script_name, tags):
# XXX urllib.quote
return genshi.Markup(u', ').join(