File Coverage

blib/lib/API/Plesk.pm
Criterion Covered Total %
statement 78 109 71.5
branch 15 40 37.5
condition 8 24 33.3
subroutine 16 20 80.0
pod 3 7 42.8
total 120 200 60.0


line stmt bran cond sub pod time code
1              
2             package API::Plesk;
3              
4 14     14   381623 use strict;
  14         26  
  14         363  
5 14     14   59 use warnings;
  14         20  
  14         409  
6              
7 14     14   62 use Carp;
  14         25  
  14         761  
8 14     14   65 use Data::Dumper;
  14         24  
  14         505  
9              
10 14     14   5770 use HTTP::Request;
  14         246805  
  14         399  
11 14     14   8599 use LWP::UserAgent;
  14         269763  
  14         463  
12 14     14   6426 use XML::Fast;
  14         117037  
  14         696  
13 14     14   5052 use version;
  14         20754  
  14         83  
14              
15 14     14   5940 use API::Plesk::Response;
  14         28  
  14         11089  
16              
17             our $VERSION = '2.00_3';
18              
19             # creates accessors to components
20             # can support old interface of API::Plesk
21             init_components(
22             # new
23             customer => [['1.6.3.0', 'Customer']],
24             webspace => [['1.6.3.0', 'Webspace']],
25             site => [['1.6.3.0', 'Site']],
26             site_alias => [['1.6.3.0', 'SiteAlias']],
27             sitebuilder => [['1.6.3.0', 'SiteBuilder']],
28             ftp_user => [['1.6.3.0', 'FTPUser']],
29             service_plan => [['1.6.3.0', 'ServicePlan']],
30             service_plan_addon => [['1.6.3.0', 'ServicePlanAddon']],
31             database => [['1.6.3.0', 'Database']],
32             webuser => [['1.6.3.0', 'WebUser']],
33             dns => [['1.6.3.0', 'DNS']],
34             mail => [['1.6.3.0', 'Mail']],
35            
36             # old
37             Accounts => [['1.5.0.0', 'Accounts']],
38             Domains => [['1.5.0.0', 'Domains']],
39             );
40              
41             # constructor
42             sub new {
43 15     15 1 785 my $class = shift;
44 15   66     98 $class = ref ($class) || $class;
45            
46 15         126 my $self = {
47             username => '',
48             password => '',
49             url => '',
50             api_version => '1.6.3.1',
51             debug => 0,
52             timeout => 30,
53             (@_)
54             };
55              
56 15 50       52 confess "Required username!" unless $self->{username};
57 15 50       66 confess "Required password!" unless $self->{password};
58 15 50       46 confess "Required url!" unless $self->{url};
59              
60 15         49 return bless $self, $class;
61             }
62              
63             # sends request to Plesk API
64             sub send {
65 0     0 1 0 my ( $self, $operator, $operation, $data, %params ) = @_;
66              
67 0 0 0     0 confess "Wrong request data!" unless $data && ref $data;
68              
69 0         0 my $xml = { $operator => { $operation => $data } };
70              
71 0         0 $xml = $self->render_xml($xml);
72              
73 0 0       0 warn "REQUEST $operator => $operation\n$xml" if $self->{debug};
74              
75 0         0 my ($response, $error) = $self->xml_http_req($xml);
76              
77 0 0       0 warn "RESPONSE $operator => $operation => $error\n$response" if $self->{debug};
78              
79 0 0       0 unless ( $error ) {
80 0         0 $response = xml2hash $response, array => [$operation, 'result', 'property'];
81             }
82              
83 0         0 return API::Plesk::Response->new(
84             operator => $operator,
85             operation => $operation,
86             response => $response,
87             error => $error,
88             );
89             }
90              
91 0     0 0 0 sub bulk_send { confess "Not implemented!" }
92              
93             # Send xml request to plesk api
94             sub xml_http_req {
95 0     0 1 0 my ($self, $xml) = @_;
96              
97             # HTTP::Request undestends only bytes
98 0 0       0 utf8::encode($xml) if utf8::is_utf8($xml);
99              
100 0         0 my $ua = new LWP::UserAgent( parse_head => 0 );
101 0         0 my $req = new HTTP::Request POST => $self->{url};
102              
103 0         0 $req->push_header(':HTTP_AUTH_LOGIN', $self->{username});
104 0         0 $req->push_header(':HTTP_AUTH_PASSWD', $self->{password});
105 0         0 $req->content_type('text/xml; charset=UTF-8');
106 0         0 $req->content($xml);
107              
108             # LWP6 hack to prevent verification of hostname
109 0 0       0 $ua->ssl_opts(verify_hostname => 0) if $ua->can('ssl_opts');
110              
111 0 0       0 warn $req->as_string if $self->{debug} > 1;
112              
113 0         0 my $res = eval {
114 0     0   0 local $SIG{ALRM} = sub { die "connection timeout" };
  0         0  
115 0         0 alarm $self->{timeout};
116 0         0 $ua->request($req);
117             };
118 0         0 alarm 0;
119              
120 0 0       0 warn $res->as_string if $self->{debug} > 1;
121              
122 0 0 0     0 return ('', 'connection timeout')
      0        
      0        
123             if !$res || $@ || ref $res && $res->status_line =~ /connection timeout/;
124              
125 0 0       0 return $res->is_success() ?
126             ($res->content(), '') :
127             ('', $res->status_line);
128             }
129              
130              
131             # renders xml packet for request
132             sub render_xml {
133 2     2 0 716 my ($self, $hash) = @_;
134              
135 2         20 my $xml = _render_xml($hash);
136              
137 2         6 $xml = qq|$xml|;
138              
139 2         11 $xml;
140             }
141              
142             # renders xml from hash
143             sub _render_xml {
144 12     12   14 my ( $hash ) = @_;
145              
146 12 100       18 return $hash unless ref $hash;
147              
148 11         9 my $xml = '';
149              
150 11         15 for my $tag ( keys %$hash ) {
151 14         12 my $value = $hash->{$tag};
152 14 100       32 if ( ref $value eq 'HASH' ) {
    100          
    100          
153 3         14 $value = _render_xml($value);
154             }
155             elsif ( ref $value eq 'ARRAY' ) {
156 2         2 my $tmp;
157 2         5 $tmp .= _render_xml($_) for ( @$value );
158 2         4 $value = $tmp;
159             }
160             elsif ( ref $value eq 'CODE' ) {
161 2         3 $value = _render_xml(&$value);
162             }
163              
164 14 100 100     37 if ( !defined $value or $value eq '' ) {
165 2         3 $xml .= "<$tag/>";
166             }
167             else {
168 12         25 $xml .= "<$tag>$value";
169             }
170             }
171              
172 11         15 $xml;
173             }
174              
175              
176             # initialize components
177             sub init_components {
178 14     14 0 123 my ( %c ) = @_;
179 14         26 my $caller = caller;
180              
181 14         59 for my $alias ( keys %c ) {
182              
183 196         149 my $classes = $c{$alias};
184              
185             my $sub = sub {
186 31     31   498 my( $self ) = @_;
187 31   66     185 $self->{"_$alias"} ||= $self->load_component($classes);
188 31   33     250 return $self->{"_$alias"} || confess "Not implemented!";
189 196         394 };
190            
191 14     14   73 no strict 'refs';
  14         15  
  14         2693  
192            
193 196         138 *{"$caller\::$alias"} = $sub;
  196         536  
194              
195            
196             }
197              
198             }
199              
200             # loads component package and creates object
201             sub load_component {
202 12     12 0 22 my ( $self, $classes ) = @_;
203 12         122 my $version = version->parse($self->{api_version});
204              
205 12         34 for my $item ( @$classes ) {
206            
207             # select compitable version of component
208 12 50       113 if ( $version >= $item->[0] ) {
209              
210 12         38 my $pkg = ref($self) . '::' . $item->[1];
211              
212 12         27 my $module = "$pkg.pm";
213 12         62 $module =~ s/::/\//g;
214              
215 12         35 local $@;
216 12         15 eval { require $module };
  12         783  
217 12 50       39 if ( $@ ) {
218 0         0 confess "Failed to load $pkg: $@";
219             }
220              
221 12         145 return $pkg->new(plesk => $self);
222              
223             }
224              
225             }
226              
227             }
228              
229             1;
230              
231             __END__