]> gitweb @ CieloNegro.org - pci-nopaste.git/blob - lib/POE/Component/IRC/Plugin/NoPaste/Httpd/Index.pm
migrate from GNU arch to Git
[pci-nopaste.git] / lib / POE / Component / IRC / Plugin / NoPaste / Httpd / Index.pm
1 # -*- cperl -*-
2 package POE::Component::IRC::Plugin::NoPaste::Httpd::Index;
3 use strict;
4 use warnings;
5 use POE;
6 use POE::Component::IRC::Plugin::NoPaste::Httpd;
7 use POE::Component::IRC::Plugin::NoPaste::StaticFile;
8 use POE::Component::IRC::Plugin::NoPaste::Pager;
9 use URI::QueryParam;
10 use Locale::TextDomain qw(pci-nopaste);
11 use HTTP::Status;
12 use Socket;
13 use Time::Format qw(%time);
14 use Encode qw(from_to);
15 use constant NICK_LIMIT  => 20;
16 use constant TITLE_LIMIT => 100;
17 use constant BODY_LIMIT  => 500 * 1024;
18
19 sub handler {
20     my ($this, $req, $resp) = @_;
21
22     if ($req->uri->path =~ m!^/nopaste/(.+?)/?$! and
23           $this->{nopaste}{id_to_channel}{$1}) {
24         return index_handler(
25             $this, $req, $resp, $this->{nopaste}{id_to_channel}{$1});
26     }
27     elsif ($req->uri->path =~ m!^/post/(.+?)/?$! and
28              $this->{nopaste}{id_to_channel}{$1}) {
29         return post_handler(
30             $this, $req, $resp, $this->{nopaste}{id_to_channel}{$1});
31     }
32     else {
33         return notfound_handler(@_);
34     }
35 }
36
37 sub index_handler {
38     my ($this, $req, $resp, $ch, $error) = @_;
39
40     local $ENV{LANGUAGE} = $ch->{locale};
41
42     my $t = POE::Component::IRC::Plugin::NoPaste::Template->new(
43         -data => static_file('tmpl/index.html'));
44
45     $t->expand(
46         lang  => $ch->{locale},
47         title => "NoPaste :: $ch->{name}",
48        );
49
50     my ($ptr) = gethostbyaddr(
51         inet_aton($req->{connection}->remote_ip), AF_INET);
52     my @writable = $this->{nopaste}->pickup_writable($ch->{id}, $ptr);
53     my @readable = $this->{nopaste}->pickup_readable($ch->{id}, $ptr);
54     
55     if (@writable or $ch->{restriction}{write} eq 'any') {
56         if ($error) {
57             $_ = $error;
58             s!\n!<br />!g;
59             $t->writable->error->add(error => $_);
60         }
61
62         $t->writable->expand(
63             channel_id => $ch->{id},
64             l18n_name  => __"Name",
65            );
66
67         if ($ch->{restriction}{write} ne 'any') {
68             if (@writable ==1) {
69                 $t->writable->restricted->only_one->add(
70                     nick => $writable[0],
71                    );
72             }
73             else {
74                 foreach my $nick (@writable) {
75                     $t->writable->restricted->multiple->entry->add(
76                         nick => $nick,
77                        );
78                 }
79                 $t->writable->restricted->multiple->add;
80             }
81             $t->writable->restricted->add;
82         }
83         else {
84             $t->writable->not_restricted->add;
85         }
86
87         $t->writable->add(
88             l18n_title => __"Title",
89             l18n_body  => __(
90                 # body of the post
91                 "Body",
92                ),
93             l18n_paste => __"Paste",
94            );
95
96         # set the default values
97         my $q = $req->uri->clone;
98         if (not $q->query_param('nick') and @writable == 1) {
99             $q->query_param(nick => $writable[0]);
100         }
101         $t->setform($q => 'post');
102     }
103     else {
104         my $msg = $this->{nopaste}->gen_unwritable_error($ch);
105         $msg =~ s!\n!<br />!g;
106         
107         $t->not_writable->add(
108             error => $msg,
109            );
110     }
111
112     if (@readable or $ch->{restriction}{read} eq 'any') {
113         my $pager = POE::Component::IRC::Plugin::NoPaste::Pager->new(
114             fetch => {
115                 sql => q{
116                     SELECT *
117                       FROM post
118                      WHERE channel_id = ?
119                      ORDER BY posted_time DESC
120                 },
121                 placeholder => [$ch->{id}],
122                 dbh => $this->{nopaste}{db}->dbh,
123             },
124             page_to_show   => scalar $req->uri->query_param('page'),
125             pagenums_limit => 20,
126             items_per_page => 20,
127             show_meta => sub {
128                 my %meta = @_;
129                 
130                 if ($meta{page} == 1) {
131                     $t->readable->prev->nolink->add;
132                 }
133                 else {
134                     $t->readable->prev->link->add(
135                         page => $meta{page} - 1,
136                        );
137                 }
138                 $t->readable->prev->add;
139
140                 foreach my $i ($meta{pagelink_begin} .. $meta{pagelink_end}) {
141                     if ($i == $meta{page}) {
142                         $t->readable->pages->page->nolink->add(
143                             page => $i,
144                            );
145                     }
146                     else {
147                         $t->readable->pages->page->link->add(
148                             page => $i,
149                            );
150                     }
151                     $t->readable->pages->page->add;
152                 }
153                 $t->readable->pages->add;
154
155                 if ($meta{page} == $meta{last_page}) {
156                     $t->readable->next->nolink->add;
157                 }
158                 else {
159                     $t->readable->next->link->add(
160                         page => $meta{page} + 1,
161                        );
162                 }
163                 $t->readable->next->add;
164             },
165             show_content => sub {
166                 my $row = shift;
167                 
168                 $t->readable->list_data->add(
169                     id        => $row->{post_id},
170                     title     => $row->{title},
171                     name      => $row->{nick},
172                     body      => $row->{body},
173                     timestamp => $time{'yyyy-mm-dd hh:mm:ss', $row->{posted_time}},
174                    );
175             },
176             no_content => sub {
177                 $t->readable->list_nodata->add(
178                     l18n_nodata => __"There are no entries currently.",
179                    );
180             },
181            );
182         $pager->execute;
183
184         $t->readable->add(
185             l18n_title => __"Title",
186             l18n_name  => __"Name",
187             l18n_timestamp => __"Time Stamp",
188            );
189     }
190     else {
191         my $msg = $this->{nopaste}->gen_unreadable_error($ch);
192         $msg =~ s!\n!<br />!g;
193         
194         $t->not_readable->add(
195             error => $msg,
196            );
197     }
198
199     $resp->content($t->str);
200     return RC_OK;
201 }
202
203 sub post_handler {
204     my ($this, $req, $resp, $ch) = @_;
205     my $nick  = $req->uri->query_param('nick');
206     my $title = $req->uri->query_param('title');
207     my $body  = $req->uri->query_param('body');
208
209     local $ENV{LANGUAGE} = $ch->{locale};
210     
211     my @error;
212     if (not defined $nick or not length $nick) {
213         push @error, __"Please don't omit your name.";
214     }
215     elsif (length($nick) > NICK_LIMIT) {
216         push @error, __x("Please shorten your name up to {n} bytes.", n => NICK_LIMIT);
217     }
218     if (not defined $title or not length $title) {
219         push @error, __"Please don't omit the title.";
220     }
221     elsif (length($title) > TITLE_LIMIT) {
222         push @error, __x("Please shorten the title up to {n} bytes.", n => TITLE_LIMIT);
223     }
224     if (not defined $body or not length $body) {
225         push @error, __"Please don't omit the body.";
226     }
227     elsif (length($body) > BODY_LIMIT) {
228         push @error, __x("Please shorten the body up to {n} bytes.", n => BODY_LIMIT);
229     }
230
231     if (@error) {
232         return index_handler($this, $req, $resp, $ch, join("\n", map {"* $_"} @error));
233     }
234     
235     my ($ptr) = gethostbyaddr(
236         inet_aton($req->{connection}->remote_ip), AF_INET);
237     my @writable = $this->{nopaste}->pickup_writable($ch->{id}, $ptr);
238     if ($ch->{restriction}{write} eq 'any' or
239           grep {$_ eq $nick} @writable) {
240         
241         my $db = $this->{nopaste}{db};
242         
243         # check for duplication
244         if ($db->dbh->selectrow_hashref(q{
245             SELECT *
246               FROM post
247              WHERE channel_id = ? AND nick = ? AND
248                    title = ? AND body = ?
249         }, undef, $ch->{id}, $nick, $title, $body)) {
250             return index_handler(
251                 $this, $req, $resp, $ch, __"A duplicated entry is being pasted.");
252         }
253
254         # insert it
255         $db->dbh->do(q{
256             INSERT INTO post
257                    (channel_id, posted_time, nick, title, body)
258             VALUES (?         , ?          , ?   , ?    , ?   )
259         }, undef, $ch->{id}, time, $nick, $title, $body);
260
261         # get the post id
262         my ($post_id) = $db->dbh->selectrow_array(q{
263             SELECT LAST_INSERT_ROWID()});
264
265         # announce it in the channel
266         my $name = $ch->{name};
267         from_to $name, 'UTF-8' => $ch->{charset};
268
269         my @msg = (
270             __x("{nick} pasted an entry: {title}", nick => $nick, title => $title),
271             do {
272                 my $uri = $req->uri->clone;
273                 $uri->path("/pasted/$post_id");
274                 $uri->query(undef);
275                 $uri->fragment(undef);
276                 $uri->as_string;
277             },
278            );
279         foreach (@msg) {
280             my $line = $_;
281             from_to $line, 'UTF-8' => $ch->{charset};
282             
283             $this->{nopaste}{irc}->yield(
284                 notice => $name => $line);
285         }
286
287         # redirect to the index
288         return redirect_handler(
289             $this, $req, $resp, "/nopaste/$ch->{id}/");
290     }
291     else {
292         return index_handler($this, $req, $resp, $ch);
293     }
294 }
295
296 1;