File Coverage

blib/lib/WebService/MIAB.pm
Criterion Covered Total %
statement 32 115 27.8
branch 0 30 0.0
condition 0 24 0.0
subroutine 11 25 44.0
pod 11 12 91.6
total 54 206 26.2


line stmt bran cond sub pod time code
1             package WebService::MIAB;
2              
3 1     1   66915 use 5.006;
  1         4  
4 1     1   6 use strict;
  1         2  
  1         21  
5 1     1   5 use warnings;
  1         2  
  1         45  
6              
7             =head1 NAME
8              
9             WebService::MIAB - manage emails (users) and alias addresses on a mail-in-a-box server
10              
11             =head1 VERSION
12              
13             version 0.03
14              
15             =cut
16              
17 1     1   485 use version;
  1         1826  
  1         5  
18             our $VERSION = '0.03';
19              
20 1     1   626 use Moo;
  1         11246  
  1         4  
21             with 'WebService::Client';
22              
23 1     1   2133 use LWP::UserAgent;
  1         47743  
  1         39  
24 1     1   528 use MIME::Base64;
  1         623  
  1         63  
25 1     1   7 use Carp qw(croak);
  1         2  
  1         46  
26 1     1   7 use re qw(is_regexp);
  1         8  
  1         154  
27 1     1   581 use List::MoreUtils qw(uniq);
  1         12314  
  1         6  
28              
29 1     1   1714 use JSON;
  1         9766  
  1         7  
30             my $json = JSON->new->allow_nonref;
31              
32             #Alias_Address
33             has alias_get_uri => ( is => 'ro', default => '/mail/aliases?format=json' );
34             has alias_add_uri => ( is => 'ro', default => '/mail/aliases/add' );
35             has alias_remove_uri => ( is => 'ro', default => '/mail/aliases/remove' );
36              
37             #User_Address
38             has user_get_uri => ( is => 'ro', default => '/mail/users?format=json');
39             has user_add_uri => ( is => 'ro', default => '/mail/users/add' );
40             has user_remove_uri => ( is => 'ro', default => '/mail/users/remove' );
41              
42             #General
43             has host => (is => 'ro', required => 1);
44             has pass => ( is => 'ro', required => 1 );
45             has username => ( is => 'ro', required => 1 );
46             has '+base_url' => (
47             is => 'ro',
48             lazy => 1,
49             builder => sub {
50 0     0     my ($self) = @_;
51 0           return 'https://'.$self->host.'/admin';
52             },
53             );
54              
55             # custom deserializer needed as the MIAB webservice doesn't return JSON for post requests
56             has '+deserializer' => (
57             is => 'ro',
58             lazy => 1,
59             default => sub {
60             my $self = shift;
61             my $usejson = $self->json;
62             sub {
63             my ($res, %args) = @_;
64             my $decoded = $res;
65              
66             if ($res->request->uri =~ /json/) {
67             $decoded = $json->decode($res->content);
68             }
69             # else {
70             # # no json request - nothing to do
71             # }
72             return $decoded;
73             }
74             },
75             );
76              
77              
78             sub BUILD(){
79 0     0 0   my ($self) = @_;
80 0           my $empty = q{};
81 0           my $colon = q{:};
82 0           return $self->ua->default_header('Authorization' => 'Basic '.encode_base64($self->username.$colon.$self->pass , $empty));
83             }
84              
85              
86             =head1 SYNOPSIS
87              
88             use WebService::MIAB;
89              
90             my $miab = WebService::MIAB->new(
91             username => 'adminuser@domain.com',
92             pass => 'adminpasswd',
93             host => 'domain.com',
94             );
95              
96             my $users = $miab->get_users();
97             my $result = $miab>create_user({
98             email => 'bart.simpson@domain.com',
99             password => 'EatMyShorts',
100             });
101              
102             =head1 DESCRIPTION
103              
104             WebService::MIAB is a Perl module that manages user and alias addresses on a
105             Mail-in-a-box (MIAB) server.
106              
107             You can list, create and remove user and alias addresses.
108              
109             The API methods to the DNS system of MIAB is not implemented, yet.
110             Patches are welcome.
111              
112             =head1 METHODES
113              
114             =head2 User methods
115              
116             The user methods are to handle plain email adresses on a MIAB server.
117             Each email address is a user and has (limited) access to the MIAB server.
118              
119             =head3 get_users
120              
121             Returns all defined users in JSON format.
122              
123             my $users = $miab->get_users();
124              
125             =cut
126              
127              
128             sub get_users{
129 0     0 1   my ($self) = @_;
130              
131 0           my $result = $self->get($self->user_get_uri);
132              
133 0           return $result;
134             }
135              
136              
137             =head3 create_user
138              
139             Creates a new user account. Expects the email address and the password in
140             the parameter hash.
141             Returns the answer from the webservice.
142              
143             my $result = $miab->create_user({
144             email => 'bart.simpson@springfield.com',
145             password => 'EatMyShorts'
146             });
147              
148             =cut
149              
150              
151             sub create_user{
152 0     0 1   my ($self, $param) = @_;
153              
154             my $result = $self->post($self->user_add_uri,
155             {
156             email => $param->{email},
157             password => $param->{password},
158             },
159 0           headers => { 'Content-Type' => 'application/x-www-form-urlencoded' },
160             );
161              
162 0           return $result;
163             }
164              
165              
166             =head3 remove_user
167              
168             Removes the email user account. Expects the email address in the parameter hash.
169             Returns the answer from the webservice.
170              
171             my result = $miab->remove_user({
172             email => bart.simpson@springfield.com
173             });
174              
175             =cut
176              
177              
178             sub remove_user{
179 0     0 1   my ($self, $param) = @_;
180              
181             my $result = $self->post($self->user_remove_uri,
182             {
183             email => $param->{email},
184             },
185 0           headers => { 'Content-Type' => 'application/x-www-form-urlencoded' },
186             );
187              
188 0           return $result;
189             }
190              
191              
192             =head3 find_user
193              
194             Returns a list of users records matching its forward_to record
195             to the given email_pattern and domain_pattern. The pattern can be a string
196             that is evaluated to a regexp or a regexp.
197              
198             my @users = $miab->find_user('email_pattern', qr/example.com/)
199              
200             =cut
201              
202              
203             sub find_user {
204 0     0 1   my ($self, $email_pattern, $domain_pattern) = @_;
205              
206 0           my @result;
207 0 0         if ( !is_regexp($email_pattern) ) {
208 0           $email_pattern = qr/$email_pattern/mxs;
209             }
210 0 0 0       if ($domain_pattern && !is_regexp($domain_pattern)) {
211 0           $domain_pattern = qr/$domain_pattern/mxs;
212             }
213              
214 0           my $users = $self->get_users();
215 0           foreach ( @{$users} ) {
  0            
216 0 0 0       if (!$domain_pattern || $_->{'domain'} =~ $domain_pattern) {
217 0           foreach (@{$_->{'users'}}) {
  0            
218 0           my $value = $_->{'email'};
219              
220             # filter list
221             push( @result,
222             grep {
223 0 0         $_ && $_ =~ $email_pattern
224             } ($value && 'ARRAY' eq ref $value)
225 0 0 0       ? @{$value}
  0            
226             : ( $value )
227             );
228             }
229             }
230             }
231              
232 0           return @result;
233             }
234              
235              
236             =head2 Alias methods
237              
238             =head3 get_aliases
239              
240             Returns all aliases in JSON format.
241              
242             my $aliases = $miab->get_aliases();
243              
244             =cut
245              
246              
247             sub get_aliases{
248 0     0 1   my ($self) = @_;
249              
250 0           my $result = $self->get($self->alias_get_uri);
251              
252 0           return $result;
253             }
254              
255              
256             =head3 get_domains
257              
258             Returns a list of all domains used in alias adresses.
259              
260             my @domains = $miab->get_domains();
261              
262             =cut
263              
264              
265             sub get_domains{
266 0     0 1   my ($self) = @_;
267              
268 0           my $aliases = $self->get_aliases();
269              
270 0           my @result;
271             map {
272 0           push( @result, $_->{'domain'} );
273 0           } @{$aliases};
  0            
274              
275 0           return (uniq @result);
276             }
277              
278              
279             =head3 find_forward_to_aliases
280              
281             Returns a list of alias records matching its forward_to record
282             to the given alias_pattern and domain_pattern. The pattern can be a string
283             that is evaluated to a regexp or a regexp.
284              
285             my @aliases = $miab->find_forward_to_aliases('alias_pattern', qr/example.com/);
286              
287             =cut
288              
289              
290             sub find_forward_to_aliases {
291 0     0 1   my ($self, $alias_pattern, $domain_pattern) = @_;
292              
293 0           return $self->_find_aliases_generic('forwards_to', $alias_pattern, $domain_pattern);
294             }
295              
296              
297             =head3 find_permitted_sender_aliases
298              
299             Returns a list of alias records matching its permitted_sender record
300             to the given alias_pattern and domain_pattern. The pattern can be a string
301             that is evaluated to a regexp or a regexp.
302              
303             my @aliases = $miab->find_permitted_sender_aliases('alias_pattern', qr/example.com/);
304              
305             =cut
306              
307              
308             sub find_permitted_sender_aliases {
309 0     0 1   my ($self, $alias_pattern, $domain_pattern) = @_;
310              
311 0           return $self->_find_aliases_generic('permitted_senders', $alias_pattern, $domain_pattern);
312             }
313              
314              
315             =head3 find_aliases
316              
317             Returns a list of alias records matching its address record the given
318             alias_pattern and domain_pattern. The pattern can be a string that is
319             evaluated to a regexp or a regexp.
320              
321             my @aliases = $miab->find_aliases('alias_pattern', qr/example.com/);
322              
323             =cut
324              
325              
326             sub find_aliases {
327 0     0 1   my ($self, $alias_pattern, $domain_pattern) = @_;
328              
329 0           return $self->_find_aliases_generic('address', $alias_pattern, $domain_pattern);
330             }
331              
332              
333             =head3 create_alias
334              
335             Creates a new alias address.
336              
337             $miab->create_alias({
338             address => 'bart.simpson@springfield.com',
339             forwards_to => ['lisa.simpson@springfield.com','Maggie.simpson@springfield.com'],
340             permitted_senders => ['Homer.simpson@springfield.com','Marge.simpson@springfield.com'],
341             });
342              
343             =cut
344              
345              
346             sub create_alias{
347 0     0 1   my ($self, $param) = @_;
348 0           my $empty = q{};
349 0           my $point = q{,};
350              
351 0 0 0       if (defined $param->{forwards_to} && ref $param->{forwards_to} ne 'ARRAY'){
352 0           $param->{forwards_to} = [$param->{forwards_to}];
353             }
354 0 0 0       if (defined $param->{permitted_senders} && ref $param->{permitted_senders} ne 'ARRAY'){
355 0           $param->{permitted_senders} = [$param->{permitted_senders}];
356             }
357              
358             my $forward_address_for_request = defined $param->{forwards_to}
359 0 0         ? join ($point, @{$param->{forwards_to}})
  0            
360             : $empty;
361             my $permitted_senders_for_request = defined $param->{permitted_senders}
362 0 0         ? join ($point, @{$param->{permitted_senders}})
  0            
363             : $empty;
364              
365             # One alias parameter must exist
366 0 0         if(!length($forward_address_for_request.$permitted_senders_for_request)){
367 0           croak 'forwards_to or permitted_sender are required';
368             }
369              
370             my $result = $self->post($self->alias_add_uri,
371             {
372             address => $param->{address},
373 0           forwards_to => $forward_address_for_request,
374             permitted_senders => $permitted_senders_for_request,
375             },
376             headers => { 'Content-Type' => 'application/x-www-form-urlencoded' },
377             );
378 0           return $result;
379             }
380              
381              
382             =head3 remove_alias
383              
384             Permanently deletes an alias address.
385              
386             $miab->remove_alias({
387             address => bart.simpson@springfield.com
388             });
389              
390             =cut
391              
392             sub remove_alias{
393 0     0 1   my ($self, $param) = @_;
394             my $result = $self->post($self->alias_remove_uri,
395             {
396             address => $param->{address},
397             },
398 0           headers => { 'Content-Type' => 'application/x-www-form-urlencoded' }
399             );
400              
401 0           return $result;
402             }
403              
404              
405             sub _find_aliases_generic {
406 0     0     my ($self, $param_name, $alias_pattern, $domain_pattern) = @_;
407 0           my @result;
408              
409             # force patterns to be a regex
410 0 0         if (!is_regexp($alias_pattern)) {
411 0           $alias_pattern = qr/$alias_pattern/mxs;
412             }
413 0 0 0       if ($domain_pattern && !is_regexp($domain_pattern)) {
414 0           $domain_pattern = qr/$domain_pattern/mxs;
415             }
416              
417             # get all aliases
418 0           my $aliases = $self->get_aliases();
419              
420             # filter
421 0           foreach (@{$aliases}) {
  0            
422 0 0 0       if (!$domain_pattern || $_->{'domain'} =~ $domain_pattern)
423             {
424             # either $domain_pattern is undefined (param not given)
425             # or the current domain matched the given $domain_pattern
426              
427 0           foreach (@{$_->{'aliases'}}) {
  0            
428 0           my $value = $_->{$param_name};
429              
430             # filter list
431             push( @result,
432             grep {
433 0 0         $_ && $_ =~ $alias_pattern
434             } ($value && 'ARRAY' eq ref $value)
435 0 0 0       ? @{$value}
  0            
436             : ( $value )
437             );
438             }
439             }
440             }
441 0           return @result;
442             }
443              
444             =head1 BUGS
445              
446             Please report any bugs or feature requests to C, or through
447             the web interface at L. I will be notified, and then you'll
448             automatically be notified of progress on your bug as I make changes.
449              
450              
451             =head1 SUPPORT
452              
453             You can find documentation for this module with the perldoc command.
454              
455             perldoc WebService::MIAB
456              
457              
458             You can also look for information at:
459              
460             =over 4
461              
462             =item * RT: CPAN's request tracker (report bugs here)
463              
464             L
465              
466             =item * AnnoCPAN: Annotated CPAN documentation
467              
468             L
469              
470             =item * CPAN Ratings
471              
472             L
473              
474             =item * Search CPAN
475              
476             L
477              
478             =back
479              
480              
481             =head1 AUTHORS
482              
483             Alexander Scneider C, Mario Minati
484             C.
485              
486             Currently maintained by Alexander Scneider C
487              
488              
489             =head1 LICENSE AND COPYRIGHT
490              
491             Copyright 2018 Alexander Scneider C, Mario Minati
492             C.
493              
494             This program is free software; you can redistribute it and/or modify it
495             under the terms of the the Artistic License (2.0). You may obtain a
496             copy of the full license at:
497              
498             L
499              
500             Any use, modification, and distribution of the Standard or Modified
501             Versions is governed by this Artistic License. By using, modifying or
502             distributing the Package, you accept this license. Do not use, modify,
503             or distribute the Package, if you do not accept this license.
504              
505             If your Modified Version has been derived from a Modified Version made
506             by someone other than you, you are nevertheless required to ensure that
507             your Modified Version complies with the requirements of this license.
508              
509             This license does not grant you the right to use any trademark, service
510             mark, tradename, or logo of the Copyright Holder.
511              
512             This license includes the non-exclusive, worldwide, free-of-charge
513             patent license to make, have made, use, offer to sell, sell, import and
514             otherwise transfer the Package with respect to any patent claims
515             licensable by the Copyright Holder that are necessarily infringed by the
516             Package. If you institute patent litigation (including a cross-claim or
517             counterclaim) against any party alleging that the Package constitutes
518             direct or contributory patent infringement, then this Artistic License
519             to you shall terminate on the date that such litigation is filed.
520              
521             Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER
522             AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES.
523             THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
524             PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY
525             YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR
526             CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR
527             CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE,
528             EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
529              
530              
531             =cut
532              
533             1; # End of WebService::MIAB