constance

Scripts for generating (an earlier obsolete version of) my personal web site
git clone https://code.djc.id.au/git/constance/
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:
Mapp.py | 17++++++++++++++---
Mblog.py | 33++++++++++++++++++++++-----------
Mtemplates/_commonwrapper.xml | 7++++---
Atemplates/_entry.xml | 54++++++++++++++++++++++++++++++++++++++++++++++++++++++
Atemplates/index.xml | 18++++++++++++++++++
Dtemplates/post.xml | 61-------------------------------------------------------------
Atemplates/single.xml | 17+++++++++++++++++
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>