line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package WebService::30Boxes::API; |
2
|
|
|
|
|
|
|
|
3
|
1
|
|
|
1
|
|
23738
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
41
|
|
4
|
1
|
|
|
1
|
|
5
|
use Carp qw/croak/; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
1004
|
|
5
|
|
|
|
|
|
|
require WebService::30Boxes::API::Request; |
6
|
|
|
|
|
|
|
require WebService::30Boxes::API::Response; |
7
|
|
|
|
|
|
|
require WebService::30Boxes::API::Event; |
8
|
|
|
|
|
|
|
require WebService::30Boxes::API::Todo; |
9
|
|
|
|
|
|
|
require LWP::UserAgent; |
10
|
|
|
|
|
|
|
require XML::Simple; |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
our $VERSION = '1.05'; |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
sub new { |
15
|
1
|
|
|
1
|
|
14
|
my ($class, %params) = @_; |
16
|
|
|
|
|
|
|
|
17
|
1
|
|
33
|
|
|
8
|
my $self = bless ({}, ref ($class) || $class); |
18
|
1
|
50
|
|
|
|
4
|
unless($params{'api_key'}) { |
19
|
0
|
|
|
|
|
0
|
croak "You need to set your API key before launching a request.\n". |
20
|
|
|
|
|
|
|
"See http://30boxes.com/api/api.php?method=getKeyForUser"; |
21
|
|
|
|
|
|
|
} |
22
|
1
|
|
|
|
|
7
|
$self->{'_apiKey'} = $params{'api_key'}; |
23
|
1
|
|
|
|
|
11
|
$self->{'_ua'} = LWP::UserAgent->new( |
24
|
|
|
|
|
|
|
'agent' => __PACKAGE__."/".$VERSION, |
25
|
|
|
|
|
|
|
); |
26
|
|
|
|
|
|
|
|
27
|
1
|
|
|
|
|
4714
|
return $self; |
28
|
|
|
|
|
|
|
} |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
sub call { |
31
|
0
|
|
|
0
|
|
|
my ($self, $meth, $args) = @_; |
32
|
|
|
|
|
|
|
|
33
|
0
|
0
|
|
|
|
|
croak "No method specified." unless(defined $meth); |
34
|
|
|
|
|
|
|
|
35
|
0
|
|
|
|
|
|
my $req = WebService::30Boxes::API::Request->new($meth, $args); |
36
|
0
|
0
|
|
|
|
|
if(defined $req) { |
37
|
0
|
0
|
|
|
|
|
unless(defined $self->{'_apiKey'}) { |
38
|
|
|
|
|
|
|
} |
39
|
0
|
|
|
|
|
|
$req->{'_api_args'}->{'apiKey'} = $self->{'_apiKey'}; |
40
|
0
|
|
|
|
|
|
$req->encode_args(); |
41
|
0
|
|
|
|
|
|
my $response = $self->_execute($req); |
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
#adjust |
44
|
0
|
0
|
|
|
|
|
if (defined $response->{'_xml'}->{'eventList'}->{'event'}->{'allDayEvent'}){ |
45
|
0
|
|
|
|
|
|
_adjust($response, 'event', 'allDayEvent'); |
46
|
|
|
|
|
|
|
} |
47
|
|
|
|
|
|
|
|
48
|
0
|
0
|
|
|
|
|
if (defined $response->{'_xml'}->{'todoList'}->{'todo'}->{'done'}){ |
49
|
0
|
|
|
|
|
|
_adjust($response, 'todo', 'done'); |
50
|
|
|
|
|
|
|
} |
51
|
|
|
|
|
|
|
|
52
|
0
|
|
|
|
|
|
my $error_msg = $response->{'error_msg'}; |
53
|
0
|
|
|
|
|
|
my $error_code = $response->{'error_code'}; |
54
|
|
|
|
|
|
|
|
55
|
0
|
0
|
|
|
|
|
if ($meth =~ /^events/){ |
|
|
0
|
|
|
|
|
|
56
|
0
|
|
|
|
|
|
return new WebService::30Boxes::API::Event($response, $response->{'success'}, $response->{'error_msg'}, $response->{'error_code'}); |
57
|
|
|
|
|
|
|
} |
58
|
|
|
|
|
|
|
elsif ($meth =~ /^todos/){ |
59
|
0
|
|
|
|
|
|
return new WebService::30Boxes::API::Todo($response, $response->{'success'}, $response->{'error_msg'}, $response->{'error_code'}); |
60
|
|
|
|
|
|
|
} |
61
|
|
|
|
|
|
|
} else { |
62
|
0
|
|
|
|
|
|
return; |
63
|
|
|
|
|
|
|
} |
64
|
|
|
|
|
|
|
} |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
sub _adjust { |
67
|
0
|
|
|
0
|
|
|
my ($response, $method, $identifier) = @_; |
68
|
0
|
|
|
|
|
|
my $eventId = $response->{'_xml'}->{$method . 'List'}->{$method}->{$identifier}; |
69
|
0
|
|
|
|
|
|
my %temp = %{$response->{'_xml'}->{$method . 'List'}->{$method}}; |
|
0
|
|
|
|
|
|
|
70
|
0
|
|
|
|
|
|
delete $response->{'_xml'}->{$method . 'List'}->{$method}; |
71
|
0
|
|
|
|
|
|
$response->{'_xml'}->{$method . 'List'}->{$method}->{$eventId} = \%temp; |
72
|
|
|
|
|
|
|
} |
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
sub request_auth_url { |
75
|
0
|
|
|
0
|
|
|
my ($self, $args) = @_; |
76
|
0
|
|
|
|
|
|
for my $c (qw/applicationName applicationLogoUrl/) { |
77
|
0
|
0
|
|
|
|
|
croak "$c is not defined." unless(defined $args->{$c}); |
78
|
|
|
|
|
|
|
} |
79
|
|
|
|
|
|
|
|
80
|
0
|
|
|
|
|
|
my $req = WebService::30Boxes::API::Request->new('user.Authorize', $args); |
81
|
0
|
|
|
|
|
|
$req->{'_api_args'}->{'apiKey'} = $self->{'_apiKey'}; |
82
|
0
|
|
|
|
|
|
$req->encode_args(); |
83
|
0
|
|
|
|
|
|
return $req->uri .'?'. $req->content; |
84
|
|
|
|
|
|
|
} |
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
sub _execute { |
87
|
0
|
|
|
0
|
|
|
my ($self, $req) = @_; |
88
|
|
|
|
|
|
|
|
89
|
0
|
|
|
|
|
|
my $resp = $self->{'_ua'}->request($req); |
90
|
0
|
|
|
|
|
|
bless $resp, 'WebService::30Boxes::API::Response'; |
91
|
|
|
|
|
|
|
|
92
|
0
|
0
|
|
|
|
|
if($resp->{'_rc'} != 200){ |
93
|
0
|
|
|
|
|
|
$resp->set_error(0, "API returned a non-200 status code ". |
94
|
|
|
|
|
|
|
"($resp->{'_rc'})"); |
95
|
0
|
|
|
|
|
|
return $resp; |
96
|
|
|
|
|
|
|
} |
97
|
|
|
|
|
|
|
|
98
|
0
|
|
|
|
|
|
my $result = $resp->reply(XML::Simple::XMLin($resp->{'_content'}, |
99
|
|
|
|
|
|
|
ForceArray => 0)); |
100
|
0
|
0
|
|
|
|
|
if(!defined $result->{'stat'}) { |
101
|
0
|
|
|
|
|
|
$resp->set_error(0, "API returned an invalid response"); |
102
|
0
|
|
|
|
|
|
return $resp; |
103
|
|
|
|
|
|
|
} |
104
|
|
|
|
|
|
|
|
105
|
0
|
0
|
|
|
|
|
if($result->{'stat'} eq 'fail') { |
106
|
0
|
|
|
|
|
|
$resp->set_error($result->{err}{code}, $result->{err}{msg}); |
107
|
0
|
|
|
|
|
|
return $resp; |
108
|
|
|
|
|
|
|
} |
109
|
|
|
|
|
|
|
|
110
|
0
|
|
|
|
|
|
$resp->set_success(); |
111
|
|
|
|
|
|
|
|
112
|
0
|
|
|
|
|
|
return $resp; |
113
|
|
|
|
|
|
|
} |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
1; |
116
|
|
|
|
|
|
|
#################### main pod documentation begin ################### |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
=head1 NAME |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
WebService::30Boxes::API - Perl interface to the 30 Boxes API |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
=head1 SYNOPSIS |
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
use WebService::30Boxes::API; |
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
#$api_key and $auth_token are defined before |
127
|
|
|
|
|
|
|
my $boxes = WebService::30Boxes::API->new(api_key => $api_key); |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
my $events = $boxes->call('events.Get', {authorizedUserToken => $auth_token}); |
130
|
|
|
|
|
|
|
#my $todos = $boxes->call('todos.Get', {authorizedUserToken => $auth_token}); |
131
|
|
|
|
|
|
|
if($events->{'success'}){ |
132
|
|
|
|
|
|
|
print "List start: " . $events->get_listStart . "\n"; |
133
|
|
|
|
|
|
|
print "List end: " . $events->get_listEnd . "\n"; |
134
|
|
|
|
|
|
|
print "User Id: " . $events->get_userId . "\n\n\n"; |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
#while ($events->nextEventId){ - if you use this, you don't need to specify |
137
|
|
|
|
|
|
|
#$_ as an argument |
138
|
|
|
|
|
|
|
#foreach (@{$events->get_ref_eventIds}){ |
139
|
|
|
|
|
|
|
foreach ($events->get_eventIds){ |
140
|
|
|
|
|
|
|
print "Event id: $_\n"; |
141
|
|
|
|
|
|
|
print "Title: " . $events->get_title($_) . "\n"; |
142
|
|
|
|
|
|
|
print "Repeat end date: " . $events->get_repeatEndDate($_) . "\n"; |
143
|
|
|
|
|
|
|
print "Repeat skip dates: "; |
144
|
|
|
|
|
|
|
foreach ($events->get_repeatSkipDates($_)){print "$_\n";} |
145
|
|
|
|
|
|
|
print "Repeat type: " . $events->get_repeatType($_) . "\n"; |
146
|
|
|
|
|
|
|
print "Repeat interval: " . $events->get_repeatInterval($_) . "\n"; |
147
|
|
|
|
|
|
|
print "Reminder: " . $events->get_reminder($_) . "\n"; |
148
|
|
|
|
|
|
|
print "Tags: "; |
149
|
|
|
|
|
|
|
foreach ($events->get_tags($_)){print "$_\n";} |
150
|
|
|
|
|
|
|
print "Start date: " . $events->get_startDate($_) . "\n"; |
151
|
|
|
|
|
|
|
print "Start time: " . $events->get_startTime($_) . "\n"; |
152
|
|
|
|
|
|
|
print "End date: " . $events->get_endDate($_) . "\n"; |
153
|
|
|
|
|
|
|
print "End time: " . $events->get_endTime($_) . "\n"; |
154
|
|
|
|
|
|
|
print "Is all day event: " . $events->get_isAllDayEvent($_) . "\n"; |
155
|
|
|
|
|
|
|
print "Notes: "; |
156
|
|
|
|
|
|
|
foreach ($events->get_notes($_)){print "$_\n";} |
157
|
|
|
|
|
|
|
print "Privacy: " . $events->get_privacy($_) . "\n\n"; |
158
|
|
|
|
|
|
|
} |
159
|
|
|
|
|
|
|
} |
160
|
|
|
|
|
|
|
else{ |
161
|
|
|
|
|
|
|
print "An error occured (" . $events->{'error_code'} . ": " . |
162
|
|
|
|
|
|
|
$events->{'error_msg'} . ")\n"; |
163
|
|
|
|
|
|
|
} |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
=head1 DESCRIPTION |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
C - Perl interface to the 30 Boxes API |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
=head2 METHODS |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
The following methods can be used |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
=head3 new |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
C create a new C object |
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
=head4 options |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
=over 5 |
180
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
=item api_key |
182
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
The API key is B and this module will croak if you do not set one |
184
|
|
|
|
|
|
|
here. A fresh key can be obtained at L |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
=back |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
=head3 call |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
With this method, you can call one of the available methods as described |
191
|
|
|
|
|
|
|
on L. |
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
C accepts a method name followed by a hashref with the values to |
194
|
|
|
|
|
|
|
pass on to 30Boxes. |
195
|
|
|
|
|
|
|
object. |
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
It returns an object of type WebService::30Boxes::API::Event or WebService::30Boxes::API::Todo (depending |
198
|
|
|
|
|
|
|
which API method was called), which the user can then use to get the desired information. |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
=head3 request_auth_url |
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
Some API methods require authentication (permission by the user). This |
203
|
|
|
|
|
|
|
is done by sending the user to a specific URL where permission can be granted |
204
|
|
|
|
|
|
|
or denied. This method accepts a hashref with these three values: |
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
=over 5 |
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
=item applicationName |
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
(B) applicationName sets the well, application name you want to |
211
|
|
|
|
|
|
|
show to the user. |
212
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
=item applicationLogoUrl |
214
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
(B) The URI to your logo. |
216
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
=item returnUrl |
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
(B) This is where you want the user to return too after permission |
220
|
|
|
|
|
|
|
is granted. |
221
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
=back |
223
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
=head1 SEE ALSO |
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
L, L |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
L |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
L |
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
L |
233
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
30boxes.pl - this is a Perl script you can find on CPAN under Web that can be run in the terminal |
235
|
|
|
|
|
|
|
and it will display the events for a given period of time along with the Todo list. It takes command |
236
|
|
|
|
|
|
|
line arguments that specify how many days/weeks worth of events and how many todos will be displayed. |
237
|
|
|
|
|
|
|
I use it to display events and todos when I open my terminal. Send me an email with bugs or feature requests. |
238
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
=head1 TODO |
240
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
Add more error checking. Compact the code and make it more efficient. Please email me for feature requests. |
242
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
=head1 BUGS |
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
Please email chitoiup@umich.edu with any bugs. |
246
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
=head1 AUTHORS |
248
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
M. Blom (main functionality), |
250
|
|
|
|
|
|
|
Eblom@cpan.orgE, |
251
|
|
|
|
|
|
|
L |
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
Robert Chitoiu (integration with Event and Todo) |
254
|
|
|
|
|
|
|
Echitoiup@umich.eduE |
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
=head1 COPYRIGHT |
257
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
This program is free software; you can redistribute |
259
|
|
|
|
|
|
|
it and/or modify it under the same terms as Perl itself. |
260
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
The full text of the license can be found in the |
262
|
|
|
|
|
|
|
LICENSE file included with this module. |
263
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
=cut |