File Coverage

blib/lib/Business/SiteCatalyst.pm
Criterion Covered Total %
statement 53 83 63.8
branch 3 30 10.0
condition 1 8 12.5
subroutine 17 18 94.4
pod 5 5 100.0
total 79 144 54.8


line stmt bran cond sub pod time code
1             package Business::SiteCatalyst;
2              
3 16     16   654347 use strict;
  16         41  
  16         597  
4 16     16   89 use warnings;
  16         35  
  16         416  
5              
6 16     16   17160 use Data::Dumper;
  16         153722  
  16         1284  
7 16     16   152 use Carp;
  16         30  
  16         1056  
8 16     16   20728 use LWP::UserAgent qw();
  16         921879  
  16         482  
9 16     16   193 use HTTP::Request qw();
  16         34  
  16         257  
10 16     16   19737 use JSON qw();
  16         245472  
  16         493  
11 16     16   162 use Digest::MD5 qw();
  16         35  
  16         310  
12 16     16   15600 use POSIX qw();
  16         123572  
  16         544  
13 16     16   14764 use Digest::SHA1 qw();
  16         17710  
  16         449  
14 16     16   14632 use MIME::Base64 qw();
  16         12421  
  16         723  
15              
16 16     16   10602 use Business::SiteCatalyst::Company;
  16         44  
  16         487  
17 16     16   10727 use Business::SiteCatalyst::Report;
  16         43  
  16         15160  
18              
19              
20             # Some API methods return strings or numbers rather than valid JSON.
21             # This list is used to return the raw response to the caller instead of decoding output as JSON
22             my %METHODS_RETURNING_INVALID_JSON =
23             (
24             'Company.GetEndpoint' => 1, # Returns string
25             'Company.GetTokenCount' => 1, # Returns number
26             'Report.CancelReport' => 1, # Returns number
27             );
28              
29              
30             =head1 NAME
31              
32             Business::SiteCatalyst - Interface to Adobe Omniture SiteCatalyst's REST API.
33              
34              
35             =head1 VERSION
36              
37             Version 1.2.2
38              
39             =cut
40              
41             our $VERSION = '1.2.2';
42              
43              
44             =head1 SYNOPSIS
45              
46             This module allows you to interact with Adobe (formerly Omniture) SiteCatalyst,
47             a web analytics service. It encapsulates all the communications with the API
48             provided by Adobe SiteCatalyst to offer a Perl interface for managing reports,
49             pulling company-specific SiteCatalyst data (ex: token usage), uploading SAINT
50             data (feature not implemented yet), etc.
51              
52             Please note that you will need to have purchased the Adobe SiteCatalyst product,
53             and have web services enabled within your account first in order to obtain a web
54             services shared secret, as well as agree with the Terms and Conditions for using
55             the API.
56              
57             NOTE: the 'api_subdomain' option/config variable is utilized for the api url.
58             To determine your specific API URL/Endpoint, please visit
59             https://developer.omniture.com/en_US/get-started/api-explorer
60             Most users won't need to set this variable unless the default causes errors.
61              
62             API URL: 'https://' . $api_subdomain . '.omniture.com/admin/1.3/rest/?'
63              
64              
65             use Business::SiteCatalyst;
66            
67             # Create an object to communicate with Adobe SiteCatalyst
68             my $site_catalyst = Business::SiteCatalyst->new(
69             username => 'dummyusername',
70             shared_secret => 'dummysecret',
71             api_subdomain => 'api|api2', #optional; default value='api'
72             );
73              
74              
75             =head1 METHODS
76              
77             =head2 new()
78              
79             Create a new Adobe SiteCatalyst object that will be used as the interface with
80             Adobe SiteCatalyst's API
81              
82             use Business::SiteCatalyst;
83            
84             # Create an object to communicate with Adobe SiteCatalyst
85             my $site_catalyst = Business::SiteCatalyst->new(
86             username => 'dummyusername',
87             shared_secret => 'dummysecret',
88             api_subdomain => 'api|api2', #optional; default value='api'
89             );
90              
91             Creates a new object to communicate with Adobe SiteCatalyst.
92              
93             'username' and 'shared_secret' are mandatory.
94             The 'verbose' parameter is optional and defaults to not verbose.
95              
96             =cut
97              
98             sub new
99             {
100 3     3 1 39 my ( $class, %args ) = @_;
101            
102             # Check for mandatory parameters
103 3         10 foreach my $arg ( qw( username shared_secret ) )
104             {
105 6 50 33     49 croak "Argument '$arg' is needed to create the Business::SiteCatalyst object"
106             if !defined( $args{$arg} ) || ( $args{$arg} eq '' );
107             }
108            
109             #Defaults.
110            
111             # NOTE - some users connect to api2.omniture.com, so the subdomain portion of the host is configurable
112             # in the 'api_subdomain' config variable in SiteCatalystConfig.pm
113 3 50       22 my $webservice_url = 'https://' .
114             ( defined $args{'api_subdomain'} ? $args{'api_subdomain'} : 'api' ) .
115             '.omniture.com/admin/1.3/rest/?method=';
116            
117             # Create the object
118 3         18 my $self = bless(
119             {
120             username => $args{'username'},
121             shared_secret => $args{'shared_secret'},
122             webservice_url => $webservice_url,
123             },
124             $class,
125             );
126            
127 3         16 $self->verbose( $args{'verbose'} );
128            
129 3         13 return $self;
130             }
131              
132              
133             =head2 instantiate_report()
134              
135             Create a new Business::SiteCatalyst::Report object, which
136             will allow retrieval of SiteCatalyst reports.
137              
138             # Create a new report
139             my $report = $site_catalyst->instantiate_report(
140             type => 'report type',
141             report_suite_id => 'report suite id',
142             );
143              
144             # Act on an existing report
145             my $report = $site_catalyst->instantiate_report(
146             report_id => 'report id',
147             );
148              
149            
150             Parameters:
151              
152             =over 4
153              
154             =item * type
155              
156             The type of the report to instantiate.
157             Acceptable values are 'Overtime', 'Ranked', and 'Trended'.
158              
159             =item * report_suite_id
160              
161             The Report Suite ID you want to pull data from.
162              
163             =item * report_id
164              
165             The id of the existing report you want to check status of, retrieve results for,
166             or cancel processing.
167              
168             =back
169              
170             =cut
171              
172             sub instantiate_report
173             {
174 1     1 1 8 my ( $self, %args ) = @_;
175            
176 1         10 return Business::SiteCatalyst::Report->new( $self, %args );
177             }
178              
179              
180              
181             =head2 instantiate_company()
182              
183             Create a new Business::SiteCatalyst::Company object, which
184             will allow retrieval of company-specific SiteCatalyst data.
185              
186             my $company = $site_catalyst->instantiate_company();
187              
188            
189             Parameters: none
190              
191             =cut
192              
193             sub instantiate_company
194             {
195 1     1 1 7 my ( $self, %args ) = @_;
196            
197 1         11 return Business::SiteCatalyst::Company->new( $self, %args );
198             }
199              
200              
201             =head1 INTERNAL METHODS
202              
203             =head2 send_request()
204              
205             Internal, formats the JSON call with the arguments provided and checks the
206             reply.
207              
208             my ( $error, $response_data ) = $site_catalyst->send_request(
209             method => $method,
210             data => $data,
211             );
212              
213             =cut
214              
215             sub send_request
216             {
217 0     0 1 0 my ( $self, %args ) = @_;
218            
219 0         0 my $verbose = $self->verbose();
220 0         0 my $url = $self->{'webservice_url'} . $args{'method'};
221            
222             # Check for mandatory parameters
223 0         0 foreach my $arg ( qw( method data ) )
224             {
225 0 0 0     0 croak "Argument '$arg' is needed to send a request with the Business::SiteCatalyst object"
226             if !defined( $args{$arg} ) || ( $args{$arg} eq '' );
227             }
228            
229 0         0 my $json_in = JSON::encode_json( $args{'data'} );
230 0 0       0 carp "Sending JSON request >" . ( defined( $json_in ) ? $json_in : '' ) . "<"
    0          
231             if $verbose;
232            
233             # Authentication information for header.
234 0         0 my $username = $self->{'username'};
235 0         0 my $nonce = Digest::MD5::md5_hex( rand() * time() );
236 0         0 chomp($nonce);
237            
238 0         0 my $created = POSIX::strftime("%Y-%m-%dT%H:%M:%S", gmtime());
239 0         0 my $password_digest = MIME::Base64::encode_base64(
240             Digest::SHA1::sha1_hex( $nonce . $created . $self->{'shared_secret'} )
241             );
242 0         0 chomp($password_digest);
243            
244 0         0 my $request = HTTP::Request->new(POST => $url);
245 0 0       0 carp "POSTing request to URL >" . ( defined( $url ) ? $url : '' ) . "<"
    0          
246             if $verbose;
247 0         0 my $auth_header = qq|UsernameToken Username="$username", PasswordDigest="$password_digest", Nonce="$nonce", Created="$created"|;
248 0 0       0 carp "Auth header: >$auth_header<" if $verbose;
249            
250 0         0 $request->header('X-WSSE', $auth_header);
251            
252 0         0 $request->content_type('application/json');
253 0         0 $request->content( $json_in );
254            
255 0         0 my $user_agent = LWP::UserAgent->new();
256 0         0 my $response = $user_agent->request($request);
257            
258 0 0       0 croak "Request failed:" . $response->status_line()
259             if !$response->is_success();
260              
261 0 0       0 carp "Response >" . ( defined( $response ) ? $response->content() : '' ) . "<"
    0          
262             if $verbose;
263              
264 0         0 my $json_out;
265            
266 0 0       0 if ( exists( $METHODS_RETURNING_INVALID_JSON{ $args{'method'} } ) )
267             {
268 0         0 $json_out = $response->content();
269             }
270             else
271             {
272 0         0 $json_out = JSON::decode_json( $response->content() );
273             }
274            
275 0 0       0 carp "JSON Response >" . ( defined( $json_out ) ? Dumper($json_out) : '' ) . "<"
    0          
276             if $verbose;
277            
278 0         0 return $json_out;
279             }
280              
281              
282             =head2 verbose()
283              
284             Control the verbosity of the debugging output.
285              
286             $site_catalyst->verbose( 1 ); # turn on verbose information
287              
288             $site_catalyst->verbose( 0 ); # quiet!
289              
290             warn 'Verbose' if $site_catalyst->verbose(); # getter-style
291              
292             =cut
293              
294             sub verbose
295             {
296 3     3 1 13 my ( $self, $verbose ) = @_;
297            
298 3 50 0     15 $self->{'verbose'} = ( $verbose || 0 )
299             if defined( $verbose );
300            
301 3         19 return $self->{'verbose'};
302             }
303              
304              
305             =head1 RUNNING TESTS
306              
307             By default, only basic tests that do not require a connection to Adobe
308             SiteCatalyst's platform are run in t/.
309              
310             To run the developer tests, you will need to do the following:
311              
312             =over 4
313              
314             =item *
315              
316             Request access to Adobe web services from your Adobe Online Marketing Suite administrator.
317              
318             =item *
319              
320             In Adobe SiteCatalyst's interface, you will need to log in as an admin, then go
321             to the "Admin" tab, "Admin Console > Company > Web Services". There you can find
322             your "shared secret" for your username.
323              
324             =item *
325              
326             Your report suite IDs can be found in Adobe SiteCatalyst's interface. Visit
327             "Admin > Admin Console > Report Suites".
328              
329             =back
330              
331             You can now create a file named SiteCatalystConfig.pm in your own directory, with
332             the following content:
333              
334             package Adobe SiteCatalystConfig;
335            
336             sub new
337             {
338             return
339             {
340             username => 'username',
341             shared_secret => 'shared_secret',
342             report_suite_id => 'report_suite_id',
343             api_subdomain => 'api|api2', #optional. default='api'
344             verbose => 0, # Enable this for debugging output
345             };
346             }
347            
348             1;
349              
350             You will then be able to run all the tests included in this distribution, after
351             adding the path to Adobe SiteCatalystConfig.pm to your library paths.
352              
353              
354             =head1 AUTHOR
355              
356             Jennifer Pinkham, C<< >>.
357              
358              
359             =head1 BUGS
360              
361             Please report any bugs or feature requests to C,
362             or through the web interface at L.
363             I will be notified, and then you'll automatically be notified of progress on
364             your bug as I make changes.
365              
366              
367             =head1 SUPPORT
368              
369             You can find documentation for this module with the perldoc command.
370              
371             perldoc Business::SiteCatalyst
372              
373              
374             You can also look for information at:
375              
376             =over 4
377              
378             =item * RT: CPAN's request tracker
379              
380             L
381              
382             =item * AnnoCPAN: Annotated CPAN documentation
383              
384             L
385              
386             =item * CPAN Ratings
387              
388             L
389              
390             =item * Search CPAN
391              
392             L
393              
394             =back
395              
396              
397             =head1 ACKNOWLEDGEMENTS
398              
399             Thanks to ThinkGeek (L) and its corporate overlords
400             at Geeknet (L), for footing the bill while I write code for them!
401             Special thanks for technical help from fellow ThinkGeek CPAN author Guillaume Aubert L
402              
403              
404             =head1 COPYRIGHT & LICENSE
405              
406             Copyright 2013 Jennifer Pinkham.
407              
408             This program is free software; you can redistribute it and/or modify it
409             under the terms of the Artistic License.
410              
411             See http://dev.perl.org/licenses/ for more information.
412              
413             =cut
414              
415             1;