| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package WWW::Mechanize::Plugin::phpBB; | 
| 2 |  |  |  |  |  |  |  | 
| 3 | 1 |  |  | 1 |  | 1038 | use 5.006; | 
|  | 1 |  |  |  |  | 4 |  | 
|  | 1 |  |  |  |  | 43 |  | 
| 4 | 1 |  |  | 1 |  | 6 | use strict; | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 37 |  | 
| 5 | 1 |  |  | 1 |  | 16 | use warnings; | 
|  | 1 |  |  |  |  | 3 |  | 
|  | 1 |  |  |  |  | 60 |  | 
| 6 |  |  |  |  |  |  |  | 
| 7 |  |  |  |  |  |  | our $VERSION = '0.02'; | 
| 8 |  |  |  |  |  |  |  | 
| 9 | 1 |  |  | 1 |  | 2563 | use Log::Log4perl qw(:easy); | 
|  | 1 |  |  |  |  | 70441 |  | 
|  | 1 |  |  |  |  | 8 |  | 
| 10 | 1 |  |  | 1 |  | 2233 | use HTML::TreeBuilder; | 
|  | 1 |  |  |  |  | 40860 |  | 
|  | 1 |  |  |  |  | 15 |  | 
| 11 |  |  |  |  |  |  |  | 
| 12 | 1 |  |  | 1 |  | 52 | use base qw(Class::Accessor::Fast); | 
|  | 1 |  |  |  |  | 3 |  | 
|  | 1 |  |  |  |  | 1034 |  | 
| 13 |  |  |  |  |  |  | __PACKAGE__->mk_accessors(qw(url version)); | 
| 14 |  |  |  |  |  |  |  | 
| 15 |  |  |  |  |  |  | ########################################### | 
| 16 | 1 |  |  | 1 |  | 19 | sub import { | 
| 17 |  |  |  |  |  |  | ########################################### | 
| 18 |  |  |  |  |  |  | # We need an empty import method, otherwise | 
| 19 |  |  |  |  |  |  | # the Module::Pluggable test suite breaks: | 
| 20 |  |  |  |  |  |  | #    # t/plugin.t | 
| 21 |  |  |  |  |  |  | #    use WWW::Mechanize::Pluggable helloworld=>"WORLD"; | 
| 22 |  |  |  |  |  |  | } | 
| 23 |  |  |  |  |  |  |  | 
| 24 |  |  |  |  |  |  | ########################################### | 
| 25 |  |  |  |  |  |  | sub init { | 
| 26 |  |  |  |  |  |  | ########################################### | 
| 27 | 0 |  |  | 0 | 0 |  | my($class, @args) = @_; | 
| 28 |  |  |  |  |  |  |  | 
| 29 | 1 |  |  | 1 |  | 3782 | no strict 'refs'; | 
|  | 1 |  |  |  |  | 3 |  | 
|  | 1 |  |  |  |  | 1152 |  | 
| 30 |  |  |  |  |  |  |  | 
| 31 | 0 |  |  |  |  |  | for my $method (qw(login forums forum_enter topics post_remove)) { | 
| 32 | 0 |  |  |  |  |  | *{caller() . "::phpbb_$method"} = \&$method; | 
|  | 0 |  |  |  |  |  |  | 
| 33 |  |  |  |  |  |  | } | 
| 34 |  |  |  |  |  |  | } | 
| 35 |  |  |  |  |  |  |  | 
| 36 |  |  |  |  |  |  | ########################################### | 
| 37 |  |  |  |  |  |  | sub login { | 
| 38 |  |  |  |  |  |  | ########################################### | 
| 39 | 0 |  |  | 0 | 0 |  | my ($mech, $user, $password) = @_; | 
| 40 |  |  |  |  |  |  |  | 
| 41 | 0 | 0 | 0 |  |  |  | if(!defined $user or !defined $password) { | 
| 42 | 0 |  |  |  |  |  | LOGDIE 'usage: ->login($user, $password)'; | 
| 43 |  |  |  |  |  |  | } | 
| 44 |  |  |  |  |  |  |  | 
| 45 | 0 |  |  |  |  |  | my $old_autocheck = $mech->{autocheck}; | 
| 46 | 0 |  |  |  |  |  | $mech->{autocheck} = 1; | 
| 47 |  |  |  |  |  |  |  | 
| 48 | 0 |  |  |  |  |  | DEBUG "Logging in as user '$user'"; | 
| 49 |  |  |  |  |  |  |  | 
| 50 | 0 |  |  |  |  |  | eval { | 
| 51 | 0 |  |  |  |  |  | DEBUG "Finding 'Login' link "; | 
| 52 | 0 |  |  |  |  |  | my $link = $mech->find_link(url_regex => qr/login\.php/); | 
| 53 | 0 | 0 |  |  |  |  | die "Cannot find login.php link" unless defined $link; | 
| 54 |  |  |  |  |  |  |  | 
| 55 | 0 |  |  |  |  |  | my $url = $link->url(); | 
| 56 |  |  |  |  |  |  |  | 
| 57 | 0 |  |  |  |  |  | DEBUG "Following link $url"; | 
| 58 | 0 |  |  |  |  |  | $mech->follow_link(url => $url); | 
| 59 |  |  |  |  |  |  |  | 
| 60 | 0 |  |  |  |  |  | DEBUG "Submitting login credentials for user '$user'"; | 
| 61 | 0 |  |  |  |  |  | $mech->submit_form( | 
| 62 |  |  |  |  |  |  | fields => { | 
| 63 |  |  |  |  |  |  | username => $user, | 
| 64 |  |  |  |  |  |  | password => $password, | 
| 65 |  |  |  |  |  |  | }, | 
| 66 |  |  |  |  |  |  | button => "login", | 
| 67 |  |  |  |  |  |  | ); | 
| 68 |  |  |  |  |  |  |  | 
| 69 | 0 |  |  |  |  |  | $link = $mech->find_link( | 
| 70 |  |  |  |  |  |  | url_regex => qr/\Qlogin.php?logout=true\E/); | 
| 71 | 0 | 0 |  |  |  |  | die "Login failed (wrong credentials?)" unless defined $link; | 
| 72 |  |  |  |  |  |  | }; | 
| 73 |  |  |  |  |  |  |  | 
| 74 | 0 |  |  |  |  |  | $mech->{autocheck} = $old_autocheck; | 
| 75 |  |  |  |  |  |  |  | 
| 76 | 0 | 0 |  |  |  |  | if($@) { | 
| 77 | 0 |  |  |  |  |  | ERROR "$@"; | 
| 78 | 0 |  |  |  |  |  | return undef; | 
| 79 |  |  |  |  |  |  | } | 
| 80 |  |  |  |  |  |  |  | 
| 81 | 0 |  |  |  |  |  | INFO "Logged in as user '$user'"; | 
| 82 |  |  |  |  |  |  | } | 
| 83 |  |  |  |  |  |  |  | 
| 84 |  |  |  |  |  |  | ########################################### | 
| 85 |  |  |  |  |  |  | sub forums { | 
| 86 |  |  |  |  |  |  | ########################################### | 
| 87 | 0 |  |  | 0 | 0 |  | my ($mech) = @_; | 
| 88 |  |  |  |  |  |  |  | 
| 89 | 0 |  |  |  |  |  | DEBUG "Finding all forums"; | 
| 90 |  |  |  |  |  |  |  | 
| 91 | 0 |  |  |  |  |  | my $forums = $mech->find_all_links( | 
| 92 |  |  |  |  |  |  | url_regex => qr/viewforum\.php|forumdisplay.php/ ); | 
| 93 |  |  |  |  |  |  |  | 
| 94 | 0 |  |  |  |  |  | DEBUG "Found forums ", | 
| 95 | 0 |  |  |  |  |  | join(", ", map { '"' . $_->text() . '"' } @$forums), "."; | 
| 96 |  |  |  |  |  |  |  | 
| 97 | 0 |  |  |  |  |  | return $forums; | 
| 98 |  |  |  |  |  |  | } | 
| 99 |  |  |  |  |  |  |  | 
| 100 |  |  |  |  |  |  | ########################################### | 
| 101 |  |  |  |  |  |  | sub forum_enter { | 
| 102 |  |  |  |  |  |  | ########################################### | 
| 103 | 0 |  |  | 0 | 0 |  | my ($mech, $rex) = @_; | 
| 104 |  |  |  |  |  |  |  | 
| 105 | 0 |  |  |  |  |  | for my $forum (@{ forums($mech) }) { | 
|  | 0 |  |  |  |  |  |  | 
| 106 | 0 | 0 |  |  |  |  | if($forum->text() =~ /$rex/) { | 
| 107 | 0 |  |  |  |  |  | INFO "Entering Forum ", $forum->text(); | 
| 108 | 0 |  |  |  |  |  | $mech->get($forum->url()); | 
| 109 | 0 |  |  |  |  |  | return 1; | 
| 110 |  |  |  |  |  |  | } | 
| 111 |  |  |  |  |  |  | } | 
| 112 |  |  |  |  |  |  |  | 
| 113 | 0 |  |  |  |  |  | ERROR "Cannot find forum matching $rex"; | 
| 114 |  |  |  |  |  |  |  | 
| 115 | 0 |  |  |  |  |  | return undef; | 
| 116 |  |  |  |  |  |  | } | 
| 117 |  |  |  |  |  |  |  | 
| 118 |  |  |  |  |  |  | ########################################### | 
| 119 |  |  |  |  |  |  | sub topics { | 
| 120 |  |  |  |  |  |  | ########################################### | 
| 121 | 0 |  |  | 0 | 0 |  | my ($mech) = @_; | 
| 122 |  |  |  |  |  |  |  | 
| 123 | 0 |  |  |  |  |  | DEBUG "Scraping topics from ", $mech->uri(); | 
| 124 |  |  |  |  |  |  |  | 
| 125 |  |  |  |  |  |  | # Scrape the topics and their links from a forum page | 
| 126 | 0 |  |  |  |  |  | my $tree = HTML::TreeBuilder->new(); | 
| 127 |  |  |  |  |  |  |  | 
| 128 | 0 | 0 |  |  |  |  | $tree->parse($mech->content()) or | 
| 129 |  |  |  |  |  |  | LOGDIE "Cannot parse forum HTML from ", $mech->uri(); | 
| 130 |  |  |  |  |  |  |  | 
| 131 | 0 |  |  |  |  |  | my @topics = $tree->look_down( | 
| 132 |  |  |  |  |  |  | _tag  =>  "span", | 
| 133 |  |  |  |  |  |  | class => "topictitle", | 
| 134 |  |  |  |  |  |  | ); | 
| 135 |  |  |  |  |  |  |  | 
| 136 | 0 |  |  |  |  |  | my $topics_seen = {}; | 
| 137 | 0 |  |  |  |  |  | my $topics_all  = []; | 
| 138 |  |  |  |  |  |  |  | 
| 139 | 0 |  |  |  |  |  | for my $topic (@topics) { | 
| 140 | 0 |  |  |  |  |  | my $a = $topic->content()->[0]; | 
| 141 | 0 |  |  |  |  |  | my $count = $topic->parent()->right()->as_text(); | 
| 142 |  |  |  |  |  |  |  | 
| 143 | 0 |  |  |  |  |  | my $url = URI::URL->new($a->attr('href'), $mech->uri()); | 
| 144 |  |  |  |  |  |  |  | 
| 145 |  |  |  |  |  |  | # Throw away session ID | 
| 146 | 0 |  |  |  |  |  | my %form = $url->query_form(); | 
| 147 | 0 |  |  |  |  |  | delete $form{sid}; | 
| 148 | 0 |  |  |  |  |  | $url->query_form(%form); | 
| 149 |  |  |  |  |  |  |  | 
| 150 | 0 | 0 |  |  |  |  | next if exists $topics_seen->{$form{t}}; | 
| 151 |  |  |  |  |  |  |  | 
| 152 | 0 |  |  |  |  |  | my $this_topic = { url   => $url->abs->as_string(), | 
| 153 |  |  |  |  |  |  | text  => $a->as_text(), | 
| 154 |  |  |  |  |  |  | count => $count, | 
| 155 |  |  |  |  |  |  | }; | 
| 156 |  |  |  |  |  |  |  | 
| 157 | 0 |  |  |  |  |  | $topics_seen->{$form{t}}++; | 
| 158 | 0 |  |  |  |  |  | push @$topics_all, $this_topic; | 
| 159 |  |  |  |  |  |  | } | 
| 160 |  |  |  |  |  |  |  | 
| 161 | 0 |  |  |  |  |  | $tree->delete(); | 
| 162 |  |  |  |  |  |  |  | 
| 163 | 0 |  |  |  |  |  | DEBUG "Found topics ", | 
| 164 |  |  |  |  |  |  | join(", ", | 
| 165 | 0 |  |  |  |  |  | map { '"' . $_->{text} . ' (' . $_->{count} . ')"' } @$topics_all), | 
| 166 |  |  |  |  |  |  | "."; | 
| 167 |  |  |  |  |  |  |  | 
| 168 | 0 |  |  |  |  |  | return $topics_all; | 
| 169 |  |  |  |  |  |  | } | 
| 170 |  |  |  |  |  |  |  | 
| 171 |  |  |  |  |  |  | ########################################### | 
| 172 |  |  |  |  |  |  | sub post_remove { | 
| 173 |  |  |  |  |  |  | ########################################### | 
| 174 | 0 |  |  | 0 | 0 |  | my ($mech, $post_id) = @_; | 
| 175 |  |  |  |  |  |  |  | 
| 176 | 0 |  |  |  |  |  | DEBUG "Removing post $post_id"; | 
| 177 |  |  |  |  |  |  |  | 
| 178 |  |  |  |  |  |  | # Find delete link | 
| 179 | 0 |  |  |  |  |  | my $link = $mech->find_link(url_regex => qr/\Qmode=delete&p=$post_id\E/); | 
| 180 |  |  |  |  |  |  |  | 
| 181 | 0 | 0 |  |  |  |  | LOGDIE "Cannot find delete link for posting $post_id" unless defined $link; | 
| 182 | 0 |  |  |  |  |  | DEBUG "Going to ", $link->url(); | 
| 183 | 0 |  |  |  |  |  | $mech->follow_link(url => $link->url()); | 
| 184 |  |  |  |  |  |  |  | 
| 185 |  |  |  |  |  |  | # Confirm | 
| 186 | 0 |  |  |  |  |  | DEBUG "Confirming delete"; | 
| 187 | 0 |  |  |  |  |  | $mech->submit_form( | 
| 188 |  |  |  |  |  |  | button => "confirm", | 
| 189 |  |  |  |  |  |  | ); | 
| 190 |  |  |  |  |  |  | } | 
| 191 |  |  |  |  |  |  |  | 
| 192 |  |  |  |  |  |  | 1; | 
| 193 |  |  |  |  |  |  |  | 
| 194 |  |  |  |  |  |  | __END__ |