1
0
Fork 0
mirror of https://github.com/perlbot/perlbuut synced 2025-06-07 19:15:40 -04:00
perlbuut/lib/Bot/BB3/Roles/PasteBot.pm
2009-12-05 00:02:04 -05:00

337 lines
7.3 KiB
Perl

package Bot::BB3::Roles::PasteBot;
use POE;
use POE::Component::Server::SimpleHTTP;
use HTTP::Status;
use CGI;
use Template;
use strict;
our( $INDEX_HTML, $RECEIVED_PASTE_HTML, $DISPLAY_PASTE_HTML );
sub new {
my( $class, $conf, $pm ) = @_;
my $self = bless { conf => $conf, pm => $pm }, $class;
$self->{hostname} = $conf->{roles}->{pastebot}->{hostname} || "127.0.0.1";
$self->{hostname} =~ s{^\s*http:/?/?}{};
# TODO I think this is slightly duplicating the above data
# Note that it can default to empty though..
$self->{alias_url} = $conf->{roles}->{pastebot}->{alias_url};
$self->{session} = POE::Session->create(
object_states => [
$self => [ qw/_start display_page index display_paste receive_paste/ ]
]
);
eval {
$self->dbh->do(
"CREATE TABLE paste (
paste_id INTEGER PRIMARY KEY AUTOINCREMENT,
author VARCHAR(200),
summary VARCHAR(250),
paste LONGTEXT,
date_time INTEGER
)"
);
};
return $self;
}
# This method may be called as either a class method or an object method
# so we have to have some ugly branches to account for it.
sub dbh {
my( $self ) = @_;
if( ref $self and $self->{dbh} and $self->{dbh}->ping ) {
return $self->{dbh};
}
my $dbh = DBI->connect( "dbi:SQLite:dbname=var/pastes.db", "", "", {RaiseError => 1, PrintError => 0} )
or die "Failed to create DBI connection to var/pastes.db, this is a Big Problem! $!";
if( ref $self ) {
$self->{dbh} = $dbh;
}
return $dbh;
}
# This is a public method that can be called as a class method
# therefor $self may be a class or an object.
sub get_paste {
my( $self, $paste_id ) = @_;
my $paste = $self->dbh->selectrow_hashref(
"SELECT author,summary,paste,date_time FROM paste WHERE paste_id = ? LIMIT 1",
undef,
$paste_id
);
return $paste;
}
sub insert_paste {
my( $self, $nick, $summary, $paste )= @_;
my $dbh = $self->dbh;
$dbh->do(
"INSERT INTO paste
(author, summary, paste, date_time)
VALUES (?,?,?,?)
",
undef,
$nick,
$summary,
$paste,
time
);
my $id = $dbh->last_insert_id( undef, undef, undef, undef );
return $id;
}
sub _start {
my( $self, $kernel ) = @_[OBJECT,KERNEL];
my $conf = $self->{conf};
# Create it here so it acts as a child
$self->{server} = POE::Component::Server::SimpleHTTP->new(
PORT => $conf->{pastebot_plugin_port},
ADDRESS => $conf->{pastebot_plugin_addr} || undef,
ALIAS => 'pb_httpd_alias',
HANDLERS => [
{
DIR => '^/paste/\d+',
SESSION => "pastebot_role",
EVENT => "display_paste",
},
{
DIR => '^/paste_submit',
SESSION => "pastebot_role",
EVENT => "receive_paste",
},
{
DIR => '^/',
SESSION => "pastebot_role",
EVENT => "index",
},
]
);
$kernel->alias_set( "pastebot_role" );
$kernel->sig("DIE" => 'sig_DIE' );
}
sub display_page {
my( $self, $resp, $html ) = @_[OBJECT,ARG0,ARG1,ARG2];
warn "Display Page Activating: $resp\n";
$resp->code(RC_OK);
$resp->content_type("text/html");
$resp->content( $html );
$_[KERNEL]->post( pb_httpd_alias => 'DONE' => $resp );
}
sub index {
my( $self, $kernel, $req, $resp ) = @_[OBJECT,KERNEL,ARG0,ARG1];
my $template = Template->new;
my $channels = $kernel->call("Bot::BB3::Roles::IRC", "channel_list")
or warn "Failed to call: $!";
my $context = {
channels => $channels,
alias_url => $self->{alias_url},
};
my $output_html;
$template->process( \$INDEX_HTML, $context, \$output_html )
or warn "Failed to process: $Template::ERROR\n";
$_[KERNEL]->yield( display_page => $resp, $output_html );
}
sub display_paste {
my( $self, $req, $resp ) = @_[OBJECT,ARG0,ARG1];
my $output_html = "<body>Invalid Paste ID</body>";
$req->uri =~ m{paste/(\d+)}
or goto CLEANUP;
my $paste_id = $1;
my $paste = $self->get_paste( $paste_id );
if( not $paste or not keys %$paste ) { goto CLEANUP; }
my $template = Template->new;
my $context = {
author => $paste->{author},
summary => $paste->{summary},
paste => $paste->{paste},
date_time => $paste->{date_time},
};
undef $output_html;
$template->process( \$DISPLAY_PASTE_HTML, $context, \$output_html );
CLEANUP:
$_[KERNEL]->yield( display_page => $resp, $output_html );
}
sub receive_paste {
my( $self, $req, $resp ) = @_[OBJECT,ARG0,ARG1];
warn "Request: ", $req->content;
my $query = CGI->new( $req->content );
my $input = $query->param("body");
warn "Attempting to handle request: $req $resp $input\n";
my $id = $self->insert_paste(
$query->param("nick"),
$query->param("summary"),
$query->param("paste"),
time
);
my $template = Template->new;
my $context = {
map { $_ => $query->param( $_ ) } qw/nick summary channel paste/,
id => $id,
alias_url => $self->{alias_url},
};
my $output;
$template->process( \$RECEIVED_PASTE_HTML, $context, \$output )
or warn $Template::ERROR;
$_[KERNEL]->yield( display_page => $resp, $output );
my $alert_channel = $query->param("channel");
if( $alert_channel !~ /^\s*---/ ) { # Ignore things like "---irc.freenode, skip server names
my($server,$nick,$channel) = split /:/,$alert_channel,3;
my $external_url = $self->{alias_url} || $self->{hostname};
$_[KERNEL]->post( "Bot::BB3::Roles::IRC", external_message => $server, $nick, $channel,
( $context->{nick} || "Someone" )
. " pasted a new file at $external_url/paste/$id - $context->{summary}"
);
}
}
sub sig_DIE {
# Do nothing, we're ignoring fatal errors from our child, poco-server-simplehttp. I think we don't need to respawn them.
}
$INDEX_HTML = <<'END_HTML';
<html>
<head>
<style>
#summary {
width: 60em;
}
#paste {
width: 80em;
height: 25em;
}
</style>
</head>
<body>
<h2>Welcome to the BB3 Pastebot.</h2>
<ol>
<li>Select the channel for the URL announcment.</li>
<li>Supply a nick for the announcement.</li>
<li>Supply a summary of the paste for the announcement.</li>
<li>Paste!</li>
<li>Submit the form with the Paste it! button.</li>
</ol>
<form action="[% alias_url %]/paste_submit" method="post">
<ol>
<li style="float: left">Channel:
<select name="channel" id="channel">
[% FOREACH server IN channels.keys %]
<option name="channel">----[% server %] </option>
[% FOREACH nick IN channels.$server.keys %]
[% FOREACH channel IN channels.$server.$nick %]
<option value="[% server %]:[% nick %]:[% channel %]">[% channel %]</option>
[% END %]
[% END %]
[% END %]
</select>
</li>
<li style="float: left; clear: right; margin-left: 10em;">Nick:
<input type="text" name="nick" id="nick">
</li>
<li style="clear: both;">Summary:
<input type="text" name="summary" id="summary">
</li>
<li>Paste:
<textarea name="paste" id="paste"></textarea>
</li>
<li>
<input type="submit" name="paster" value="Paste It!">
<input type="reset" value="Clear Form">
</li>
</ol>
</form>
</body>
</html>
END_HTML
$RECEIVED_PASTE_HTML = <<'END_HTML';
<html>
<head>
<style>
</style>
</head>
<body>
Stored as: <a href="[% alias_url %]/paste/[% id %]">Paste [% id %]</a>
<br> [% summary %] by [% nick %] <br>
<pre>[% paste | html %]</pre>
</body>
</html>
END_HTML
$DISPLAY_PASTE_HTML = <<'END_HTML';
<html>
<head>
<style>
#paste {
width: 95%;
background-color: rgb(230,230,230);
}
</style>
</head>
<body>
<h2> BB3 PasteBot</h2>
<h3>From [% author | html %]</h3>
<h4>[% summary | html %]</h4>
<pre id="paste">[% paste | html %]</pre>
</body>
</html>
END_HTML
1;