File Coverage

blib/lib/WWW/Formspring.pm
Criterion Covered Total %
statement 1 3 33.3
branch n/a
condition n/a
subroutine 1 1 100.0
pod n/a
total 2 4 50.0


line stmt bran cond sub pod time code
1             package WWW::Formspring;
2              
3             =pod
4              
5             =head1 NAME
6              
7             WWW::Formspring - Perl interface for formspring.me
8              
9             =head1 SYNOPSIS
10              
11             use WWW::Formspring;
12             my $fs = WWW::Formspring->new({
13             access_token => "xxx",
14             access_secret => "yyy",
15             consumer_secret => "aaa",
16             consumer_key => "bbb",
17             username => "johndoe",
18             });
19              
20             $fs->profile_ask("worr2400", "Hey, what's up?");
21              
22             =head1 DESCRIPTION
23              
24             This is a Perl interface for the very beta formspring.me API. This module is subject to breakage as they play with the
25             final spec of their API.
26             Most methods share names with the paths of the API counterparts, making the formspring API documentation on dev.formspring.me
27             just as useful as this documentation.
28              
29             =head2 EXPORT
30              
31             None by default.
32              
33             =cut
34              
35 1     1   369422 use Moose;
  0            
  0            
36             use Moose::Util::TypeConstraints;
37              
38             use 5.010001;
39              
40             require Exporter;
41              
42             use Carp;
43             use LWP::UserAgent;
44             use Net::OAuth;
45             use URI;
46             use XML::Simple;
47              
48             use WWW::Formspring::User;
49             use WWW::Formspring::Question;
50             use WWW::Formspring::Response;
51              
52             $Net::OAuth::PROTOCOL_VERSION = Net::OAuth::PROTOCOL_VERSION_1_0A;
53              
54             our @ISA = qw(Exporter);
55              
56             # Items to export into callers namespace by default. Note: do not export
57             # names by default without a very good reason. Use EXPORT_OK instead.
58             # Do not simply export all your public functions/methods/constants.
59              
60             # This allows declaration use WWW::Formspring ':all';
61             # If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
62             # will save memory.
63             our %EXPORT_TAGS = ( 'all' => [ qw(
64            
65             ) ] );
66              
67             our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
68              
69             our $VERSION = '0.03';
70              
71              
72             # Preloaded methods go here.
73             subtype 'WWW::Formspring::URI' => as class_type('URI');
74              
75             coerce 'WWW::Formspring::URI'
76             => from 'Object'
77             => via { $_->isa('URI') ? $_ :
78             Params::Coerce::coerce('URI', $_); }
79             => from 'Str'
80             => via { URI->new($_) };
81              
82             has 'username' => (is => 'rw', isa => 'Str', predicate => 'has_username');
83             has 'consumer_key' => (is => 'rw', isa => 'Str', predicate => 'has_consumer_key');
84             has 'consumer_secret' => (is => 'rw', isa => 'Str', predicate => 'has_consumer_secret');
85             has 'access_token' => (is => 'rw', isa => 'Str', predicate => 'has_access_token');
86             has 'access_secret' => (is => 'rw', isa => 'Str', predicate => 'has_access_secret');
87             has 'request_url' => (is => 'ro', isa => 'WWW::Formspring::URI', default => 'http://www.formspring.me/oauth/request_token', coerce => 1);
88             has 'auth_url' => (is => 'ro', isa => 'WWW::Formspring::URI', default => 'http://www.formspring.me/oauth/authorize', coerce => 1);
89             has 'access_url' => (is => 'ro', isa => 'WWW::Formspring::URI', default => 'http://www.formspring.me/oauth/access_token', coerce => 1);
90             has 'callback_url' => (is => 'rw', isa => 'Str', default => 'oob');
91             has 'api_url' => (is => 'ro', isa => 'WWW::Formspring::URI', default => 'http://beta-api.formspring.me', coerce => 1);
92             has 'ua' => (is => 'ro',
93             isa => 'LWP::UserAgent',
94             default => sub {
95             LWP::UserAgent->new
96             });
97              
98             =pod
99              
100             =head1 ATTRIBUTES
101              
102             The constructor can take any of these attributes in a hashref, just like normal Moose objects. Read-only attributes that are not
103             for use outside of the module are not described here, and it is not recommended that you change their values on construction.
104              
105             =over
106              
107             =item username
108              
109             Supply a default username. Any method that takes a username may use this username if none is provided. Also used when posting questions
110             non-anonymously.
111              
112             =item consumer_key
113              
114             OAuth consumer key for authentication.
115              
116             =item consumer_secret
117              
118             OAuth consumer secret for authentication. Be sure to keep this safe somewhere.
119              
120             =item access_token
121              
122             OAuth access token for a user after they have successfully authorized your app to access their account.
123              
124             =item access_secret
125              
126             OAuth access token secret for a user after they have successfully authorized your app to access their account. Like the consumer secret,
127             you should try and keep this safe somewhere.
128              
129             =item callback_url
130              
131             URL for OAuth to redirect to in after authorization has occurred. Defaults to 'oob' for desktop apps, which means that no redirection occurs,
132             and that they are provided a pin to manually enter into your application.
133              
134             =back
135              
136             =cut
137              
138             # Shamelessly ripped from http://www.social.com/main/twitter-oauth-using-perl/
139             sub _nonce {
140             my ($self) = @_;
141             my $lower = 999999;
142             my $upper = 2 ** 31;
143            
144             return int(rand($upper - $lower + 1) + $lower);
145             }
146              
147             sub get_request_token {
148             my $self = shift;
149              
150             if (not $self->has_consumer_key or not $self->has_consumer_secret) {
151             croak "Missing consumer_key or consumer_secret";
152             }
153              
154             my $req = Net::OAuth->request("request token")->new(
155             consumer_key => $self->consumer_key,
156             consumer_secret => $self->consumer_secret,
157             request_url => $self->request_url,
158             request_method => 'POST',
159             signature_method => 'HMAC-SHA1',
160             timestamp => time,
161             nonce => $self->_nonce,
162             callback => $self->callback_url,
163             version => '1.0',
164             );
165              
166             $req->sign;
167              
168             my $res = $self->ua->post($req->request_url, Content => $req->to_post_body);
169              
170             if ($res->is_success) {
171             my $response = Net::OAuth->response("request token")->from_post_body($res->content);
172             my $token = $response->token;
173             my $secret = $response->token_secret;
174              
175             return { token => $token, token_secret => $secret };
176             } else {
177             croak "Could not get request tokens";
178             }
179             }
180              
181             =pod
182              
183             =head1 OAUTH AUTHENTICATION
184              
185             WWW::Formspring uses Net::OAuth to handle authentication. It abstracts away some of the messy details, of using formspring's OAuth from the
186             programmer.
187              
188             To outline the process, first you need to get a request token, then redirect the user to the Formspring authorization page. Your app
189             will either get a PIN from the user, or a get a PIN as a parameter to your callback_url. Then, with the request token info and the
190             PIN, you can get access tokens which will allow your app to authenticate as the user again and again. So it would be a good idea
191             to store these somewhere persistent.
192              
193             =head2 Getting a request token
194              
195             NOTE: consumer_key and consumer_secret must be set for this function call to work.
196              
197             my $request_token = $fs->get_request_token
198              
199             =head2 Redirecting the user
200              
201             Redirect the user to formspring authorization page:
202              
203             my $auth_url = $fs->auth_url."?token=".$request_token->{token}."&secret="$request_token->{token_secret}
204              
205             =head2 Getting the access token
206              
207             Depending on the value of callback_url, you will either have to prompt the user for a PIN, or get the pin as a parameter to your
208             callback_url. Pass this in with the request token and secret to get_access_token, and you'll get your access token and secret.
209              
210             $fs->get_access_token($request_token->{token}, $request_token->{token_secret}, $pin)
211              
212             =head1 METHODS
213              
214             =over
215              
216             =item get_request_token
217              
218             Gets a request token from formspring.me as the first step of OAuth authentication. Returns a hashref with keys token and token_secret.
219             consumer_key, consumer_secret, and callback_url must be set before you call this method.
220              
221             =cut
222              
223             sub get_access_token {
224             my ($self, $request_token, $request_token_secret, $oauth_verifier) = @_;
225              
226             croak "Missing request_token" if (not $request_token);
227             croak "Missing request_token_secret" if (not $request_token_secret);
228             croak "Missing oauth_verifier" if (not $oauth_verifier);
229              
230             if (not $self->has_consumer_key or not $self->has_consumer_secret) {
231             croak "Missing consumer_key or consumer_secret";
232             }
233              
234             my $req = Net::OAuth->request("access token")->new(
235             consumer_key => $self->consumer_key,
236             consumer_secret => $self->consumer_secret,
237             token => $request_token,
238             token_secret => $request_token_secret,
239             request_url => $self->access_url,
240             request_method => 'POST',
241             signature_method => 'HMAC-SHA1',
242             timestamp => time,
243             nonce => $self->_nonce,
244             version => '1.0',
245             verifier => $oauth_verifier
246             );
247              
248             $req->sign;
249              
250             my $res = $self->ua->post($req->request_url, Content => $req->to_post_body);
251              
252             if ($res->is_success) {
253             my $response = Net::OAuth->response("access token")->from_post_body($res->content);
254             my $token = $response->token;
255             my $secret = $response->token_secret;
256             return { token => $token, token_secret => $secret };
257             } else {
258             croak $res->code.": ".$res->message;
259             }
260             }
261              
262             =pod
263              
264             =item get_access_token($request_token, $request_token_secret, $verifier)
265              
266             Gets an access token from formspring.me as the last step of OAuth verification. Takes the token and secret from get_request_token, as well
267             as the oauth_verifier that was received as a parameter to your callback URL, or as a PIN from the formspring site.
268              
269             =cut
270              
271             sub _unauth_connect {
272             my ($self, $suffix, $type) = @_;
273             my $params;
274              
275             if ($self->has_access_secret and
276             $self->has_access_token and
277             $self->has_consumer_key and
278             $self->has_consumer_secret) {
279             return $self->_auth_connect(@_[1..@_-1]);
280             }
281              
282             $params = $_[3] if (@_ > 3);
283             my $api_url = $self->api_url;
284              
285             my $req = HTTP::Request->new($type => "$api_url$suffix");
286             $req->headers($params) if ($params);
287              
288             my $res = $self->ua->request($req);
289              
290             croak $res->code.": ".$res->message if ($res->is_error);
291              
292             return $self->_xmlify($res->content);
293             }
294              
295             sub _auth_connect {
296             my ($self, $suffix, $type) = @_;
297             my $params;
298             my $res;
299              
300             $params = $_[3] if (@_ > 3);
301             my $api_url = $self->api_url->as_string;
302              
303             if (not $self->has_consumer_key or not $self->has_consumer_secret) {
304             croak "Missing consumer_key or consumer_secret";
305             }
306              
307             if (not $self->has_access_token or not $self->has_access_secret) {
308             croak "Missing access_token or access_secret";
309             }
310              
311             my $req = Net::OAuth->request("protected resource")->new(
312             consumer_key => $self->consumer_key,
313             consumer_secret => $self->consumer_secret,
314             token => $self->access_token,
315             token_secret => $self->access_secret,
316             request_url => $api_url.$suffix,
317             request_method => $type,
318             signature_method => 'HMAC-SHA1',
319             timestamp => time,
320             nonce => $self->_nonce,
321             version => 1.0,
322             );
323              
324             $req->extra_params($params) if ($params);
325             $req->sign;
326              
327             if ($type eq "POST") {
328             $res = $self->ua->post($req->request_url, Content => $req->to_post_body);
329             } else {
330             $res = $self->ua->get($req->to_url);
331             }
332              
333             croak $res->code.": ".$res->message if (not $res->is_success);
334              
335             return $self->_xmlify($res->content);
336             }
337              
338             sub _xmlify {
339             my ($self, $data) = @_;
340             my ($user, $ret);
341             my $xml = XMLin($data, SuppressEmpty => '', ForceArray => [ 'item' ]);
342              
343             if ($xml->{'item'}) {
344             my @ret_items;
345              
346             foreach my $id (keys %{$xml->{'item'}}) {
347             if ($xml->{'item'}->{$id}->{'asked_by'} ne '') {
348             $user = WWW::Formspring::User->new($xml->{'item'}->{$id}->{'asked_by'});
349             } else {
350             $user = WWW::Formspring::User->new;
351             }
352              
353             $xml->{'item'}->{$id}->{'asked_by'} = $user;
354             $xml->{'item'}->{$id}->{'id'} = $id;
355              
356             my $response = WWW::Formspring::Response->new($xml->{'item'}->{$id});
357             if (defined $xml->{'item'}->{$id}->{'profile'}) {
358             $response->asked_to(WWW::Formspring::User->new($xml->{'item'}->{$id}->{'profile'}));
359             }
360              
361             push @ret_items, $response;
362             }
363              
364             $ret = \@ret_items;
365             } elsif (defined $xml->{'count'}) {
366             $ret = $xml->{'count'};
367             } elsif ($xml->{'profiles'}) {
368             my @results;
369             if ($xml->{'profiles'}->{'profile'}->{'name'}) {
370             return [ WWW::Formspring::User->new($xml->{'profiles'}->{'profile'}) ];
371             }
372             foreach my $name (keys %{$xml->{'profiles'}->{'profile'}}) {
373             $xml->{'profiles'}->{'profile'}->{$name}->{'name'} = $name;
374             $user = WWW::Formspring::User->new($xml->{'profiles'}->{'profile'}->{$name});
375             push @results, $user;
376             }
377              
378             $ret = \@results;
379             } elsif ($xml->{'profile'}) {
380             $ret = WWW::Formspring::User->new($xml->{'profile'});
381              
382             if (not defined $ret->username) {
383             my @results;
384              
385             foreach my $name (keys %{$xml->{'profile'}}) {
386             $xml->{'profile'}->{$name}->{'name'} = $name;
387             $user = WWW::Formspring::User->new($xml->{'profile'}->{$name});
388             push @results, $user;
389             }
390              
391             $ret = \@results;
392             }
393             } elsif ($xml->{'username'}) {
394             $ret = WWW::Formspring::User->new($xml);
395             } elsif ((keys %$xml) == 1) {
396             return 0;
397             }
398              
399             return $ret;
400             }
401              
402             sub answered_count {
403             my $self = shift;
404             my $username = $self->username;
405              
406             $username = shift if (@_);
407              
408             my $count = $self->_unauth_connect("/answered/count/$username.xml", "GET");
409              
410             return $count;
411             }
412              
413             =pod
414              
415             =item answered_count
416              
417             =item answered_count($username)
418              
419             Gets the answer count, as an int, of the provided (or default) username.
420              
421             =cut
422              
423             sub answered_details {
424             my $self = shift;
425             my $id = shift;
426             my $username = $self->username;
427             my $response;
428              
429             $username = shift if (@_);
430              
431             if (ref($id) eq "WWW::Formspring::Response") {
432             $response = $self->_unauth_connect("/answered/details/".$id->asked_to->username."/".$id->id.".xml", "GET");
433             } else {
434             $response = $self->_unauth_connect("/answered/details/$username/$id.xml", "GET");
435             }
436              
437             return $response->[0];
438             }
439              
440             =pod
441              
442             =item answered_details($id)
443              
444             =item answered_details($response)
445              
446             =item answered_details($id, $username)
447              
448             Gets the all of the information you could ever want about a specific question of the id and username provided. Returns a
449             filled out WWW::Formspring::Response object.
450              
451             Can also fill out a user created WWW::Formspring::Response object if at least the asked_to and the id are present.
452              
453             =cut
454              
455             sub answered_list {
456             my $self = shift;
457             my $username = $self->username;
458             my $params = {};
459             my ($response, $user);
460              
461             $username = shift if (@_);
462             $params->{max_id} = shift if (@_);
463             $params->{since_id} = shift if (@_);
464              
465             if (ref($username) eq "WWW::Formspring::User") {
466             $response = $self->_unauth_connect("/answered/list/".$username->username.".xml", "GET", $params);
467             $user = $self->profile_details($username->username);
468             } else {
469             $response = $self->_unauth_connect("/answered/list/$username.xml", "GET", $params);
470             $user = $self->profile_details($username);
471             }
472              
473              
474             $_->asked_to($user) foreach (@$response);
475              
476             return $response;
477             }
478              
479             =pod
480              
481             =item answered_list
482              
483             =item answered_list($user)
484              
485             =item answered_list($username)
486              
487             =item answered_list($username, $max_id)
488              
489             =item answered_list($username, $max_id, $since_id)
490              
491             Gets a list of questions and answers from given (or default) username. Returns an arrayref of WWW::Formspring::Response objects.
492             If max_id parameter is provided, it will get all responses from before the given id. Can also take a WWW::Formspring::User object.
493             If since_id is also set, it will get only posts after the id passed.
494              
495             =cut
496              
497             sub answered_remove {
498             my ($self, $id) = @_;
499             my $response;
500              
501             if (ref($id) eq "WWW::Formspring::Response") {
502             $response = $self->_auth_connect("/answered/remove/".$id->id.".xml", "POST");
503             } else {
504             $response = $self->_auth_connect("/answered/remove/$id.xml", "POST");
505             }
506              
507             return $response;
508             }
509              
510             =pod
511              
512             =item answered_remove($id)
513              
514             =item answered_remove($question)
515              
516             Deletes an answered question from the authenticated user by id and returns it to the inbox. Takes either a numeric question id or a
517             WWW::Formspring::Response object. Returns 0 on success.
518              
519             =cut
520              
521             sub follow_add {
522             my ($self, $username) = @_;
523             my $response;
524              
525             if (ref($username) eq "WWW::Formspring::User") {
526             $response = $self->_auth_connect("/follow/add/".$username->username.".xml", "POST");
527             } else {
528             $response = $self->_auth_connect("/follow/add/$username.xml", "POST");
529             }
530              
531             return $response;
532             }
533              
534             =pod
535              
536             =item follow_add($user)
537              
538             =item follow_add($username)
539              
540             Adds the provided user to the authenticated users followed list. Takes either a string or a WWW::Formspring::User object.
541             Returns a 0 on success.
542              
543             =cut
544              
545             sub follow_answers {
546             my $self = shift;
547             my $params = {};
548              
549             $params->{max_id} = shift if (@_);
550             $params->{since_id} = shift if (@_);
551              
552             my $response = $self->_auth_connect("/follow/answers.xml", "GET", $params);
553             return $response;
554             }
555              
556             =pod
557              
558             =item follow_answers
559              
560             =item follow_answers($max_id)
561              
562             =item follow_answers($max_id, $since_id)
563              
564             Gets all of the questions and answers from the authenticated user's friends. Returns an arrayref of WWW::Formspring::Response objects.
565             If $max_id is provided, then it only fetches questions from before the passed in id. If $since_id is also passed in, it will get only
566             posts after the post of the id specified.
567              
568             =cut
569              
570             sub follow_count {
571             my $self = shift;
572              
573             my $count = $self->_auth_connect("/follow/count.xml", "GET");
574             return $count;
575             }
576              
577             =pod
578              
579             =item follow_count
580              
581             Returns the number of people the authenticated user is following.
582              
583             =cut
584              
585             sub follow_list {
586             my $self = shift;
587             my $params = {};
588              
589             $params->{page} = shift if (@_);
590             my $followees = $self->_auth_connect("/follow/list.xml", "GET", $params);
591             return $followees;
592             }
593              
594             =pod
595              
596             =item follow_list
597              
598             =item follow_list($page)
599              
600             Get list of people the authenticated use is following. If page is provided, get that page of results (100 per page). Else,
601             returns the first page. Returns an arrayref of WWW::Formspring::User objects.
602              
603             =cut
604              
605             sub follow_remove {
606             my ($self, $username) = @_;
607             my $ret;
608              
609             if (ref($username) eq "WWW::Formspring::User") {
610             $ret = $self->_auth_connect("/follow/remove/".$username->username.".xml", "GET");
611             } else {
612             $ret = $self->_auth_connect("/follow/remove/$username.xml", "GET");
613             }
614              
615             return $ret;
616             }
617              
618             =pod
619              
620             =item follow_remove($username)
621              
622             Removes the passed in user from the authenticated user's follower list. Returns 0 on success.
623              
624             =cut
625              
626             sub inbox_block {
627             my ($self, $id) = @_;
628             my $params = {};
629             my $ret;
630              
631             $params->{reason} = $_[2] if (@_ > 2);
632              
633             if (ref($id) eq "WWW::Formspring::Response") {
634             $ret = $self->_auth_connect("/inbox/block/".$id->id.".xml", "POST", $params);
635             } else {
636             $ret = $self->_auth_connect("/inbox/block/$id.xml", "POST", $params);
637             }
638              
639             return $ret;
640             }
641              
642             =pod
643              
644             =item inbox_block($question)
645              
646             =item inbox_block($id)
647              
648             =item inbox_block($id, $reason)
649              
650             Deletes a question from the authenticated user's inbox and blocks the user from asking anymore questions to the authenticated
651             user. A numeric id can be provided as well as a WWW::Formspring::Response. $reason can be either "spam" or "abuse," but does
652             not need to be provided at all. Returns 0 on success.
653              
654             =cut
655              
656             sub inbox_count {
657             my $self = shift;
658              
659             my $ret = $self->_auth_connect("/inbox/count.xml", "GET");
660             return $ret;
661             }
662              
663             =pod
664              
665             =item inbox_count
666              
667             Returns the number of questions in the authenticated user's inbox.
668              
669             =cut
670              
671             sub inbox_list {
672             my $self = shift;
673             my $params = {};
674              
675             $params->{max_id} = $_[1] if (@_ > 1 and $_[1]);
676             $params->{since_id} = $_[2] if (@_ > 2 and $_[2]);
677             my $questions = $self->_auth_connect("/inbox/list.xml", "GET", $params);
678             return $questions;
679             }
680              
681             =pod
682              
683             =item inbox_list
684              
685             =item inbox_list($max_id)
686              
687             =item inbox_list($max_id, $since_id)
688              
689             Returns a list of questions in the authenticated user's inbox. If $max_id is provided, then no questions later than $max_id will be
690             returned. If $since_id is provided, no questions before $since_id will be returned. Either value can be 0 to indicate that you do not
691             wish to use that parameter.
692              
693             Returns an arrayref of WWW::Formspring::Response objects.
694              
695             =cut
696              
697             sub inbox_random {
698             my $self = shift;
699              
700             my $question = $self->_auth_connect("/inbox/random.xml", "GET");
701             return $question;
702             }
703              
704             =pod
705              
706             =item inbox_random
707              
708             Asks the authenticated user a random questions generated by the site. Returns a WWW::Formspring object.
709              
710             =cut
711              
712             sub inbox_remove {
713             my ($self, $id) = @_;
714             my $ret;
715              
716             if (ref($id) eq "WWW::Formspring::Response") {
717             $ret = $self->_auth_connect("/inbox/remove/".$id->id.".xml", "POST");
718             } else {
719             $ret = $self->_auth_connect("/inbox/remove/$id.xml", "POST");
720             }
721              
722             return $ret;
723             }
724              
725             =pod
726              
727             =item inbox_remove($question)
728              
729             =item inbox_remove($id)
730              
731             Removes a question from the authenticated user's inbox. Takes either a numeric id or a WWW::Formspring::Response object. Returns
732             0 on success.
733              
734             =cut
735              
736             # TODO: Add posting to services
737             sub inbox_respond {
738             my $self = shift;
739             my $ret;
740              
741             if (ref $_[0] eq "WWW::Formspring::Response") {
742             my $question = shift;
743             $ret = $self->_auth_connect("/inbox/respond/".$question->id.".xml", "POST", { response => $question->answer });
744             } elsif (@_ >= 2) {
745             my ($id, $response) = @_;
746             $ret = $self->_auth_connect("/inbox/respond/$id.xml", "POST", { response => $response });
747             } else {
748             carp "inbox_respond called with improper arguments";
749             $ret = -1;
750             }
751              
752             return $ret;
753             }
754              
755             =pod
756              
757             =item inbox_respond($question)
758              
759             =item inbox_respond($id, $response)
760              
761             Respond to a question in the authenticated user's inbox. $question must be a WWW::Formspring::Question object, however you can also
762             just provide the id of the question and the user's response. Returns 0 on success.
763              
764             =cut
765              
766             sub profile_ask {
767             my $self = shift;
768             my $ret;
769              
770             if (@_ == 1) {
771             my $quest = shift;
772             $ret = $self->_auth_connect("/profile/ask/".$quest->asked_to->username.".xml", "POST", { question => $quest->question,
773             anonymous => not $quest->has_asked_by });
774             } elsif (@_ == 3) {
775             my ($username, $question, $anonymous) = @_;
776             $ret = $self->_auth_connect("/profile/ask/$username.xml", "POST", { question => $question, anonymous => $anonymous });
777             } else {
778             carp "profile_ask called with improper arguments";
779             $ret = -1;
780             }
781              
782             return $ret;
783             }
784              
785             =pod
786              
787             =item profile_ask($question)
788              
789             =item profile_ask($username, $question, $anonymous)
790              
791             Ask a question to a user. $question must be a WWW::Formspring::Response object. In this case, anonymity is determined by whether or not
792             the WWW::Formspring::Response object contains a valid WWW::Formspring::User object in the asked_by field. The user that the question
793             is directed at goes in the asked_to field as a WWW::Formspring::User object.
794              
795             Alternatively, strings can be provided in the place of objects. $anonymous can be 1 or 0 to represent true or false.
796              
797             =cut
798              
799             sub profile_details {
800             my $self = shift;
801             my ($user, $username);
802              
803             $username = shift if (@_);
804              
805             if (defined $username) {
806             if (ref($username) eq "WWW::Formspring::User") {
807             $user = $self->_unauth_connect("/profile/details/".$username->username.".xml", "GET");
808             } else {
809             $user = $self->_unauth_connect("/profile/details/$username.xml", "GET");
810             }
811             } else {
812             $user = $self->_auth_connect("/profile/details.xml", "GET");
813             }
814              
815             return $user;
816              
817             }
818              
819             =pod
820              
821             =item profile_details
822              
823             =item profile_details($user)
824              
825             =item profile_details($username)
826              
827             Get user details based on passed in username. If no username is provided, then the default username IS NOT used, and the details on the
828             authenticated user is provided instead (as directed by the formspring API). Returns a WWW::Formspring::User object.
829              
830             =cut
831              
832             sub search_profiles {
833             my $self = shift;
834             my $params = { query => shift };
835              
836             $params->{page} = shift if (@_);
837              
838             my $results = $self->_unauth_connect("/search/profiles.xml", "GET", $params);
839             return $results;
840             }
841              
842             =pod
843              
844             =item search_profiles($query)
845              
846             =item search_profiles($query, $page)
847              
848             Searches profiles based on $query. If $page is provided, that page is returned. Returns page 1 by default, 50 results per page.
849             A max of 20 pages will be returned by the search function.
850              
851             =cut
852              
853             __PACKAGE__->meta->make_immutable;
854             1;
855             __END__
856              
857             =pod
858              
859             =back
860              
861             =head1 WWW::Formspring::User
862              
863             This object represents a formspring.me user, and it has the following accessors/mutators
864              
865             =over
866              
867             =item username
868              
869             =item name
870              
871             =item website
872              
873             =item location
874              
875             =item bio
876              
877             =item photo_url
878              
879             =item answered_count
880              
881             =item is_following
882              
883             =back
884              
885             =head1 WWW::Formspring::Question
886              
887             This represents a formspring.me question, and has the following accessors/mutators
888              
889             =over
890              
891             =item id
892              
893             =item question
894              
895             =item time
896              
897             =item asked_by
898              
899             =item asked_to
900              
901             =item ask
902              
903             This asks the user in the ask_to field the question. You can fill out a Question object and just call ask on it and it will submit the question.
904              
905             =back
906              
907             =head1 WWW::Formspring::Response
908              
909             This represents a response to a question, and inherits from WWW::Formspring::Question. Additionally it includes the following
910              
911             =over
912              
913             =item answer
914              
915             =item respond
916              
917             Like the Question object, you can fill out a response object that references a formspring question and a response and then call respond on it to respond to it.
918              
919             =back
920              
921             =head1 SEE ALSO
922              
923             Mention other useful documentation such as the documentation of
924             related modules or operating system documentation (such as man pages
925             in UNIX), or any relevant external documentation such as RFCs or
926             standards.
927              
928             If you have a mailing list set up for your module, mention it here.
929              
930             If you have a web site set up for your module, mention it here.
931              
932             =head1 AUTHOR
933              
934             William Orr, E<lt>will@worrbase.comE<gt>
935              
936             =head1 COPYRIGHT AND LICENSE
937              
938             Copyright (C) 2010 by William Orr
939              
940             This library is free software; you can redistribute it and/or modify
941             it under the same terms as Perl itself, either Perl version 5.10.1 or,
942             at your option, any later version of Perl 5 you may have available.
943              
944              
945             =cut