File Coverage

blib/lib/WebService/Mailgun.pm
Criterion Covered Total %
statement 137 167 82.0
branch 21 38 55.2
condition 5 9 55.5
subroutine 33 39 84.6
pod 17 24 70.8
total 213 277 76.9


line stmt bran cond sub pod time code
1             package WebService::Mailgun;
2              
3              
4 5     5   298868 use 5.008001;
  5         60  
5 5     5   26 use strict;
  5         12  
  5         97  
6 5     5   21 use warnings;
  5         12  
  5         116  
7              
8 5     5   3038 use Furl;
  5         144908  
  5         160  
9 5     5   3527 use JSON;
  5         53036  
  5         41  
10 5     5   4704 use URI;
  5         22690  
  5         152  
11 5     5   2801 use Try::Tiny;
  5         10752  
  5         284  
12 5     5   38 use Carp;
  5         11  
  5         226  
13 5     5   2692 use HTTP::Request::Common;
  5         100954  
  5         416  
14 5     5   4404 use File::Temp;
  5         90067  
  5         603  
15              
16              
17             our $VERSION = "0.16";
18             our $API_BASE = 'api.mailgun.net/v3';
19             our $API_BASE_EU = 'api.eu.mailgun.net/v3';
20              
21             use Class::Accessor::Lite (
22 5         66 new => 1,
23             rw => [qw(api_key domain RaiseError region)],
24             ro => [qw(error error_status)],
25 5     5   44 );
  5         12  
26              
27             sub decode_response {
28 24     24 0 133 my ($self, $res) = @_;
29              
30 24 100       171 if ($res->is_success) {
31 22         544 return decode_json $res->content;
32             } else {
33 2         36 my $json;
34             try {
35 2     2   354 $json = decode_json $res->content;
36             } catch {
37 1     1   81 $json = { message => $res->content };
38 2         42 };
39 2         72 $self->{error} = $json->{message};
40 2         14 $self->{error_status} = $res->status_line;
41 2 100       48 if ($self->RaiseError) {
42 1         10 carp $self->error;
43 1         622 croak $self->error_status;
44             } else {
45 1         85 return;
46             }
47             }
48             }
49              
50             sub recursive {
51 3     3 0 21 my ($self, $method, $query, $key, $api_uri) = @_;
52              
53 3   50     38 $query //= {};
54 3   50     24 $key //= 'items';
55 3         11 my @result;
56             my $previous;
57 3 50       14 unless($api_uri) {
58 3         19 $api_uri = URI->new($self->api_url($method));
59 3         12551 $api_uri->query_form($query);
60             }
61              
62 3         462 while (1) {
63 6         589 my $res = $self->client->get($api_uri->as_string);
64 6         1022377 my $json = $self->decode_response($res);
65 6 100 50     454 unless($json && scalar @{$json->{$key}}) {
  6         64  
66             try {
67 3     3   627 $previous = URI->new($json->{paging}->{previous});
68 3         580 $previous->userinfo('api:'.$self->api_key);
69 3     0   72 } catch {};
70 3         609 last;
71             }
72 3         10 push @result, @{$json->{$key}};
  3         15  
73 3         33 $api_uri = URI->new($json->{paging}->{next});
74 3         503 $api_uri->userinfo('api:'.$self->api_key);
75             }
76              
77 3         41 return \@result, $previous;
78             }
79              
80             sub client {
81 24     24 0 115 my $self = shift;
82              
83 24   66     300 $self->{_client} //= Furl->new(
84             agent => __PACKAGE__ . '/' . $VERSION,
85             );
86             }
87              
88             sub api_base {
89 21     21 0 265 my ($self) = @_;
90              
91 21 50       114 if ($self->region) {
92 0 0       0 if (lc($self->region) eq "eu") {
    0          
93 0         0 return $API_BASE_EU;
94             } elsif (lc($self->region) ne "us") {
95 0         0 die "unsupported region '" . $self->region ."'";
96             }
97             }
98 21         480 return $API_BASE;
99             }
100              
101             sub api_url {
102 15     15 0 131 my ($self, $method) = @_;
103              
104 15         84 sprintf 'https://api:%s@%s/%s',
105             $self->api_key, $self->api_base, $method;
106             }
107              
108             sub domain_api_url {
109 6     6 0 22 my ($self, $method) = @_;
110              
111 6         42 sprintf 'https://api:%s@%s/%s/%s',
112             $self->api_key, $self->api_base, $self->domain, $method;
113             }
114              
115             sub message {
116 5     5 1 8064 my ($self, $args) = @_;
117              
118 5         16 my @content;
119 5 100       41 if (ref($args) eq 'HASH') {
    100          
120 2         10 @content = %$args;
121             }
122             elsif (ref($args) eq 'ARRAY') {
123 1         10 @content = @$args;
124             }
125             else {
126 2         47 die 'unsupport argument. message() need HashRef or ArrayRef.';
127             }
128              
129 3         22 my $req = POST $self->domain_api_url('messages'), Content_type => 'form-data', Content => \@content;
130              
131 3         48443 my $res = $self->client->request($req);
132 3         894374 $self->decode_response($res);
133             }
134              
135              
136              
137             sub mime {
138            
139 3     3 1 5490 my ($self, $args) = @_;
140              
141 3 50       29 if (ref($args) eq 'HASH') {
142             # Well, good!
143             }
144             else {
145 0         0 die 'unsupport argument. mime() needs a hash ref.';
146             }
147            
148            
149 3         8 my $tmp = undef;
150              
151 3 100       30 if(exists($args->{message})){
    50          
152 2         22 $tmp = File::Temp->new();
153            
154 2 100       1552 if(ref $args->{message} eq 'SCALAR'){
155             # save from a ref
156 1         5 print $tmp ${$args->{message}};
  1         21  
157 1         75 seek $tmp, 0, 0;
158             }
159             else {
160             # Save from a string
161 1         9 print $tmp $args->{message};
162 1         60 seek $tmp, 0, 0;
163             }
164 2         17 $args->{message} = [$tmp->filename];
165             }
166             elsif(exists($args->{file})){
167 1 50       41 if(-f $args->{file}){
168 1         9 $args->{message} = [$args->{file}];
169 1         7 delete $args->{file};
170             }
171             else {
172 0         0 die "cannot find file, " . $args->{file};
173             }
174             }
175            
176             # Put it back together:
177 3         48 my @content = %$args;
178              
179 3         17 my $req = POST $self->domain_api_url('messages.mime'),
180             Content_Type => 'form-data',
181             Content => \@content;
182            
183 3         33107 my $res = $self->client->request($req);
184            
185 3         841785 undef $tmp;
186            
187 3         1358 $self->decode_response($res);
188              
189             }
190              
191              
192              
193              
194             sub lists {
195 1     1 1 862 my $self = shift;
196              
197 1         7 return $self->recursive('lists/pages');
198             }
199              
200             sub add_list {
201 1     1 1 1865 my ($self, $args) = @_;
202              
203 1         7 my $res = $self->client->post($self->api_url("lists"), [], $args);
204 1         415125 $self->decode_response($res);
205             }
206              
207             sub list {
208 3     3 1 2691 my ($self, $address) = @_;
209              
210 3         17 my $res = $self->client->get($self->api_url("lists/$address"));
211 3 50       316002 my $json = $self->decode_response($res) or return;
212 2         91 return $json->{list};
213             }
214              
215             sub update_list {
216 1     1 1 6197 my ($self, $address, $args) = @_;
217              
218 1         8 my $res = $self->client->put($self->api_url("lists/$address"), [], $args);
219 1         109188 $self->decode_response($res);
220             }
221              
222             sub delete_list {
223 1     1 1 5729 my ($self, $address) = @_;
224              
225 1         11 my $res = $self->client->delete($self->api_url("lists/$address"));
226 1         117345 $self->decode_response($res);
227             }
228              
229             sub list_members {
230 2     2 1 2396 my ($self, $address) = @_;
231              
232 2         28 return $self->recursive("lists/$address/members/pages");
233             }
234              
235             sub add_list_member {
236 1     1 1 6575 my ($self, $address, $args) = @_;
237              
238 1         8 my $res = $self->client->post(
239             $self->api_url("lists/$address/members"), [], $args);
240 1         115748 $self->decode_response($res);
241             }
242              
243             sub add_list_members {
244 1     1 1 1116 my ($self, $address, $args) = @_;
245              
246 1         7 my $res = $self->client->post(
247             $self->api_url("lists/$address/members.json"), [], $args);
248 1         131635 $self->decode_response($res);
249             }
250              
251             sub list_member {
252 2     2 1 2474 my ($self, $address, $member) = @_;
253              
254 2         20 my $res = $self->client->get($self->api_url("lists/$address/members/$member"));
255 2 50       219036 my $json = $self->decode_response($res) or return;
256 2         91 return $json->{member};
257             }
258              
259             sub update_list_member {
260 1     1 1 6853 my ($self, $address, $member, $args) = @_;
261              
262 1         8 my $res = $self->client->put(
263             $self->api_url("lists/$address/members/$member"), [], $args);
264 1         111450 $self->decode_response($res);
265             }
266              
267             sub delete_list_member {
268 1     1 0 6074 my ($self, $address, $member) = @_;
269              
270 1         9 my $res = $self->client->delete(
271             $self->api_url("lists/$address/members/$member"));
272 1         523432 $self->decode_response($res);
273             }
274              
275             sub event {
276 0     0 1   my ($self, $query) = @_;
277              
278 0           my $api_url = URI->new($self->domain_api_url("events"));
279 0           $api_url->query_form($query);
280 0           return $self->recursive("events", {}, "items", $api_url);
281             }
282              
283             sub get_message_from_event {
284 0     0 1   my ($self, $event) = @_;
285              
286 0 0         die "invalid event! this method need 'stored' event only." if $event->{event} ne 'stored';
287 0           my $uri = URI->new($event->{storage}->{url});
288 0           $uri->userinfo('api:'.$self->api_key);
289              
290 0           my $res = $self->client->get($uri->as_string);
291 0           $self->decode_response($res);
292             }
293              
294             sub delete_templates {
295 0     0 1   my ($self) = @_;
296              
297 0           my $res = $self->client->delete($self->domain_api_url("templates"));
298 0           $self->decode_response($res);
299             }
300              
301             sub delete_template {
302 0     0 1   my ($self, $name) = @_;
303              
304 0           my $res = $self->client->delete(
305             $self->domain_api_url("templates/$name"));
306 0           $self->decode_response($res);
307             }
308              
309             sub add_template {
310 0     0 1   my ($self, $args) = @_;
311              
312 0           my @content;
313 0 0         if (ref($args) eq 'HASH') {
    0          
314 0           @content = %$args;
315             }
316             elsif (ref($args) eq 'ARRAY') {
317 0           @content = @$args;
318             }
319             else {
320 0           die 'unsupport argument. add_template() need HashRef or ArrayRef.';
321             }
322              
323 0           my $req = POST $self->domain_api_url('templates'), Content_type => 'form-data', Content => \@content;
324              
325 0           my $res = $self->client->request($req);
326 0           $self->decode_response($res);
327             }
328              
329             1;
330             __END__