<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://panoptic.com/mediawiki/aolserver/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Havard</id>
	<title>AOLserver Wiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://panoptic.com/mediawiki/aolserver/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Havard"/>
	<link rel="alternate" type="text/html" href="https://panoptic.com/wiki/aolserver/Special:Contributions/Havard"/>
	<updated>2026-04-25T16:19:46Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.34.2</generator>
	<entry>
		<id>https://panoptic.com/mediawiki/aolserver/index.php?title=User:Havard&amp;diff=5164</id>
		<title>User:Havard</title>
		<link rel="alternate" type="text/html" href="https://panoptic.com/mediawiki/aolserver/index.php?title=User:Havard&amp;diff=5164"/>
		<updated>2008-09-15T20:16:58Z</updated>

		<summary type="html">&lt;p&gt;Havard: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;John Havard.  I wrote the crappy blog software known as [[Havard's Crappy Blog]].&lt;/div&gt;</summary>
		<author><name>Havard</name></author>
		
	</entry>
	<entry>
		<id>https://panoptic.com/mediawiki/aolserver/index.php?title=Havard%27s_Crappy_Blog&amp;diff=5163</id>
		<title>Havard's Crappy Blog</title>
		<link rel="alternate" type="text/html" href="https://panoptic.com/mediawiki/aolserver/index.php?title=Havard%27s_Crappy_Blog&amp;diff=5163"/>
		<updated>2008-09-15T20:13:53Z</updated>

		<summary type="html">&lt;p&gt;Havard: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Havard's Crappy Blog is an aptly-named piece of software written by [[User:Havard|John Havard]] to power one of his web sites.  It's a simple blog-style web app that runs under our favorite web application server.  It was initially a couple of &amp;lt;tt&amp;gt;.adp&amp;lt;/tt&amp;gt; scripts, but with a little prodding from [[User:Dossy|Dossy]], it was whipped into shape to be insanely fast.  Since most blogs are relatively small, and RAM is cheap, everything is cached.&lt;br /&gt;
&lt;br /&gt;
All the code is kept in the [http://aolserver.cvs.sourceforge.net/aolserver/ AOLserver CVS repository] as the &amp;lt;tt&amp;gt;havardblog&amp;lt;/tt&amp;gt; package.  Be warned that the code is likely full of WTF-isms.  It's bad enough that I considered contributing it anonymously to avoid tarnishing my family's good name.&lt;/div&gt;</summary>
		<author><name>Havard</name></author>
		
	</entry>
	<entry>
		<id>https://panoptic.com/mediawiki/aolserver/index.php?title=Havard%27s_Crappy_Blog&amp;diff=5162</id>
		<title>Havard's Crappy Blog</title>
		<link rel="alternate" type="text/html" href="https://panoptic.com/mediawiki/aolserver/index.php?title=Havard%27s_Crappy_Blog&amp;diff=5162"/>
		<updated>2008-09-15T20:12:51Z</updated>

		<summary type="html">&lt;p&gt;Havard: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Havard's Crappy Blog is an aptly-named piece of software written by [[User:Havard|John Havard]] to power one of his web sites.  It's a simple blog-style web app that runs under our favorite web application server.  It was initially a couple of &amp;lt;tt&amp;gt;.adp&amp;lt;/tt&amp;gt; scripts, but with a little prodding from [[User:Dossy|Dossy]], it was whipped into shape to be insanely fast.  Since most blogs are relatively small, and RAM is cheap, everything is cached.&lt;br /&gt;
&lt;br /&gt;
All the code is kept in the [http://aolserver.cvs.sourceforge.net/aolserver/ AOLserver CVS repository] as the &amp;lt;tt&amp;gt;havardblog&amp;lt;/tt&amp;gt; package.  Be warned that the code is likely full of WTF-isms.&lt;/div&gt;</summary>
		<author><name>Havard</name></author>
		
	</entry>
	<entry>
		<id>https://panoptic.com/mediawiki/aolserver/index.php?title=User:Havard&amp;diff=5161</id>
		<title>User:Havard</title>
		<link rel="alternate" type="text/html" href="https://panoptic.com/mediawiki/aolserver/index.php?title=User:Havard&amp;diff=5161"/>
		<updated>2008-09-15T20:07:38Z</updated>

		<summary type="html">&lt;p&gt;Havard: New page: I wrote the crappy blog software known as Havard's Crappy Blog.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;I wrote the crappy blog software known as [[Havard's Crappy Blog]].&lt;/div&gt;</summary>
		<author><name>Havard</name></author>
		
	</entry>
	<entry>
		<id>https://panoptic.com/mediawiki/aolserver/index.php?title=Havard%27s_Crappy_Blog&amp;diff=5160</id>
		<title>Havard's Crappy Blog</title>
		<link rel="alternate" type="text/html" href="https://panoptic.com/mediawiki/aolserver/index.php?title=Havard%27s_Crappy_Blog&amp;diff=5160"/>
		<updated>2008-09-09T17:38:59Z</updated>

		<summary type="html">&lt;p&gt;Havard: New page: I whipped up a quick bloggish app in php, but decided to port it over to AOLserver for good measure.  It's not very complete, has little to no sanity checking, was written in a little unde...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;I whipped up a quick bloggish app in php, but decided to port it over to AOLserver for good measure.  It's not very complete, has little to no sanity checking, was written in a little under an hour without any thought or planning, and is barely useful, but it does work.&lt;br /&gt;
&lt;br /&gt;
First thing's first, you'll need to create a pool for your PostgreSQL database.  Let's assume for this project the name of the pool is &amp;lt;tt&amp;gt;pool1&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== schema.pgsql ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 CREATE DOMAIN AUTHOR_ID AS VARCHAR(16) NOT NULL;&lt;br /&gt;
 CREATE DOMAIN EMAIL AS VARCHAR(128) NOT NULL;&lt;br /&gt;
 CREATE DOMAIN SLUG AS VARCHAR(32) NOT NULL;&lt;br /&gt;
 &lt;br /&gt;
 CREATE TABLE AUTHOR (&lt;br /&gt;
        ID AUTHOR_ID PRIMARY KEY,&lt;br /&gt;
        PERSONAL_NAME VARCHAR(64) NOT NULL,&lt;br /&gt;
        DISPLAY_EMAIL EMAIL,&lt;br /&gt;
        REAL_EMAIL EMAIL,&lt;br /&gt;
        PASSWORD VARCHAR(64) NOT NULL&lt;br /&gt;
 );&lt;br /&gt;
 &lt;br /&gt;
 CREATE TABLE ARTICLE (&lt;br /&gt;
        SLUG SLUG NOT NULL,&lt;br /&gt;
        PUBDATE DATE NOT NULL,&lt;br /&gt;
        UPDATED TIMESTAMP NOT NULL,&lt;br /&gt;
        AUTHOR AUTHOR_ID REFERENCES AUTHOR(ID) NOT NULL,&lt;br /&gt;
        LEAD TEXT NOT NULL,&lt;br /&gt;
        BODY TEXT NOT NULL,&lt;br /&gt;
        TITLE VARCHAR(128) NOT NULL,&lt;br /&gt;
        PRIMARY KEY (SLUG, PUBDATE)&lt;br /&gt;
 );&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== init.tcl ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 proc do_article {} {&lt;br /&gt;
        set mainStuff &amp;quot;&amp;quot;&lt;br /&gt;
        # /article/YYYY/MM/DD/slug/junk&lt;br /&gt;
        set urlv [ns_conn urlv]&lt;br /&gt;
        set qslug [lindex $urlv 4]&lt;br /&gt;
        set qpubdate [lindex $urlv 1]-[lindex $urlv 2]-[lindex $urlv 3]&lt;br /&gt;
        set qry &amp;quot;SELECT ARTICLE.*,AUTHOR.PERSONAL_NAME FROM ARTICLE,AUTHOR WHERE AUTHOR.ID=ARTICLE.AUTHOR AND PUBDATE =  '${qpubdate}' AND SLUG = '${qslug}'&amp;quot;&lt;br /&gt;
        catch {&lt;br /&gt;
                set hdl [ns_db gethandle pool1]&lt;br /&gt;
                set res [ns_db 1row $hdl $qry]&lt;br /&gt;
 &lt;br /&gt;
                #[ns_db getrow $hdl $res]&lt;br /&gt;
                set slug    [subst [ns_set get $res slug   ]]&lt;br /&gt;
                set pubdate [subst [ns_set get $res pubdate]]&lt;br /&gt;
                set updated [subst [ns_set get $res updated]]&lt;br /&gt;
                set author  [subst [ns_set get $res author ]]&lt;br /&gt;
                set title   [subst [ns_set get $res title  ]]&lt;br /&gt;
                set lead    [subst [ns_set get $res lead   ]]&lt;br /&gt;
                set body    [subst [ns_set get $res body   ]]&lt;br /&gt;
                ns_db releasehandle $hdl&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        if { [string compare $slug $qslug] == 0 } {&lt;br /&gt;
                set mainStuff [ns_adp_parse -file template/article.adp]&lt;br /&gt;
                set rPole [ns_adp_parse -file template/rpole.adp]&lt;br /&gt;
                ns_return 200 &amp;quot;text/html&amp;quot; [ns_adp_parse -file template/template.adp]&lt;br /&gt;
        } else {&lt;br /&gt;
                ns_returnfile 404 &amp;quot;text/html&amp;quot; &amp;quot;global/file-not-found.html&amp;quot;&lt;br /&gt;
        }&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 ns_register_proc GET /article do_article&lt;br /&gt;
 &lt;br /&gt;
 ns_log warning &amp;quot;We processed init.tcl!&amp;quot;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== index.adp ==&lt;br /&gt;
 &amp;lt;%&lt;br /&gt;
        set mainStuff &amp;quot;&amp;quot;&lt;br /&gt;
        set qry &amp;quot;SELECT ARTICLE.*,AUTHOR.PERSONAL_NAME FROM ARTICLE,AUTHOR WHERE AUTHOR.ID=ARTICLE.AUTHOR ORDER BY PUBDATE DESC, UPDATED DESC LIMIT 10&amp;quot;&lt;br /&gt;
        catch {&lt;br /&gt;
                set hdl [ns_db gethandle pool1]&lt;br /&gt;
                set res [ns_db select $hdl $qry]&lt;br /&gt;
 &lt;br /&gt;
                while {[ns_db getrow $hdl $res]} {&lt;br /&gt;
                        set slug    [subst [ns_set get $res slug   ]]&lt;br /&gt;
                        set pubdate [subst [ns_set get $res pubdate]]&lt;br /&gt;
                        set updated [subst [ns_set get $res updated]]&lt;br /&gt;
                        set author  [subst [ns_set get $res author ]]&lt;br /&gt;
                        set title   [subst [ns_set get $res title  ]]&lt;br /&gt;
                        set lead    [subst [ns_set get $res lead   ]]&lt;br /&gt;
                        set body    [subst [ns_set get $res body   ]]&lt;br /&gt;
                        set pubdate [string map {- /} $pubdate]&lt;br /&gt;
                        set mainStuff &amp;quot;$mainStuff [ns_adp_parse -file template/entry.adp]&amp;quot;&lt;br /&gt;
                }&lt;br /&gt;
        }&lt;br /&gt;
 ns_adp_puts [ns_adp_parse -file template/template.adp]&lt;br /&gt;
 %&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== /admin/post.adp ==&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 &amp;lt;html&amp;gt;&lt;br /&gt;
 &amp;lt;head&amp;gt;&lt;br /&gt;
 &amp;lt;title&amp;gt;Post an article&amp;lt;/title&amp;gt;&lt;br /&gt;
 &amp;lt;/head&amp;gt;&lt;br /&gt;
 &amp;lt;body&amp;gt;&lt;br /&gt;
 &amp;amp;lt;table&amp;amp;gt;&lt;br /&gt;
 &amp;amp;lt;form method=&amp;quot;POST&amp;quot; action=&amp;quot;do_post.adp&amp;quot;&amp;amp;gt;&lt;br /&gt;
 &amp;lt;tr&amp;gt;&lt;br /&gt;
        &amp;lt;td&amp;gt;Title&amp;lt;/td&amp;gt;&lt;br /&gt;
        &amp;lt;td&amp;gt;&amp;lt;input name=&amp;quot;title&amp;quot; size=&amp;quot;80&amp;quot; value=&amp;quot;&amp;quot;/&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
 &amp;lt;/tr&amp;gt;&lt;br /&gt;
 &amp;lt;tr&amp;gt;&lt;br /&gt;
         &amp;lt;td&amp;gt;username&amp;lt;/td&amp;gt;&lt;br /&gt;
         &amp;lt;td&amp;gt;&amp;lt;input name=&amp;quot;username&amp;quot; value=&amp;quot;&amp;quot;/&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
 &amp;lt;/tr&amp;gt;&lt;br /&gt;
 &amp;lt;tr&amp;gt;&lt;br /&gt;
         &amp;lt;td&amp;gt;password&amp;lt;/td&amp;gt;&lt;br /&gt;
         &amp;lt;td&amp;gt;&amp;lt;input type=&amp;quot;password&amp;quot; name=&amp;quot;password&amp;quot; value=&amp;quot;&amp;quot;/&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
 &amp;lt;/tr&amp;gt;&lt;br /&gt;
 &amp;lt;tr&amp;gt;&lt;br /&gt;
         &amp;lt;td&amp;gt;date (YYYY/MM/DD)&amp;lt;/td&amp;gt;&lt;br /&gt;
         &amp;lt;td&amp;gt;&amp;lt;input name=&amp;quot;date&amp;quot; value=&amp;quot;&amp;quot;/&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
 &amp;lt;/tr&amp;gt;&lt;br /&gt;
 &amp;lt;tr&amp;gt;&lt;br /&gt;
         &amp;lt;td&amp;gt;slug&amp;lt;/td&amp;gt;&lt;br /&gt;
         &amp;lt;td&amp;gt;&amp;lt;input name=&amp;quot;slug&amp;quot; value=&amp;quot;&amp;quot;/&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
 &amp;lt;/tr&amp;gt;&lt;br /&gt;
 &amp;lt;tr&amp;gt;&lt;br /&gt;
         &amp;lt;td&amp;gt;lead&amp;lt;/td&amp;gt;&lt;br /&gt;
         &amp;lt;td&amp;gt;&amp;lt;textarea name=&amp;quot;lead&amp;quot; cols=&amp;quot;80&amp;quot; rows=&amp;quot;5&amp;quot;&amp;gt;&amp;lt;/textarea&amp;gt;&lt;br /&gt;
 &amp;lt;/tr&amp;gt;&lt;br /&gt;
 &amp;lt;tr&amp;gt;&lt;br /&gt;
         &amp;lt;td&amp;gt;body&amp;lt;/td&amp;gt;&lt;br /&gt;
         &amp;lt;td&amp;gt;&amp;lt;textarea name=&amp;quot;body&amp;quot; cols=&amp;quot;80&amp;quot; rows=&amp;quot;12&amp;quot;&amp;gt;&amp;lt;/textarea&amp;gt;&lt;br /&gt;
 &amp;lt;/tr&amp;gt;&lt;br /&gt;
 &amp;lt;tr&amp;gt;&lt;br /&gt;
        &amp;lt;td&amp;gt;&amp;lt;input type=&amp;quot;submit&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
        &amp;lt;td&amp;gt;&amp;lt;input type=&amp;quot;reset&amp;quot;&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;
 &amp;lt;/tr&amp;gt;&lt;br /&gt;
 &amp;lt;/form&amp;gt;&lt;br /&gt;
 &amp;lt;/table&amp;gt;&lt;br /&gt;
 &amp;lt;/body&amp;gt;&lt;br /&gt;
 &amp;lt;/html&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== /admin/do_post.adp ==&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 &amp;lt;%&lt;br /&gt;
 set title [ns_dbquotevalue [ns_queryget title]]&lt;br /&gt;
 set user  [ns_dbquotevalue [ns_queryget username]]&lt;br /&gt;
 set pass  [ns_dbquotevalue [ns_queryget password]]&lt;br /&gt;
 set date  [ns_dbquotevalue [ns_queryget date]]&lt;br /&gt;
 set slug  [ns_dbquotevalue [ns_queryget slug]]&lt;br /&gt;
 set lead  [ns_dbquotevalue [ns_queryget lead]]&lt;br /&gt;
 set body  [ns_dbquotevalue [ns_queryget body]]&lt;br /&gt;
 &lt;br /&gt;
 set qry &amp;quot;INSERT INTO ARTICLE VALUES ($slug, $date, now(), (SELECT ID FROM AUTHOR WHERE ID = $user and PASSWORD = $pass), $lead, $body, $title)&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
        set hdl [ns_db gethandle pool1]&lt;br /&gt;
 &lt;br /&gt;
        if {[catch {ns_db dml $hdl $qry} res]} {&lt;br /&gt;
                ns_adp_puts &amp;quot;post probably failed, hit back and try again&amp;quot;&lt;br /&gt;
                ns_adp_puts &amp;quot;$res&amp;quot;&lt;br /&gt;
        } else {&lt;br /&gt;
                ns_adp_puts &amp;quot;post was a success!&amp;quot;&lt;br /&gt;
                ns_adp_puts &amp;quot;$res&amp;quot;&lt;br /&gt;
        }&lt;br /&gt;
 %&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
== notes ==&lt;br /&gt;
&lt;br /&gt;
You'll need a &amp;lt;tt&amp;gt;template&amp;lt;/tt&amp;gt; directory off your pageroot.  The files &amp;lt;tt&amp;gt;entry.adp&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;article.adp&amp;lt;/tt&amp;gt; are virtually the same except that &amp;lt;tt&amp;gt;entry.adp&amp;lt;/tt&amp;gt; is used for the home page listing, while &amp;lt;tt&amp;gt;article.adp&amp;lt;/tt&amp;gt; is used for the full article page.  You'll generally want to use the lead in &amp;lt;tt&amp;gt;entry.adp&amp;lt;/tt&amp;gt; and body in &amp;lt;tt&amp;gt;article.adp&amp;lt;/tt&amp;gt;.  The main template is &amp;lt;tt&amp;gt;template.adp&amp;lt;/tt&amp;gt;.  The main content section is filled with the &amp;lt;tt&amp;gt;mainStuff&amp;lt;/tt&amp;gt; variable.&lt;br /&gt;
&lt;br /&gt;
Your links to articles will be in the form of &amp;lt;tt&amp;gt;/article/YYYY/MM/DD/slug/whatever.html&amp;lt;/tt&amp;gt;.  If you'll notice, pubdate has dashes substituted for slashes.  This makes forming the URL nice and easy.  What I use to form the &amp;lt;em&amp;gt;Read More&amp;lt;/em&amp;gt; link is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 &amp;lt;a href=&amp;quot;/article/&amp;lt;%= $pubdate %&amp;gt;/&amp;lt;%= $slug %&amp;gt;/article.html&amp;quot;&amp;gt;Read More&amp;lt;/a&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Havard</name></author>
		
	</entry>
</feed>