# -*- cperl -*-
package POE::Component::IRC::Plugin::NoPaste::Httpd::Index;
use strict;
use warnings;
use POE;
use POE::Component::IRC::Plugin::NoPaste::Httpd;
use POE::Component::IRC::Plugin::NoPaste::StaticFile;
use POE::Component::IRC::Plugin::NoPaste::Pager;
use URI::QueryParam;
use Locale::TextDomain qw(pci-nopaste);
use HTTP::Status;
use Socket;
use Time::Format qw(%time);
use Encode qw(from_to);
use constant NICK_LIMIT => 20;
use constant TITLE_LIMIT => 100;
use constant BODY_LIMIT => 500 * 1024;
sub handler {
my ($this, $req, $resp) = @_;
if ($req->uri->path =~ m!^/nopaste/(.+?)/?$! and
$this->{nopaste}{id_to_channel}{$1}) {
return index_handler(
$this, $req, $resp, $this->{nopaste}{id_to_channel}{$1});
}
elsif ($req->uri->path =~ m!^/post/(.+?)/?$! and
$this->{nopaste}{id_to_channel}{$1}) {
return post_handler(
$this, $req, $resp, $this->{nopaste}{id_to_channel}{$1});
}
else {
return notfound_handler(@_);
}
}
sub index_handler {
my ($this, $req, $resp, $ch, $error) = @_;
local $ENV{LANGUAGE} = $ch->{locale};
my $t = POE::Component::IRC::Plugin::NoPaste::Template->new(
-data => static_file('tmpl/index.html'));
$t->expand(
lang => $ch->{locale},
title => "NoPaste :: $ch->{name}",
);
my ($ptr) = gethostbyaddr(
inet_aton($req->{connection}->remote_ip), AF_INET);
my @writable = $this->{nopaste}->pickup_writable($ch->{id}, $ptr);
my @readable = $this->{nopaste}->pickup_readable($ch->{id}, $ptr);
if (@writable or $ch->{restriction}{write} eq 'any') {
if ($error) {
$_ = $error;
s!\n!
!g;
$t->writable->error->add(error => $_);
}
$t->writable->expand(
channel_id => $ch->{id},
l18n_name => __"Name",
);
if ($ch->{restriction}{write} ne 'any') {
if (@writable ==1) {
$t->writable->restricted->only_one->add(
nick => $writable[0],
);
}
else {
foreach my $nick (@writable) {
$t->writable->restricted->multiple->entry->add(
nick => $nick,
);
}
$t->writable->restricted->multiple->add;
}
$t->writable->restricted->add;
}
else {
$t->writable->not_restricted->add;
}
$t->writable->add(
l18n_title => __"Title",
l18n_body => __(
# body of the post
"Body",
),
l18n_paste => __"Paste",
);
# set the default values
my $q = $req->uri->clone;
if (not $q->query_param('nick') and @writable == 1) {
$q->query_param(nick => $writable[0]);
}
$t->setform($q => 'post');
}
else {
my $msg = $this->{nopaste}->gen_unwritable_error($ch);
$msg =~ s!\n!
!g;
$t->not_writable->add(
error => $msg,
);
}
if (@readable or $ch->{restriction}{read} eq 'any') {
my $pager = POE::Component::IRC::Plugin::NoPaste::Pager->new(
fetch => {
sql => q{
SELECT *
FROM post
WHERE channel_id = ?
ORDER BY posted_time DESC
},
placeholder => [$ch->{id}],
dbh => $this->{nopaste}{db}->dbh,
},
page_to_show => scalar $req->uri->query_param('page'),
pagenums_limit => 20,
items_per_page => 20,
show_meta => sub {
my %meta = @_;
if ($meta{page} == 1) {
$t->readable->prev->nolink->add;
}
else {
$t->readable->prev->link->add(
page => $meta{page} - 1,
);
}
$t->readable->prev->add;
foreach my $i ($meta{pagelink_begin} .. $meta{pagelink_end}) {
if ($i == $meta{page}) {
$t->readable->pages->page->nolink->add(
page => $i,
);
}
else {
$t->readable->pages->page->link->add(
page => $i,
);
}
$t->readable->pages->page->add;
}
$t->readable->pages->add;
if ($meta{page} == $meta{last_page}) {
$t->readable->next->nolink->add;
}
else {
$t->readable->next->link->add(
page => $meta{page} + 1,
);
}
$t->readable->next->add;
},
show_content => sub {
my $row = shift;
$t->readable->list_data->add(
id => $row->{post_id},
title => $row->{title},
name => $row->{nick},
body => $row->{body},
timestamp => $time{'yyyy-mm-dd hh:mm:ss', $row->{posted_time}},
);
},
no_content => sub {
$t->readable->list_nodata->add(
l18n_nodata => __"There are no entries currently.",
);
},
);
$pager->execute;
$t->readable->add(
l18n_title => __"Title",
l18n_name => __"Name",
l18n_timestamp => __"Time Stamp",
);
}
else {
my $msg = $this->{nopaste}->gen_unreadable_error($ch);
$msg =~ s!\n!
!g;
$t->not_readable->add(
error => $msg,
);
}
$resp->content($t->str);
return RC_OK;
}
sub post_handler {
my ($this, $req, $resp, $ch) = @_;
my $nick = $req->uri->query_param('nick');
my $title = $req->uri->query_param('title');
my $body = $req->uri->query_param('body');
local $ENV{LANGUAGE} = $ch->{locale};
my @error;
if (not defined $nick or not length $nick) {
push @error, __"Please don't omit your name.";
}
elsif (length($nick) > NICK_LIMIT) {
push @error, __x("Please shorten your name up to {n} bytes.", n => NICK_LIMIT);
}
if (not defined $title or not length $title) {
push @error, __"Please don't omit the title.";
}
elsif (length($title) > TITLE_LIMIT) {
push @error, __x("Please shorten the title up to {n} bytes.", n => TITLE_LIMIT);
}
if (not defined $body or not length $body) {
push @error, __"Please don't omit the body.";
}
elsif (length($body) > BODY_LIMIT) {
push @error, __x("Please shorten the body up to {n} bytes.", n => BODY_LIMIT);
}
if (@error) {
return index_handler($this, $req, $resp, $ch, join("\n", map {"* $_"} @error));
}
my ($ptr) = gethostbyaddr(
inet_aton($req->{connection}->remote_ip), AF_INET);
my @writable = $this->{nopaste}->pickup_writable($ch->{id}, $ptr);
if ($ch->{restriction}{write} eq 'any' or
grep {$_ eq $nick} @writable) {
my $db = $this->{nopaste}{db};
# check for duplication
if ($db->dbh->selectrow_hashref(q{
SELECT *
FROM post
WHERE channel_id = ? AND nick = ? AND
title = ? AND body = ?
}, undef, $ch->{id}, $nick, $title, $body)) {
return index_handler(
$this, $req, $resp, $ch, __"A duplicated entry is being pasted.");
}
# insert it
$db->dbh->do(q{
INSERT INTO post
(channel_id, posted_time, nick, title, body)
VALUES (? , ? , ? , ? , ? )
}, undef, $ch->{id}, time, $nick, $title, $body);
# get the post id
my ($post_id) = $db->dbh->selectrow_array(q{
SELECT LAST_INSERT_ROWID()});
# announce it in the channel
my $name = $ch->{name};
from_to $name, 'UTF-8' => $ch->{charset};
my @msg = (
__x("{nick} pasted an entry: {title}", nick => $nick, title => $title),
do {
my $uri = $req->uri->clone;
$uri->path("/pasted/$post_id");
$uri->query(undef);
$uri->fragment(undef);
$uri->as_string;
},
);
foreach (@msg) {
my $line = $_;
from_to $line, 'UTF-8' => $ch->{charset};
$this->{nopaste}{irc}->yield(
notice => $name => $line);
}
# redirect to the index
return redirect_handler(
$this, $req, $resp, "/nopaste/$ch->{id}/");
}
else {
return index_handler($this, $req, $resp, $ch);
}
}
1;