File Coverage

blib/lib/WebService/Mailgun.pm
Criterion Covered Total %
statement 137 152 90.1
branch 21 34 61.7
condition 5 9 55.5
subroutine 33 36 91.6
pod 14 21 66.6
total 210 252 83.3


line stmt bran cond sub pod time code
1             package WebService::Mailgun;
2              
3              
4 5     5   297232 use 5.008001;
  5         63  
5 5     5   25 use strict;
  5         11  
  5         120  
6 5     5   24 use warnings;
  5         10  
  5         120  
7              
8 5     5   2477 use Furl;
  5         144668  
  5         177  
9 5     5   3356 use JSON;
  5         51436  
  5         28  
10 5     5   4455 use URI;
  5         22891  
  5         168  
11 5     5   3115 use Try::Tiny;
  5         11133  
  5         305  
12 5     5   37 use Carp;
  5         10  
  5         232  
13 5     5   2583 use HTTP::Request::Common;
  5         79773  
  5         464  
14 5     5   4005 use File::Temp;
  5         94125  
  5         594  
15              
16              
17             our $VERSION = "0.14";
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         62 new => 1,
23             rw => [qw(api_key domain RaiseError region)],
24             ro => [qw(error error_status)],
25 5     5   43 );
  5         11  
26              
27             sub decode_response {
28 24     24 0 101 my ($self, $res) = @_;
29              
30 24 100       154 if ($res->is_success) {
31 22         347 return decode_json $res->content;
32             } else {
33 2         50 my $json;
34             try {
35 2     2   312 $json = decode_json $res->content;
36             } catch {
37 1     1   56 $json = { message => $res->content };
38 2         39 };
39 2         81 $self->{error} = $json->{message};
40 2         12 $self->{error_status} = $res->status_line;
41 2 100       37 if ($self->RaiseError) {
42 1         11 carp $self->error;
43 1         852 croak $self->error_status;
44             } else {
45 1         50 return;
46             }
47             }
48             }
49              
50             sub recursive {
51 3     3 0 13 my ($self, $method, $query, $key, $api_uri) = @_;
52              
53 3   50     24 $query //= {};
54 3   50     19 $key //= 'items';
55 3         6 my @result;
56             my $previous;
57 3 50       10 unless($api_uri) {
58 3         15 $api_uri = URI->new($self->api_url($method));
59 3         9202 $api_uri->query_form($query);
60             }
61              
62 3         266 while (1) {
63 6         432 my $res = $self->client->get($api_uri->as_string);
64 6         1579249 my $json = $self->decode_response($res);
65 6 100 50     429 unless($json && scalar @{$json->{$key}}) {
  6         50  
66             try {
67 3     3   445 $previous = URI->new($json->{paging}->{previous});
68 3         395 $previous->userinfo('api:'.$self->api_key);
69 3     0   63 } catch {};
70 3         379 last;
71             }
72 3         10 push @result, @{$json->{$key}};
  3         13  
73 3         27 $api_uri = URI->new($json->{paging}->{next});
74 3         444 $api_uri->userinfo('api:'.$self->api_key);
75             }
76              
77 3         28 return \@result, $previous;
78             }
79              
80             sub client {
81 24     24 0 65 my $self = shift;
82              
83 24   66     261 $self->{_client} //= Furl->new(
84             agent => __PACKAGE__ . '/' . $VERSION,
85             );
86             }
87              
88             sub api_base {
89 21     21 0 190 my ($self) = @_;
90              
91 21 50       98 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         357 return $API_BASE;
99             }
100              
101             sub api_url {
102 15     15 0 113 my ($self, $method) = @_;
103              
104 15         66 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 25 my ($self, $method) = @_;
110              
111 6         44 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 7651 my ($self, $args) = @_;
117              
118 5         17 my @content;
119 5 100       45 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         37 die 'unsupport argument. message() need HashRef or ArrayRef.';
127             }
128              
129 3         18 my $req = POST $self->domain_api_url('messages'), Content_type => 'form-data', Content => \@content;
130              
131 3         47211 my $res = $self->client->request($req);
132 3         1793117 $self->decode_response($res);
133             }
134              
135              
136              
137             sub mime {
138            
139 3     3 1 3499 my ($self, $args) = @_;
140              
141 3 50       16 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       13 if(exists($args->{message})){
    50          
152 2         20 $tmp = File::Temp->new();
153            
154 2 100       1342 if(ref $args->{message} eq 'SCALAR'){
155             # save from a ref
156 1         3 print $tmp ${$args->{message}};
  1         19  
157 1         51 seek $tmp, 0, 0;
158             }
159             else {
160             # Save from a string
161 1         7 print $tmp $args->{message};
162 1         54 seek $tmp, 0, 0;
163             }
164 2         17 $args->{message} = [$tmp->filename];
165             }
166             elsif(exists($args->{file})){
167 1 50       28 if(-f $args->{file}){
168 1         9 $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         41 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         30918 my $res = $self->client->request($req);
184            
185 3         1419888 undef $tmp;
186            
187 3         876 $self->decode_response($res);
188              
189             }
190              
191              
192              
193              
194             sub lists {
195 1     1 1 699 my $self = shift;
196              
197 1         7 return $self->recursive('lists/pages');
198             }
199              
200             sub add_list {
201 1     1 1 1782 my ($self, $args) = @_;
202              
203 1         4 my $res = $self->client->post($self->api_url("lists"), [], $args);
204 1         825555 $self->decode_response($res);
205             }
206              
207             sub list {
208 3     3 1 2782 my ($self, $address) = @_;
209              
210 3         16 my $res = $self->client->get($self->api_url("lists/$address"));
211 3 50       336942 my $json = $self->decode_response($res) or return;
212 2         81 return $json->{list};
213             }
214              
215             sub update_list {
216 1     1 1 3420 my ($self, $address, $args) = @_;
217              
218 1         37 my $res = $self->client->put($self->api_url("lists/$address"), [], $args);
219 1         143252 $self->decode_response($res);
220             }
221              
222             sub delete_list {
223 1     1 1 2997 my ($self, $address) = @_;
224              
225 1         6 my $res = $self->client->delete($self->api_url("lists/$address"));
226 1         237617 $self->decode_response($res);
227             }
228              
229             sub list_members {
230 2     2 1 1239 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 3345 my ($self, $address, $args) = @_;
237              
238 1         6 my $res = $self->client->post(
239             $self->api_url("lists/$address/members"), [], $args);
240 1         156692 $self->decode_response($res);
241             }
242              
243             sub add_list_members {
244 1     1 1 671 my ($self, $address, $args) = @_;
245              
246 1         6 my $res = $self->client->post(
247             $self->api_url("lists/$address/members.json"), [], $args);
248 1         154441 $self->decode_response($res);
249             }
250              
251             sub list_member {
252 2     2 1 1632 my ($self, $address, $member) = @_;
253              
254 2         12 my $res = $self->client->get($self->api_url("lists/$address/members/$member"));
255 2 50       282536 my $json = $self->decode_response($res) or return;
256 2         76 return $json->{member};
257             }
258              
259             sub update_list_member {
260 1     1 1 4007 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         192272 $self->decode_response($res);
265             }
266              
267             sub delete_list_member {
268 1     1 0 3845 my ($self, $address, $member) = @_;
269              
270 1         7 my $res = $self->client->delete(
271             $self->api_url("lists/$address/members/$member"));
272 1         903481 $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             1;
295             __END__