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   246057 use 5.008001;
  5         55  
5 5     5   22 use strict;
  5         7  
  5         97  
6 5     5   19 use warnings;
  5         7  
  5         103  
7              
8 5     5   2092 use Furl;
  5         118831  
  5         137  
9 5     5   2751 use JSON;
  5         42669  
  5         25  
10 5     5   3716 use URI;
  5         18673  
  5         152  
11 5     5   2730 use Try::Tiny;
  5         8787  
  5         258  
12 5     5   29 use Carp;
  5         13  
  5         194  
13 5     5   2159 use HTTP::Request::Common;
  5         64913  
  5         353  
14 5     5   3298 use File::Temp;
  5         76395  
  5         508  
15              
16              
17             our $VERSION = "0.15";
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         51 new => 1,
23             rw => [qw(api_key domain RaiseError region)],
24             ro => [qw(error error_status)],
25 5     5   36 );
  5         19  
26              
27             sub decode_response {
28 24     24 0 114 my ($self, $res) = @_;
29              
30 24 100       224 if ($res->is_success) {
31 22         408 return decode_json $res->content;
32             } else {
33 2         27 my $json;
34             try {
35 2     2   244 $json = decode_json $res->content;
36             } catch {
37 1     1   54 $json = { message => $res->content };
38 2         34 };
39 2         56 $self->{error} = $json->{message};
40 2         11 $self->{error_status} = $res->status_line;
41 2 100       37 if ($self->RaiseError) {
42 1         11 carp $self->error;
43 1         559 croak $self->error_status;
44             } else {
45 1         56 return;
46             }
47             }
48             }
49              
50             sub recursive {
51 3     3 0 12 my ($self, $method, $query, $key, $api_uri) = @_;
52              
53 3   50     24 $query //= {};
54 3   50     18 $key //= 'items';
55 3         6 my @result;
56             my $previous;
57 3 50       10 unless($api_uri) {
58 3         13 $api_uri = URI->new($self->api_url($method));
59 3         8171 $api_uri->query_form($query);
60             }
61              
62 3         248 while (1) {
63 6         479 my $res = $self->client->get($api_uri->as_string);
64 6         1321551 my $json = $self->decode_response($res);
65 6 100 50     395 unless($json && scalar @{$json->{$key}}) {
  6         57  
66             try {
67 3     3   829 $previous = URI->new($json->{paging}->{previous});
68 3         501 $previous->userinfo('api:'.$self->api_key);
69 3     0   67 } catch {};
70 3         425 last;
71             }
72 3         11 push @result, @{$json->{$key}};
  3         10  
73 3         33 $api_uri = URI->new($json->{paging}->{next});
74 3         493 $api_uri->userinfo('api:'.$self->api_key);
75             }
76              
77 3         35 return \@result, $previous;
78             }
79              
80             sub client {
81 24     24 0 65 my $self = shift;
82              
83 24   66     309 $self->{_client} //= Furl->new(
84             agent => __PACKAGE__ . '/' . $VERSION,
85             );
86             }
87              
88             sub api_base {
89 21     21 0 179 my ($self) = @_;
90              
91 21 50       105 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         348 return $API_BASE;
99             }
100              
101             sub api_url {
102 15     15 0 111 my ($self, $method) = @_;
103              
104 15         63 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 16 my ($self, $method) = @_;
110              
111 6         37 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 7096 my ($self, $args) = @_;
117              
118 5         15 my @content;
119 5 100       39 if (ref($args) eq 'HASH') {
    100          
120 2         10 @content = %$args;
121             }
122             elsif (ref($args) eq 'ARRAY') {
123 1         8 @content = @$args;
124             }
125             else {
126 2         35 die 'unsupport argument. message() need HashRef or ArrayRef.';
127             }
128              
129 3         15 my $req = POST $self->domain_api_url('messages'), Content_type => 'form-data', Content => \@content;
130              
131 3         38639 my $res = $self->client->request($req);
132 3         1711413 $self->decode_response($res);
133             }
134              
135              
136              
137             sub mime {
138            
139 3     3 1 3182 my ($self, $args) = @_;
140              
141 3 50       15 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         5 my $tmp = undef;
150              
151 3 100       11 if(exists($args->{message})){
    50          
152 2         17 $tmp = File::Temp->new();
153            
154 2 100       1167 if(ref $args->{message} eq 'SCALAR'){
155             # save from a ref
156 1         3 print $tmp ${$args->{message}};
  1         8  
157 1         60 seek $tmp, 0, 0;
158             }
159             else {
160             # Save from a string
161 1         6 print $tmp $args->{message};
162 1         53 seek $tmp, 0, 0;
163             }
164 2         15 $args->{message} = [$tmp->filename];
165             }
166             elsif(exists($args->{file})){
167 1 50       32 if(-f $args->{file}){
168 1         6 $args->{message} = [$args->{file}];
169 1         4 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         29 my @content = %$args;
178              
179 3         13 my $req = POST $self->domain_api_url('messages.mime'),
180             Content_Type => 'form-data',
181             Content => \@content;
182            
183 3         25582 my $res = $self->client->request($req);
184            
185 3         1171275 undef $tmp;
186            
187 3         6325 $self->decode_response($res);
188              
189             }
190              
191              
192              
193              
194             sub lists {
195 1     1 1 662 my $self = shift;
196              
197 1         7 return $self->recursive('lists/pages');
198             }
199              
200             sub add_list {
201 1     1 1 1520 my ($self, $args) = @_;
202              
203 1         7 my $res = $self->client->post($self->api_url("lists"), [], $args);
204 1         914355 $self->decode_response($res);
205             }
206              
207             sub list {
208 3     3 1 1932 my ($self, $address) = @_;
209              
210 3         17 my $res = $self->client->get($self->api_url("lists/$address"));
211 3 50       483355 my $json = $self->decode_response($res) or return;
212 2         87 return $json->{list};
213             }
214              
215             sub update_list {
216 1     1 1 3170 my ($self, $address, $args) = @_;
217              
218 1         6 my $res = $self->client->put($self->api_url("lists/$address"), [], $args);
219 1         164061 $self->decode_response($res);
220             }
221              
222             sub delete_list {
223 1     1 1 2589 my ($self, $address) = @_;
224              
225 1         7 my $res = $self->client->delete($self->api_url("lists/$address"));
226 1         192067 $self->decode_response($res);
227             }
228              
229             sub list_members {
230 2     2 1 1247 my ($self, $address) = @_;
231              
232 2         15 return $self->recursive("lists/$address/members/pages");
233             }
234              
235             sub add_list_member {
236 1     1 1 3503 my ($self, $address, $args) = @_;
237              
238 1         8 my $res = $self->client->post(
239             $self->api_url("lists/$address/members"), [], $args);
240 1         173037 $self->decode_response($res);
241             }
242              
243             sub add_list_members {
244 1     1 1 662 my ($self, $address, $args) = @_;
245              
246 1         6 my $res = $self->client->post(
247             $self->api_url("lists/$address/members.json"), [], $args);
248 1         179283 $self->decode_response($res);
249             }
250              
251             sub list_member {
252 2     2 1 2218 my ($self, $address, $member) = @_;
253              
254 2         28 my $res = $self->client->get($self->api_url("lists/$address/members/$member"));
255 2 50       341140 my $json = $self->decode_response($res) or return;
256 2         99 return $json->{member};
257             }
258              
259             sub update_list_member {
260 1     1 1 6848 my ($self, $address, $member, $args) = @_;
261              
262 1         11 my $res = $self->client->put(
263             $self->api_url("lists/$address/members/$member"), [], $args);
264 1         168723 $self->decode_response($res);
265             }
266              
267             sub delete_list_member {
268 1     1 0 3305 my ($self, $address, $member) = @_;
269              
270 1         5 my $res = $self->client->delete(
271             $self->api_url("lists/$address/members/$member"));
272 1         491036 $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__