commit a3a7cf1cf4f9479895fb4f554c2664fa52122a34
parent 735ffac07e6300ec05dffedaba6f7ea1e609b525
Author: Dan Callaghan <djc@djc.id.au>
Date: Sat, 7 Jun 2008 01:10:01 +1000
index (TODO pagination)
committer: Dan Callaghan <djc@djc.id.au>
--HG--
extra : convert_revision : dcd6ae50cfce64ff7aa2a5591be25da6a20b214f
Diffstat:
7 files changed, 129 insertions(+), 78 deletions(-)
diff --git a/app.py b/app.py
@@ -4,10 +4,14 @@ from colubrid import RegexApplication, HttpResponse, execute
from colubrid.exceptions import PageNotFound, HttpFound
from colubrid.server import StaticExports
-from blog import Entry
+from blog import Entries
+
+ENTRIES_DIR = os.path.join(os.path.dirname(__file__), u'entries')
+BASE_URL = ''
template_loader = TemplateLoader(
os.path.join(os.path.dirname(__file__), 'templates'),
+ variable_lookup='strict',
auto_reload=True)
class BlogApplication(RegexApplication):
@@ -17,11 +21,18 @@ class BlogApplication(RegexApplication):
(r'^([^/]+)/?$', 'post')]
charset = 'utf-8'
+ def __init__(self, *args, **kwargs):
+ super(BlogApplication, self).__init__(*args, **kwargs)
+ self.entries = Entries(ENTRIES_DIR)
+
def index(self):
- return HttpResponse('blah')
+ rendered = template_loader.load('index.xml').generate(entries=self.entries).render('xhtml')
+ return HttpResponse(rendered, [('Content-Type', 'text/html')], 200)
def post(self, id):
- rendered = template_loader.load('post.xml').generate(entry=Entry(id)).render('xhtml')
+ id = id.decode(self.charset) # shouldn't Colubrid do this?
+ entry = self.entries[id]
+ rendered = template_loader.load('single.xml').generate(entry=entry).render('xhtml')
return HttpResponse(rendered, [('Content-Type', 'text/html')], 200)
app = BlogApplication
diff --git a/blog.py b/blog.py
@@ -3,10 +3,6 @@ from datetime import datetime
import markdown
-ENTRIES_DIR = os.path.join(os.path.dirname(__file__), 'entries')
-BASE_URL = ''
-
-
def cleanup_metadata(meta):
cleaned = {}
for k, v in meta.iteritems():
@@ -26,11 +22,29 @@ class CommentNotFoundError(ValueError): pass
class CommentForbiddenError(ValueError): pass
+class Entries(object):
+
+ def __init__(self, entries_dir):
+ self.entries_dir = entries_dir
+
+ def __contains__(self, id):
+ return os.path.exists(os.path.join(self.entries_dir, id))
+
+ def __getitem__(self, id):
+ return Entry(self.entries_dir, id)
+
+ def __iter__(self):
+ return (Entry(self.entries_dir, filename)
+ for filename in os.listdir(self.entries_dir)
+ if not filename.startswith('.'))
+
+
class Entry(object):
- def __init__(self, id):
+ def __init__(self, entries_dir, id):
+ assert isinstance(id, unicode), id
self.id = id
- self.dir = os.path.join(ENTRIES_DIR, id)
+ self.dir = os.path.join(entries_dir, id)
self.comments_dir = os.path.join(self.dir, 'comments')
if not os.path.exists(self.dir):
@@ -38,7 +52,7 @@ class Entry(object):
if not os.access(self.dir, os.R_OK):
raise EntryForbiddenError()
- self.raw = open(os.path.join(self.dir, 'content.txt'), 'r').read()
+ self.raw = open(os.path.join(self.dir, 'content.txt'), 'r').read().decode('utf-8')
md = markdown.Markdown(extensions=['meta'])
self.body = md.convert(self.raw)
self.metadata = cleanup_metadata(md.Meta)
@@ -58,9 +72,6 @@ class Entry(object):
self.modified_date = datetime.fromtimestamp(os.path.getmtime(os.path.join(self.dir, 'content.txt')))
self.publication_date = self.metadata.get('publication-date', None) or self.modified_date
- def permalink(self):
- return '%s/%s/' % (BASE_URL, self.id)
-
def comments(self):
return Comments(self.comments_dir)
@@ -100,7 +111,7 @@ class Comment(object):
raise CommentForbiddenError()
self.id = id
- self.raw = open(path, 'r').read()
+ self.raw = open(path, 'r').read().decode('utf-8')
md = markdown.Markdown(extensions=['meta'])
self.body = md.convert(self.raw)
if not hasattr(md, 'Meta'): raise Exception(self.raw)
diff --git a/templates/_commonwrapper.xml b/templates/_commonwrapper.xml
@@ -5,13 +5,14 @@
py:strip="True">
<?python
-from blog import BASE_URL
+from app import BASE_URL
?>
<py:match path="head">
- <head profile="http://gmpg.org/xfn/11" py:attrs="select('@*')">
+ <head profile="http://gmpg.org/xfn/11" py:attrs="select('@*')" py:with="title = unicode(select('title[1]/text()'))">
${select('./*[local-name() != "title"]')}
- <title>${select('title[1]/text()')} - djc</title>
+ <title py:if="title">${title} - djc</title>
+ <title py:if="not title">djc</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<meta name="generator" content="Dan’s blogging engine" />
<link rel="stylesheet" type="text/css" href="${BASE_URL}/static/css/common.css" />
diff --git a/templates/_entry.xml b/templates/_entry.xml
@@ -0,0 +1,54 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1.dtd">
+<div xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:py="http://genshi.edgewall.org/"
+ py:strip="True"
+ py:def="show_entry(entry, show_comments=True)">
+
+<div class="entry">
+
+ <h3 class="entrytitle" id="post-${entry.id}"><a href="${BASE_URL}/${entry.id}" rel="bookmark">${entry.title}</a></h3>
+
+ <div class="entrymeta">
+ Posted ${entry.publication_date.strftime(str('%-1d %B %Y'))}
+ <py:if test="entry.categories">
+ in
+ <py:with vars="category = entry.categories[0]">
+ <a href="${BASE_URL}/+categories/${category}">${category}</a>
+ </py:with>
+ <py:for each="category in entry.categories[1:]">
+ , <a href="${BASE_URL}/+categories/${category}">${category}</a>
+ </py:for>
+ </py:if>
+ </div>
+
+ <div class="entrybody">
+ ${Markup(entry.body)}
+ <p py:if="entry.tags">
+ <img src="${BASE_URL}/static/images/tag_blue.png" alt="Tags:" /> ${', '.join(entry.tags)}
+ </p>
+ </div>
+
+</div>
+
+<div id="commentblock"
+ py:if="show_comments and entry.has_comments()"
+ py:with="comments = sorted(entry.comments(), key=lambda c: c.date)">
+ <h2 id="comments">${len(comments) == 1 and '1 comment' or '%d comments' % len(comments)} so far</h2>
+ <ol class="commentlist" id="commentlist">
+ <li py:for="n, comment in enumerate(comments)"
+ class="${(n % 2) and 'alt' or 'standard'}"
+ id="comment-${comment.id}">
+ <div class="commentname">
+ <a py:strip="not comment.author_url" href="${comment.author_url}">${comment.author_name()}</a>
+ on <a href="#comment-${comment.id}">${comment.date.strftime(str('%-1d %B %Y'))}</a>
+ </div>
+ <div class="commenttext">
+ <div class="commentp">
+ ${Markup(comment.body)}
+ </div>
+ </div>
+ </li>
+ </ol>
+</div>
+
+</div>
diff --git a/templates/index.xml b/templates/index.xml
@@ -0,0 +1,18 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:py="http://genshi.edgewall.org/"
+ xmlns:xi="http://www.w3.org/2001/XInclude"
+ lang="en-AU">
+<xi:include href="_commonwrapper.xml" />
+<xi:include href="_entry.xml" />
+
+<head>
+</head>
+<body>
+
+<py:for each="entry in sorted(entries, key=lambda e: e.publication_date, reverse=True)[:20]">
+ ${show_entry(entry, show_comments=False)}
+</py:for>
+
+</body>
+</html>
diff --git a/templates/post.xml b/templates/post.xml
@@ -1,61 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml"
- xmlns:py="http://genshi.edgewall.org/"
- xmlns:xi="http://www.w3.org/2001/XInclude"
- lang="en-AU">
-<xi:include href="_commonwrapper.xml" />
-
-<head>
- <title>${entry.title}</title>
-</head>
-<body>
-
-<div class="entry">
-
- <h3 class="entrytitle" id="post-${entry.id}"><a href="${entry.permalink()}" rel="bookmark">${entry.title}</a></h3>
-
- <div class="entrymeta">
- Posted ${entry.publication_date.strftime(str('%-1d %B %Y'))}
- <py:if test="entry.categories">
- in
- <py:with vars="category = entry.categories[0]">
- <a href="${BASE_URL}/+categories/${category}">${category}</a>
- </py:with>
- <py:for each="category in entry.categories[1:]">
- , <a href="${BASE_URL}/+categories/${category}">${category}</a>
- </py:for>
- </py:if>
- </div>
-
- <div class="entrybody">
- ${Markup(entry.body)}
- <p py:if="entry.tags">
- <img src="${BASE_URL}/static/images/tag_blue.png" alt="Tags:" /> ${', '.join(entry.tags)}
- </p>
- </div>
-
-</div>
-
-<div id="commentblock"
- py:if="entry.has_comments()"
- py:with="comments = sorted(entry.comments(), key=lambda c: c.date)">
- <h2 id="comments">${len(comments) == 1 and '1 comment' or '%d comments' % len(comments)} so far</h2>
- <ol class="commentlist" id="commentlist">
- <li py:for="n, comment in enumerate(comments)"
- class="${(n % 2) and 'alt' or 'standard'}"
- id="comment-${comment.id}">
- <div class="commentname">
- <a py:strip="not comment.author_url" href="${comment.author_url}">${comment.author_name()}</a>
- on <a href="#comment-${comment.id}">${comment.date.strftime(str('%-1d %B %Y'))}</a>
- </div>
- <div class="commenttext">
- <div class="commentp">
- ${Markup(comment.body)}
- </div>
- </div>
- </li>
- </ol>
-</div>
-
-</body>
-</html>
diff --git a/templates/single.xml b/templates/single.xml
@@ -0,0 +1,17 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:py="http://genshi.edgewall.org/"
+ xmlns:xi="http://www.w3.org/2001/XInclude"
+ lang="en-AU">
+<xi:include href="_commonwrapper.xml" />
+<xi:include href="_entry.xml" />
+
+<head>
+ <title>${entry.title}</title>
+</head>
+<body>
+
+${show_entry(entry, show_comments=True)}
+
+</body>
+</html>