File Coverage

blib/lib/WWW/Mixi/OO/Session.pm
Criterion Covered Total %
statement 53 206 25.7
branch 3 72 4.1
condition 2 17 11.7
subroutine 17 49 34.6
pod 32 32 100.0
total 107 376 28.4


line stmt bran cond sub pod time code
1             # -*- cperl -*-
2             # copyright (C) 2005 Topia . all rights reserved.
3             # This is free software; you can redistribute it and/or modify it
4             # under the same terms as Perl itself.
5             # $Id: Session.pm 103 2005-02-05 06:07:57Z topia $
6             # $URL: file:///usr/minetools/svnroot/mixi/trunk/WWW-Mixi-OO/lib/WWW/Mixi/OO/Session.pm $
7             package WWW::Mixi::OO::Session;
8 3     3   23574 use strict;
  3         5  
  3         6465  
9 3     3   17 use warnings;
  3         5  
  3         90  
10 3     3   17 use Carp;
  3         5  
  3         291  
11 3     3   2865 use URI;
  3         29123  
  3         98  
12 3     3   2539 use URI::QueryParam;
  3         2326  
  3         81  
13 3     3   22 use File::Basename;
  3         7  
  3         333  
14 3     3   2835 use HTTP::Cookies;
  3         40305  
  3         129  
15 3     3   2788 use HTTP::Request::Common;
  3         75824  
  3         278  
16             #use base qw(LWP::RobotUA);
17 3     3   25 use base qw(LWP::UserAgent);
  3         9  
  3         3687  
18 3     3   94832 use base qw(WWW::Mixi::OO::Util);
  3         8  
  3         2994  
19              
20 3     3   677 use WWW::Mixi::OO;
  3         6  
  3         85  
21 3     3   17 use constant base_class => 'WWW::Mixi::OO';
  3         4  
  3         201  
22 3     3   15 use constant base_uri => 'http://mixi.jp/';
  3         5  
  3         142  
23              
24 3     3   1908 use WWW::Mixi::OO::I18N;
  3         6  
  3         84  
25 3     3   16 use constant i18n_base_class => 'WWW::Mixi::OO::I18N';
  3         40  
  3         327  
26 3     3   12 use constant web_charset => 'euc-jp';
  3         5  
  3         6677  
27              
28             =head1 NAME
29              
30             WWW::Mixi::OO::Session - WWW::Mixi::OO's session class
31              
32             =head1 SYNOPSIS
33              
34             use WWW::Mixi::OO::Session;
35             my $mixi = WWW::Mixi::OO::Session->new(
36             email => 'foo@example.com',
37             password => 'password');
38             $mixi->login;
39             my @friends = $mixi->page('list_friend')->fetch;
40             # ...
41              
42             =head1 DESCRIPTION
43              
44             WWW::Mixi::OO::Session is WWW::Mixi::OO session class.
45              
46              
47             =head1 METHODS
48              
49             =over 4
50              
51             =cut
52              
53             =item new
54              
55             my $mixi = WWW::Mixi::OO::Session->new(
56             email => $email,
57             password => $password,
58             encoding => $encoding,
59             [rewriter => sub { WWW::Mixi::OO::Util->rewrite(shift); }],
60             );
61              
62             WWW::Mixi::OO constructor.
63              
64             =over 4
65              
66             =item email
67              
68             mixi email address.
69              
70             =item password
71              
72             mixi password.
73              
74             =item encoding
75              
76             internal encoding (necessary!)
77              
78             =item rewriter
79              
80             coderef to rewriter, into text
81              
82             =back
83              
84             =cut
85              
86             sub new {
87 0     0 1 0 my ($class, %opt) = @_;
88              
89 0         0 my $base_class = $class->base_class;
90 0         0 (my $name = lc("lib$base_class-perl")) =~ s/::/-/g;
91 0         0 $name .= '/' . $base_class->VERSION;
92 0         0 my $this = $class->SUPER::new(
93             agent => $name,
94             from => 'www-mixi-oo@example.com');
95 0 0       0 $this->delay(1/60) if $this->can('delay');
96 0         0 $this->cookie_jar({});
97              
98             # set private variables
99 0         0 $this->{mixi} = {
100             response => undef,
101             content => undef,
102             cache => undef,
103             rewriter => \&_rewriter_default,
104             timeout => 1,
105             };
106              
107 0         0 foreach (qw(email password rewriter encoding)) {
108 0 0       0 $this->$_($opt{$_}) if exists $opt{$_};
109             }
110              
111             # set default
112 0         0 foreach (qw(UTF-8 EUC-JP)) {
113 0 0       0 last if defined $this->encoding;
114 0 0       0 $this->encoding($_) if $this->i18n_base_class->is_supported($_);
115             }
116              
117 0         0 return $this;
118             }
119              
120             =item email
121              
122             $mixi->email('foo@example.com');
123             my $email = $mixi->email;
124              
125             set/get mixi email address
126              
127             =cut
128              
129             sub email {
130 0     0 1 0 my $this = shift;
131              
132 0 0       0 if (@_ > 0) {
133 0         0 my $value = shift;
134 0         0 $this->{mixi}->{email} = $value;
135 0         0 $this->from($value);
136             }
137 0         0 $this->{mixi}->{email};
138             }
139              
140             =item password
141              
142             $mixi->password('foobar');
143             my $email = $mixi->password;
144              
145             set/get mixi password
146              
147             =cut
148              
149             sub password {
150 0     0 1 0 my $this = shift;
151              
152 0 0       0 if (@_ > 0) {
153 0         0 my $value = shift;
154 0         0 $this->{mixi}->{password} = $value;
155             }
156 0         0 $this->{mixi}->{password};
157             }
158              
159             =item rewriter
160              
161             $mixi->rewriter->('bar');
162              
163             get/set rewriter (into text).
164              
165             =cut
166              
167             sub rewriter {
168 0     0 1 0 my $this = shift;
169              
170 0 0       0 if (@_ > 0) {
171 0         0 my $value = shift;
172 0 0 0     0 if (defined $value and (ref($value) eq 'CODE')) {
173 0         0 $this->{mixi}->{rewriter} = $value;
174             } else {
175 0         0 croak 'please specify valid coderef';
176             }
177             }
178 0         0 $this->{mixi}->{rewriter};
179             }
180              
181             =item encoding
182              
183             $mixi->encoding('euc-jp');
184              
185             get/set internal encoding.
186              
187             see also L.
188              
189             =cut
190              
191             sub encoding {
192 0     0 1 0 my $this = shift;
193              
194 0 0       0 if (@_ > 0) {
195 0         0 my $value = shift;
196 0 0       0 if ($this->i18n_base_class->is_supported($value)) {
197 0         0 $this->{mixi}->{i18n_class} =
198             $this->i18n_base_class->get_processor($value);
199             } else {
200 0         0 croak "not suported internal encoding: $value";
201             }
202             # remove cache
203 0 0       0 if (defined $this->response) {
204 0         0 $this->response($this->response);
205             }
206             }
207 0         0 $this->{mixi}->{i18n_class};
208             }
209              
210             sub _rewriter_default {
211 0     0   0 __PACKAGE__->rewrite(shift);
212             }
213              
214             =item response
215              
216             my $res = $mixi->response;
217              
218             get last response
219              
220             =cut
221              
222             sub response {
223 0     0 1 0 my $this = shift;
224              
225 0 0       0 if (@_ > 0) {
226 0         0 my $value = shift;
227 0         0 $this->{mixi}->{response} = $value;
228 0         0 $this->{mixi}->{content} = $this->convert_from_http_content(
229             $this->web_charset, $value->content);
230 0         0 $this->{mixi}->{cache} = {}; # clear
231             }
232 0         0 $this->{mixi}->{response};
233             }
234              
235             =item content
236              
237             my $data = $mixi->content;
238              
239             get last content
240              
241             =cut
242              
243             sub content {
244 0     0 1 0 my $this = shift;
245              
246 0 0       0 if (defined $this->{mixi}->{content}) {
247 0         0 $this->{mixi}->{content};
248             } else {
249 0         0 undef;
250             }
251             }
252              
253             =item cache
254              
255             # call
256             my $cache = $mixi->cache(ref($this));
257             # or in Page subclass
258             my $cache = $page->cache;
259              
260             get/set cache
261              
262             =cut
263              
264             sub cache {
265 0     0 1 0 my ($this, $page) = @_;
266              
267 0 0       0 if (defined $this->{mixi}->{cache}) {
268 0   0     0 $this->{mixi}->{cache}->{$page} ||= {};
269             } else {
270 0         0 undef;
271             }
272             }
273              
274             =item login
275              
276             $mixi->login
277              
278             login to mixi.
279              
280             =cut
281              
282             sub login {
283 0     0 1 0 my $this = shift;
284              
285 0 0       0 croak 'please set email' unless defined $this->email;
286 0 0       0 croak 'please set password' unless defined $this->password;
287              
288 0         0 my $page = $this->page('login');
289 0         0 $page->do_login;
290 0 0       0 return wantarray ? ($this->session_id, $this->response) : $this->session_id;
291             }
292              
293             =item page
294              
295             $mixi->page($pagename);
296              
297             get page(mixi's class)
298              
299             =cut
300              
301             sub page {
302 0     0 1 0 my ($this, $page) = @_;
303              
304 0         0 my $pkg = $this->page_to_class($page);
305 0         0 eval "require $pkg";
306 0 0       0 if ($@) {
307 0         0 die "$pkg not found or couldn't load: $@";
308             } else {
309 0         0 $pkg->new($this);
310             }
311             }
312              
313             =item page_to_class
314              
315             $mixi->page_to_class($pagename);
316              
317             get classname from pagename
318              
319             =cut
320              
321             sub page_to_class {
322 0     0 1 0 my ($this, $page) = @_;
323              
324 0         0 $page =~ s/(?:^|_)(.)/uc($1)/eg; # titleize
  0         0  
325 0         0 return $this->base_class . '::' . $page;
326             }
327              
328             =item class_to_page
329              
330             $mixi->class_to_page($classname);
331              
332             get pagename from classname
333              
334             =cut
335              
336             sub class_to_page {
337 0     0 1 0 my ($this, $class) = @_;
338              
339 0         0 my $base_class = $this->base_class . '::';
340 0         0 $class =~ s/^\Q$base_class\E//;
341 0         0 $class =~ s/([[:upper:]])/lc("_$1")/eg; # titleize
  0         0  
342 0         0 $class =~ s/^_//; # and remove precedence underbar
343 0         0 return $class;
344             }
345              
346             =item save_cookies
347              
348             $mixi->save_cookies($file);
349              
350             save cookies to file
351              
352             =cut
353              
354             sub save_cookies {
355 0     0 1 0 my $this = shift;
356              
357 0 0       0 croak 'please specify cookie filename to save' if @_ < 1;
358 0         0 my $file = shift;
359              
360 0 0       0 if (!defined $this->cookie_jar) {
361             # cookie disabled
362 0         0 return undef;
363             }
364              
365 0         0 return $this->cookie_jar->save($file);
366             }
367              
368             =item load_cookies
369              
370             $mixi->load_cookies($file);
371              
372             load cookies to file
373              
374             =cut
375              
376             sub load_cookies {
377 0     0 1 0 my $this = shift;
378              
379 0 0       0 croak 'please specify cookie filename to save' if @_ < 1;
380 0         0 my $file = shift;
381              
382 0         0 return $this->cookie_jar(HTTP::Cookies->new({})->load($file));
383             }
384              
385             =item is_logined
386              
387             croak 'please login!' unless $mixi->is_logined;
388              
389             return true if logined
390              
391             =cut
392              
393 0     0 1 0 sub is_logined { shift->session_id }
394              
395             =item is_login_required
396              
397             croak 'please login before this method' if $mixi->is_login_required;
398              
399             return true if login required
400              
401             =cut
402              
403 0     0 1 0 sub is_login_required { !shift->is_logined }
404              
405             =item can_login
406              
407             # call (for example only, check_logined method has this code already)
408             if ($mixi->is_login_required) {
409             if ($mixi->can_login) {
410             $mixi->login;
411             } else {
412             croak "Couldn't login to mixi!";
413             }
414             }
415              
416             return true if we are able to login to mixi
417              
418             =cut
419              
420             sub can_login {
421 0     0 1 0 my $this = shift;
422              
423 0   0     0 return (defined $this->email) && (defined $this->password);
424             }
425              
426             =item check_logined
427              
428             $mixi->check_logined;
429             $mixi->get(...);
430              
431             if didn't login, try login or die.
432              
433             =cut
434              
435             sub check_logined {
436 0     0 1 0 my $this = shift;
437 0 0       0 if ($this->is_login_required) {
438 0 0       0 if ($this->can_login) {
439 0         0 $this->login;
440             } else {
441 0         0 croak "Couldn't login to mixi!";
442             }
443             }
444             }
445              
446             =item session_id
447              
448             my $session_id = $mixi->session_id;
449              
450             return session id
451              
452             =cut
453              
454             sub session_id {
455 0     0 1 0 my $this = shift;
456 0 0       0 return undef unless defined $this->cookie_jar;
457 0         0 my $request = HTTP::Request->new(GET => $this->page('login')->uri);
458 0         0 $this->cookie_jar->add_cookie_header($request);
459 0         0 my $cookie = $request->header('Cookie');
460 0 0 0     0 if (defined $cookie and $cookie =~ /BF_SESSION=(.*?)(;|$)/) {
461 0         0 return $1;
462             } else {
463 0         0 return undef;
464             }
465             }
466              
467             =item set_content
468              
469             $mixi->set_content($uri);
470              
471             set content to specified resource
472              
473             =cut
474              
475             sub set_content {
476 0     0 1 0 my ($this, $uri) = @_;
477 0 0       0 return undef unless defined $uri;
478 0 0       0 return $this->refresh_content if $uri eq 'refresh';
479 0 0       0 if (defined $this->response) {
480 0         0 my $latest_uri = $this->response->request->uri->as_string;
481 0 0 0     0 return 0 if $uri eq $latest_uri and $this->response->is_success;
482 0         0 return $this->get($uri);
483             }
484             }
485              
486             =item refresh_content
487              
488             $mixi->refresh_content;
489              
490             refresh content
491              
492             =cut
493              
494             sub refresh_content {
495 0     0 1 0 my ($this) = @_;
496 0 0       0 if (defined $this->response) {
497 0         0 my $latest_uri = $this->response->request->uri->as_string;
498 0         0 return $this->get($latest_uri);
499             }
500             }
501              
502             =item analyze_uri
503              
504             my @options = $mixi->analyze_uri($uri);
505              
506             analyze URI and return options.
507              
508             =cut
509              
510             sub analyze_uri {
511 0     0 1 0 my ($this, $uri) = @_;
512 0         0 $uri = $this->absolute_uri($uri)->rel($this->base_uri);
513 0         0 my $path = $uri->path;
514 0         0 $path =~ s/\.pl$//;
515 0         0 my $page = eval { $this->page($path) };
  0         0  
516 0 0       0 if (defined $page) {
517 0         0 $page->parse_uri({
518             path => $path,
519             uri => $uri,
520             params => $uri->query_form_hash});
521             } else {
522 0         0 (__warn => "page($path) not found: $@");
523             }
524             }
525              
526             =item relative_uri
527              
528             my $uri = $mixi->relative_uri('http://mixi.jp/login,pl');
529              
530             generate relative URI from mixi.
531              
532             =cut
533              
534             sub relative_uri {
535 0     0 1 0 my ($this, $uri, $base) = @_;
536 0 0       0 $base = $this->base_uri unless defined $base;
537 0         0 $this->SUPER::relative_uri($uri, $base);
538             }
539              
540             =item absolute_uri
541              
542             my $uri = $mixi->absolute_uri('login');
543              
544             generate absolute URI from mixi
545              
546             =cut
547              
548             sub absolute_uri {
549 3     3 1 14169 my ($this, $uri, $base) = @_;
550 3 50       17 $base = $this->base_uri unless defined $base;
551 3 100 66     187 if (defined $uri && basename($uri) !~ /[.?]/) {
552 1         3 $uri .= '.pl';
553             }
554 3         28 $this->SUPER::absolute_uri($uri, $base);
555             }
556              
557             =item absolute_linked_uri
558              
559             my $uri = $mixi->absolute_linked_uri('foo.pl?bar=baz...');
560              
561             generate absolute uri from link(or other relative URIs)
562              
563             =cut
564              
565             sub absolute_linked_uri {
566 0     0 1   my ($this, $uri) = @_;
567 0           my $res = $this->response;
568 0 0         if (defined $res) {
569 0           $this->absolute_uri($uri, $res->request->uri);
570             } else {
571 0           $this->absolute_uri($uri);
572             }
573             }
574              
575             sub simple_request {
576             # wrap simple_request for save response
577 0     0 1   my $this = shift;
578              
579 0           return $this->response($this->SUPER::simple_request(@_));
580             }
581              
582             =item post
583              
584             my $res = $mixi->post('login', foo => bar, baz => qux);
585              
586             http/post to mixi.
587              
588             =cut
589              
590             sub post {
591 0     0 1   my $this = shift;
592 0           my $uri = $this->absolute_uri(shift);
593 0           my @form = @_;
594 0           my $req;
595              
596 0 0         if (grep {ref eq 'ARRAY'} @form) {
  0            
597 0           $req = POST($uri, Content_Type => 'form-data',
598             Content => [@form]);
599             } else {
600 0           $req = POST($uri, [@form]);
601             }
602              
603 0           return $this->request($req);
604             }
605              
606             =item get
607              
608             my $res = $mixi->get('home');
609              
610             http/get to mixi.
611              
612             =cut
613              
614             sub get {
615 0     0 1   my $this = shift;
616 0           my $uri = $this->absolute_uri(shift);
617              
618 0           return $this->request(HTTP::Request->new('GET', $uri));
619             }
620              
621             =back
622              
623             =head1 PROXY METHODS
624              
625             =over 4
626              
627             =item convert_from_http_content
628              
629             =item convert_to_http_content
630              
631             =item convert_login_time
632              
633             =item convert_time
634              
635             see L.
636              
637             =cut
638              
639             foreach (qw(convert_from_http_content convert_to_http_content
640             convert_login_time convert_time)) {
641 0     0 1   eval <<"END";
  0     0 1    
  0     0 1    
  0     0 1    
642             sub $_ \{
643             shift->{mixi}->{i18n_class}->$_(\@_);
644             \}
645             END
646             }
647              
648             1;
649             __END__