File Coverage

blib/lib/WebService/Hatena/Fotolife.pm
Criterion Covered Total %
statement 6 6 100.0
branch n/a
condition n/a
subroutine 2 2 100.0
pod n/a
total 8 8 100.0


line stmt bran cond sub pod time code
1             package WebService::Hatena::Fotolife;
2 2     2   996 use 5.008001;
  2         8  
  2         110  
3 2     2   19 use base qw(XML::Atom::Client);
  2         4  
  2         26314  
4              
5             use strict;
6             use warnings;
7             use FileHandle;
8             use Encode qw(encode_utf8 is_utf8);
9             use Image::Info qw(image_info);
10              
11             use WebService::Hatena::Fotolife::Entry;
12              
13             our $VERSION = '0.07';
14             our $PostURI = 'http://f.hatena.ne.jp/atom/post';
15             our $FeedURI = 'http://f.hatena.ne.jp/atom/feed';
16              
17             use constant GEORSS => q;
18              
19             sub new {
20             my $class = shift;
21             my %params = @_;
22             my $headers = delete $params{headers} || [];
23             my $consumer_key = delete $params{consumer_key};
24             my $consumer_secret = delete $params{consumer_secret};
25             my $access_token = delete $params{access_token};
26             my $access_token_secret = delete $params{access_token_secret};
27             my $self = $class->SUPER::new(%params)
28             or return $class->error($class->SUPER::errstr);
29              
30             $self->{consumer_key} = $consumer_key;
31             $self->{consumer_secret} = $consumer_secret;
32             $self->{access_token} = $access_token;
33             $self->{access_token_secret} = $access_token_secret;
34              
35             $self->{headers} = $headers;
36             $self->{ua}->agent(__PACKAGE__."/$VERSION");
37             $self;
38             }
39              
40             sub use_oauth {
41             return defined $_[0]->access_token;
42             }
43              
44             sub consumer_key { $_[0]->{consumer_key} }
45             sub consumer_secret { $_[0]->{consumer_secret} }
46             sub access_token { $_[0]->{access_token} }
47             sub access_token_secret { $_[0]->{access_token_secret} }
48              
49             sub createEntry {
50             my ($self, %param) = @_;
51              
52             return $self->error('title and image source are both required')
53             unless $param{title} || grep {!$_} @param{qw(filename scalarref)};
54              
55             my $image = $self->_get_image($param{filename} || $param{scalarref})
56             or return $self->error($self->errstr);
57             my $entry = $self->_make_entry(create => +{ %param, image => $image });
58              
59             $self->SUPER::createEntry($PostURI, $entry);
60             }
61              
62             sub updateEntry {
63             my ($self, $EditURI, %param) = @_;
64              
65             return $self->error('EditURI and title are both required')
66             unless $EditURI || $param{title};
67              
68             my $entry = $self->_make_entry(update => \%param);
69              
70             $self->SUPER::updateEntry($EditURI, $entry);
71             }
72              
73             sub munge_request {
74             my $self = shift;
75             my $req = shift;
76             my $headers = [@{ $self->{headers} }];
77              
78             if ($self->use_oauth) {
79             require OAuth::Lite::Consumer;
80             require OAuth::Lite::Token;
81             require OAuth::Lite::AuthMethod;
82              
83             my $consumer = OAuth::Lite::Consumer->new(
84             consumer_key => $self->consumer_key,
85             consumer_secret => $self->consumer_secret,
86             auth_method => OAuth::Lite::AuthMethod::URL_QUERY(),
87             );
88             my $access_token = OAuth::Lite::Token->new(
89             token => $self->access_token,
90             secret => $self->access_token_secret,
91             );
92             my $url = $req->uri;
93             $req->uri($url . '?' . $consumer->gen_auth_query($req->method, $url, $access_token, {}));
94             } else {
95             $self->SUPER::munge_request($req);
96             }
97             while (my ($key, $value) = splice @$headers, 0, 2) {
98             $req->header($key => $value);
99             }
100              
101             $req;
102             }
103              
104             sub munge_response {
105             my $self = shift;
106             my $res = shift;
107              
108             my $status = $res->header('Status');
109             if ($status and $status =~ s/^(\d+)\s+(?=.+)//) {
110             $res->code($1);
111             $res->message($status);
112             }
113              
114             $self->SUPER::munge_response($res, @_);
115             }
116              
117             sub getFeed {
118             my $self = shift;
119             $self->SUPER::getFeed($FeedURI);
120             }
121              
122             sub _make_entry {
123             my ($self, $method, $param) = @_;
124             $param ||= {};
125              
126             my $entry = WebService::Hatena::Fotolife::Entry->new;
127             $entry->title($param->{title});
128             $entry->generator($param->{generator}) if defined $param->{generator};
129              
130             if ($method eq 'create') {
131             my $image = $param->{image};
132             $entry->content(${$image->{content}});
133             $entry->content->type($image->{content_type});
134             }
135              
136             if (defined $param->{folder}) {
137             my $dc = XML::Atom::Namespace->new(dc => 'http://purl.org/dc/elements/1.1/');
138             $entry->set($dc, 'subject', $param->{folder});
139             }
140              
141             if (defined $param->{lat} && defined $param->{lon}) {
142             my $georss = XML::Atom::Namespace->new(georss => GEORSS);
143             $entry->set($georss, 'point', $param->{lat} . ' ' . $param->{lon});
144             }
145              
146             if ($param->{hatena} && ref $param->{hatena} eq 'HASH') {
147             my $hatena = XML::Atom::Namespace->new(
148             hatena => 'http://www.hatena.ne.jp/info/xmlns#'
149             );
150              
151             for my $key (keys %{$param->{hatena}}) {
152             $entry->set($hatena, $key, $param->{hatena}{$key});
153             }
154             }
155              
156             $entry;
157             }
158              
159             sub _get_image {
160             my ($self, $image_source) = @_;
161             my $image;
162              
163             if (ref $image_source eq 'SCALAR') {
164             $image = $image_source;
165             }
166             else {
167             $image = do {
168             local $/ = undef;
169             my $fh = FileHandle->new($image_source)
170             or return $self->error("can't open $image_source: $!");
171             my $content = <$fh>;
172             \$content;
173             };
174             }
175              
176             my $info = Image::Info::image_info($image);
177             return $self->error($info->{error})
178             if $info->{error} and $info->{error} !~ /short read/;
179              
180             my $mime = $info->{file_media_type};
181             if (ref $mime eq 'ARRAY') {
182             $mime = $mime->[0];
183             }
184              
185             +{
186             content => $image,
187             content_type => $mime,
188             };
189             }
190              
191             1;
192              
193             __END__