File Coverage

blib/lib/Net/Backpack.pm
Criterion Covered Total %
statement 19 21 90.4
branch n/a
condition n/a
subroutine 7 7 100.0
pod n/a
total 26 28 92.8


line stmt bran cond sub pod time code
1             # $Id: Backpack.pm 29 2008-07-13 10:35:47Z dave $
2              
3             =head1 NAME
4              
5             Net::Backpack - Perl extension for interfacing with Backpack
6              
7             =head1 SYNOPSIS
8              
9             use Net::Backpack;
10              
11             my $bp = Net::Backpack(user => $your_backpack_username,
12             token => $your_backpack_api_token,
13             ssl => $use_ssl);
14              
15             # Fill out a Perl data structure with information about
16             # your Backspace pages.
17             my $pages = $bp->list_all_pages;
18              
19             # Alternatively get the same information in XML format
20             # my $pages = $bp->list_all_pages(xml => 1);
21              
22             # Create a new page
23             my $page = $bp->create_page(title => 'A test page',
24             description => 'Created with the Backpack API');
25              
26             # Get the id of the new page
27             my $page_id = $page->{page}{id};
28              
29             # Get details of the new page (in XML format)
30             my $page_xml = $bp->show_page(id => $page->{page}{id});
31              
32             # Rename the page
33             $bp->update_title(id => $page_id,
34             title => 'A new title');
35              
36             # Change the body
37             $bp->update_description(id => $page_id,
38             description => 'Something new');
39              
40             # Remove the page
41             $bp->destroy_page(id => $page_id);
42              
43             =head1 DESCRIPTION
44              
45             Net::Backpack provides a thin Perl wrapper around the Backpack API
46             (L). Currently it only implements the
47             parts of the API that manipulate Backpack pages. Future releases
48             will increase the coverage.
49              
50             =head2 Getting Started
51              
52             In order to use the Backpack API, you'll need to have a Backpack
53             API token. And in order to get one of those, you'll need a Backpack
54             account. But then again, the API will be pretty useless to you if
55             you don't have a Backpack account to manipulate with it.
56              
57             You can get a Backpack account from L.
58              
59             =head2 Backback API
60              
61             The Backpack API is based on XML over HTTP. You send an XML message
62             over HTTP to the Backpack server and the server sends a response to
63             you which is also in XML. The format of the various XML requests and
64             responses are defined at L.
65              
66             This module removes the need to deal with any XML. You create an
67             object to talk to the Backpack server and call methods on that object
68             to manipulate your Backpage pages. The values returned from Backpack
69             are converted to Perl data structures before being handed back to
70             you (although it is also possible to get back the raw XML).
71              
72             =head1 Important Note
73              
74             Net::Backpack uses XML::Simple to parse the data that is returned from
75             Backpack. From version 1.10 of Net::Backpack has changed. By default we
76             now pass the parameter C 1> to XML::Simple. This will
77             change the Perl data structure returned by most calls.
78              
79             To get the old behaviour back, you can pass the parameter C
80             =E 0> to the C function.
81              
82             =cut
83              
84             package Net::Backpack;
85              
86 1     1   22829 use 5.006;
  1         4  
  1         45  
87 1     1   6 use strict;
  1         2  
  1         39  
88 1     1   5 use warnings;
  1         6  
  1         32  
89              
90 1     1   6 use Carp;
  1         11  
  1         125  
91 1     1   1240 use LWP::UserAgent;
  1         85346  
  1         131  
92 1     1   12 use HTTP::Request;
  1         2  
  1         32  
93 1     1   507 use XML::Simple;
  0            
  0            
94              
95             our $VERSION = '1.14';
96              
97             my %data = (
98             'list_all_pages' =>
99             {
100             url => '/ws/pages/all',
101             req => '
102             [S:token]
103             '
104             },
105             'create_page' =>
106             {
107             url => '/ws/pages/new',
108             req => '
109             [S:token]
110            
111             [P:title]
112             [P:description]
113            
114             '
115             },
116             'show_page' =>
117             {
118             url => '/ws/page/[P:id]',
119             req => '
120             [S:token]
121             '
122             },
123             'destroy_page' =>
124             {
125             url => '/ws/page/[P:id]/destroy',
126             req => '
127             [S:token]
128             '
129             },
130             'update_title' =>
131             {
132             url => '/ws/page/[P:id]/update_title',
133             req => '
134             [S:token]
135             [P:title]
136             '
137             },
138             update_body =>
139             {
140             url => '/ws/page/[P:id]/update_body',
141             req => '
142             [S:token]
143             [P:description]
144             '
145             },
146             'duplicate_page' =>
147             {
148             url => '/ws/page/[P:id]/duplicate',
149             req => '
150             [S:token]
151             '
152             },
153             'link_page' =>
154             {
155             url => '/ws/page/[P:to_page]/link',
156             req => '
157             [S:token]
158             [P:link_page]
159             '
160             },
161             'unlink_page' =>
162             {
163             url => '/ws/page/[P:from_page]/link',
164             req => '
165             [S:token]
166             [P:link_page]
167             '
168             },
169             'share_people' =>
170             {
171             url => '/ws/page/[P:id]/share',
172             req => '
173             [S:token]
174            
175             [P:people]
176            
177             '
178             },
179             'make_page_public' =>
180             {
181             url => '/ws/page/[P:id]/share',
182             req => '
183             [S:token]
184            
185             [P:public]
186            
187             '
188             },
189             'unshare_friend_page' =>
190             {
191             url => '/ws/page/[P:id]/unshare_friend_page',
192             req => '
193             [S:token]
194             '
195             },
196             'email_page' =>
197             {
198             url => '/ws/page/[P:id]/email',
199             req => '
200             [S:token]
201             '
202             },
203             'list_all_items' =>
204             {
205             url => '/ws/page/[P:page_id]/items/list',
206             req => '
207             [S:token]
208             '
209             },
210             'create_item' =>
211             {
212             url => '/ws/page/[P:page_id]/items/add',
213             req => '
214             [S:token]
215            
216             [P:item]
217            
218             '
219             },
220             'update_item' =>
221             {
222             url => '/ws/page/[P:page_id]/items/update/[P:id]',
223             req => '
224             [S:token]
225            
226             [P:item]
227            
228             '
229             },
230             'toggle_item' =>
231             {
232             url => '/ws/page/[P:page_id]/items/toggle/[P:id]',
233             req => '
234             [S:token]
235             '
236             },
237             'destroy_item' =>
238             {
239             url => '/ws/page/[P:page_id]/items/destroy/[P:id]',
240             req => '
241             [S:token]
242             '
243             },
244             'move_item' =>
245             {
246             url => '/ws/page/[P:page_id]/items/move/[P:id]',
247             req => '
248             [S:token]
249             [P:direction]
250             '
251             },
252             'list_all_notes' =>
253             {
254             url => '/ws/page/[P:page_id]/notes/list',
255             req => '
256             [S:token]
257             '
258             },
259             'create_note' =>
260             {
261             url => '/ws/page/[P:page_id]/notes/create',
262             req => '
263             [S:token]
264            
265             [P:title]
266             [P:body]
267            
268             '
269             },
270             'update_note' =>
271             {
272             url => '/ws/page/[P:page_id]/notes/update/[P:id]',
273             req => '
274             [S:token]
275            
276             [P:title]
277             [P:body]
278            
279             '
280             },
281             'destroy_note' =>
282             {
283             url => '/ws/page/[P:page_id]/notes/destroy/[P:id]',
284             req => '
285             [S:token]
286             '
287             },
288             'get_tag_pages' =>
289             {
290             url => '/ws/tags/[P:page_id]',
291             req => '
292             [S:token]
293             '
294             },
295             'set_page_tags' =>
296             {
297             url => '/ws/page/[P:page_id]/tags/tag',
298             req => '
299             [S:token]
300             [P:tags]
301             '
302             },
303             'upcoming_reminders' =>
304             {
305             url => '/ws/reminders',
306             req => '
307             [S:token]
308             '
309             },
310             'create_reminder' =>
311             {
312             url => '/ws/reminders/create',
313             req => '
314             [S:token]
315            
316             [P:content]
317             [P:remind_at]
318            
319             '
320             },
321             'update_reminder' =>
322             {
323             url => '/ws/reminders/update/[P:id]',
324             req => '
325             [S:token]
326            
327             [P:content]
328             [P:remind_at]
329            
330             '
331             },
332             'destroy_reminder' =>
333             {
334             url => '/ws/reminders/destroy/[P:id]',
335             req => '
336             [S:token]
337             '
338             },
339             'list_all_emails' =>
340             {
341             url => '/ws/page/[P:page_id]/emails/list',
342             req => '
343             [S:token]
344             '
345             },
346             'show_email' =>
347             {
348             url => '/ws/page/[P:page_id]/emails/show/[P:id]',
349             req => '
350             [S:token]
351             '
352             },
353             'destroy_email' =>
354             {
355             url => '/ws/page/[P:page_id]/emails/destroy/[P:id]',
356             req => '
357             [S:token]
358             '
359             },
360             'export' =>
361             {
362             url => '/ws/account/export',
363             req => '
364             [S:token]
365             '
366             },
367             'list_all_lists' =>
368             {
369             url => '/ws/page/[P:page_id]/lists/list',
370             req => '
371             [S:token]
372             '
373             },
374             'list_this_list' =>
375             {
376             url => '/ws/page/[P:page_id]/items/list?list_id=[P:list_id]',
377             req => '
378             [S:token]
379             '
380             },
381             'create_list' =>
382             {
383             url => '/ws/page/[P:page_id]/lists/add',
384             req => '
385             [S:token]
386             [P:title]
387             '
388             },
389             'update_list' =>
390             {
391             url => '/ws/page/[P:page_id]/lists/update/[P:list_id]',
392             req => '
393             [S:token]
394            
395             [P:title]
396            
397             '
398             },
399             'destroy_list' =>
400             {
401             url => '/ws/page/[P:page_id]/lists/destroy/[P:list_id]',
402             req => '
403             [S:token]
404             '
405             },
406             'create_list_item' =>
407             {
408             url => '/ws/page/[P:page_id]/items/add?list_id=[P:list_id]',
409             req => '
410             [S:token]
411            
412             [P:item]
413            
414             '
415             },
416             );
417              
418             =head1 METHODS
419              
420             =head2 $bp = Net::Backpack->new(token => $token, user => $user, [forcearray => 0], ssl => 0);
421              
422             Creates a new Net::Backpack object. All communication with the
423             Backpack server is made through this object.
424              
425             Takes two mandatory arguments, your Backpack API token and your
426             Backpack username. Returns the new Net:Backpack object.
427              
428             There is also an optional parameter, forcearray. This controls the
429             value of the C parameter that is used by C. The
430             default value is 1.
431              
432             If the C parameter is provided, then communication will take
433             place over SSL. This is required for Plus and Premium accounts.
434              
435             =cut
436              
437             sub new {
438             my $class = shift;
439             my %params = @_;
440              
441             my $self;
442             $self->{token} = $params{token}
443             || croak "No Backpack API token passed Net::Backpack::new\n";
444             $self->{user} = $params{user}
445             || croak "No Backpack API user passed Net::Backpack::new\n";
446              
447             $self->{protocol} = $params{ssl} ? 'https' : 'http';
448              
449             $self->{forcearray} = $params{forcearray} || 1;
450              
451             $self->{ua} = LWP::UserAgent->new;
452             $self->{ua}->env_proxy;
453             $self->{ua}->default_header('X-POST-DATA-FORMAT' => 'xml');
454              
455             $self->{base_url} = "$self->{protocol}://$self->{user}.backpackit.com";
456              
457             return bless $self, $class;
458             }
459              
460             =head2 $pages = $bp->list_all_pages([xml => 1]);
461              
462             Get a list of all of your Backpack pages. Returns a Perl data structure
463             unless the C parameter is true, in which case it returns the raw
464             XML as returned by the Backpack server.
465              
466             =cut
467              
468             sub list_all_pages {
469             my $self = shift;
470             my %params = @_;
471              
472             my $req_data = $data{list_all_pages};
473             my $url = $self->{base_url} . $req_data->{url};
474              
475             my $req = HTTP::Request->new('POST', $url);
476             $req->content($self->_expand($req_data->{req}, %params));
477              
478             return $self->_call(%params, req => $req);
479             }
480              
481             =head2 $page = $bp->create_page(title => $title,
482             [description => $desc, xml => 1]);
483              
484             Create a new Backpack page with the given title and (optional)
485             description. Returns a Perl data structure unless the C parameter is
486             true, in which case it returns the raw XML as returned by the Backpack server.
487              
488             =cut
489              
490             sub create_page {
491             my $self = shift;
492             my %params = @_;
493              
494             croak 'No title for new page' unless $params{title};
495             $params{description} ||= '';
496              
497             my $req_data = $data{create_page};
498             my $url = $self->{base_url} . $req_data->{url};
499              
500             my $req = HTTP::Request->new(POST => $url);
501             $req->content($self->_expand($req_data->{req}, %params));
502              
503             return $self->_call(%params, req => $req);
504             }
505              
506             =head2 $rc = $bp->show_page(id => $id, [xml => 1]);
507              
508             Get details of the Backpack page with the given id. Returns a Perl data
509             structure unless the C parameter is true, in which case it returns the
510             raw XML as returned by the Backpack server.
511              
512             =cut
513              
514             sub show_page {
515             my $self = shift;
516             my %params = @_;
517              
518             croak 'No id' unless $params{id};
519              
520             my $req_data = $data{show_page};
521             my $url = $self->{base_url} . $self->_expand($req_data->{url}, %params);
522              
523             my $req = HTTP::Request->new(POST => $url);
524              
525             $req->content($self->_expand($req_data->{req}, %params));
526              
527             return $self->_call(%params, req => $req);
528             }
529              
530             =head2 $rc = $bp->destroy_page(id => $id, [xml => 1]);
531              
532             Delete the Backpack page with the given id. Returns a Perl data structure
533             unless the C parameter is true, in which case it returns the raw XML
534             as returned by the Backpack server.
535              
536             =cut
537              
538             sub destroy_page {
539             my $self = shift;
540             my %params = @_;
541              
542             croak 'No id' unless $params{id};
543              
544             my $req_data = $data{destroy_page};
545             my $url = $self->{base_url} . $self->_expand($req_data->{url}, %params);
546              
547             my $req = HTTP::Request->new(POST => $url);
548              
549             $req->content($self->_expand($req_data->{req}, %params));
550              
551             return $self->_call(%params, req => $req);
552             }
553              
554             =head2 $rc = $bp->update_title(id => $id, title => $title, [xml => 1]);
555              
556             Update the title of the given Backpack page. Returns a Perl data structure
557             unless the C parameter is true, in which case it returns the raw XML
558             as returned by the Backpack server.
559              
560             =cut
561              
562             sub update_title {
563             my $self = shift;
564             my %params = @_;
565              
566             croak 'No id' unless $params{id};
567             croak 'No title' unless $params{title};
568              
569             my $req_data = $data{update_title};
570             my $url = $self->{base_url} . $self->_expand($req_data->{url}, %params);
571              
572             my $req = HTTP::Request->new(POST => $url);
573              
574             $req->content($self->_expand($req_data->{req}, %params));
575              
576             return $self->_call(%params, req => $req);
577             }
578              
579             =head2 $rc = $bp->update_body(id => $id, description => $desc, [xml => 1]);
580              
581             Update the description of the given Backpack page. Returns a Perl data
582             structure unless the C parameter is true, in which case it returns the
583             raw XML as returned by the Backpack server.
584              
585             =cut
586              
587             sub update_body {
588             my $self = shift;
589             my %params = @_;
590              
591             croak 'No id' unless $params{id};
592             croak 'No description' unless defined $params{description};
593              
594             my $req_data = $data{update_body};
595             my $url = $self->{base_url} .$self->_expand($req_data->{url}, %params);
596             my $req = HTTP::Request->new(POST => $url);
597              
598             $req->content($self->_expand($req_data->{req}, %params));
599              
600             return $self->_call(%params, req => $req);
601             }
602              
603             =head2 $page = $bp->duplicate_page(id => $id, [xml => 1]);
604              
605             Create a duplicate of the given Backpack page. Returns a Perl data
606             structure unless the C parameter is true, in which case it returns the
607             raw XML as returned by the Backpack server.
608              
609             =cut
610              
611             sub duplicate_page {
612             my $self = shift;
613             my %params = @_;
614              
615             croak 'No id' unless $params{id};
616              
617             my $req_data = $data{duplicate_page};
618             my $url = $self->{base_url} . $self->_expand($req_data->{url}, %params);
619             my $req = HTTP::Request->new(POST => $url);
620              
621             $req->content($self->_expand($req_data->{req}, %params));
622              
623             return $self->_call(%params, req => $req);
624             }
625              
626             =head2 $rc = $bp->link_page(link_page => $id1, to_page => $id2, [xml => 1]);
627              
628             Link one Backpack page to another. Returns a Perl data structure unless the
629             C parameter is true, in which case it returns the raw XML as returned
630             by the Backpack server.
631              
632             =cut
633              
634             sub link_page {
635             my $self = shift;
636             my %params = @_;
637              
638             croak 'No id' unless $params{link_page} and $params{to_page};
639              
640             my $req_data = $data{link_page};
641             my $url = $self->{base_url} . $self->_expand($req_data->{url}, %params);
642             my $req = HTTP::Request->new(POST => $url);
643              
644             $req->content($self->_expand($req_data->{req}, %params));
645              
646             return $self->_call(%params, req => $req);
647             }
648              
649             =head2 $rc = $bp->unlink_page(link_page => $id1, from_page => $id2,
650             [xml => 1]);
651              
652             Unlink one Backpack page from another. Returns a Perl data structure unless
653             the C parameter is true, in which case it returns the raw XML as returned
654             by the Backpack server.
655              
656             =cut
657              
658             sub unlink_page {
659             my $self = shift;
660             my %params = @_;
661              
662             croak 'No id' unless $params{link_page} and $params{from_page};
663              
664             my $req_data = $data{unlink_page};
665             my $url = $self->{base_url} . $self->_expand($req_data->{url}, %params);
666             my $req = HTTP::Request->new(POST => $url);
667              
668             $req->content($self->_expand($req_data->{req}, %params));
669              
670             return $self->_call(%params, req => $req);
671             }
672              
673             =head2 $rc = $bp->share_page(id => $id, people => \@people,
674             [ xml => 1 ]);
675              
676             Share a given Backpack page with a list of other people. The parameter
677             'people' is a list of email addresses of the people you wish to share the
678             page with.
679              
680             =cut
681              
682             sub share_page {
683             my $self = shift;
684             my %params = @_;
685              
686             croak 'No id' unless $params{id};
687             croak 'No people' unless scalar @{$params{people}};
688              
689             $params{people} = join "\n", @{$params{people}};
690             my $req_data = $data{share_people};
691             my $url = $self->{base_url} . $self->_expand($req_data->{url}, %params);
692             my $req = HTTP::Request->new(POST => $url);
693              
694             $req->content($self->_expand($req_data->{req}, %params));
695              
696             return $self->_call(%params, req => $req);
697             }
698              
699             =head2 $rc = $bp->make_page_public(id => $id, public => $public,
700             [ xml => 1 ]);
701              
702             Make a given Backpage page public or private. The parameter 'public' is
703             a boolean flag indicating whether the page should be made public or
704             private
705              
706             =cut
707              
708             sub make_page_public {
709             my $self = shift;
710             my %params = @_;
711              
712             croak 'No id' unless $params{id};
713             croak 'No public flag' unless exists $params{public};
714              
715             $params{public} = !!$params{public};
716             my $req_data = $data{make_page_public};
717             my $url = $self->{base_url} . $self->_expand($req_data->{url}, %params);
718             my $req = HTTP::Request->new(POST => $url);
719              
720             $req->content($self->_expand($req_data->{req}, %params));
721              
722             return $self->_call(%params, req => $req);
723             }
724              
725             =head2 $rc = $bp->unshare_friend_page(id => $id, [ xml => 1 ]);
726              
727             Unshare yourself from a friend's page.
728              
729             =cut
730              
731             sub unshare_friend_page {
732             my $self = shift;
733             my %params = @_;
734              
735             croak 'No id' unless $params{id};
736              
737             my $req_data = $data{unshare_friend_page};
738             my $url = $self->{base_url} . $self->_expand($req_data->{url}, %params);
739             my $req = HTTP::Request->new(POST => $url);
740              
741             $req->content($self->_expand($req_data->{req}, %params));
742              
743             return $self->_call(%params, req => $req);
744             }
745              
746              
747             =head2 $rc = $bp->email_page(id => $id, [ xml => 1 ]);
748              
749             Email a page to yourself.
750              
751             =cut
752              
753             sub email_page {
754             my $self = shift;
755             my %params = @_;
756              
757             croak 'No id' unless $params{id};
758              
759             my $req_data = $data{email_page};
760             my $url = $self->{base_url} . $self->_expand($req_data->{url}, %params);
761             my $req = HTTP::Request->new(POST => $url);
762              
763             $req->content($self->_expand($req_data->{req}, %params));
764              
765             return $self->_call(%params, req => $req);
766             }
767              
768             =head2 $items = $bp->list_all_items(page_id => $page_id, [xml => 1]);
769              
770             Get a list of all of your Backpack checklist items. Returns a Perl data structure
771             unless the C parameter is true, in which case it returns the raw
772             XML as returned by the Backpack server.
773              
774             =cut
775              
776             sub list_all_items {
777             my $self = shift;
778             my %params = @_;
779              
780             croak 'No id' unless $params{page_id};
781            
782             my $req_data = $data{list_all_items};
783             my $url = $self->{base_url} . $self->_expand($req_data->{url}, %params);
784              
785             my $req = HTTP::Request->new('POST', $url);
786             $req->content($self->_expand($req_data->{req}, %params));
787              
788             return $self->_call(%params, req => $req);
789             }
790              
791             =head2 $item = $bp->create_item(page_id => $page_id, item => $item, [xml => 1]);
792              
793             Create a Backpack checklist item given a page id and some item content.
794             Returns a Perl data structure unless the C parameter is true, in which case
795             it returns the raw XML as returned by the Backpack server.
796              
797             =cut
798              
799             sub create_item {
800             my $self = shift;
801             my %params = @_;
802              
803             croak 'No page id' unless $params{page_id};
804             croak 'No item content' unless $params{item};
805              
806             my $req_data = $data{create_item};
807             my $url = $self->{base_url} . $self->_expand($req_data->{url}, %params);
808              
809             my $req = HTTP::Request->new('POST', $url);
810             $req->content($self->_expand($req_data->{req}, %params));
811              
812             return $self->_call(%params, req => $req);
813             }
814              
815             =head2 $item = $bp->update_item(page_id => $page_id, item => $item, [xml => 1]
816             id => $item_id);
817              
818             Updates a Backpack checklist item given a page id, item id, and new content.
819             Returns a Perl data structure unless the C parameter is true, in which
820             case it returns the raw XML as returned by the Backpack server.
821              
822             =cut
823              
824             sub update_item {
825             my $self = shift;
826             my %params = @_;
827              
828             croak 'No page id' unless $params{page_id};
829             croak 'No item id' unless $params{id};
830             croak 'No item content' unless $params{item};
831              
832             my $req_data = $data{update_item};
833             my $url = $self->{base_url} . $self->_expand($req_data->{url}, %params);
834              
835             my $req = HTTP::Request->new('POST', $url);
836             $req->content($self->_expand($req_data->{req}, %params));
837              
838             return $self->_call(%params, req => $req);
839             }
840              
841             =head2 $response = $bp->toggle_item(page_id => $page_id, id => $item_id,
842             [xml => 1]);
843              
844             Toggles a Backpack checklist item given a page id and an item id.
845             Returns a Perl data structure unless the C parameter is true, in which
846             case it returns the raw XML as returned by the Backpack server.
847              
848             =cut
849              
850             sub toggle_item {
851             my $self = shift;
852             my %params = @_;
853              
854             croak 'No page id' unless $params{page_id};
855             croak 'No item id' unless $params{id};
856              
857             my $req_data = $data{toggle_item};
858             my $url = $self->{base_url} . $self->_expand($req_data->{url}, %params);
859              
860             my $req = HTTP::Request->new('POST', $url);
861             $req->content($self->_expand($req_data->{req}, %params));
862              
863             return $self->_call(%params, req => $req);
864             }
865              
866             =head2 $response = $bp->destroy_item(page_id => $page_id, id => $item_id,
867             [xml => 1]);
868              
869             Destroys a Backpack checklist item given a page id and an item id.
870             Returns a Perl data structure unless the C parameter is true, in which
871             case it returns the raw XML as returned by the Backpack server.
872              
873             =cut
874              
875             sub destroy_item {
876             my $self = shift;
877             my %params = @_;
878              
879             croak 'No page id' unless $params{page_id};
880             croak 'No item id' unless $params{id};
881              
882             my $req_data = $data{destroy_item};
883             my $url = $self->{base_url} . $self->_expand($req_data->{url}, %params);
884              
885             my $req = HTTP::Request->new('POST', $url);
886             $req->content($self->_expand($req_data->{req}, %params));
887              
888             return $self->_call(%params, req => $req);
889             }
890              
891             =head2 $response = $bp->move_item(page_id => $page_id, id => $item_id,
892             direction => $direction, [xml => 1]);
893              
894             Modifies the location in the list of a Backpack checklist item. Requires a
895             page id, a direction and an item id. Valid values for direction are
896             "move_lower", "move_higher", "move_to_top", and "move_to_bottom". Returns a
897             Perl data structure unless the C parameter is true, in which case it
898             returns the raw XML as returned by the Backpack server.
899              
900             =cut
901              
902             sub move_item {
903             my $self = shift;
904             my %params = @_;
905              
906             croak 'No page id' unless $params{page_id};
907             croak 'No item id' unless $params{id};
908             unless (exists $params{direction} &&
909             $params{direction} =~ /move_(lower|higher|to_top|to_bottom)/) {
910             croak 'No direction specified';
911             }
912              
913             my $req_data = $data{move_item};
914             my $url = $self->{base_url} . $self->_expand($req_data->{url}, %params);
915             #print "url : $url\n";
916             #sleep 2;
917             my $req = HTTP::Request->new('POST', $url);
918             $req->content($self->_expand($req_data->{req}, %params));
919              
920             return $self->_call(%params, req => $req);
921             }
922              
923             =head2 $notes = $bp->list_all_notes(page_id => $page_id, [xml => 1]);
924              
925             Get a list of all of your Backpack notes. Returns a Perl data structure
926             unless the C parameter is true, in which case it returns the raw
927             XML as returned by the Backpack server.
928              
929             =cut
930              
931             sub list_all_notes {
932             my $self = shift;
933             my %params = @_;
934              
935             croak 'No id' unless $params{page_id};
936            
937             my $req_data = $data{list_all_notes};
938             my $url = $self->{base_url} . $self->_expand($req_data->{url}, %params);
939              
940             my $req = HTTP::Request->new('POST', $url);
941             $req->content($self->_expand($req_data->{req}, %params));
942              
943             return $self->_call(%params, req => $req);
944             }
945              
946             =head2 $note = $bp->create_note(page_id => $page_id, title => $title,
947             body => $body, [xml => 1]);
948              
949             Create a Backpack note given a page id and some content. Title is required,
950             body is optional. Returns a Perl data structure unless the C parameter
951             is true, in which case it returns the raw XML as returned by the Backpack
952             server.
953              
954             =cut
955              
956             sub create_note {
957             my $self = shift;
958             my %params = @_;
959              
960             croak 'No page id' unless $params{page_id};
961             croak 'No note title' unless $params{title};
962              
963             $params{body} ||= "";
964            
965             my $req_data = $data{create_note};
966             my $url = $self->{base_url} . $self->_expand($req_data->{url}, %params);
967              
968             print "url: $url\n";
969              
970             my $req = HTTP::Request->new('POST', $url);
971             $req->content($self->_expand($req_data->{req}, %params));
972              
973             return $self->_call(%params, req => $req);
974             }
975              
976             =head2 $note = $bp->update_note(page_id => $page_id, id => $note_id, [xml => 1]
977             title => $title, body => $body);
978              
979             Updates a Backpack note given a page id, note id, and new content.
980             Returns a Perl data structure unless the C parameter is true, in which
981             case it returns the raw XML as returned by the Backpack server.
982              
983             =cut
984              
985             sub update_note {
986             my $self = shift;
987             my %params = @_;
988              
989             croak 'No page id' unless $params{page_id};
990             croak 'No note id' unless $params{id};
991              
992             $params{title} ||= "";
993             $params{body} ||= "";
994            
995             my $req_data = $data{update_note};
996             my $url = $self->{base_url} . $self->_expand($req_data->{url}, %params);
997              
998             my $req = HTTP::Request->new('POST', $url);
999             $req->content($self->_expand($req_data->{req}, %params));
1000              
1001             return $self->_call(%params, req => $req);
1002             }
1003              
1004             =head2 $response = $bp->destroy_note(page_id => $page_id, id => $note_id,
1005             [xml => 1]);
1006              
1007             Destroys a Backpack note given a page id and an note id.
1008             Returns a Perl data structure unless the C parameter is true, in which
1009             case it returns the raw XML as returned by the Backpack server.
1010              
1011             =cut
1012              
1013             sub destroy_note {
1014             my $self = shift;
1015             my %params = @_;
1016              
1017             croak 'No page id' unless $params{page_id};
1018             croak 'No note id' unless $params{id};
1019              
1020             my $req_data = $data{destroy_note};
1021             my $url = $self->{base_url} . $self->_expand($req_data->{url}, %params);
1022              
1023             my $req = HTTP::Request->new('POST', $url);
1024             $req->content($self->_expand($req_data->{req}, %params));
1025              
1026             return $self->_call(%params, req => $req);
1027             }
1028              
1029             =head2 $pages = $bp->get_tag_pages(page_id => $id, [ xml => 1 ]);
1030              
1031             Retrieve all the pages associated with a particular tag id. Returns a Perl
1032             data structure unless the C parameter is true, in which case it returns
1033             the raw XML as returned by the Backpack server.
1034              
1035             =cut
1036              
1037             sub get_tag_pages {
1038             my $self = shift;
1039             my %params = @_;
1040              
1041             croak 'No page id' unless $params{page_id};
1042            
1043             my $req_data = $data{get_tag_pages};
1044             my $url = $self->{base_url} . $self->_expand($req_data->{url}, %params);
1045             my $req = HTTP::Request->new(POST => $url);
1046              
1047             $req->content($self->_expand($req_data->{req}, %params));
1048              
1049             return $self->_call(%params, req => $req);
1050             }
1051              
1052             =head2 $response = $bp->set_page_tags(page_id => $id, tags => \@tags,
1053             [ xml => 1 ]);
1054              
1055             Set the tags for a given Backpack page. This method overwrites all tags for
1056             the page. An empty set of tags serves to remove all the tags for the page.
1057             Returns a Perl data structure unless the C parameter is true, in which
1058             case it returns the raw XML as returned by the Backpack server.
1059              
1060             This is currently returning true, and though it seems to create and submit a
1061             valid request, the tags are not being updated.
1062              
1063             =cut
1064              
1065             sub set_page_tags {
1066             my $self = shift;
1067             my %params = @_;
1068              
1069             croak 'No page id' unless $params{page_id};
1070              
1071             $params{tags} = join "\n", map { '"'.$_.'"' } @{$params{tags}};
1072             my $req_data = $data{set_page_tags};
1073              
1074             my $url = $self->{base_url} . $self->_expand($req_data->{url}, %params);
1075              
1076             # print $url.$self->_expand($req_data->{req}, %params);
1077              
1078             my $req = HTTP::Request->new(POST => $url);
1079              
1080             $req->content($self->_expand($req_data->{req}, %params));
1081              
1082             return $self->_call(%params, req => $req);
1083             }
1084              
1085             =head2 $reminders = $bp->upcoming_reminders([ xml => 1 ]);
1086              
1087             Gets the upcoming Backpack reminders for an account, in the time zone
1088             specified per the account's settings.
1089             Returns a Perl data structure unless the C parameter is true, in which
1090             case it returns the raw XML as returned by the Backpack server.
1091              
1092             =cut
1093              
1094             sub upcoming_reminders {
1095             my $self = shift;
1096             my %params = @_;
1097              
1098             my $req_data = $data{upcoming_reminders};
1099              
1100             my $url = $self->{base_url} . $self->_expand($req_data->{url});
1101             my $req = HTTP::Request->new(POST => $url);
1102              
1103             $req->content($self->_expand($req_data->{req}, %params));
1104              
1105             return $self->_call(%params, req => $req);
1106             }
1107              
1108             =head2 $reminder = $bp->create_reminder(content => $reminder, [xml => 1],
1109             [remind_at => $remind_at]);
1110              
1111             Create a Backpack reminder given some reminder content. The content
1112             takes fuzzy date/times like "+30 Do foo and bar" to set the reminder for 30
1113             minutes from now. Optionally, specify a date in a relatively parseable date
1114             format and use the remind_at parameter instead.
1115             Returns a Perl data structure unless the C parameter is true, in which
1116             case it returns the raw XML as returned by the Backpack server.
1117              
1118             =cut
1119              
1120             sub create_reminder {
1121             my $self = shift;
1122             my %params = @_;
1123              
1124             croak 'No reminder content' unless $params{content};
1125              
1126             $params{remind_at} ||= "";
1127            
1128             my $req_data = $data{create_reminder};
1129             my $url = $self->{base_url} . $self->_expand($req_data->{url}, %params);
1130              
1131             my $req = HTTP::Request->new('POST', $url);
1132             $req->content($self->_expand($req_data->{req}, %params));
1133              
1134             return $self->_call(%params, req => $req);
1135             }
1136              
1137             =head2 $reminder = $bp->update_reminder(id => $reminder_id,
1138             [content => $reminder], [xml => 1],
1139             [remind_at => $remind_at);
1140              
1141             Update a Backpack reminder given a reminder id. The content takes fuzzy
1142             date/times like "+30 Do foo and bar" to set the reminder for 30 minutes
1143             from now. Optionally, specify a date in a relatively parseable date format
1144             and use the remind_at parameter instead.
1145             Returns a Perl data structure unless the C parameter is true, in which
1146             case it returns the raw XML as returned by the Backpack server.
1147              
1148             =cut
1149              
1150             sub update_reminder {
1151             my $self = shift;
1152             my %params = @_;
1153              
1154             croak 'No reminder id' unless $params{id};
1155             unless (exists $params{content} && exists $params{remind_at}) {
1156             my $reminders = $self->upcoming_reminders();
1157             $params{content} ||=
1158             $reminders->{reminders}{reminder}{$params{id}}{content};
1159             $params{remind_at} ||=
1160             $reminders->{reminders}{reminder}{$params{id}}{remind_at};
1161             }
1162            
1163             my $req_data = $data{update_reminder};
1164             my $url = $self->{base_url} . $self->_expand($req_data->{url}, %params);
1165              
1166             my $req = HTTP::Request->new('POST', $url);
1167             $req->content($self->_expand($req_data->{req}, %params));
1168              
1169             return $self->_call(%params, req => $req);
1170             }
1171              
1172             =head2 $response = $bp->destroy_reminder( id => $reminder_id, [xml => 1]);
1173              
1174             Destroys a Backpack reminder given a reminder id.
1175             Returns a Perl data structure unless the C parameter is true, in which
1176             case it returns the raw XML as returned by the Backpack server.
1177              
1178             =cut
1179              
1180             sub destroy_reminder {
1181             my $self = shift;
1182             my %params = @_;
1183              
1184             croak 'No reminder id' unless $params{id};
1185              
1186             my $req_data = $data{destroy_reminder};
1187             my $url = $self->{base_url} . $self->_expand($req_data->{url}, %params);
1188              
1189             my $req = HTTP::Request->new('POST', $url);
1190             $req->content($self->_expand($req_data->{req}, %params));
1191              
1192             return $self->_call(%params, req => $req);
1193             }
1194              
1195             =head2 $emails = $bp->list_all_emails(page_id => $page_id, [xml => 1]);
1196              
1197             Get a list of all of your Backpack email items for a page. Returns a Perl
1198             data structure unless the C parameter is true, in which case it returns
1199             the raw XML as returned by the Backpack server.
1200              
1201             =cut
1202              
1203             sub list_all_emails {
1204             my $self = shift;
1205             my %params = @_;
1206              
1207             croak 'No id' unless $params{page_id};
1208            
1209             my $req_data = $data{list_all_emails};
1210             my $url = $self->{base_url} . $self->_expand($req_data->{url}, %params);
1211              
1212             my $req = HTTP::Request->new('POST', $url);
1213             $req->content($self->_expand($req_data->{req}, %params));
1214              
1215             return $self->_call(%params, req => $req);
1216             }
1217              
1218             =head2 $email = $bp->show_email(page_id => $page_id, id => $reminder_id,
1219             [xml => 1]);
1220              
1221             Returns a Backpack email item given a page id and an email id.
1222             Returns a Perl data structure unless the C parameter is true, in which
1223             case it returns the raw XML as returned by the Backpack server.
1224              
1225             =cut
1226              
1227             sub show_email {
1228             my $self = shift;
1229             my %params = @_;
1230              
1231             croak 'No page id' unless $params{page_id};
1232             croak 'No email id' unless $params{id};
1233              
1234             my $req_data = $data{show_email};
1235             my $url = $self->{base_url} . $self->_expand($req_data->{url}, %params);
1236              
1237             my $req = HTTP::Request->new('POST', $url);
1238             $req->content($self->_expand($req_data->{req}, %params));
1239              
1240             return $self->_call(%params, req => $req);
1241             }
1242              
1243             =head2 $response = $bp->destroy_email(page_id => $page_id, id => $reminder_id,
1244             [xml => 1]);
1245              
1246             Destroys a Backpack email item for a page given a page id and an email id.
1247             Returns a Perl data structure unless the C parameter is true, in which
1248             case it returns the raw XML as returned by the Backpack server.
1249              
1250             =cut
1251              
1252             sub destroy_email {
1253             my $self = shift;
1254             my %params = @_;
1255              
1256             croak 'No page id' unless $params{page_id};
1257             croak 'No email id' unless $params{id};
1258              
1259             my $req_data = $data{destroy_email};
1260             my $url = $self->{base_url} . $self->_expand($req_data->{url}, %params);
1261              
1262             my $req = HTTP::Request->new('POST', $url);
1263             $req->content($self->_expand($req_data->{req}, %params));
1264              
1265             return $self->_call(%params, req => $req);
1266             }
1267              
1268             =head2 $exported_bp = $bp->export([xml => 1]);
1269              
1270             Exports an account's entire Backpack. Returns a Perl data structure
1271             unless the C parameter is true, in which case it returns the raw
1272             XML as returned by the Backpack server.
1273              
1274             =cut
1275              
1276             sub export {
1277             my $self = shift;
1278             my %params = @_;
1279              
1280             my $req_data = $data{export};
1281             my $url = $self->{base_url} . $req_data->{url};
1282              
1283             my $req = HTTP::Request->new('POST', $url);
1284             $req->content($self->_expand($req_data->{req}, %params));
1285              
1286             return $self->_call(%params, req => $req);
1287             }
1288              
1289             =head2 $lists = $bp->list_all_lists(page_id => $page_id, [xml => 1]);
1290              
1291             Get a list of *all* of your Backpack checklists for a specific page.
1292             Returns a Perl data structure unless the C parameter is true,
1293             in which case it returns the raw XML as returned by the Backpack server.
1294              
1295             =cut
1296              
1297             sub list_all_lists {
1298             my $self = shift;
1299             my %params = @_;
1300              
1301             croak 'No id' unless $params{page_id};
1302              
1303             my $req_data = $data{list_all_lists};
1304             my $url = $self->{base_url} . $self->_expand($req_data->{url}, %params);
1305              
1306             my $req = HTTP::Request->new('POST', $url);
1307             $req->content($self->_expand($req_data->{req}, %params));
1308              
1309             return $self->_call(%params, req => $req);
1310             }
1311              
1312             =head2 $list = $bp->list_this_list(page_id => $page_id, list_id => $list_id, [xml => 1]);
1313              
1314             Get details of a specific list with the given list_id on a specific Backpack
1315             page with the given page_id. Returns a Perl data structure unless the C
1316             parameter is true, in which case it returns the raw XML as returned by the
1317             Backpack server.
1318              
1319             =cut
1320              
1321             sub list_this_list {
1322             my $self = shift;
1323             my %params = @_;
1324              
1325             croak 'No page id' unless $params{page_id};
1326             croak 'No list id' unless $params{list_id};
1327              
1328             my $req_data = $data{list_this_list};
1329             my $url = $self->{base_url} . $self->_expand($req_data->{url}, %params);
1330              
1331             my $req = HTTP::Request->new('POST', $url);
1332             $req->content($self->_expand($req_data->{req}, %params));
1333              
1334             return $self->_call(%params, req => $req);
1335             }
1336              
1337             =head2 $list = $bp->create_list(page_id => $page_id, title => $title, [xml => 1]);
1338              
1339             Create a new Backpack checklist given a page id and a list title.
1340             Returns a Perl data structure unless the C parameter is true, in which
1341             case it returns the raw XML as returned by the Backpack server.
1342              
1343             =cut
1344              
1345             sub create_list {
1346             my $self = shift;
1347             my %params = @_;
1348              
1349             croak 'No page id' unless $params{page_id};
1350             croak 'No list title' unless $params{title};
1351              
1352             my $req_data = $data{create_list};
1353             my $url = $self->{base_url} . $self->_expand($req_data->{url}, %params);
1354              
1355             my $req = HTTP::Request->new('POST', $url);
1356             $req->content($self->_expand($req_data->{req}, %params));
1357              
1358             return $self->_call(%params, req => $req);
1359             }
1360              
1361             =head2 $list = $bp->update_list(page_id => $page_id, list_id => $list_id, title => $title, [xml => 1]);
1362              
1363             Update the title of a specific list with the given list_id on a specific
1364             Backpack page with the given page_id. Returns a Perl data structure unless
1365             the C parameter is true, in which case it returns the raw XML as
1366             returned by the Backpack server.
1367              
1368             =cut
1369              
1370             sub update_list {
1371             my $self = shift;
1372             my %params = @_;
1373              
1374             croak 'No page id' unless $params{page_id};
1375             croak 'No list id' unless $params{list_id};
1376             croak 'No title' unless $params{title};
1377              
1378             my $req_data = $data{update_list};
1379             my $url = $self->{base_url} . $self->_expand($req_data->{url}, %params);
1380              
1381             my $req = HTTP::Request->new('POST', $url);
1382             $req->content($self->_expand($req_data->{req}, %params));
1383              
1384             return $self->_call(%params, req => $req);
1385             }
1386              
1387             =head2 $list = $bp->destroy_list(page_id => $page_id, list_id => $list_id, [xml => 1]);
1388              
1389             Destroy a specific list with the given list_id on a specific Backpack page
1390             with the given page_id. Returns a Perl data structure unless the C
1391             parameter is true, in which case it returns the raw XML as returned by the
1392             Backpack server.
1393              
1394             =cut
1395              
1396             sub destroy_list {
1397             my $self = shift;
1398             my %params = @_;
1399              
1400             croak 'No page id' unless $params{page_id};
1401             croak 'No list id' unless $params{list_id};
1402              
1403             my $req_data = $data{destroy_list};
1404             my $url = $self->{base_url} . $self->_expand($req_data->{url}, %params);
1405              
1406             my $req = HTTP::Request->new('POST', $url);
1407             $req->content($self->_expand($req_data->{req}, %params));
1408              
1409             return $self->_call(%params, req => $req);
1410             }
1411              
1412             =head2 $list = $bp->create_list_item(page_id => $page_id, list_id => $list_id, item = $item, [xml => 1]);
1413              
1414             Create an item on a specific list with the given list_id on a specific
1415             Backpack page with the given page_id. This differs from the usual
1416             "create_item" function in that you can specify which list on a page you want
1417             to add the item to. Returns a Perl data structure unless the C parameter
1418             is true, in which case it returns the raw XML as returned by the Backpack
1419             server.
1420              
1421             =cut
1422              
1423             sub create_list_item {
1424             my $self = shift;
1425             my %params = @_;
1426              
1427             croak 'No page id' unless $params{page_id};
1428             croak 'No list id' unless $params{list_id};
1429             croak 'No item content' unless $params{item};
1430              
1431             my $req_data = $data{create_list_item};
1432             my $url = $self->{base_url} . $self->_expand($req_data->{url}, %params);
1433              
1434             my $req = HTTP::Request->new('POST', $url);
1435             $req->content($self->_expand($req_data->{req}, %params));
1436              
1437             return $self->_call(%params, req => $req);
1438             }
1439              
1440              
1441             sub _call {
1442             my $self = shift;
1443             my %params = @_;
1444              
1445             my $resp = $self->{ua}->request($params{req});
1446             my $xml = $resp->content;
1447              
1448             if ($params{xml}) {
1449             return $xml;
1450             } else {
1451             my $data = XMLin($xml, ForceArray => $self->{forcearray});
1452             return $data;
1453             }
1454             }
1455              
1456             sub _expand {
1457             my $self = shift;
1458             my $string = shift;
1459             my %params = @_;
1460              
1461             $string =~ s/\[S:(\w+)]/$self->{$1}/g;
1462             $string =~ s/\[P:(\w+)]/$params{$1}/g;
1463              
1464             return $string;
1465             }
1466              
1467             =head1 TO DO
1468              
1469             =over 4
1470              
1471             =item *
1472              
1473             Improve documentation (I know, it's shameful)
1474              
1475             =item *
1476              
1477             More tests
1478              
1479             =back
1480              
1481             =head1 AUTHOR
1482              
1483             Dave Cross Edave@dave@mag-sol.comE
1484              
1485             Please feel free to email me to tell me how you are using the module.
1486              
1487             Lots of stuff implemented by neshura when I was being too tardy!
1488              
1489             =head1 BUGS
1490              
1491             Please report bugs by email to Ebug-Net-Backpack@rt.cpan.orgE.
1492              
1493             =head1 LICENSE AND COPYRIGHT
1494              
1495             Copyright (c) 2005, Dave Cross. All Rights Reserved.
1496              
1497             This script is free software; you can redistribute it and/or
1498             modify it under the same terms as Perl itself.
1499              
1500             =head1 SEE ALSO
1501              
1502             L, L, L
1503              
1504             =cut
1505              
1506             1;
1507             __END__