| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package EVDB::API; | 
| 2 |  |  |  |  |  |  |  | 
| 3 |  |  |  |  |  |  | =head1 NAME | 
| 4 |  |  |  |  |  |  |  | 
| 5 |  |  |  |  |  |  | EVDB::API - Perl interface to EVDB public API | 
| 6 |  |  |  |  |  |  |  | 
| 7 |  |  |  |  |  |  | =head1 SYNOPSIS | 
| 8 |  |  |  |  |  |  |  | 
| 9 |  |  |  |  |  |  | use EVDB::API; | 
| 10 |  |  |  |  |  |  |  | 
| 11 |  |  |  |  |  |  | my $evdb = EVDB::API->new(app_key => $app_key); | 
| 12 |  |  |  |  |  |  |  | 
| 13 |  |  |  |  |  |  | $evdb->login(user => 'harry', password => 'H0gwart$') | 
| 14 |  |  |  |  |  |  | or die "Can't log in: $EVDB::API::errstr"; | 
| 15 |  |  |  |  |  |  |  | 
| 16 |  |  |  |  |  |  | # call() accepts either an array ref or a hash ref. | 
| 17 |  |  |  |  |  |  | my $event = $evdb->call('events/get', {id => 'E0-001-000218163-6'}) | 
| 18 |  |  |  |  |  |  | or die "Can't retrieve event: $EVDB::API::errstr"; | 
| 19 |  |  |  |  |  |  |  | 
| 20 |  |  |  |  |  |  | print "Title: $event->{title}\n"; | 
| 21 |  |  |  |  |  |  |  | 
| 22 |  |  |  |  |  |  | my $venue = $evdb->call('venues/get', [id => $event->{venue_id}]) | 
| 23 |  |  |  |  |  |  | or die "Can't retrieve venue: $EVDB::API::errstr"; | 
| 24 |  |  |  |  |  |  |  | 
| 25 |  |  |  |  |  |  | print "Venue: $venue->{name}\n"; | 
| 26 |  |  |  |  |  |  |  | 
| 27 |  |  |  |  |  |  |  | 
| 28 |  |  |  |  |  |  | =head1 DESCRIPTION | 
| 29 |  |  |  |  |  |  |  | 
| 30 |  |  |  |  |  |  | The EVDB API allows you to build tools and applications that interact with EVDB, the Events & Venues Database.  This module provides a Perl interface to that  API, including the digest-based authentication infrastructure. | 
| 31 |  |  |  |  |  |  |  | 
| 32 |  |  |  |  |  |  | See http://api.evdb.com/ for details. | 
| 33 |  |  |  |  |  |  |  | 
| 34 |  |  |  |  |  |  | =head1 AUTHOR | 
| 35 |  |  |  |  |  |  |  | 
| 36 |  |  |  |  |  |  | Copyright 2006 Eventful, Inc. All rights reserved. | 
| 37 |  |  |  |  |  |  |  | 
| 38 |  |  |  |  |  |  | You may distribute under the terms of either the GNU General Public License or the Artistic License, as specified in the Perl README file. | 
| 39 |  |  |  |  |  |  |  | 
| 40 |  |  |  |  |  |  | =head1 ACKNOWLEDGEMENTS | 
| 41 |  |  |  |  |  |  |  | 
| 42 |  |  |  |  |  |  | Special thanks to Daniel Westermann-Clark for adding support for "flavors" of | 
| 43 |  |  |  |  |  |  | plug-in parsers.  Visit Podbop.org to see other cool things made by Daniel. | 
| 44 |  |  |  |  |  |  |  | 
| 45 |  |  |  |  |  |  | =cut | 
| 46 |  |  |  |  |  |  |  | 
| 47 |  |  |  |  |  |  | require 5.6.0; | 
| 48 |  |  |  |  |  |  |  | 
| 49 | 3 |  |  | 3 |  | 2378 | use strict; | 
|  | 3 |  |  |  |  | 8 |  | 
|  | 3 |  |  |  |  | 101 |  | 
| 50 | 3 |  |  | 3 |  | 17 | use warnings; | 
|  | 3 |  |  |  |  | 6 |  | 
|  | 3 |  |  |  |  | 88 |  | 
| 51 | 3 |  |  | 3 |  | 26 | no warnings qw(uninitialized); | 
|  | 3 |  |  |  |  | 6 |  | 
|  | 3 |  |  |  |  | 111 |  | 
| 52 |  |  |  |  |  |  |  | 
| 53 | 3 |  |  | 3 |  | 35 | use Carp; | 
|  | 3 |  |  |  |  | 6 |  | 
|  | 3 |  |  |  |  | 269 |  | 
| 54 | 3 |  |  | 3 |  | 5676 | use LWP::UserAgent; | 
|  | 3 |  |  |  |  | 228522 |  | 
|  | 3 |  |  |  |  | 91 |  | 
| 55 | 3 |  |  | 3 |  | 4870 | use HTTP::Request::Common; | 
|  | 3 |  |  |  |  | 6195 |  | 
|  | 3 |  |  |  |  | 1454 |  | 
| 56 | 3 |  |  | 3 |  | 17 | use Digest::MD5 qw(md5_hex); | 
|  | 3 |  |  |  |  | 5 |  | 
|  | 3 |  |  |  |  | 146 |  | 
| 57 | 3 |  |  | 3 |  | 2487 | use Module::Pluggable::Object; | 
|  | 3 |  |  |  |  | 28468 |  | 
|  | 3 |  |  |  |  | 5389 |  | 
| 58 |  |  |  |  |  |  |  | 
| 59 |  |  |  |  |  |  | =head1 VERSION | 
| 60 |  |  |  |  |  |  |  | 
| 61 |  |  |  |  |  |  | 0.99 - August 2006 | 
| 62 |  |  |  |  |  |  |  | 
| 63 |  |  |  |  |  |  | =cut | 
| 64 |  |  |  |  |  |  |  | 
| 65 |  |  |  |  |  |  | our $VERSION = 0.99; | 
| 66 |  |  |  |  |  |  |  | 
| 67 |  |  |  |  |  |  | our $VERBOSE = 0; | 
| 68 |  |  |  |  |  |  | our $DEBUG = 0; | 
| 69 |  |  |  |  |  |  |  | 
| 70 |  |  |  |  |  |  | our $default_api_server = 'http://api.evdb.com'; | 
| 71 |  |  |  |  |  |  | our $default_flavor = 'rest'; | 
| 72 |  |  |  |  |  |  |  | 
| 73 |  |  |  |  |  |  | our $errcode; | 
| 74 |  |  |  |  |  |  | our $errstr; | 
| 75 |  |  |  |  |  |  |  | 
| 76 |  |  |  |  |  |  | =head1 CLASS METHODS | 
| 77 |  |  |  |  |  |  |  | 
| 78 |  |  |  |  |  |  | =head2 new | 
| 79 |  |  |  |  |  |  |  | 
| 80 |  |  |  |  |  |  | $evdb = EVDB::API->new(app_key => $app_key); | 
| 81 |  |  |  |  |  |  |  | 
| 82 |  |  |  |  |  |  | Creates a new API object. Requires a valid app_key as provided by EVDB. | 
| 83 |  |  |  |  |  |  |  | 
| 84 |  |  |  |  |  |  | You can also specify an API "flavor", such as C, to use a different format. | 
| 85 |  |  |  |  |  |  |  | 
| 86 |  |  |  |  |  |  | $evdb = EVDB::API->new(app_key => $app_key, flavor => 'yaml'); | 
| 87 |  |  |  |  |  |  |  | 
| 88 |  |  |  |  |  |  | Valid flavors are C, C, and C. | 
| 89 |  |  |  |  |  |  |  | 
| 90 |  |  |  |  |  |  | =cut | 
| 91 |  |  |  |  |  |  |  | 
| 92 |  |  |  |  |  |  | sub new | 
| 93 |  |  |  |  |  |  | { | 
| 94 | 1 |  |  | 1 | 1 | 207 | my $thing = shift; | 
| 95 | 1 |  | 33 |  |  | 9 | my $class = ref($thing) || $thing; | 
| 96 |  |  |  |  |  |  |  | 
| 97 | 1 |  |  |  |  | 5 | my %params = @_; | 
| 98 | 1 |  | 33 |  |  | 19 | my $self = | 
|  |  |  | 33 |  |  |  |  | 
| 99 |  |  |  |  |  |  | { | 
| 100 |  |  |  |  |  |  | 'app_key'     => $params{app_key} || $params{app_token}, | 
| 101 |  |  |  |  |  |  | 'debug'       => $params{debug}, | 
| 102 |  |  |  |  |  |  | 'verbose'     => $params{verbose}, | 
| 103 |  |  |  |  |  |  | 'user_key'    => '', | 
| 104 |  |  |  |  |  |  | 'api_root'    => $params{api_root} || $default_api_server, | 
| 105 |  |  |  |  |  |  | }; | 
| 106 |  |  |  |  |  |  |  | 
| 107 | 1 |  | 33 |  |  | 10 | $DEBUG   ||= $params{debug}; | 
| 108 | 1 |  | 33 |  |  | 7 | $VERBOSE ||= $params{verbose}; | 
| 109 |  |  |  |  |  |  |  | 
| 110 | 1 | 50 |  |  |  | 22 | print "Creating object in class ($class)...\n" if $VERBOSE; | 
| 111 |  |  |  |  |  |  |  | 
| 112 | 1 |  |  |  |  | 3 | bless $self, $class; | 
| 113 |  |  |  |  |  |  |  | 
| 114 | 1 |  | 33 |  |  | 6 | my $flavor = $params{flavor} || $default_flavor; | 
| 115 | 1 |  |  |  |  | 7 | $self->{parser} = $self->_find_parser($flavor); | 
| 116 | 1 | 50 |  |  |  | 8 | croak "No parser found for flavor [$flavor]" | 
| 117 |  |  |  |  |  |  | unless $self->{parser}; | 
| 118 |  |  |  |  |  |  |  | 
| 119 |  |  |  |  |  |  | # Create an LWP user agent for later use. | 
| 120 | 1 |  |  |  |  | 30 | $self->{user_agent} = LWP::UserAgent->new( | 
| 121 |  |  |  |  |  |  | agent => "EVDB_API_Perl_Wrapper/$VERSION-$flavor", | 
| 122 |  |  |  |  |  |  | ); | 
| 123 |  |  |  |  |  |  |  | 
| 124 | 1 |  |  |  |  | 3878 | return $self; | 
| 125 |  |  |  |  |  |  | } | 
| 126 |  |  |  |  |  |  |  | 
| 127 |  |  |  |  |  |  | # Attempt to find a parser for the specified API flavor. | 
| 128 |  |  |  |  |  |  | # Returns the package name if one is found. | 
| 129 |  |  |  |  |  |  | sub _find_parser | 
| 130 |  |  |  |  |  |  | { | 
| 131 | 1 |  |  | 1 |  | 3 | my ($self, $requested_flavor) = @_; | 
| 132 |  |  |  |  |  |  |  | 
| 133 |  |  |  |  |  |  | # Based on Catalyst::Plugin::ConfigLoader | 
| 134 | 1 |  |  |  |  | 12 | my $finder = Module::Pluggable::Object->new( | 
| 135 |  |  |  |  |  |  | search_path => [ __PACKAGE__ ], | 
| 136 |  |  |  |  |  |  | require     => 1, | 
| 137 |  |  |  |  |  |  | ); | 
| 138 |  |  |  |  |  |  |  | 
| 139 | 1 |  |  |  |  | 8 | my $parser; | 
| 140 | 1 |  |  |  |  | 5 | foreach my $plugin ($finder->plugins) { | 
| 141 | 3 |  |  |  |  | 2878 | my $flavor = $plugin->flavor; | 
| 142 | 3 | 100 |  |  |  | 12 | if ($flavor eq $requested_flavor) { | 
| 143 | 1 |  |  |  |  | 3 | $parser = $plugin; | 
| 144 |  |  |  |  |  |  | } | 
| 145 |  |  |  |  |  |  | } | 
| 146 |  |  |  |  |  |  |  | 
| 147 | 1 |  |  |  |  | 28 | return $parser; | 
| 148 |  |  |  |  |  |  | } | 
| 149 |  |  |  |  |  |  |  | 
| 150 |  |  |  |  |  |  |  | 
| 151 |  |  |  |  |  |  | =head1 OBJECT METHODS | 
| 152 |  |  |  |  |  |  |  | 
| 153 |  |  |  |  |  |  | =head2 login | 
| 154 |  |  |  |  |  |  |  | 
| 155 |  |  |  |  |  |  | $evdb->login(user => $username, password => $password); | 
| 156 |  |  |  |  |  |  | $evdb->login(user => $username, password_md5 => $password_md5); | 
| 157 |  |  |  |  |  |  |  | 
| 158 |  |  |  |  |  |  | Retrieves an authentication token from the EVDB API server. | 
| 159 |  |  |  |  |  |  |  | 
| 160 |  |  |  |  |  |  | =cut | 
| 161 |  |  |  |  |  |  |  | 
| 162 |  |  |  |  |  |  | sub login | 
| 163 |  |  |  |  |  |  | { | 
| 164 | 0 |  |  | 0 | 1 | 0 | my $self = shift; | 
| 165 |  |  |  |  |  |  |  | 
| 166 | 0 |  |  |  |  | 0 | my %args = @_; | 
| 167 |  |  |  |  |  |  |  | 
| 168 | 0 |  |  |  |  | 0 | $self->{user} = $args{user}; | 
| 169 |  |  |  |  |  |  |  | 
| 170 |  |  |  |  |  |  | # Call login to receive a nonce. | 
| 171 |  |  |  |  |  |  | # (The nonce is stored in an error structure.) | 
| 172 | 0 |  |  |  |  | 0 | $self->call('users/login'); | 
| 173 | 0 | 0 |  |  |  | 0 | my $nonce = $self->{response_data}{nonce} or return; | 
| 174 |  |  |  |  |  |  |  | 
| 175 |  |  |  |  |  |  | # Generate the digested password response. | 
| 176 | 0 |  | 0 |  |  | 0 | my $password_md5 = $args{password_md5} || md5_hex($args{password}); | 
| 177 | 0 |  |  |  |  | 0 | my $response = md5_hex( $nonce . ":" . $password_md5 ); | 
| 178 |  |  |  |  |  |  |  | 
| 179 |  |  |  |  |  |  | # Send back the nonce and response. | 
| 180 | 0 |  |  |  |  | 0 | my $params = | 
| 181 |  |  |  |  |  |  | { | 
| 182 |  |  |  |  |  |  | nonce => $nonce, | 
| 183 |  |  |  |  |  |  | response => $response, | 
| 184 |  |  |  |  |  |  | }; | 
| 185 |  |  |  |  |  |  |  | 
| 186 | 0 | 0 |  |  |  | 0 | my $r = $self->call('users/login', $params) or return; | 
| 187 |  |  |  |  |  |  |  | 
| 188 |  |  |  |  |  |  | # Store the provided user_key. | 
| 189 | 0 |  | 0 |  |  | 0 | $self->{user_key} = $r->{user_key} || $r->{auth_token}; | 
| 190 |  |  |  |  |  |  |  | 
| 191 | 0 |  |  |  |  | 0 | return 1; | 
| 192 |  |  |  |  |  |  | } | 
| 193 |  |  |  |  |  |  |  | 
| 194 |  |  |  |  |  |  | =head2 call | 
| 195 |  |  |  |  |  |  |  | 
| 196 |  |  |  |  |  |  | $data = $evdb->call($method, \%arguments, [$force_array]); | 
| 197 |  |  |  |  |  |  |  | 
| 198 |  |  |  |  |  |  | Calls the specified method with the given arguments and any previous authentication information (including C).  Returns a hash reference containing the results. | 
| 199 |  |  |  |  |  |  |  | 
| 200 |  |  |  |  |  |  | =cut | 
| 201 |  |  |  |  |  |  |  | 
| 202 |  |  |  |  |  |  | sub call | 
| 203 |  |  |  |  |  |  | { | 
| 204 | 1 |  |  | 1 | 1 | 7 | my $self = shift; | 
| 205 |  |  |  |  |  |  |  | 
| 206 | 1 |  |  |  |  | 3 | my $method = shift; | 
| 207 | 1 |  | 50 |  |  | 4 | my $args = shift || []; | 
| 208 | 1 |  |  |  |  | 1 | my $force_array = shift; | 
| 209 |  |  |  |  |  |  |  | 
| 210 |  |  |  |  |  |  | # Remove any leading slash from the method name. | 
| 211 | 1 |  |  |  |  | 3 | $method =~ s%^/%%; | 
| 212 |  |  |  |  |  |  |  | 
| 213 |  |  |  |  |  |  | # If we have no force_array, see if we have one for this method. | 
| 214 | 1 | 50 | 33 |  |  | 9 | if ($self->{parser}->flavor eq 'rest' and !$force_array) { | 
| 215 |  |  |  |  |  |  |  | 
| 216 |  |  |  |  |  |  | # The following code is automatically generated.  Edit | 
| 217 |  |  |  |  |  |  | #   /main/trunk/evdb/public_api/force_array/force_array.conf | 
| 218 |  |  |  |  |  |  | # and run | 
| 219 |  |  |  |  |  |  | #   /main/trunk/evdb/public_api/force_array/enforcer | 
| 220 |  |  |  |  |  |  | # instead. | 
| 221 |  |  |  |  |  |  | # | 
| 222 |  |  |  |  |  |  | # BEGIN REPLACE | 
| 223 | 1 | 50 |  |  |  | 20 | if($method eq 'calendars/latest/stickers') { | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
| 224 | 0 |  |  |  |  | 0 | $force_array = ['site']; | 
| 225 |  |  |  |  |  |  | } | 
| 226 |  |  |  |  |  |  |  | 
| 227 |  |  |  |  |  |  | elsif($method eq 'calendars/tags/cloud') { | 
| 228 | 0 |  |  |  |  | 0 | $force_array = ['tag']; | 
| 229 |  |  |  |  |  |  | } | 
| 230 |  |  |  |  |  |  |  | 
| 231 |  |  |  |  |  |  | elsif($method eq 'demands/get') { | 
| 232 | 0 |  |  |  |  | 0 | $force_array = ['link', 'comment', 'image', 'tag', 'event', 'member']; | 
| 233 |  |  |  |  |  |  | } | 
| 234 |  |  |  |  |  |  |  | 
| 235 |  |  |  |  |  |  | elsif($method eq 'demands/latest/hottest') { | 
| 236 | 0 |  |  |  |  | 0 | $force_array = ['demand', 'event']; | 
| 237 |  |  |  |  |  |  | } | 
| 238 |  |  |  |  |  |  |  | 
| 239 |  |  |  |  |  |  | elsif($method eq 'demands/search') { | 
| 240 | 0 |  |  |  |  | 0 | $force_array = ['demand', 'event']; | 
| 241 |  |  |  |  |  |  | } | 
| 242 |  |  |  |  |  |  |  | 
| 243 |  |  |  |  |  |  | elsif($method eq 'events/get') { | 
| 244 | 1 |  |  |  |  | 6 | $force_array = ['link', 'comment', 'trackback', 'image', 'parent', 'child', 'tag', 'feed', 'calendar', 'group', 'user', 'relationship', 'performer', 'rrule', 'exrule', 'rdate', 'exdate', 'date', 'category']; | 
| 245 |  |  |  |  |  |  | } | 
| 246 |  |  |  |  |  |  |  | 
| 247 |  |  |  |  |  |  | elsif($method eq 'events/recurrence/list') { | 
| 248 | 0 |  |  |  |  | 0 | $force_array = ['recurrence']; | 
| 249 |  |  |  |  |  |  | } | 
| 250 |  |  |  |  |  |  |  | 
| 251 |  |  |  |  |  |  | elsif($method eq 'events/tags/cloud') { | 
| 252 | 0 |  |  |  |  | 0 | $force_array = ['tag']; | 
| 253 |  |  |  |  |  |  | } | 
| 254 |  |  |  |  |  |  |  | 
| 255 |  |  |  |  |  |  | elsif($method eq 'events/validate/hcal') { | 
| 256 | 0 |  |  |  |  | 0 | $force_array = ['tag', 'event_url', 'venue_url', 'event']; | 
| 257 |  |  |  |  |  |  | } | 
| 258 |  |  |  |  |  |  |  | 
| 259 |  |  |  |  |  |  | elsif($method eq 'groups/get') { | 
| 260 | 0 |  |  |  |  | 0 | $force_array = ['user', 'calendar', 'link', 'comment', 'trackback', 'image', 'tag']; | 
| 261 |  |  |  |  |  |  | } | 
| 262 |  |  |  |  |  |  |  | 
| 263 |  |  |  |  |  |  | elsif($method eq 'groups/search') { | 
| 264 | 0 |  |  |  |  | 0 | $force_array = ['group']; | 
| 265 |  |  |  |  |  |  | } | 
| 266 |  |  |  |  |  |  |  | 
| 267 |  |  |  |  |  |  | elsif($method eq 'groups/users/list') { | 
| 268 | 0 |  |  |  |  | 0 | $force_array = ['user']; | 
| 269 |  |  |  |  |  |  | } | 
| 270 |  |  |  |  |  |  |  | 
| 271 |  |  |  |  |  |  | elsif($method eq 'internal/events/submissions/pending') { | 
| 272 | 0 |  |  |  |  | 0 | $force_array = ['submission']; | 
| 273 |  |  |  |  |  |  | } | 
| 274 |  |  |  |  |  |  |  | 
| 275 |  |  |  |  |  |  | elsif($method eq 'internal/events/submissions/set_status') { | 
| 276 | 0 |  |  |  |  | 0 | $force_array = ['submission']; | 
| 277 |  |  |  |  |  |  | } | 
| 278 |  |  |  |  |  |  |  | 
| 279 |  |  |  |  |  |  | elsif($method eq 'internal/events/submissions/status') { | 
| 280 | 0 |  |  |  |  | 0 | $force_array = ['target']; | 
| 281 |  |  |  |  |  |  | } | 
| 282 |  |  |  |  |  |  |  | 
| 283 |  |  |  |  |  |  | elsif($method eq 'internal/submissions/targets') { | 
| 284 | 0 |  |  |  |  | 0 | $force_array = ['target']; | 
| 285 |  |  |  |  |  |  | } | 
| 286 |  |  |  |  |  |  |  | 
| 287 |  |  |  |  |  |  | elsif($method eq 'performers/demands/list') { | 
| 288 | 0 |  |  |  |  | 0 | $force_array = ['demand']; | 
| 289 |  |  |  |  |  |  | } | 
| 290 |  |  |  |  |  |  |  | 
| 291 |  |  |  |  |  |  | elsif($method eq 'performers/get') { | 
| 292 | 0 |  |  |  |  | 0 | $force_array = ['link', 'comment', 'image', 'tag', 'event', 'demand', 'trackback']; | 
| 293 |  |  |  |  |  |  | } | 
| 294 |  |  |  |  |  |  |  | 
| 295 |  |  |  |  |  |  | elsif($method eq 'performers/search') { | 
| 296 | 0 |  |  |  |  | 0 | $force_array = ['performer']; | 
| 297 |  |  |  |  |  |  | } | 
| 298 |  |  |  |  |  |  |  | 
| 299 |  |  |  |  |  |  | elsif($method eq 'users/calendars/get') { | 
| 300 | 0 |  |  |  |  | 0 | $force_array = ['rule', 'feed']; | 
| 301 |  |  |  |  |  |  | } | 
| 302 |  |  |  |  |  |  |  | 
| 303 |  |  |  |  |  |  | elsif($method eq 'users/calendars/list') { | 
| 304 | 0 |  |  |  |  | 0 | $force_array = ['calendar']; | 
| 305 |  |  |  |  |  |  | } | 
| 306 |  |  |  |  |  |  |  | 
| 307 |  |  |  |  |  |  | elsif($method eq 'users/comments/get') { | 
| 308 | 0 |  |  |  |  | 0 | $force_array = ['comment']; | 
| 309 |  |  |  |  |  |  | } | 
| 310 |  |  |  |  |  |  |  | 
| 311 |  |  |  |  |  |  | elsif($method eq 'users/events/recent') { | 
| 312 | 0 |  |  |  |  | 0 | $force_array = ['event']; | 
| 313 |  |  |  |  |  |  | } | 
| 314 |  |  |  |  |  |  |  | 
| 315 |  |  |  |  |  |  | elsif($method eq 'users/get') { | 
| 316 | 0 |  |  |  |  | 0 | $force_array = ['site', 'im_account', 'event', 'venue', 'performer', 'comment', 'trackback', 'calendar', 'locale', 'link', 'event']; | 
| 317 |  |  |  |  |  |  | } | 
| 318 |  |  |  |  |  |  |  | 
| 319 |  |  |  |  |  |  | elsif($method eq 'users/groups/list') { | 
| 320 | 0 |  |  |  |  | 0 | $force_array = ['group']; | 
| 321 |  |  |  |  |  |  | } | 
| 322 |  |  |  |  |  |  |  | 
| 323 |  |  |  |  |  |  | elsif($method eq 'users/search') { | 
| 324 | 0 |  |  |  |  | 0 | $force_array = ['user']; | 
| 325 |  |  |  |  |  |  | } | 
| 326 |  |  |  |  |  |  |  | 
| 327 |  |  |  |  |  |  | elsif($method eq 'users/venues/get') { | 
| 328 | 0 |  |  |  |  | 0 | $force_array = ['user_venue']; | 
| 329 |  |  |  |  |  |  | } | 
| 330 |  |  |  |  |  |  |  | 
| 331 |  |  |  |  |  |  | elsif($method eq 'venues/get') { | 
| 332 | 0 |  |  |  |  | 0 | $force_array = ['link', 'comment', 'trackback', 'image', 'parent', 'child', 'event', 'tag', 'feed', 'calendar', 'group']; | 
| 333 |  |  |  |  |  |  | } | 
| 334 |  |  |  |  |  |  |  | 
| 335 |  |  |  |  |  |  | elsif($method eq 'venues/tags/cloud') { | 
| 336 | 0 |  |  |  |  | 0 | $force_array = ['tag']; | 
| 337 |  |  |  |  |  |  | } | 
| 338 |  |  |  |  |  |  |  | 
| 339 |  |  |  |  |  |  | else { | 
| 340 | 0 |  |  |  |  | 0 | $force_array = ['event', 'venue', 'comment', 'trackback', 'calendar', 'group', 'user', 'performer', 'member']; | 
| 341 |  |  |  |  |  |  | } | 
| 342 |  |  |  |  |  |  |  | 
| 343 |  |  |  |  |  |  | # END REPLACE | 
| 344 |  |  |  |  |  |  |  | 
| 345 |  |  |  |  |  |  | } | 
| 346 |  |  |  |  |  |  |  | 
| 347 |  |  |  |  |  |  | # Construct the method URL. | 
| 348 | 1 |  |  |  |  | 5 | my $url = join '/', $self->{api_root}, $self->{parser}->flavor, $method; | 
| 349 | 1 | 50 |  |  |  | 23 | print "Calling ($url)...\n" if $VERBOSE; | 
| 350 |  |  |  |  |  |  |  | 
| 351 |  |  |  |  |  |  | # Pre-process the arguments into a hash (for searching) and an array ref | 
| 352 |  |  |  |  |  |  | # (to pass on to HTTP::Request::Common). | 
| 353 | 1 |  |  |  |  | 3 | my $arg_present = {}; | 
| 354 | 1 | 50 |  |  |  | 7 | if (ref($args) eq 'ARRAY') | 
|  |  | 50 |  |  |  |  |  | 
| 355 |  |  |  |  |  |  | { | 
| 356 |  |  |  |  |  |  | # Create a hash of the array values (assumes [foo => 'bar', baz => 1]). | 
| 357 | 0 |  |  |  |  | 0 | my %arg_present = @{$args}; | 
|  | 0 |  |  |  |  | 0 |  | 
| 358 | 0 |  |  |  |  | 0 | $arg_present = \%arg_present; | 
| 359 |  |  |  |  |  |  | } | 
| 360 |  |  |  |  |  |  | elsif (ref($args) eq 'HASH') | 
| 361 |  |  |  |  |  |  | { | 
| 362 |  |  |  |  |  |  | # Migrate the provided hash to an array ref. | 
| 363 | 1 |  |  |  |  | 2 | $arg_present = $args; | 
| 364 | 1 |  |  |  |  | 2 | my @args = %{$args}; | 
|  | 1 |  |  |  |  | 4 |  | 
| 365 | 1 |  |  |  |  | 2 | $args = \@args; | 
| 366 |  |  |  |  |  |  | } | 
| 367 |  |  |  |  |  |  | else | 
| 368 |  |  |  |  |  |  | { | 
| 369 | 0 |  |  |  |  | 0 | $errcode = 'Missing parameter'; | 
| 370 | 0 |  |  |  |  | 0 | $errstr  = 'Missing parameters: The second argument to call() should be an array or hash reference.'; | 
| 371 | 0 |  |  |  |  | 0 | return undef; | 
| 372 |  |  |  |  |  |  | } | 
| 373 |  |  |  |  |  |  |  | 
| 374 |  |  |  |  |  |  | # Add the standard arguments to the list. | 
| 375 | 1 |  |  |  |  | 2 | foreach my $k ('app_key', 'user', 'user_key') | 
| 376 |  |  |  |  |  |  | { | 
| 377 | 3 | 100 | 66 |  |  | 13 | if ($self->{$k} and !$arg_present->{$k}) | 
| 378 |  |  |  |  |  |  | { | 
| 379 | 1 |  |  |  |  | 2 | push @{$args}, $k, $self->{$k}; | 
|  | 1 |  |  |  |  | 3 |  | 
| 380 |  |  |  |  |  |  | } | 
| 381 |  |  |  |  |  |  | } | 
| 382 |  |  |  |  |  |  |  | 
| 383 |  |  |  |  |  |  | # If one of the arguments is a file, set up the Common-friendly | 
| 384 |  |  |  |  |  |  | # file indicator field and set the content-type. | 
| 385 | 1 |  |  |  |  | 2 | my $content_type = ''; | 
| 386 | 1 |  |  |  |  | 2 | foreach my $this_field (keys %{$arg_present}) | 
|  | 1 |  |  |  |  | 2 |  | 
| 387 |  |  |  |  |  |  | { | 
| 388 |  |  |  |  |  |  | # Any argument with a name that ends in "_file" is a file. | 
| 389 | 1 | 50 |  |  |  | 4 | if ($this_field =~ /_file$/) | 
| 390 |  |  |  |  |  |  | { | 
| 391 | 0 |  |  |  |  | 0 | $content_type = 'form-data'; | 
| 392 | 0 | 0 |  |  |  | 0 | next if ref($arg_present->{$this_field}) eq 'ARRAY'; | 
| 393 | 0 |  |  |  |  | 0 | my $file = | 
| 394 |  |  |  |  |  |  | [ | 
| 395 |  |  |  |  |  |  | $arg_present->{$this_field}, | 
| 396 |  |  |  |  |  |  | ]; | 
| 397 |  |  |  |  |  |  |  | 
| 398 |  |  |  |  |  |  | # Replace the original argument with the file indicator. | 
| 399 | 0 |  |  |  |  | 0 | $arg_present->{$this_field} = $file; | 
| 400 | 0 |  |  |  |  | 0 | my $last_arg = scalar(@{$args}) - 1; | 
|  | 0 |  |  |  |  | 0 |  | 
| 401 | 0 |  |  |  |  | 0 | ARG: for my $i (0..$last_arg) | 
| 402 |  |  |  |  |  |  | { | 
| 403 | 0 | 0 |  |  |  | 0 | if ($args->[$i] eq $this_field) | 
| 404 |  |  |  |  |  |  | { | 
| 405 |  |  |  |  |  |  | # If this is the right arg, replace the item after it. | 
| 406 | 0 |  |  |  |  | 0 | splice(@{$args}, $i + 1, 1, $file); | 
|  | 0 |  |  |  |  | 0 |  | 
| 407 | 0 |  |  |  |  | 0 | last ARG; | 
| 408 |  |  |  |  |  |  | } | 
| 409 |  |  |  |  |  |  | } | 
| 410 |  |  |  |  |  |  | } | 
| 411 |  |  |  |  |  |  | } | 
| 412 |  |  |  |  |  |  |  | 
| 413 |  |  |  |  |  |  | # Fetch the data using the POST method. | 
| 414 | 1 |  |  |  |  | 3 | my $ua = $self->{user_agent}; | 
| 415 |  |  |  |  |  |  |  | 
| 416 | 1 |  |  |  |  | 7 | my $response = $ua->request(POST $url, | 
| 417 |  |  |  |  |  |  | 'Content-type' => $content_type, | 
| 418 |  |  |  |  |  |  | 'Content' => $args, | 
| 419 |  |  |  |  |  |  | ); | 
| 420 | 1 | 50 |  |  |  | 466915 | unless ($response->is_success) | 
| 421 |  |  |  |  |  |  | { | 
| 422 | 0 |  |  |  |  | 0 | $errcode = $response->code; | 
| 423 | 0 |  |  |  |  | 0 | $errstr  = $response->code . ': ' . $response->message; | 
| 424 | 0 |  |  |  |  | 0 | return undef; | 
| 425 |  |  |  |  |  |  | } | 
| 426 |  |  |  |  |  |  |  | 
| 427 | 1 |  |  |  |  | 25 | $self->{response_content} = $response->content(); | 
| 428 | 1 |  |  |  |  | 19 | my $data; | 
| 429 |  |  |  |  |  |  |  | 
| 430 | 1 |  |  |  |  | 12 | my $ctype = $self->{parser}->ctype; | 
| 431 | 1 | 50 |  |  |  | 6 | if ($response->header('Content-Type') =~ m/$ctype/i) | 
| 432 |  |  |  |  |  |  | { | 
| 433 |  |  |  |  |  |  | # Parse the response into a Perl data structure. | 
| 434 | 1 | 50 |  |  |  | 63 | if ($self->{parser}->flavor eq 'rest') | 
| 435 |  |  |  |  |  |  | { | 
| 436 |  |  |  |  |  |  | # Maintain backwards compatibility. | 
| 437 | 1 |  |  |  |  | 3 | $self->{response_xml} = $self->{response_content}; | 
| 438 |  |  |  |  |  |  | } | 
| 439 | 1 |  |  |  |  | 6 | $data = $self->{response_data} = $self->{parser}->parse($self->{response_content}, $force_array); | 
| 440 |  |  |  |  |  |  |  | 
| 441 |  |  |  |  |  |  | # Check for errors. | 
| 442 | 0 | 0 |  |  |  |  | if ($data->{string}) | 
| 443 |  |  |  |  |  |  | { | 
| 444 | 0 |  |  |  |  |  | $errcode = $data->{string}; | 
| 445 | 0 |  |  |  |  |  | $errstr  = $data->{string} . ": " .$data->{description}; | 
| 446 | 0 | 0 |  |  |  |  | print "\n", $self->{response_content}, "\n" if $DEBUG; | 
| 447 | 0 |  |  |  |  |  | return undef; | 
| 448 |  |  |  |  |  |  | } | 
| 449 |  |  |  |  |  |  | } | 
| 450 |  |  |  |  |  |  | else | 
| 451 |  |  |  |  |  |  | { | 
| 452 | 0 |  |  |  |  |  | print "Content-type is: ", $response->header('Content-Type'), "\n"; | 
| 453 | 0 |  |  |  |  |  | $data = $self->{response_content}; | 
| 454 |  |  |  |  |  |  | } | 
| 455 |  |  |  |  |  |  |  | 
| 456 | 0 |  |  |  |  |  | return $data; | 
| 457 |  |  |  |  |  |  | } | 
| 458 |  |  |  |  |  |  |  | 
| 459 |  |  |  |  |  |  | # Copied shamelessly from CGI::Minimal. | 
| 460 |  |  |  |  |  |  | sub url_encode | 
| 461 |  |  |  |  |  |  | { | 
| 462 | 0 |  |  | 0 | 0 |  | my $s = shift; | 
| 463 | 0 | 0 |  |  |  |  | return '' unless defined($s); | 
| 464 |  |  |  |  |  |  |  | 
| 465 |  |  |  |  |  |  | # Filter out any URL-unfriendly characters. | 
| 466 | 0 |  |  |  |  |  | $s =~ s/([^-_.a-zA-Z0-9])/"\%".unpack("H",$1).unpack("h",$1)/egs; | 
|  | 0 |  |  |  |  |  |  | 
| 467 |  |  |  |  |  |  |  | 
| 468 | 0 |  |  |  |  |  | return $s; | 
| 469 |  |  |  |  |  |  | } | 
| 470 |  |  |  |  |  |  |  | 
| 471 |  |  |  |  |  |  | 1; | 
| 472 |  |  |  |  |  |  |  | 
| 473 |  |  |  |  |  |  | __END__ |