Even though Stuart Langridge is no longer using and developing Vellum, I'm aiming to stick with it and add any features I need in it until I come up with my very own NIH redundant and unnecessary web publishing platform. Anyway, one of the Tactical Tech people asked if she could get a grouping of just my Africa Source web log entries. So, I hacked together this to generate per-category pages...
The page-building process uses "funky caching" to generate pages via the CGI if they don't exist. When they do exist, the web server just grabs it off the filesystem, bypassing the CGI. Thus, to generate a new page, you delete the file on the filesystem. This is how Vellum "rebuilds" a page.
It has a dictionary in each Entry object in the attribute links with the name of the page as a key, and a template as the value. The code in question:
theseEntries = []
for blog in Blog.all():
for entry in blog.entries():
#print "Looking in the following keys: %s
" % str(entry.links.keys())
if url in entry.links.keys():
tmpl = entry.links[url]
theseEntries.append(entry)
if not theseEntries:
print "Looking for url %s: not found, so sorry." % url
return ('','Status: 404')
I created a simple startup script to mess around with the objects in the python interpreter:
#!/usr/bin/env python
import os
import sys
sys.path.append('/usr/mirror/web/mithrandr.moria.org/vellum')
os.chdir('/usr/mirror/web/mithrandr.moria.org/vellum')
import vellum.plugins
import vellum.functions
import vellum.auth
vellum.functions.pluginInfo = vellum.plugins.pluginInfo
import vellum.Entry
Entry = vellum.Entry
With this, I could look around the Entry object a little easier:
(nbm@dirk) /mirror/db/vellum# env PYTHONSTARTUP=startup.py python Python 2.2.2 (#1, Jul 22 2003, 14:50:26) [GCC 3.2.2 [FreeBSD] 20030205 (release)] on freebsd5 Type "help", "copyright", "credits" or "license" for more information. >>> e = Entry.get(1) >>> print e.links.keys() ['/blog/index.html', '/blog/include.html', '/blog/2003-04.html', '/blog/1.html', '/blog/rss2.0.xml']
So, Vellum determines whether the file to be built is valid, which template to use, and which entries to pass to the template by walking through all the entries and looking in their links attribute. (It also uses it to determine which files to delete when an entry is changed so they can be rebuilt the next time they're requested.)
Next, determine where the links attribute is set; Entry's setMyPermalink method. It initialises links as a new dictionary, and walks through each of the templates set up with the web log, and associates the filename generated from the template expression with an instance of the template.
setMyPermalink is after the Vellum hook 'entry-save-pre', so that could not be used to add the links. And no other hooks existed before the Entry is saved to the database. So, I added a hook call after the setMyPermalink. Here's the simple patch to Entry.py:
--- Entry.py.old Wed Apr 7 16:07:17 2004
+++ Entry.py Wed Apr 7 12:30:28 2004
@@ -70,6 +70,7 @@
if b.staticdir == '': raise "The entry was saved but the rebuild failed because this blog has no static directory set"
self.setMyPermalink(b)
+ hooks.call_hook("entry-permalink-post", self)
first = self.firstpost
self.firstpost = 0
vellumObject.save(self)
Vellum's hook system is a nice feature, and is used by its plugin system to allow plugins to affect changes to the standard workflow. In this case, the category functionality is implemented as a plugin, and is available on the Vellum web site. I just needed a simple patch to add the hook to add the additional entries in the links attribute:
--- category.py.old Wed Apr 7 16:12:09 2004
+++ category.py Wed Apr 7 13:26:42 2004
@@ -9,6 +9,29 @@
# Add a new blank category attribute to every Entry
vellum.Entry.Entry.category = ''
+import copy
+
+def addLinks(entry):
+ category_template = None
+ for tmpl in entry.blog().templates:
+ if tmpl.templateName == "Category":
+ category_template = tmpl
+ break
+
+ if entry.links.has_key("/blog/category_.html"):
+ del entry.links["/blog/category_.html"]
+ if not category_template:
+ return
+ if not hasattr(entry, "category"):
+ return
+ for category in entry.category.split(','):
+ category = category.strip()
+ ct = copy.copy(category_template)
+ ct.outputPage = '"category_%s.html"' % category
+ entry.links["/blog/category_%s.html" % category] = ct
+
+vellum.hooks.register_hook("entry-permalink-post",addLinks)
+
# Print an entry's category in the entry list
def printListCategory(entry):
print ''
First, I find the Category template that I'd set up in my Vellum configuration (or return gracefully). I remove the fake "category_.html" entry that template is forced to create, and then set up an entry in the Entry's links dictionary for each category the entry belongs to. Due to the way Vellum's build function works, I need to change the outputPage attribute in the template, so I have to make a copy of the category template for this.
Ok, the template configuration for adding the per-category pages is:
- Template name: Category
- Template filename: templates/category.tmpl
- Output page: "category_.html"
Leave the rest blank.
I saved an existing entry again to trigger the creation of the new links, and checked it out in the interpreter:
(nbm@dirk) /mirror/db/vellum# env PYTHONSTARTUP=startup.py python Python 2.2.2 (#1, Jul 22 2003, 14:50:26) [GCC 3.2.2 [FreeBSD] 20030205 (release)] on freebsd5 Type "help", "copyright", "credits" or "license" for more information. >>> e = Entry.get(1) >>> print e.links.keys() ['/blog/category_meta.html', '/blog/index.html', '/blog/include.html', '/blog/2003-04.html', '/blog/1.html', '/blog/rss2.0.xml']
Went to category_meta.html, and I had a single entry.
So, I needed to resave all my files again. I used this:
#!/usr/bin/env python
import os
import sys
sys.path.append('/usr/mirror/web/mithrandr.moria.org/vellum')
os.chdir('/usr/mirror/web/mithrandr.moria.org/vellum')
import vellum.plugins
import vellum.functions
import vellum.auth
vellum.functions.pluginInfo = vellum.plugins.pluginInfo
import vellum.Entry
Entry = vellum.Entry
entries = Entry.all()
for entry in entries:
entry.save(skipRebuild = True)
So, after all this, I now have categories, and Stephanie got a page of my Africa Source entries.
Got an RSS feed? If not, that's what Vellum needs next...