constance

Scripts for generating (an earlier obsolete version of) my personal web site
git clone https://code.djc.id.au/git/constance/
commit 33194f9e20c26ffb4f3ea38b26731a33d1f6a388
parent 06ce84e6db72be2bc02e37c9719776e241acca94
Author: Dan Callaghan <djc@djc.id.au>
Date:   Fri,  6 Jun 2008 23:00:30 +1000

comments

committer: Dan Callaghan <djc@djc.id.au>

--HG--
extra : convert_revision : 9877f93ed324df60000629e45a7d96602617ec28

Diffstat:
Mblog.py | 33+++++++++++++++++++++++++--------
Mexport_wp.py | 97++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------
Astatic/images/comm.gif | 0
Mtemplates/post.xml | 29++++++++++++++++++++---------
4 files changed, 116 insertions(+), 43 deletions(-)
diff --git a/blog.py b/blog.py
@@ -61,6 +61,9 @@ class Entry(object):
 	def permalink(self):
 		return '%s/%s/' % (BASE_URL, self.id)
 
+	def comments(self):
+		return Comments(self.comments_dir)
+
 	def has_comments(self):
 		"""
 		Returns True if this Entry could *possibly* have comments, although it 
@@ -69,29 +72,43 @@ class Entry(object):
 		return os.path.isdir(self.comments_dir) and \
 				os.access(self.comments_dir, os.R_OK)
 
-	def comments(self):
-		for filename in sorted(os.listdir(self.comments_dir), key=int):
-			yield Comment(os.path.join(self.comments_dir, filename))
 
-	def comment(self, id):
-		return Comment(os.path.join(self.comments_dir, str(id)))
+class Comments(object):
+
+	def __init__(self, path):
+		self.path = path
+	
+	def __contains__(self, id):
+		return os.path.exists(os.path.join(self.path, id))
+	
+	def __getitem__(self, id):
+		return Comment(self.path, id)
+	
+	def __iter__(self):
+		return (Comment(self.path, filename) 
+				for filename in os.listdir(self.path)
+				if not filename.startswith('.'))
 
 
 class Comment(object):
 
-	def __init__(self, path):
+	def __init__(self, comments_dir, id):
+		path = os.path.join(comments_dir, id)
 		if not os.path.exists(path):
 			raise CommentNotFoundError()
 		if not os.access(path, os.R_OK):
 			raise CommentForbiddenError()
 
+		self.id = id
 		self.raw = open(path, 'r').read()
 		md = markdown.Markdown(extensions=['meta'])
 		self.body = md.convert(self.raw)
+		if not hasattr(md, 'Meta'): raise Exception(self.raw)
 		self.metadata = md.Meta
 		
 		self.author = self.metadata.get('from', None)
-		self.date = self.metadata['date']
+		self.author_url = self.metadata.get('author-url', None)
+		self.date = datetime.fromtimestamp(os.path.getmtime(path))
 
-	def author_link(self):
+	def author_name(self):
 		return self.author or u'Anonymous'
diff --git a/export_wp.py b/export_wp.py
@@ -1,28 +1,73 @@
-import os, time
+import os, time, re, urllib, uuid
 import MySQLdb
 
-cn = MySQLdb.connect(host='cruz', user='root', passwd='ELIDED', db='wordpress')
-
-cur = cn.cursor()
-cur.execute('SELECT id, post_name, post_title, post_date, post_modified, guid, post_content FROM wp_posts WHERE post_status = %s', ('publish',))
-for row in cur.fetchall():
-    id, post_name, post_title, post_date, post_modified, guid, post_content = row
-    subcur = cn.cursor()
-    subcur.execute('SELECT wp_terms.name FROM wp_term_relationships INNER JOIN wp_term_taxonomy ON wp_term_relationships.term_taxonomy_id = wp_term_taxonomy.term_taxonomy_id INNER JOIN wp_terms ON wp_term_taxonomy.term_id = wp_terms.term_id WHERE taxonomy = %s AND object_id = %s', ('category', id,))
-    categories = [category for category, in subcur.fetchall()]
-    subcur = cn.cursor()
-    subcur.execute('SELECT wp_terms.name FROM wp_term_relationships INNER JOIN wp_term_taxonomy ON wp_term_relationships.term_taxonomy_id = wp_term_taxonomy.term_taxonomy_id INNER JOIN wp_terms ON wp_term_taxonomy.term_id = wp_terms.term_id WHERE taxonomy = %s AND object_id = %s', ('post_tag', id,))
-    tags = [tag for tag, in subcur.fetchall()]
-
-    os.mkdir(post_name)
-    f = open(os.path.join(post_name, 'content.txt'), 'w')
-    f.write('Title: %s\n' % post_title)
-    f.write('Publication-date: %s\n' % post_date.strftime('%Y-%m-%d %H:%M:%S'))
-    f.write('Guid: %s\n' % guid)
-    f.write('Categories: %s\n' % ', '.join(categories))
-    f.write('Tags: %s\n' % ', '.join(tags))
-    f.write('\n')
-    f.write(post_content)
-    del f
-    os.utime(os.path.join(post_name, 'content.txt'), 
-            (time.mktime(post_modified.timetuple()), time.mktime(post_modified.timetuple())))
+def html2md(s):
+	s = s.replace('<p>', '')
+	s = s.replace('</p>', '')
+	# XXX
+	return s
+
+def export(base_dir):
+	if not os.path.exists(base_dir):
+		os.mkdir(base_dir)
+
+	cn = MySQLdb.connect(host='cruz', user='root', passwd='ELIDED', db='wordpress')
+
+	cur = cn.cursor()
+	cur.execute('SELECT id, post_name, post_title, post_date, post_modified, guid, post_content FROM wp_posts WHERE post_status = %s', ('publish',))
+	for row in cur.fetchall():
+		id, post_name, post_title, post_date, post_modified, guid, post_content = row
+		
+		# Wordpress stores these URL-encoded
+		post_name = urllib.unquote(post_name)
+		guid = urllib.unquote(guid)
+
+		subcur = cn.cursor()
+		subcur.execute('SELECT wp_terms.name FROM wp_term_relationships INNER JOIN wp_term_taxonomy ON wp_term_relationships.term_taxonomy_id = wp_term_taxonomy.term_taxonomy_id INNER JOIN wp_terms ON wp_term_taxonomy.term_id = wp_terms.term_id WHERE taxonomy = %s AND object_id = %s', ('category', id,))
+		categories = [category for category, in subcur.fetchall()]
+		subcur = cn.cursor()
+		subcur.execute('SELECT wp_terms.name FROM wp_term_relationships INNER JOIN wp_term_taxonomy ON wp_term_relationships.term_taxonomy_id = wp_term_taxonomy.term_taxonomy_id INNER JOIN wp_terms ON wp_term_taxonomy.term_id = wp_terms.term_id WHERE taxonomy = %s AND object_id = %s', ('post_tag', id,))
+		tags = [tag for tag, in subcur.fetchall()]
+
+		os.mkdir(os.path.join(base_dir, post_name))
+		f = open(os.path.join(base_dir, post_name, 'content.txt'), 'w')
+		f.write('Title: %s\n' % post_title)
+		f.write('Publication-Date: %s\n' % post_date.strftime('%Y-%m-%d %H:%M:%S'))
+		f.write('GUID: %s\n' % guid)
+		f.write('Categories: %s\n' % ', '.join(categories))
+		f.write('Tags: %s\n' % ', '.join(tags))
+		f.write('\n')
+		f.write(post_content)
+		del f
+		os.utime(os.path.join(base_dir, post_name, 'content.txt'), 
+				(time.mktime(post_modified.timetuple()), time.mktime(post_modified.timetuple())))
+
+		# comments
+		subcur = cn.cursor()
+		subcur.execute('SELECT comment_author, comment_author_email, comment_author_url, comment_author_ip, comment_date, comment_agent, comment_content FROM wp_comments WHERE comment_post_id = %s AND comment_approved LIKE %s', (id, 1))
+		os.mkdir(os.path.join(base_dir, post_name, 'comments'))
+		# XXX dir perms
+		for subrow in subcur.fetchall():
+			author, email, url, ip_addr, date, user_agent, content = subrow
+			id = str(uuid.uuid4()).replace('-', '')
+			filename = os.path.join(base_dir, post_name, 'comments', id)
+			f = open(filename, 'w')
+			if author:
+				f.write('From: %s\n' % author)
+			if email:
+				f.write('Author-Email: %s\n' % email)
+			if url:
+				f.write('Author-URL: %s\n' % url)
+			if user_agent:
+				f.write('User-Agent: %s\n' % user_agent)
+			if ip_addr:
+				f.write('Received: from %s\n' % ip_addr)
+			f.write('\n')
+			f.write(html2md(content)) # Wordpress HTMLifies comments >_<
+			del f
+			os.utime(filename, 
+					(time.mktime(date.timetuple()), time.mktime(date.timetuple())))
+
+if __name__ == '__main__':
+	import sys
+	export(sys.argv[1])
diff --git a/static/images/comm.gif b/static/images/comm.gif
Binary files differ.
diff --git a/templates/post.xml b/templates/post.xml
@@ -17,7 +17,13 @@
 	<div class="entrymeta">
 		Posted ${entry.publication_date.strftime(str('%-1d %B %Y'))}
 		<py:if test="entry.categories">
-			in ${', '.join(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>
   
@@ -30,17 +36,22 @@
 
 </div>
 
-<div id="commentblock" py:if="entry.has_comments()">
+<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="comment in entry.comments()"
-			class="(comment.id % 2) and 'alt' or 'standard'"
+		<li py:for="n, comment in enumerate(comments)"
+			class="${(n % 2) and 'alt' or 'standard'}"
 			id="comment-${comment.id}">
-			<div class="commentmeta">
-				${comment.author_link()}
-				on ${comment.date.strftime(str('F j, Y'))}
+			<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="commentbody">
-				${comment.body}
+			<div class="commenttext">
+				<div class="commentp">
+					${Markup(comment.body)}
+				</div>
 			</div>
 		</li>
 	</ol>