File Coverage

blib/lib/WWW/TWikiClient.pm
Criterion Covered Total %
statement 18 140 12.8
branch 0 48 0.0
condition 0 15 0.0
subroutine 6 24 25.0
pod 9 9 100.0
total 33 236 13.9


line stmt bran cond sub pod time code
1             package WWW::TWikiClient;
2              
3 1     1   2036 use WWW::Mechanize;
  1         244285  
  1         38  
4              
5 1     1   11 use strict;
  1         3  
  1         34  
6 1     1   16 use warnings;
  1         2  
  1         28  
7              
8 1     1   4 use vars qw($VERSION);
  1         1  
  1         53  
9             $VERSION = '0.11';
10              
11 1     1   4 use base 'WWW::Mechanize';
  1         2  
  1         123  
12              
13             use Class::MethodMaker
14 1         19 get_set => [
15             'bin_url',
16             'current_default_web',
17             'current_topic',
18             'auth_user',
19             'auth_passwd',
20             'override_locks',
21             'release_edit_lock',
22             'verbose',
23             'skin_hints',
24             ],
25             new_hash_init => 'hash_init'
26 1     1   1026 ;
  1         26900  
27              
28             sub new {
29 0     0 1   my $class = shift;
30 0           my $self = WWW::Mechanize::new ($class);
31 0           $self->pre_init ();
32 0           $self->hash_init (@_);
33 0           $self->post_init ();
34 0           return $self;
35             }
36              
37             sub pre_init {
38 0     0 1   my $self = shift;
39 0           $self->override_locks (0);
40 0           $self->release_edit_lock (1);
41 0           $self->verbose (0);
42 0           $self->skin_hints ({});
43             }
44              
45             sub post_init {
46 0     0 1   my $self = shift;
47             }
48              
49             # overloaded to provide username and password
50             # that we have in two own getters/setters
51             sub get_basic_credentials {
52 0     0 1   my $self = shift;
53 0           return ($self->auth_user, $self->auth_passwd);
54             }
55              
56             # constructs URL
57             # if topic doesn't contain a Web prefix, "current_default_web" is prepended
58             sub _make_url {
59 0     0     my $self = shift;
60 0           my $cmd = shift;
61 0           my $topic = shift;
62 0           my $tail = shift;
63              
64 0           my $url = $self->bin_url;
65 0 0         if ($topic =~ /\./) {
66 0           $topic =~ s!\.!/!;
67             } else {
68 0           $topic = $self->current_default_web."/$topic";
69             }
70 0 0         $url .= '/' if $url !~ m!/$!;
71 0           $url .= "$cmd/";
72 0           $url .= $topic;
73 0 0         $url .= $tail if $tail;
74 0           return $url;
75             }
76              
77             sub _skin_regex_topic_locked {
78 0     0     my $self = shift;
79 0           return qr/\(oops\).*name="Topic_is_locked_by_another_user"/s;
80             }
81              
82             sub _skin_regex_topic_locked_edit_anyway {
83 0     0     my $self = shift;
84 0           return qr/Edit anyway/;
85             }
86              
87             sub _skin_regex_authentication_failed {
88 0     0     my $self = shift;
89 0           return qr/TWikiRegistration.*\(oops\).*name="Either_you_need_to_register_or_t"/s;
90             }
91              
92             sub _skin_regex_save_or_preview_page {
93 0     0     my $self = shift;
94 0   0       my $topic = shift || ''; # needed for "where I am"-heuristic
95              
96 0           return qr/form name=".*".*action=".*\/save\/.*$topic">/s;
97             }
98              
99             # a little helper function
100             sub _htmlparse_get_text {
101 0     0     my $self = shift;
102              
103 0           my($p, $stop) = @_;
104 0           my $text;
105 0           while (defined(my $t = $p->get_token)) {
106 0 0         if (ref $t) {
107 0 0         $p->unget_token($t) unless $t->[0] eq $stop;
108 0           last;
109             }
110             else {
111 0           $text .= $t;
112             }
113             }
114 0           return $text;
115             }
116              
117             sub htmlparse_extract_single_textarea {
118 0     0 1   my $self = shift;
119 0   0       my $doc = shift || $self->doc || '';
120              
121 0           my @FORM_TAGS = qw(form textarea);
122 0           my $p = HTML::PullParser->new (
123             doc => $doc,
124             start => 'tag, attr',
125             end => 'tag',
126             text => '@{text}',
127             report_tags => \@FORM_TAGS,
128             );
129 0           while (defined(my $t = $p->get_token)) {
130 0 0         next unless ref $t; # skip text
131 0 0         if ($t->[0] eq "form") {
    0          
132 0           shift @$t;
133 0           while (defined(my $t = $p->get_token)) {
134 0 0         next unless ref $t; # skip text
135 0 0         last if $t->[0] eq "/form";
136 0 0         if ($t->[0] eq "textarea") {
137 0           return $self->_htmlparse_get_text ($p, "/textarea");
138             }
139             }
140             } elsif ($t->[0] eq "textarea") {
141 0           return $self->_htmlparse_get_text ($p, "/textarea");
142             }
143             }
144 0           return undef;
145             }
146              
147             sub edit_press_cancel {
148 0     0 1   my $self = shift;
149              
150 0           my $url = $self->_make_url ('view', $self->current_topic, '?unlock=on');
151             #print STDERR "edit_press_cancel: $url\n" if $self->verbose;
152 0           $self->follow_link (url => $url);
153             }
154              
155             sub read_topic {
156 0     0 1   my $self = shift;
157 0   0       my $topic = shift || $self->current_topic;
158 0           my $url = $self->_make_url ('view', $topic, '?raw=on');
159             #print STDERR "read_topic: $url\n" if $self->verbose;
160 0           $self->get ($url);
161 0           return $self->htmlparse_extract_single_textarea ($self->content);
162             }
163              
164             sub _handle_release_edit_lock {
165 0     0     my $self = shift;
166              
167 0           my $unlock_checkbox = $self->current_form->find_input ('unlock', 'checkbox');
168             # "release edit lock"
169 0 0         if ($unlock_checkbox) {
170 0 0         if ($self->release_edit_lock) {
171 0           $self->tick ('unlock', 'on');
172             } else {
173 0           $self->untick ('unlock', 'on');
174             }
175             }
176             }
177              
178             sub save_topic {
179 0     0 1   my $self = shift;
180 0           my $content = shift;
181 0   0       my $topic = shift || $self->current_topic;
182              
183 0           my $url = $self->_make_url ('edit', $topic);
184             #print STDERR "save_topic: $url\n" if $self->verbose;
185              
186             # get page
187 0           $self->get ($url);
188              
189             # locked?
190 0 0         $self->_save_topic_handle_locks ($url) or return undef;
191              
192             # fill form
193 0           $self->form_number (1);
194 0           $self->current_form;
195 0           $self->set_fields ( text => $content );
196 0           $self->_save_topic_Save ($topic);
197 0           return 1;
198             }
199              
200             sub attach_to_topic {
201 0     0 1   my $self = shift;
202 0           my $local_filename = shift;
203 0           my $comment = shift;
204 0           my $create_link = shift;
205 0           my $hide_file = shift;
206 0   0       my $topic = shift || $self->current_topic;
207              
208 0           my $url = $self->_make_url ('attach', $topic);
209 0 0         print STDERR "attach_to_topic url: $url\n" if $self->verbose;
210              
211             # get page
212 0           $self->get ($url);
213              
214             # fill form
215 0           $self->form_number (1);
216 0           $self->current_form;
217              
218 0           $self->set_fields
219             (
220             filepath => $local_filename,
221             filecomment => $comment,
222             );
223 0 0         $self->tick ('createlink', 'on') if $create_link;
224 0 0         $self->tick ('hidefile', 'on') if $hide_file;
225              
226 0           $self->submit();
227 0           return;
228             }
229              
230             sub _save_topic_handle_locks {
231 0     0     my $self = shift;
232 0           my $url = shift;
233              
234 0           my $html_content = $self->content;
235 0 0         if ($html_content =~ $self->_skin_regex_topic_locked) {
    0          
236 0 0         if ($self->override_locks) {
237             # edit anyway
238 0 0         print STDERR "Override topic lock.\n" if $self->verbose;
239 0           $self->follow_link (text_regex => $self->_skin_regex_topic_locked_edit_anyway);
240 0           $self->get ($url);
241             } else {
242 0 0         print STDERR "Topic is locked.\n" if $self->verbose;
243 0           return undef;
244             }
245             } elsif ($html_content =~ $self->_skin_regex_authentication_failed) {
246 0 0         print STDERR "Access denied. Authentication failed.\n" if $self->verbose;
247 0           return undef;
248             }
249 0           return 1;
250             }
251              
252             sub _save_topic_Save {
253 0     0     my $self = shift;
254 0   0       my $topic = shift || ''; # needed for "where I am"-heuristic
255              
256 0           $self->_handle_release_edit_lock;
257             # simply submit (== either "Preview Changes" or "Save Changes")
258 0           $self->submit();
259             # did we arrive at a preview page?
260 0           my $content = $self->content;
261 0 0         if ($content =~ _skin_regex_save_or_preview_page ($topic)) {
262             # simply submit again (== "Save Changes")
263 0           $self->_handle_release_edit_lock;
264 0           $self->submit();
265             }
266             }
267              
268             1;