File Coverage

blib/lib/Mojo/Cloudflare.pm
Criterion Covered Total %
statement 57 98 58.1
branch 12 36 33.3
condition 3 11 27.2
subroutine 10 15 66.6
pod 5 5 100.0
total 87 165 52.7


line stmt bran cond sub pod time code
1             package Mojo::Cloudflare;
2              
3             =head1 NAME
4              
5             Mojo::Cloudflare - Talk with the Cloudflare API using Mojo::UserAgent
6              
7             =head1 VERSION
8              
9             0.03
10              
11             =head1 DESCRIPTION
12              
13             L is an (async) client for the
14             L.
15              
16             =head1 SYNOPSIS
17              
18             use Mojo::Cloudflare;
19             my $cf = Mojo::Cloudflare->new(
20             email => 'sample@example.com',
21             key => '8afbe6dea02407989af4dd4c97bb6e25',
22             zone => 'example.com',
23             );
24              
25             # add a record
26             $cf->record({
27             content => 'mojolicio.us',
28             name => 'direct.example.pm',
29             type => 'CNAME',
30             })->save;
31              
32             # retrieve and update records
33             for my $record ($cf->records->all) {
34             warn $record->name;
35             $record->ttl(1)->save; # update a record
36             }
37              
38             # update a record
39             $cf->record({
40             content => 'mojolicio.us',
41             id => 'some_id_fom_cloudflare', # <-- cause update instead of insert
42             name => 'direct.example.pm',
43             type => 'CNAME',
44             })->save;
45              
46             =cut
47              
48 3     3   1675854 use Mojo::Base -base;
  3         10  
  3         113  
49 3     3   652 use Mojo::JSON::Pointer;
  3         8  
  3         27  
50 3     3   71 use Mojo::UserAgent;
  3         6  
  3         23  
51 3     3   1849 use Mojo::Cloudflare::Record;
  3         8  
  3         153  
52 3     3   2181 use Mojo::Cloudflare::RecordSet;
  3         8  
  3         36  
53              
54             our $VERSION = '0.03';
55              
56             =head1 ATTRIBUTES
57              
58             =head2 api_url
59              
60             Holds the endpoint where we communicate. Default is
61             L.
62              
63             =head2 email
64              
65             $str = $self->email;
66             $self = $self->email($str);
67              
68             The e-mail address associated with the API key.
69              
70             =head2 key
71              
72             $str = $self->key;
73             $self = $self->key($str);
74              
75             This is the API key made available on your Account page.
76              
77             =head2 zone
78              
79             $str = $self->zone;
80             $self = $self->zone($str);
81              
82             The zone (domain) to act on.
83              
84             =cut
85              
86             has api_url => 'https://www.cloudflare.com/api_json.html';
87             has email => '';
88             has key => '';
89             has zone => '';
90             has _ua => sub { Mojo::UserAgent->new };
91              
92             =head1 METHODS
93              
94             =head2 add_record
95              
96             Will be deprecated. Use L instead.
97              
98             =cut
99              
100             sub add_record {
101 0     0 1 0 my($self, $args, $cb) = @_;
102 0         0 my %args;
103              
104 0         0 %args = map {
105 0         0 ($_, $args->{$_});
106             } grep {
107 0         0 defined $args->{$_};
108             } qw( type name content ttl );
109              
110 0         0 $args{_class} = 'Mojo::Cloudflare::Record';
111 0         0 $args{a} = 'rec_new';
112 0 0       0 $args{prio} = $args->{priority} if defined $args->{priority};
113 0   0     0 $args{ttl} ||= 1;
114              
115 0         0 return $self->_post(\%args, $cb);
116             }
117              
118             =head2 delete_record
119              
120             Will be deprecated. Use L instead.
121              
122             =cut
123              
124             sub delete_record {
125 1     1 1 9377 my($self, $id, $cb) = @_;
126              
127 1         12 $self->_post(
128             { a => 'rec_delete', id => $id, _class => 'Mojo::Cloudflare::Record' },
129             $cb,
130             );
131             }
132              
133             =head2 edit_record
134              
135             Will be deprecated. Use L instead.
136              
137             =cut
138              
139             sub edit_record {
140 1     1 1 5179 my($self, $args, $cb) = @_;
141 1         3 my %args;
142              
143 3         12 %args = map {
144 5         14 ($_, $args->{$_});
145             } grep {
146 1         3 defined $args->{$_};
147             } qw( id type name content ttl );
148              
149 1         5 $args{_class} = 'Mojo::Cloudflare::Record';
150 1         3 $args{a} = 'rec_edit';
151 1 50       7 $args{prio} = $args->{priority} if defined $args->{priority};
152 1 50       10 $args{service_mode} = $args->{service_mode} ? 1 : 0 if defined $args->{service_mode};
    50          
153              
154 1         5 return $self->_post(\%args, $cb);
155             }
156              
157             =head2 record
158              
159             $record_obj = $self->record(\%record_construction_args);
160              
161             Returns a L object.
162              
163             =cut
164              
165             sub record {
166 0     0 1 0 my $self = shift;
167 0 0       0 my $args = @_ ? @_ > 1 ? {@_} : $_[0] : {};
    0          
168 0         0 my $obj = Mojo::Cloudflare::Record->new({});
169 0         0 $obj->$_($args->{$_}) for grep { $obj->can($_) } keys %$args;
  0         0  
170 0         0 Scalar::Util::weaken($obj->_cf($self)->{_cf});
171 0         0 $obj;
172             }
173              
174             =head2 records
175              
176             $records_obj = $self->records($offset);
177             $self = $self->records($offset, sub {
178             my($self, $err, $records_obj) = @_;
179             });
180              
181             Used to retrieve L objects. The return value will
182             be a L object.
183              
184             C<$offset> is optional and defaults to "all", which will retrieve all the DNS
185             records instead of the limit of 180 set by CloudFlare.
186              
187             =cut
188              
189             sub records {
190 1     1 1 1075 my($self, $offset, $cb) = @_;
191              
192 1 50       6 if(ref $offset eq 'CODE') {
193 0         0 $cb = $offset;
194 0         0 $offset = 'all';
195             }
196              
197 1 50 33     10 if(!defined $offset or $offset eq 'all') {
198 1         20 my $record_set = Mojo::Cloudflare::RecordSet->new({ count => 0, has_more => undef, objs => [] });
199 1         35 Scalar::Util::weaken($record_set->_cf($self)->{_cf});
200 1 50       19 return $cb ? $self->_all_records_nb($record_set, $cb) : $self->_all_records($record_set);
201             }
202             else {
203 0         0 return $self->_post({ a => 'rec_load_all', o => $offset, _class => 'Mojo::Cloudflare::RecordSet' }, $cb);
204             }
205             }
206              
207             sub _all_records {
208 1     1   3 my($self, $record_set) = @_;
209 1         2 my $has_more = 1;
210 1         2 my $offset = 0;
211              
212 1         6 while($has_more) {
213 1         8 my $json = $self->_post({ a => 'rec_load_all', o => $offset, _class => 'Mojo::Cloudflare::RecordSet' });
214              
215 1         370 $record_set->data->{count} += $json->get('/count');
216 1 50       78 push @{ $record_set->data->{objs} }, @{ $json->get('/objs') || [] };
  1         24  
  1         9  
217 1         49 $has_more = $json->get('/has_more');
218 1 50       56 $offset += $has_more ? $json->get('/count') : 0;
219             }
220              
221 1         7 return $record_set;
222             }
223              
224             sub _all_records_nb {
225 0     0   0 my($self, $record_set, $cb) = @_;
226 0         0 my $offset = 0;
227 0         0 my $retriever;
228              
229             $retriever = sub {
230 0     0   0 my($self, $err, $json) = @_;
231 0         0 my $offset;
232              
233 0 0       0 return $self->$cb($err, $record_set) if $err;
234              
235 0         0 $offset += $json->get('/count');
236 0         0 $record_set->data->{count} = $offset;
237 0 0       0 push @{ $record_set->data->{objs} }, @{ $json->get('/objs') || [] };
  0         0  
  0         0  
238              
239 0 0       0 return $self->$cb('', $record_set) unless $json->get('/has_more');
240 0         0 return $self->_post({ a => 'rec_load_all', o => $offset, _class => 'Mojo::Cloudflare::RecordSet' }, $retriever);
241 0         0 };
242              
243 0         0 $self->_post({ a => 'rec_load_all', _class => 'Mojo::Cloudflare::RecordSet' }, $retriever);
244             }
245              
246             sub _post {
247 3     3   7 my($self, $data, $cb) = @_;
248 3         10 my $class = delete $data->{_class};
249              
250 3 50       14 $data->{a} or die "Internal error: Unknown action";
251 3   33     110 $data->{email} ||= $self->email;
252 3   33     136 $data->{tkn} ||= $self->key;
253 3 50       113 $data->{z} = $self->zone if $data->{a} =~ /^rec/;
254              
255 3 50       329 unless($cb) {
256 3         89 my $tx = $self->_ua->post($self->api_url, form => $data);
257 3         118640 my($err, $obj) = $class->_new_from_tx($tx);
258              
259 3 50       64 die $err if $err;
260 3         97 Scalar::Util::weaken($obj->_cf($self)->{_cf});
261 3         188 return $obj;
262             }
263              
264 0           Scalar::Util::weaken($self);
265             $self->_ua->post(
266             $self->api_url,
267             form => $data,
268             sub {
269 0     0     my($err, $obj) = $class->_new_from_tx($_[1]);
270              
271 0           Scalar::Util::weaken($obj->_cf($self)->{_cf});
272 0           $self->$cb($err, $obj);
273             },
274 0           );
275              
276 0           return $self;
277             }
278              
279             =head1 COPYRIGHT AND LICENSE
280              
281             Copyright (C) 2014, Jan Henning Thorsen
282              
283             This program is free software, you can redistribute it and/or modify it under
284             the terms of the Artistic License version 2.0.
285              
286             =head1 AUTHOR
287              
288             Jan Henning Thorsen - C
289              
290             =cut
291              
292             1;