File Coverage

blib/lib/OvhApi.pm
Criterion Covered Total %
statement 30 83 36.1
branch 0 30 0.0
condition 0 11 0.0
subroutine 10 17 58.8
pod 3 4 75.0
total 43 145 29.6


line stmt bran cond sub pod time code
1             package OvhApi;
2              
3 1     1   419 use strict;
  1         1  
  1         25  
4 1     1   3 use warnings;
  1         1  
  1         31  
5              
6             our $VERSION = 0.2;
7              
8              
9 1     1   285 use OvhApi::Answer;
  1         2  
  1         21  
10              
11 1     1   4 use Carp qw{ carp croak };
  1         1  
  1         33  
12 1     1   3 use List::Util 'first';
  1         1  
  1         57  
13 1     1   520 use LWP::UserAgent ();
  1         28530  
  1         19  
14 1     1   7 use JSON ();
  1         1  
  1         14  
15 1     1   494 use Digest::SHA1 'sha1_hex';
  1         513  
  1         61  
16              
17              
18              
19             # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
20             # Class constants
21              
22             use constant {
23 1         619 OVH_API_EU => 'https://eu.api.ovh.com/1.0',
24             OVH_API_CA => 'https://ca.api.ovh.com/1.0',
25 1     1   5 };
  1         1  
26              
27             # End - Class constants
28             # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
29              
30              
31              
32             # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
33             # Class variables
34              
35             my $UserAgent = LWP::UserAgent->new(timeout => 10);
36             my $Json = JSON->new->allow_nonref;
37              
38             my @accessRuleMethods = qw{ GET POST PUT DELETE };
39              
40             # End - Class variables
41             # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
42              
43              
44              
45             # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
46             # Class methods
47              
48             sub new
49             {
50 0     0 0   my @keys = qw{ applicationKey applicationSecret consumerKey };
51              
52 0           my ($class, %params) = @_;
53              
54 0 0         if (my @missingParameters = grep { not $params{$_} } qw{ applicationKey applicationSecret })
  0            
55             {
56 0           local $" = ', ';
57 0           croak "Missing parameter: @missingParameters";
58             }
59              
60 0 0 0       unless ($params{'type'} and grep { $params{'type'} eq $_ } (OVH_API_EU, OVH_API_CA))
  0            
61             {
62 0           carp 'Missing or invalid type parameter: defaulting to OVH_API_EU';
63             }
64              
65             my $self = {
66 0   0       _type => ($params{'type'} or OVH_API_EU),
67             };
68              
69 0           @$self{@keys} = @params{@keys};
70              
71 0           bless $self, $class;
72             }
73              
74             sub setRequestTimeout
75             {
76 0     0 1   my ($class, %params) = @_;
77              
78 0 0         if ($params{'timeout'} =~ /^\d+$/)
    0          
79             {
80 0           $UserAgent->timeout($params{'timeout'});
81             }
82             elsif (exists $params{'timeout'})
83             {
84 0           carp "Invalid timeout: $params{'timeout'}";
85             }
86             else
87             {
88 0           carp 'Missing parameter: timeout';
89             }
90             }
91              
92             # End - Class methods
93             # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
94              
95              
96              
97             # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
98             # Instance methods
99              
100             sub rawCall
101             {
102 0     0 1   my ($self, %params) = @_;
103              
104 0           my $method = lc $params{'method'};
105 0 0         my $url = $self->{'_type'} . (substr($params{'path'}, 0, 1) eq '/' ? '' : '/') . $params{'path'};
106              
107 0           my %httpHeaders;
108              
109 0           my $body = '';
110 0           my %content;
111              
112 0 0 0       if ($method ne 'get' and $method ne 'delete')
113             {
114 0           $body = $Json->encode($params{'body'});
115              
116 0           $httpHeaders{'Content-type'} = 'application/json';
117 0           $content{'Content'} = $body;
118             }
119              
120 0 0         unless ($params{'noSignature'})
121             {
122 0           my $now = $self->_timeDelta + time;
123              
124             $httpHeaders{'X-Ovh-Consumer'} = $self->{'consumerKey'},
125             $httpHeaders{'X-Ovh-Timestamp'} = $now,
126             $httpHeaders{'X-Ovh-Signature'} = '$1$' . sha1_hex(join('+', (
127             # Full signature is '$1$' followed by the hex digest of the SHA1 of all these data joined by a + sign
128             $self->{'applicationSecret'}, # Application secret
129 0           $self->{'consumerKey'}, # Consumer key
130             uc $method, # HTTP method (uppercased)
131             $url, # Full URL
132             $body, # Full body
133             $now, # Curent OVH server time
134             )));
135             }
136              
137 0           $httpHeaders{'X-Ovh-Application'} = $self->{'applicationKey'},
138              
139             return OvhApi::Answer->new(response => $UserAgent->$method($url, %httpHeaders, %content));
140             }
141              
142             sub requestCredentials
143             {
144 0     0 1   my ($self, %params) = @_;
145              
146 0 0         croak 'Missing parameter: accessRules' unless $params{'accessRules'};
147 0 0         croak 'Invalid parameter: accessRules' if ref $params{'accessRules'} ne 'ARRAY';
148              
149             my @rules = map {
150 0 0         croak 'Invalid access rule: must be HASH ref' if ref ne 'HASH';
151              
152 0           my %rule = %$_;
153              
154 0           $rule{'method'} = uc $rule{'method'};
155              
156 0 0 0       croak 'Access rule must have method and path keys' unless $rule{'method'} and $rule{'path'};
157 0 0   0     croak 'Invalid access rule method' unless first { $_ eq $rule{'method'} } (@accessRuleMethods, 'ALL');
  0            
158              
159 0 0         if ($rule{'method'} eq 'ALL')
160             {
161 0           map { path => $rule{'path'}, method => $_ }, @accessRuleMethods;
162             }
163             else
164             {
165 0           \%rule
166             }
167 0           } @{ $params{'accessRules'} };
  0            
168              
169 0           return $self->post(path => '/auth/credential/', noSignature => 1, body => { accessRules => \@rules });
170             }
171              
172             # Generation of helper subs: simple wrappers to rawCall
173             # Generate: get(), post(), put(), delete()
174             {
175 1     1   4 no strict 'refs';
  1         1  
  1         124  
176              
177             for my $method (qw{ get post put delete })
178             {
179 0     0     *$method = sub { rawCall(@_, 'method', $method ) };
180             }
181             }
182              
183             # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
184             # Private part
185              
186             sub _timeDelta
187             {
188 0     0     my ($self, %params) = @_;
189              
190 0 0         unless (defined $self->{'_timeDelta'})
191             {
192 0 0         if (my $ServerTimeResponse = $self->get(path => 'auth/time', noSignature => 1))
193             {
194 0           $self->{'_timeDelta'} = ($ServerTimeResponse->content - time);
195             }
196             else
197             {
198 0           return 0;
199             }
200             }
201              
202 0           return $self->{'_timeDelta'};
203             }
204              
205             # End - Instance methods
206             # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
207              
208              
209             return 42;
210              
211              
212             __END__