Simple Threaded Web Posts

From ClassDBI

Jump to: navigation, search

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

...

Personal tools