File Coverage

blib/lib/App/Maisha/Plugin/Twitter.pm
Criterion Covered Total %
statement 16 18 88.8
branch n/a
condition n/a
subroutine 6 6 100.0
pod n/a
total 22 24 91.6


line stmt bran cond sub pod time code
1             package App::Maisha::Plugin::Twitter;
2              
3 5     5   129948 use strict;
  5         14  
  5         539  
4 5     5   29 use warnings;
  5         10  
  5         395  
5              
6             our $VERSION = '0.19';
7              
8             #----------------------------------------------------------------------------
9             # Library Modules
10              
11 5     5   29 use base qw(App::Maisha::Plugin::Base);
  5         13  
  5         3292  
12 5     5   38 use base qw(Class::Accessor::Fast);
  5         10  
  5         1177  
13 5     5   5221 use File::Path;
  5         9  
  5         510  
14 5     5   3844 use Net::Twitter;
  0            
  0            
15             use Storable;
16              
17             #----------------------------------------------------------------------------
18             # Accessors
19              
20             __PACKAGE__->mk_accessors($_) for qw(api users config);
21              
22             #----------------------------------------------------------------------------
23             # Public API
24              
25             #Request token URL
26             #https://api.twitter.com/oauth/request_token
27              
28             #Access token URL
29             #https://api.twitter.com/oauth/access_token
30              
31             #Authorize URL
32             #https://api.twitter.com/oauth/authorize
33              
34             # http://dev.twitter.com/apps/347040
35              
36             sub new {
37             my $class = shift;
38             my $self = {
39             consumer_key => 'ifCuNOQXA5KTnKVXVcZg',
40             consumer_secret => 'OXyHE1PSgfy66gbCu3QshXgP9RNA1fOVLdqv4afPDug',
41             };
42              
43             bless $self, $class;
44             return $self;
45             }
46              
47             sub login {
48             my ($self,$config) = @_;
49             my $api;
50              
51             unless($config->{username}) { warn "No username supplied\n"; return }
52              
53             eval {
54             $api = Net::Twitter->new(
55             traits => [qw/API::Search API::REST OAuth/],
56             consumer_key => $self->{consumer_key},
57             consumer_secret => $self->{consumer_secret},
58             ssl => 1
59             );
60             };
61              
62             unless($api) {
63             warn "Unable to establish connection to Twitter API\n";
64             return 0;
65             }
66              
67             # for testing purposes we don't want to login
68             if(!$config->{test}) {
69             eval {
70             my $datafile = $config->{home} . '/.maisha/twitter.dat';
71             my $access_tokens = eval { retrieve($datafile) } || {};
72              
73             if ( $access_tokens && $access_tokens->{$config->{username}}) {
74             $api->access_token($access_tokens->{$config->{username}}->[0]);
75             $api->access_token_secret($access_tokens->{$config->{username}}->[1]);
76             } else {
77             my $auth_url = $api->get_authorization_url;
78             print " Authorize this application at: $auth_url\nThen, enter the PIN# provided to continue: ";
79              
80             my $pin = <STDIN>; # wait for input
81             chomp $pin;
82              
83             unless($pin) {
84             warn "No PIN provided, Maisha will not be able to access Twitter account until authorized to do so\n";
85             return 0;
86             }
87              
88             # request_access_token stores the tokens in $nt AND returns them
89             my $access_tokens = {};
90             my @access_tokens;
91             eval { @access_tokens = $api->request_access_token(verifier => $pin) };
92             unless(@access_tokens) {
93             warn "Invalid PIN provided, Maisha will not be able to access your Twitter account until authorized to do so\n";
94             return 0;
95             }
96             $access_tokens->{$config->{username}} = \@access_tokens;
97              
98             mkpath( $config->{home} . '/.maisha' );
99              
100             # save the access tokens
101             store $access_tokens, $datafile;
102             chmod 0640, $datafile; # make sure it has reasonable permissions
103             }
104             };
105              
106             if($@) {
107             warn "Unable to login to Twitter\n";
108             return 0;
109             }
110             }
111              
112             $self->api($api);
113             $self->config($config);
114              
115             if(!$config->{test}) {
116             print "...building user cache for Twitter\n";
117             $self->_build_users();
118             }
119              
120             return 1;
121             }
122              
123             sub _build_users {
124             my $self = shift;
125             my %users;
126              
127             eval {
128             my $f = $self->api->friends();
129             if($f && @$f) { for(@$f) { next unless($_); $users{$_->{screen_name}} = 1 } }
130             $f = $self->api->followers();
131             if($f && @$f) { for(@$f) { next unless($_); $users{$_->{screen_name}} = 1 } }
132             };
133              
134             $self->users(\%users);
135             }
136              
137             sub api_reauthorize {
138             my $self = shift;
139             my $config = $self->config;
140             my $api = $self->api;
141              
142             # for testing purposes we don't want to login
143             if(!$config->{test}) {
144             eval {
145             my $datafile = $config->{home} . '/.maisha/twitter.dat';
146              
147             my $auth_url = $api->get_authorization_url;
148             print "Please re-authorize this application at: $auth_url\nThen, enter the PIN# provided to continue: ";
149              
150             my $pin = <STDIN>; # wait for input
151             chomp $pin;
152              
153             unless($pin) {
154             warn "No PIN provided, Maisha will not be able to access direct messages until reauthorization is completed\n";
155             return 0;
156             }
157              
158             # request_access_token stores the tokens in $nt AND returns them
159             my $access_tokens = {};
160             my @access_tokens;
161             eval { @access_tokens = $api->request_access_token(verifier => $pin) };
162             unless(@access_tokens) {
163             warn "Invalid PIN provided, Maisha will not be able to access direct messages until reauthorization is completed\n";
164             return 0;
165             }
166             $access_tokens->{$config->{username}} = \@access_tokens;
167              
168             unlink $datafile;
169             mkpath( $config->{home} . '/.maisha' );
170              
171             # save the access tokens
172             store $access_tokens, $datafile;
173             chmod 0640, $datafile; # make sure it has reasonable permissions
174             };
175              
176             if($@) {
177             warn "Unable to login to Twitter\n";
178             return 0;
179             }
180             }
181              
182             return 1;
183             }
184              
185             sub api_follow {
186             my $self = shift;
187             $self->api->create_friend(@_);
188             }
189              
190             sub api_unfollow {
191             my $self = shift;
192             $self->api->destroy_friend(@_);
193             }
194              
195             sub api_user {
196             my $self = shift;
197             $self->api->show_user(@_);
198             }
199              
200             sub api_user_timeline {
201             my $self = shift;
202             $self->api->user_timeline(@_);
203             }
204              
205             sub api_friends {
206             my $self = shift;
207             $self->api->following(@_);
208             }
209              
210             sub api_friends_timeline {
211             my $self = shift;
212             $self->api->following_timeline(@_);
213             }
214              
215             sub api_public_timeline {
216             my $self = shift;
217             $self->api->public_timeline(@_);
218             }
219              
220             sub api_followers {
221             my $self = shift;
222             $self->api->followers(@_);
223              
224             # below is meant to be the same as the above, but it isn't :(
225             #$self->api->lookup_users( { user_id => $self->api->followers_ids() } );
226             }
227              
228             sub api_update {
229             my $self = shift;
230             $self->api->update(@_);
231             }
232              
233             sub api_replies {
234             my $self = shift;
235             $self->api->replies(@_);
236             }
237              
238             sub api_send_message {
239             my $self = shift;
240             $self->api->new_direct_message(@_);
241             }
242              
243             sub api_direct_messages_to {
244             my $self = shift;
245             $self->api->direct_messages(@_);
246             }
247              
248             sub api_direct_messages_from {
249             my $self = shift;
250             $self->api->sent_direct_messages(@_);
251             }
252              
253             sub api_search {
254             my $self = shift;
255             $self->api->search(@_);
256             }
257              
258             1;
259              
260             __END__
261              
262             =head1 NAME
263              
264             App::Maisha::Plugin::Twitter - Maisha interface to Twitter
265              
266             =head1 SYNOPSIS
267              
268             maisha
269             maisha> use Twitter
270             use ok
271              
272             =head1 DESCRIPTION
273              
274             App::Maisha::Plugin::Twitter is the gateway for Maisha to access the Twitter
275             API.
276              
277             =head1 METHODS
278              
279             =head2 Constructor
280              
281             =over 4
282              
283             =item * new
284              
285             =back
286              
287             =head2 Process Methods
288              
289             =over 4
290              
291             =item * login
292              
293             Login to the service. See Authentication below.
294              
295             =back
296              
297             =head2 API Methods
298              
299             The API methods are used to interface to with the Twitter API.
300              
301             =over 4
302              
303             =item * api_reauthorize
304              
305             =item * api_follow
306              
307             =item * api_unfollow
308              
309             =item * api_user
310              
311             =item * api_user_timeline
312              
313             =item * api_friends
314              
315             =item * api_friends_timeline
316              
317             =item * api_public_timeline
318              
319             =item * api_followers
320              
321             =item * api_update
322              
323             =item * api_replies
324              
325             =item * api_send_message
326              
327             =item * api_direct_messages_to
328              
329             =item * api_direct_messages_from
330              
331             =item * api_search
332              
333             =back
334              
335             =head1 AUTHENTICATION
336              
337             On 31st August 2010, Twitter disabled Basic Authentication to access their API.
338             Instead they have introduce the OAuth method of authrntication, which now
339             requires application developers to request the user to authenticate themselves
340             and provide a PIN (Personal Identification Number) to allow the application to
341             retrieve access tokens.
342              
343             With this new method of authentication, the application will provide a URL,
344             which the user needs to cut-n-paste into a browser to logging in to the
345             service, using your regular username/password, then 'Allow' Maisha to access
346             your account. This will then allow Maisha to post to your account. You will
347             then be given a PIN, which should then be entered at the prompt on the Maisha
348             command line.
349              
350             Once you have completed authentication, the application will then store your
351             access tokens permanently under your profile on your computer. Then when you
352             next use the application it will retrieve these access tokens automatically and
353             you will no longer need to register the application.
354              
355             =head1 SEE ALSO
356              
357             For further information regarding the commands and configuration, please see
358             the 'maisha' script included with this distribution.
359              
360             L<App::Maisha>
361              
362             L<Net::Twitter>
363              
364             =head1 WEBSITES
365              
366             =over 4
367              
368             =item * Main Site: L<http://maisha.grango.org>
369              
370             =item * Git Repo: L<http://github.com/barbie/maisha/tree/master>
371              
372             =item * RT Queue: L<RT: http://rt.cpan.org/Public/Dist/Display.html?Name=App-Maisha>
373              
374             =back
375              
376             =head1 AUTHOR
377              
378             Barbie, <barbie@cpan.org>
379             for Miss Barbell Productions <http://www.missbarbell.co.uk>.
380              
381             =head1 COPYRIGHT AND LICENSE
382              
383             Copyright (C) 2009-2014 by Barbie
384              
385             This distribution is free software; you can redistribute it and/or
386             modify it under the Artistic License v2.
387              
388             =cut