Skip to content
Browse files

Added archive and Atom support

  • Loading branch information...
1 parent 8d92bff commit f2cf9dcf21271a270a5df251db79abaf0d420615 @Arachnid Arachnid committed Oct 11, 2009
Showing with 107 additions and 11 deletions.
  1. +4 −0 app.yaml
  2. +3 −0 config.py
  3. +60 −7 generators.py
  4. +6 −2 models.py
  5. +30 −0 themes/default/atom.xml
  6. +4 −2 themes/default/base.html
View
4 app.yaml
@@ -8,6 +8,10 @@ handlers:
script: $PYTHON_LIB/google/appengine/ext/remote_api/handler.py
login: admin
+- url: /_ah/queue/deferred
+ script: $PYTHON_LIB/google/appengine/ext/deferred/__init__.py
+ login: admin
+
- url: /admin/.*
script: admin.py
login: admin
View
3 config.py
@@ -7,6 +7,9 @@
# (Optional) slogan
slogan = 'This is my blog'
+# The hostname this site will primarially serve off (used for Atom feeds)
+host = 'localhost'
+
# Selects the theme to use. Theme names correspond to directories under
# the 'themes' directory, containing templates and static content.
theme = 'default'
View
67 generators.py
@@ -1,5 +1,7 @@
import hashlib
+import os
from google.appengine.ext import db
+from google.appengine.ext import deferred
import fix_path
import config
@@ -13,6 +15,9 @@
class ContentGenerator(object):
"""A class that generates content and dependency lists for blog posts."""
+ can_defer = True
+ """If True, this ContentGenerator's resources can be generated later."""
+
@classmethod
def name(cls):
return cls.__name__
@@ -54,17 +59,23 @@ def generate_resource(cls, post, resource):
class PostContentGenerator(ContentGenerator):
"""ContentGenerator for the actual blog post itself."""
+ can_defer = False
+
@classmethod
def get_resource_list(cls, post):
- return [post.path]
+ return [post.key().id()]
@classmethod
def get_etag(cls, post):
return hashlib.sha1(db.model_to_protobuf(post).Encode()).hexdigest()
@classmethod
def generate_resource(cls, post, resource):
- assert resource == post.path
+ import models
+ if not post:
+ post = models.BlogPost.get_by_id(resource)
+ else:
+ assert resource == post.key().id()
template_vals = {
'post': post,
}
@@ -85,14 +96,56 @@ def get_etag(cls, post):
return hashlib.sha1((post.title + post.summary).encode('utf-8')).hexdigest()
@classmethod
- def generate_resource(cls, post, resource):
- assert resource == "index"
+ def generate_resource(cls, post, resource, pagenum=1, start_ts=None):
import models
q = models.BlogPost.all().order('-published')
- posts = q.fetch(config.posts_per_page)
+ if start_ts:
+ q.filter('published <=', start_ts)
+
+ posts = q.fetch(config.posts_per_page + 1)
+ more_posts = len(posts) > config.posts_per_page
+
template_vals = {
- 'posts': posts,
+ 'posts': posts[:config.posts_per_page],
+ 'prev_page': pagenum - 1,
+ 'next_page': pagenum + 1 if more_posts else None,
}
rendered = utils.render_template("listing.html", template_vals)
- static.set('/', rendered, config.html_mime_type)
+
+ path_args = {
+ 'resource': resource,
+ 'pagenum': pagenum,
+ }
+ static.set('/page/%d' % (pagenum,), rendered, config.html_mime_type)
+ if pagenum == 1:
+ static.set('/', rendered, config.html_mime_type)
+
+ if more_posts:
+ deferred.defer(cls.generate_resource, None, resource, pagenum + 1,
+ posts[-1].published)
generator_list.append(IndexContentGenerator)
+
+
+class AtomContentGenerator(ContentGenerator):
+ """ContentGenerator for Atom feeds."""
+
+ @classmethod
+ def get_resource_list(cls, post):
+ return ["atom"]
+
+ @classmethod
+ def get_etag(cls, post):
+ return hashlib.sha1(db.model_to_protobuf(post).Encode()).hexdigest()
+
+ @classmethod
+ def generate_resource(cls, post, resource):
+ import models
+ q = models.BlogPost.all().order('-updated')
+ posts = q.fetch(10)
+ template_vals = {
+ 'posts': posts,
+ }
+ rendered = utils.render_template("atom.xml", template_vals)
+ static.set('/feeds/atom.xml', rendered,
+ 'application/atom+xml; charset=utf-8')
+generator_list.append(AtomContentGenerator)
View
8 models.py
@@ -49,7 +49,11 @@ def publish(self):
else:
# Otherwise just regenerate the changes
to_regenerate = new_deps ^ old_deps
- for dep in to_regenerate:
- generator_class.generate_resource(self, dep)
+ if generator_class.can_defer:
+ for dep in to_regenerate:
+ deferred.defer(generator_class.generate_resource, None, dep)
+ else:
+ for dep in to_regenerate:
+ generator_class.generate_resource(self, dep)
self.deps[generator_class.name()] = (new_deps, new_etag)
self.put()
View
30 themes/default/atom.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<feed xmlns="http://www.w3.org/2005/Atom">
+ <title type="text">{{config.blog_name}}</title>
+ <subtitle type="html">{{config.slogan}}</subtitle>
+ <updated>{{posts.0.updated}}</updated>
+ <id>tag:{{config.host}},2009:atom.xml</id>
+ <link rel="alternate" type="text/html" hreflang="en" href="http://{{config.host}}/" />
+ <link rel="self" type="application/atom+xml" href="http://{{config.host}}/feeds/atom.xml" />
+ <rights>Copyright (c) 2009</rights>
+ <generator uri="http://{{config.host}}/" version="1.0">
+ Bloggart 1.0
+ </generator>
+ {% for post in posts %}
+ <entry>
+ <title>{{post.title}}</title>
+ <link rel="alternate" type="text/html" href="http://{{config.host}}{{post.path}}" />
+ <id>tag:{{config.host}},2009:post:{{post.key.id}}</id>
+ <updated>{{post.updated|date:"Y-m-d\TH:i:s\Z"}}</updated>
+ <published>{{post.published|date:"Y-m-d\TH:i:s\Z"}}</published>
+ <author>
+ <name>{{config.author_name}}</name>
+ <uri>http://{{config.host}}/</uri>
+ </author>
+ <content type="html">
+ {{post.body|escape}}
+ </content>
+ </entry>
+ {% endfor %}
+</feed>
View
6 themes/default/base.html
@@ -2,12 +2,13 @@
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>{% block title %}Bloggart{% endblock %}</title>
- <link rel="stylesheet" type="text/css" media="screen" href="/static/default/css/screen.css" />
+ <link rel="stylesheet" type="text/css" media="screen" href="/static/{{config.theme}}/css/screen.css" />
+ <link rel="alternate" type="application/atom+xml" href="/feeds/atom.xml" />
{% block head %}{% endblock %}
</head>
<body>
<div id="header-wrap"><div id="header" class="container_16">
- <h1 id="logo-text"><a href="index.html" title="">{{config.blog_name}}</a></h1>
+ <h1 id="logo-text"><a href="/" title="">{{config.blog_name}}</a></h1>
<p id="intro">{{config.slogan}}</p>
<div id="nav">
<ul>
@@ -41,6 +42,7 @@ <h1 id="logo-text"><a href="index.html" title="">{{config.blog_name}}</a></h1>
</p>
<p class="bottom-right" >
<a href="/">Home</a> |
+ <a href="/feeds/atom.xml">Atom</a> |
<a href="http://jigsaw.w3.org/css-validator/check/referer">CSS</a> |
<a href="http://validator.w3.org/check/referer">XHTML</a>
</p>

0 comments on commit f2cf9dc

Please sign in to comment.
Something went wrong with that request. Please try again.