File Coverage

blib/lib/WWW/Connpass/Session.pm
Criterion Covered Total %
statement 45 228 19.7
branch 0 30 0.0
condition 0 2 0.0
subroutine 15 41 36.5
pod 0 20 0.0
total 60 321 18.6


line stmt bran cond sub pod time code
1             package WWW::Connpass::Session;
2 1     1   4 use strict;
  1         2  
  1         21  
3 1     1   3 use warnings;
  1         1  
  1         22  
4              
5 1     1   3 use Carp qw/croak/;
  1         2  
  1         49  
6 1     1   442 use Web::Query qw/wq/;
  1         97579  
  1         48  
7 1     1   737 use Text::CSV_XS;
  1         13239  
  1         41  
8 1     1   503 use JSON 2;
  1         6166  
  1         5  
9 1     1   124 use URI;
  1         3  
  1         17  
10              
11 1     1   363 use WWW::Connpass::Agent;
  1         3  
  1         35  
12 1     1   376 use WWW::Connpass::Event;
  1         2  
  1         22  
13 1     1   308 use WWW::Connpass::Event::Questionnaire;
  1         2  
  1         22  
14 1     1   319 use WWW::Connpass::Event::Participants;
  1         2  
  1         23  
15 1     1   312 use WWW::Connpass::Group;
  1         2  
  1         23  
16 1     1   301 use WWW::Connpass::Place;
  1         2  
  1         21  
17 1     1   293 use WWW::Connpass::User;
  1         2  
  1         26  
18              
19 1     1   5 use constant DEBUG => $ENV{WWW_CONNPASS_DEBUG};
  1         1  
  1         2072  
20              
21             my $_JSON = JSON->new->utf8;
22              
23             sub new {
24 0     0 0   my ($class, $user, $pass, $opt) = @_;
25              
26 0           my $mech = WWW::Connpass::Agent->new(%$opt, cookie_jar => {});
27 0           $mech->get('https://connpass.com/');
28 0           $mech->get('https://connpass.com/login/');
29 0           $mech->form_id('login_form');
30 0           $mech->set_fields(username => $user, password => $pass);
31 0           my $res = $mech->submit();
32 0           _check_response_error_or_throw($res);
33              
34 0     0     my $error = wq($res->decoded_content)->find('.errorlist > li')->map(sub { $_->text });
  0            
35 0 0         if (@$error) {
36 0           my $message = join "\n", @$error;
37 0           croak "Failed to login by user: $user. error: $message";
38             }
39              
40 0           return bless {
41             mech => $mech,
42             user => $user,
43             } => $class;
44             }
45              
46 0     0 0   sub user { shift->{user} }
47              
48             sub _check_response_error_or_throw {
49 0     0     my $res = shift;
50 0 0         unless ($res->is_success) {
51 0           my $message = sprintf '[ERROR] %d %s: %s', $res->code, $res->message, $res->decoded_content;
52 0           $message = "=REQUEST\n".$res->request->as_string."\nRESPONSE=\n".$res->as_string if DEBUG;
53 0           local $Carp::CarpLevel = $Carp::CarpLevel + 1;
54 0           croak $message;
55             }
56 0           return $res;
57             }
58              
59             sub new_event {
60 0     0 0   my ($self, $title, $opts) = @_;
61 0   0       $opts ||= {};
62              
63             # pre-request (for referer check)
64 0 0         $self->{mech}->get($opts->{group} ? $opts->{group}->url : 'https://connpass.com/dashboard/');
65              
66 0 0         my $url = $opts->{group} ? URI->new($opts->{group}->url) : URI->new('https://connpass.com/');
67 0           $url->scheme('https');
68 0           $url->path('/api/event/');
69              
70             my $res = $self->{mech}->request_like_xhr(POST => $url->as_string, {
71             title => $title,
72             place => undef,
73 0 0         $opts->{group} ? (series => $opts->{group}->id) : (),
74             });
75 0           _check_response_error_or_throw($res);
76              
77 0           my $data = $_JSON->decode($res->decoded_content);
78 0           return WWW::Connpass::Event->new(session => $self, event => $data);
79             }
80              
81             sub fetch_event_by_id {
82 0     0 0   my ($self, $event_id) = @_;
83 0           my $uri = sprintf 'https://connpass.com/api/event/%d', $event_id;
84              
85 0           my $res = $self->{mech}->get($uri);
86 0 0         return if $res->code == 404;
87 0           _check_response_error_or_throw($res);
88              
89 0           my $data = $_JSON->decode($res->decoded_content);
90 0           return WWW::Connpass::Event->new(session => $self, event => $data);
91             }
92              
93             sub fetch_event_owners {
94 0     0 0   my ($self, $event) = @_;
95 0           $self->_update_event_pre_flight_request($event);
96              
97 0           my $uri = sprintf 'https://connpass.com/api/event/%d/owner/', $event->id;
98 0           my $res = $self->{mech}->get($uri);
99 0 0         return if $res->code == 404;
100 0           _check_response_error_or_throw($res);
101              
102 0           my $data = $_JSON->decode($res->decoded_content);
103 0           return map { WWW::Connpass::User->new(user => $_) } @$data;
  0            
104             }
105              
106             sub refetch_event {
107 0     0 0   my ($self, $event) = @_;
108 0           return $self->fetch_event_by_id($event->id);
109             }
110              
111             sub _update_event_pre_flight_request {
112 0     0     my ($self, $event) = @_;
113              
114             # pre-request (for referer check)
115 0           $self->{mech}->get(sprintf 'https://connpass.com/event/%d/edit/', $event->id);
116             }
117              
118             sub _update_questionnaire_pre_flight_request {
119 0     0     my ($self, $questionnaire) = @_;
120              
121             # pre-request (for referer check)
122 0           $self->{mech}->get(sprintf 'https://connpass.com/event/%d/edit/form/', $questionnaire->event);
123             }
124              
125             sub update_event {
126 0     0 0   my ($self, $event, $diff) = @_;
127 0           my $uri = sprintf 'https://connpass.com/api/event/%d', $event->id;
128              
129 0           $self->_update_event_pre_flight_request($event);
130             my $res = $self->{mech}->request_like_xhr(PUT => $uri, {
131 0           %{ $event->raw_data },
132             $event->place ? (
133             place => $event->place->{id},
134 0 0         ) : (),
135             %$diff,
136             });
137 0           _check_response_error_or_throw($res);
138              
139 0           $event = $_JSON->decode($res->decoded_content);
140 0           return WWW::Connpass::Event->new(session => $self, event => $event);
141             }
142              
143             sub update_waitlist_count {
144 0     0 0   my ($self, $event, @waitlist_count) = @_;
145 0           my %update = map { $_->id => $_ } grep { !$_->is_new } @waitlist_count;
  0            
  0            
146 0 0         my @update = map { $_->raw_data } map { delete $update{$_->id} || $_ } $event->waitlist_count();
  0            
  0            
147 0           push @update => map { $_->raw_data } grep { $_->is_new } @waitlist_count;
  0            
  0            
148              
149 0           my $uri = sprintf 'https://connpass.com/api/event/%d/participation_type/', $event->id;
150              
151 0           $self->_update_event_pre_flight_request($event);
152 0           my $res = $self->{mech}->request_like_xhr(PUT => $uri, \@update);
153 0           _check_response_error_or_throw($res);
154              
155 0           return $self->refetch_event($event);
156             }
157              
158             sub fetch_questionnaire_by_event {
159 0     0 0   my ($self, $event) = @_;
160 0           my $uri = sprintf 'https://connpass.com/api/question/%d', $event->id;
161 0           my $res = $self->{mech}->get($uri);
162             # HTTP::Response
163 0 0         if ($res->code == 404) {
164 0           return WWW::Connpass::Event::Questionnaire->new(
165             session => $self,
166             questionnaire => {
167             id => undef,
168             questions => [],
169             event => $event->id,
170             },
171             );
172             }
173 0           _check_response_error_or_throw($res);
174              
175 0           my $data = $_JSON->decode($res->decoded_content);
176 0           return WWW::Connpass::Event::Questionnaire->new(session => $self, questionnaire => $data);
177             }
178              
179             sub update_questionnaire {
180 0     0 0   my ($self, $questionnaire, @question) = @_;
181              
182 0 0         my $method = $questionnaire->is_new ? 'POST' : 'PUT';
183 0           my $uri = sprintf 'https://connpass.com/api/question/%d', $questionnaire->event;
184              
185 0           $self->_update_questionnaire_pre_flight_request($questionnaire);
186             my $res = $self->{mech}->request_like_xhr($method => $uri, {
187 0           %{ $questionnaire->raw_data },
188 0           questions => [map { $_->raw_data } @question],
  0            
189             });
190 0           _check_response_error_or_throw($res);
191              
192 0           my $data = $_JSON->decode($res->decoded_content);
193 0           return WWW::Connpass::Event::Questionnaire->new(session => $self, questionnaire => $data);
194             }
195              
196             sub register_place {
197 0     0 0   my ($self, %data) = @_;
198              
199 0           my $res = $self->{mech}->request_like_xhr(POST => 'https://connpass.com/api/place/', \%data);
200 0           _check_response_error_or_throw($res);
201              
202 0           my $data = $_JSON->decode($res->decoded_content);
203 0           return WWW::Connpass::Place->new(session => $self, place => $data);
204             }
205              
206             sub add_owner_to_event {
207 0     0 0   my ($self, $event, $user) = @_;
208 0           $self->_update_event_pre_flight_request($event);
209              
210 0           my $uri = sprintf 'https://connpass.com/api/event/%d/owner/%d', $event->id, $user->id;
211 0           my $res = $self->{mech}->request_like_xhr(POST => $uri, { id => $user->id });
212 0           _check_response_error_or_throw($res);
213              
214 0           my $data = $_JSON->decode($res->decoded_content);
215 0           return WWW::Connpass::User->new(user => $data);
216             }
217              
218             sub update_place {
219 0     0 0   my ($self, $place, %data) = @_;
220              
221 0           my $uri = sprintf 'https://connpass.com/api/place/%d', $place->id;
222             my $res = $self->{mech}->request_like_xhr(PUT => $uri, {
223 0           %{ $place->raw_data },
  0            
224             %data,
225             });
226 0           _check_response_error_or_throw($res);
227              
228 0           my $data = $_JSON->decode($res->decoded_content);
229 0           return WWW::Connpass::Place->new(session => $self, place => $data);
230             }
231              
232             sub fetch_all_places {
233 0     0 0   my $self = shift;
234              
235 0           my $res = $self->{mech}->get('https://connpass.com/api/place/');
236 0           _check_response_error_or_throw($res);
237              
238 0           my $data = $_JSON->decode($res->decoded_content);
239 0           return map { WWW::Connpass::Place->new(session => $self, place => $_) } @$data;
  0            
240             }
241              
242             sub fetch_place_by_id {
243 0     0 0   my ($self, $place_id) = @_;
244 0           my $uri = sprintf 'https://connpass.com/api/place/%d', $place_id;
245              
246 0           my $res = $self->{mech}->get($uri);
247 0 0         return if $res->code == 404;
248 0           _check_response_error_or_throw($res);
249              
250 0           my $data = $_JSON->decode($res->decoded_content);
251 0           return WWW::Connpass::Place->new(session => $self, place => $data);
252             }
253              
254             sub refetch_place {
255 0     0 0   my ($self, $place) = @_;
256 0           return $self->fetch_place_by_id($place->id);
257             }
258              
259             sub search_users_by_name {
260 0     0 0   my ($self, $name) = @_;
261 0           my $uri = URI->new('https://connpass.com/api/user/');
262 0           $uri->query_form(q => $name);
263              
264 0           my $res = $self->{mech}->get($uri);
265 0           _check_response_error_or_throw($res);
266              
267 0           my $data = $_JSON->decode($res->decoded_content);
268 0           return map { WWW::Connpass::User->new(user => $_) } @$data;
  0            
269             }
270              
271             sub fetch_managed_events {
272 0     0 0   my $self = shift;
273 0           my $res = $self->{mech}->get('https://connpass.com/editmanage/');
274 0           _check_response_error_or_throw($res);
275 0           return map { WWW::Connpass::Event->new(session => $self, event => $_) }
276 0           map { $_JSON->decode($_) } @{
277 0     0     wq($res->decoded_content)->find('#EventManageTable .event_list > table')->map(sub { $_->data('obj') })
  0            
278 0           };
279             }
280              
281             sub fetch_organized_groups {
282 0     0 0   my $self = shift;
283 0           my $res = $self->{mech}->get('https://connpass.com/group/');
284 0           _check_response_error_or_throw($res);
285              
286             my $groups = wq($res->decoded_content)->find('.series_lists_area .series_list .title a')->map(sub {
287 0     0     my $title = $_->text;
288 0           my $url = $_->attr('href');
289 0           my ($id) = wq(_check_response_error_or_throw($self->{mech}->get($url))->decoded_content)->find('.icon_gray_edit')->parent()->attr('href') =~ m{/series/([^/]+)/edit/$};
290 0           my ($name) = $url =~ m{^https?://([^.]+)\.connpass\.com/};
291 0 0         return unless $id;
292             return {
293 0           id => $id,
294             name => $name,
295             title => $title,
296             url => $url,
297             };
298 0           });
299              
300 0           return map { WWW::Connpass::Group->new(session => $self, group => $_) } @$groups;
  0            
301             }
302              
303             sub fetch_participants_info {
304 0     0 0   my ($self, $event) = @_;
305 0           my $uri = sprintf 'https://connpass.com/event/%d/participants_csv/', $event->id;
306              
307 0           my $res = $self->{mech}->get($uri);
308 0           _check_response_error_or_throw($res);
309              
310             # HTTP::Response
311 0           my $content = $res->decoded_content;
312              
313 0           my $csv = Text::CSV_XS->new({ binary => 1, decode_utf8 => 0, eol => "\r\n", auto_diag => 1 });
314              
315 0           my @questions = $event->questionnaire->questions;
316 0           my @params = qw/waitlist_name username nickname comment registration attendance/;
317 0           push @params => map { 'answer_'.$_ } keys @questions;
  0            
318 0           push @params => qw/updated_at receipt_id/;
319              
320 0           my @lines = split /\r\n/, $content;
321 0           my %label; @label{@params} = do {
  0            
322 0           my $header = shift @lines;
323 0           my $success = $csv->parse($header);
324 0 0         die "Invalid CSV syntax: $header" unless $success;
325 0           $csv->fields;
326             };
327              
328 0           my @rows;
329 0           for my $line (@lines) {
330 0           my $success = $csv->parse($line);
331 0 0         die "Invalid CSV syntax: $line" unless $success;
332              
333 0           my %row;
334 0           @row{@params} = $csv->fields;
335 0           push @rows => \%row;
336             }
337              
338 0           return WWW::Connpass::Event::Participants->new(
339             label => \%label,
340             rows => \@rows,
341             );
342             }
343              
344             1;
345             __END__