Simple Threaded Web Posts
From ClassDBI
Contents |
Simple threaded web posts
This is a simple recipe for threaded posts with CDBI. A live version of the following code is available sometimes here: http://majenta.org/cgi/threaded-posts.cgi (posted by [apv]). It is not a finished application, but a proof of concept for how this can be setup in just around 100 lines of code.
MySQL setup
USE test; DROP TABLE IF EXISTS post; CREATE TABLE post ( id INT(9) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, parent INT(9), # post.id referential text TEXT NOT NULL, );
GRANT ALL ON test.post TO nobody@localhost identified by 'abadpassword';
.my-web.cnf
[client] password=abadpassword database=test user=nobody
ThreadedPosts.pm
note: Class::DBI::DATA::Schema w/ SQL
package ThreadedPosts;
use base 'Class::DBI';
use Class::DBI::DATA::Schema;
my $DBD = 'mysql';
my $DB = 'test';
my $HOST = 'localhost';
my $CONNECT_FILE = "./.my-web.cnf";
my $ATTR = {};
__PACKAGE__->connection("dbi:$DBD:$DB:$HOST;" .
"mysql_read_default_file=$CONNECT_FILE;",
undef, undef,
$ATTR );
__PACKAGE__->table('post');
__PACKAGE__->columns(All => qw( id parent text ) );
__PACKAGE__->has_a(parent => __PACKAGE__);
__PACKAGE__->has_many(replies => __PACKAGE__,
{ order_by => 'id' }
);
sub drop_and_recreate {
my $package = shift;
$package->run_data_sql;
}
1;
__DATA__
USE test;
DROP TABLE IF EXISTS post;
CREATE TABLE post
(
id INT(9) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
parent INT(9), # post.id referential
text TEXT NOT NULL,
);
# probably have to run this as mysql root
# GRANT ALL ON test.post TO nobody@localhost;
threaded-posts.cgi
use warnings; no warnings 'uninitialized';
use strict;
use CGI qw(:standard);
use ThreadedPosts;
print
header,
start_html(
-head => style({type => 'text/css'},
join(,<DATA>),
),
-title => "Threaded Posts with CDBI"
),
start_form();
if ( param('DELETE ALL!') ) {
ThreadedPosts->drop_and_recreate;
}
if ( param('Add Post') ) {
my $post = ThreadedPosts->create
({text => 'This is an original post'});
$post->update();
}
if ( my $id = param('reply_id') ) {
my $post = ThreadedPosts->retrieve( $id );
$post->add_to_replies({ text => "This is a reply to $id" });
}
my @posts = ThreadedPosts->retrieve_all();
for my $post ( @posts ) {
print show_post($post);
}
print submit("Add Post");
print submit("DELETE ALL!") if @posts;
exit 0;
# Subroutines
#================================================================
sub show_post {
my $post = shift;
my $depth = shift;
return if $post->parent and not $depth;
$depth++;
return
div({-class => 'post',},
div({-style => 'padding:1ex; margin:0'},
"id: ", $post,
'('. $post->text .")",
'depth: ', $depth,
br,
"In reply to",
( $post->parent() ?
$post->parent->text() : 'nothing') . '.',
( $depth >= 8 ? :
a({-href => '?reply_id=' . $post},
'Reply to this',
),
),
),
( map { show_post($_, $depth) } $post->replies ),
);
}
__DATA__
.post {
border-left:1px dotted black;
border-top:1px dotted black;
margin:.3ex 0 0 1em;
padding:.3ex 0 0 0;
background-color:#eef;
font-size:10pt;
}
.post > .post {
background-color:#ffe;
}
.post > .post > .post {
background-color:#fef;
}
.post > .post > .post > .post {
background-color:#eff;
}
.post > .post > .post > .post > .post {
background-color:#ffe;
}
.post > .post > .post > .post > .post > .post {
background-color:#dde;
}
.post > .post > .post > .post > .post > .post >
.post {
background-color:#ded;
}
.post > .post > .post > .post > .post > .post >
.post > .post {
background-color:#edd;
}
Comments and feedback
...

