File Coverage

lib/API/DirectAdmin.pm
Criterion Covered Total %
statement 99 133 74.4
branch 24 52 46.1
condition 15 30 50.0
subroutine 17 19 89.4
pod 0 11 0.0
total 155 245 63.2


line stmt bran cond sub pod time code
1             package API::DirectAdmin;
2              
3 1     1   2655 use Modern::Perl '2010';
  1         15075  
  1         7  
4 1     1   4833 use LWP::UserAgent;
  1         129270  
  1         42  
5 1     1   27 use HTTP::Request;
  1         2  
  1         26  
6 1     1   6 use Data::Dumper;
  1         2  
  1         74  
7 1     1   7 use Carp;
  1         2  
  1         65  
8 1     1   7 use URI;
  1         2  
  1         1545  
9              
10             our $VERSION = 0.09;
11             our $DEBUG = '';
12             our $FAKE_ANSWER = '';
13              
14             # for init subclasses
15             init_components(
16             domain => 'Domain',
17             mysql => 'Mysql',
18             user => 'User',
19             dns => 'DNS',
20             ip => 'Ip',
21             );
22              
23             # init
24             sub new {
25 1     1 0 760 my $class = shift;
26 1   33     12 $class = ref ($class) || $class;
27            
28 1         10 my $self = {
29             auth_user => '',
30             auth_passwd => '',
31             host => '',
32             ip => '',
33             debug => $DEBUG,
34             allow_https => 1,
35             fake_answer => $FAKE_ANSWER,
36             (@_)
37             };
38              
39 1 50       5 confess "Required auth_user!" unless $self->{auth_user};
40 1 50       5 confess "Required auth_passwd!" unless $self->{auth_passwd};
41 1 50       3 confess "Required host!" unless $self->{host};
42              
43 1         5 return bless $self, $class;
44             }
45              
46             # initialize components
47             sub init_components {
48 1     1 0 7 my ( %c ) = @_;
49 1         4 my $caller = caller;
50              
51 1         5 for my $alias ( keys %c ) {
52              
53 5         8 my $item = $c{$alias};
54              
55             my $sub = sub {
56 13     13   7376 my( $self ) = @_;
57 13   66     64 $self->{"_$alias"} ||= $self->load_component($item);
58 13   33     116 return $self->{"_$alias"} || confess "Not implemented!";
59 5         38 };
60            
61 1     1   8 no strict 'refs';
  1         2  
  1         11801  
62            
63 5         9 *{"$caller\::$alias"} = $sub;
  5         32  
64             }
65             }
66              
67             # loads component package and creates object
68             sub load_component {
69 4     4 0 8 my ( $self, $item ) = @_;
70              
71 4         11 my $pkg = ref($self) . '::' . $item;
72              
73 4         12 my $module = "$pkg.pm";
74 4         87 $module =~ s/::/\//g;
75              
76 4         6 local $@;
77 4         8 eval { require $module };
  4         26  
78 4 50       11 if ( $@ ) {
79 0         0 confess "Failed to load $pkg: $@";
80             }
81              
82 4         36 return $pkg->new(directadmin => $self);
83              
84             }
85              
86             # Filter hash
87             # STATIC(HASHREF: hash, ARRREF: allowed_keys)
88             # RETURN: hashref only with allowed keys
89             sub filter_hash {
90 17     17 0 40 my ($self, $hash, $allowed_keys) = @_;
91            
92 17 100       41 return {} unless defined $hash;
93            
94 14 50 33     99 confess "Wrong params" unless ref $hash eq 'HASH' && ref $allowed_keys eq 'ARRAY';
95              
96 14         27 my $new_hash = { };
97              
98 14         26 foreach my $allowed_key (@$allowed_keys) {
99 120 100       355 if (exists $hash->{$allowed_key}) {
    50          
100 42         101 $new_hash->{$allowed_key} = $hash->{$allowed_key};
101             }
102             elsif (exists $hash->{lc $allowed_key}) {
103 0         0 $new_hash->{$allowed_key} = $hash->{lc $allowed_key};
104             };
105             }
106              
107 14         49 return $new_hash;
108             }
109              
110             # all params derived from get_auth_hash
111             sub query {
112 13     13 0 51 my ( $self, %params ) = @_;
113              
114 13         213 my $command = delete $params{command};
115 13   100     47 my $fields = $params{allowed_fields} || '';
116              
117 13         15 my $allowed_fields;
118 13 50       28 warn 'query_abstract ' . Dumper( \%params ) if $self->{debug};
119              
120 13 50       26 confess "Empty command" unless $command;
121              
122 13         27 $fields = "host port auth_user auth_passwd method allow_https command $fields";
123 13         93 @$allowed_fields = split /\s+/, $fields;
124              
125 13         47 my $params = $self->filter_hash( $params{params}, $allowed_fields );
126              
127 13         77 my $query_string = $self->mk_full_query_string( {
128             command => $command,
129             %$params,
130             } );
131              
132 13 50       66 carp Dumper $query_string if $self->{debug};
133            
134 13   100     63 my $server_answer = $self->process_query(
135             method => $params{method} || 'GET',
136             query_string => $query_string,
137             params => $params,
138             );
139            
140 13 50       30 carp Dumper $server_answer if $self->{debug};
141              
142 13         70 return $server_answer;
143             }
144              
145             # Kill slashes at start / end string
146             # STATIC(STRING:input_string)
147             sub kill_start_end_slashes {
148 17     17 0 23 my ($self ) = @_;
149              
150 17         38 for ( $self->{host} ) {
151 17         25 s/^\/+//sgi;
152 17         48 s/\/+$//sgi;
153             }
154              
155 17         29 return 1;
156             }
157              
158             # Make full query string
159             # STATIC(HASHREF: params)
160             # params:
161             # host*
162             # port*
163             # param1
164             # param2
165             # ...
166             sub mk_full_query_string {
167 17     17 0 33 my ( $self, $params ) = @_;
168              
169 17 50 50     181 confess "Wrong params: " . Dumper( $params ) unless ref $params eq 'HASH'
      33        
      33        
170             && scalar keys %$params
171             && $self->{host}
172             && $params->{command};
173              
174 17 100       51 my $allow_https = defined $params->{allow_https} ? $params->{allow_https} : $self->{allow_https};
175 17         84 delete $params->{allow_https};
176            
177 17         31 my $host = $self->{host};
178 17   50     69 my $port = $self->{port} || 2222;
179 17         29 my $command = delete $params->{command};
180 17         32 my $auth_user = $self->{auth_user};
181 17         25 my $auth_passwd = $self->{auth_passwd};
182              
183 17         39 $self->kill_start_end_slashes();
184              
185 17 100       76 my $query_path = ( $allow_https ? 'https' : 'http' ) . "://$auth_user:$auth_passwd\@$host:$port/$command?";
186 17         38 return $query_path . $self->mk_query_string($params);
187             }
188              
189             # Make query string
190             # STATIC(HASHREF: params)
191             sub mk_query_string {
192 24     24 0 44 my ($self, $params) = @_;
193              
194 24 100 100     148 return '' unless ref $params eq 'HASH' && scalar keys %$params;
195              
196 14         57 my %params = %$params;
197              
198 14         66 my $result = join '&', map { "$_=$params{$_}" } sort keys %params;
  50         143  
199              
200 14         89 return $result;
201             }
202              
203             # Get + deparse
204             # STATIC(STRING: query_string)
205             sub process_query {
206 13     13 0 45 my ( $self, %params ) = @_;
207              
208 13         19 my $query_string = $params{query_string};
209 13         19 my $method = $params{method};
210              
211 13 50       29 confess "Empty query string" unless $query_string;
212              
213 13 50       30 my $answer = $self->{fake_answer} ? $self->{fake_answer} : $self->mk_query_to_server( $method, $query_string, $params{params} );
214 13 50       31 carp $answer if $self->{debug};
215              
216 13         34 return $answer;
217             }
218              
219             # Make request to server and get answer
220             # STATIC (STRING: query_string)
221             sub mk_query_to_server {
222 0     0 0   my ( $self, $method, $url, $params ) = @_;
223            
224 0 0         unless ( $method ~~ [ qw( POST GET ) ] ) {
225 0           confess "Unknown request method: '$method'";
226             }
227              
228 0 0         confess "URL is empty" unless $url;
229              
230 0           my $content;
231 0           my $ua = LWP::UserAgent->new;
232 0           my $request = HTTP::Request->new( $method, $url );
233            
234 0 0         if ( $method eq 'GET' ) {
235 0           my $response = $ua->request( $request );
236 0           $content = $response->content;
237             }
238             else { # Temporary URL for making request
239 0           my $temp_uri = URI->new('http:');
240 0           $temp_uri->query_form( $params );
241 0           $request->content( $temp_uri->query );
242 0           $request->content_type('application/x-www-form-urlencoded');
243 0           my $response = $ua->request($request);
244 0           $content = $response->content;
245             }
246            
247 0 0         warn "Answer: " . $content if $self->{debug};
248            
249 0 0         return $content if $params->{noparse};
250 0           return $self->parse_answer($content);
251             }
252              
253             # Parse answer
254             sub parse_answer {
255 0     0 0   my ($self, $response) = @_;
256              
257 0 0         return '' unless $response;
258            
259 0           my %answer;
260 0           $response =~ s/<br>|&#\d+//ig; # Some trash from answer
261 0           $response =~ s/\n+/\n/ig;
262 0           my @params = split /&/, $response;
263            
264 0           foreach my $param ( @params ) {
265 0           my ($key, $value) = split /=/, $param;
266 0 0         if ( $key =~ /(.*)\[\]/ ) { # lists
267 0           push @{ $answer{$1} }, $value;
  0            
268             }
269             else {
270 0           $answer{$key} = $value;
271             }
272             }
273              
274 0   0       return \%answer || '';
275             }
276              
277             1;
278              
279             __END__