File Coverage

blib/lib/WWW/Namecheap/Domain.pm
Criterion Covered Total %
statement 25 144 17.3
branch 2 52 3.8
condition 0 15 0.0
subroutine 8 18 44.4
pod 12 12 100.0
total 47 241 19.5


line stmt bran cond sub pod time code
1             package WWW::Namecheap::Domain;
2              
3 11     11   211 use 5.006;
  11         27  
4 11     11   38 use strict;
  11         12  
  11         237  
5 11     11   29 use warnings;
  11         11  
  11         190  
6 11     11   34 use Carp();
  11         10  
  11         109  
7 11     11   4596 use MIME::Base64();
  11         5109  
  11         13052  
8              
9             =head1 NAME
10              
11             WWW::Namecheap::Domain - Namecheap API domain methods
12              
13             =cut
14              
15             our $VERSION = '0.06';
16              
17             =head1 SYNOPSIS
18              
19             Namecheap API domain methods.
20              
21             See L for main documentation.
22              
23             use WWW::Namecheap::Domain;
24              
25             my $domain = WWW::Namecheap::Domain->new(API => $api);
26             $domain->check(...);
27             $domain->create(...);
28             ...
29              
30             =head1 SUBROUTINES/METHODS
31              
32             =head2 WWW::Namecheap::Domain->new(API => $api)
33              
34             Instantiate a new Domain object for making domain-related API calls.
35             Requires a WWW::Namecheap::API object.
36              
37             =cut
38              
39             sub new {
40 2     2 1 3 my $class = shift;
41              
42 2         4 my $params = _argparse(@_);
43              
44 2         4 for (qw(API)) {
45 2 50       6 Carp::croak("${class}->new(): Mandatory parameter $_ not provided.") unless $params->{$_};
46             }
47              
48             my $self = {
49 2         3 api => $params->{'API'},
50             };
51              
52 2         7 return bless($self, $class);
53             }
54              
55             =head2 $domain->check(Domains => ['example.com'])
56              
57             Check a list of domains. Returns a hashref of availablity status with
58             domain names as the keys and 0/1 as the values for not available/available.
59              
60             my $result = $domain->check(Domains => [qw(
61             example.com
62             example2.com
63             foobar.com
64             )]);
65              
66             Will give a $result something like:
67              
68             $result = {
69             'example.com' => 0, # example.com is taken
70             'example2.com' => 1, # example2.com is available
71             'foobar.com' => 0, # damn, foobar.com is taken
72             };
73              
74             =cut
75              
76             sub check {
77 0     0 1 0 my $self = shift;
78              
79 0         0 my $params = _argparse(@_);
80              
81 0         0 my %domains = map { $_ => -1 } @{$params->{'Domains'}};
  0         0  
  0         0  
82 0         0 my $DomainList = join(',', keys %domains);
83             my $xml = $self->api->request(
84             Command => 'namecheap.domains.check',
85             ClientIp => $params->{'ClientIp'},
86 0         0 UserName => $params->{'UserName'},
87             DomainList => $DomainList,
88             );
89              
90 0 0       0 return unless $xml;
91              
92 0         0 my $result = $xml->{CommandResponse}->{DomainCheckResult};
93             # XML returns a hashref if only one returned value, otherwise an array
94 0 0       0 $result = [$result] if (ref $result eq 'HASH');
95              
96 0         0 foreach my $entry (@$result) {
97 0 0       0 unless ($domains{$entry->{Domain}}) {
98 0         0 Carp::carp("Unexpected domain found: $entry->{Domain}");
99 0         0 next;
100             }
101 0 0       0 if ($entry->{Available} eq 'true') {
102 0         0 $domains{$entry->{Domain}} = 1;
103             } else {
104 0         0 $domains{$entry->{Domain}} = 0;
105             }
106             }
107              
108 0         0 return \%domains;
109             }
110              
111             =head2 $domain->create(%hash)
112              
113             Register a new domain name.
114              
115             Example:
116              
117             my $result = $domain->create(
118             UserName => 'username', # optional if DefaultUser specified in $api
119             ClientIp => '1.2.3.4', # optional if DefaultIp specified in $api
120             DomainName => 'example.com',
121             Years => 1, # required; default is 2
122             Registrant => {
123             OrganizationName => 'Example Dot Com', # optional
124             JobTitle => 'CTO', # optional
125             FirstName => 'Domain',
126             LastName => 'Manager',
127             Address1 => '123 Fake Street',
128             Address2 => 'Suite 555', # optional
129             City => 'Univille',
130             StateProvince => 'SD',
131             StateProvinceChoice => 'S', # optional; 'S' for 'State' or 'P' for 'Province'
132             PostalCode => '12345',
133             Country => 'US',
134             Phone => '+1.2025551212',
135             PhoneExt => '4444', # optional
136             Fax => '+1.2025551212', # optional
137             EmailAddress => 'foo@example.com',
138             },
139             Tech => {
140             # same fields as Registrant
141             },
142             Admin => {
143             # same fields as Registrant
144             },
145             AuxBilling => {
146             # same fields as Registrant
147             },
148             Billing => {
149             # Optional; fields as Registrant except OrganizationName, JobTitle
150             },
151             Nameservers => 'ns1.foo.com,ns2.bar.com', # optional
152             AddFreeWhoisguard => 'yes', # or 'no', default 'no'
153             WGEnabled => 'yes', # or 'no', default 'no'
154             PromotionCode => 'some-string', # optional
155             IdnCode => '', # optional, see Namecheap API doc
156             'Extended attributes' => '', # optional, see Namecheap API doc
157             IsPremiumDomain => '', # optional, see Namecheap API doc
158             PremiumPrice => '', # optional, see Namecheap API doc
159             EapFreee => '', # optional, see Namecheap API doc
160             );
161              
162             Unspecified contacts will be automatically copied from Registrant, which
163             must be provided.
164              
165             Returns:
166              
167             $result = {
168             Domain => 'example.com',
169             DomainID => '12345',
170             Registered => 'true',
171             OrderID => '12345',
172             TransactionID => '12345',
173             ChargedAmount => '10.45', # dollars and cents
174             };
175              
176             =cut
177              
178             sub create {
179 0     0 1 0 my $self = shift;
180              
181 0         0 my $params = _argparse(@_);
182              
183             my %request = (
184             Command => 'namecheap.domains.create',
185             ClientIp => $params->{'ClientIp'},
186             UserName => $params->{'UserName'},
187             DomainName => $params->{'DomainName'},
188             Years => $params->{Years},
189 0         0 );
190              
191             # Optional parameters are only included if supplied in the function argument
192 0         0 foreach my $parameter (qw(PromotionCode Nameservers IdnCode AddFreeWhoisguard WGEnabled IsPremiumDomain PremiumPrice EapFee), 'Extended attributes') {
193 0 0       0 $request{$parameter} = $params->{$parameter} if (exists $params->{$parameter});
194             }
195              
196 0         0 foreach my $contact (qw(Registrant Tech Admin AuxBilling)) {
197 0   0     0 $params->{$contact} ||= $params->{Registrant};
198 0         0 map { $request{"$contact$_"} = $params->{$contact}{$_} } keys %{$params->{$contact}};
  0         0  
  0         0  
199             }
200              
201 0 0       0 if ($params->{Billing}) {
202 0         0 my $contact = "Billing";
203             # Billing does not have these keys: OrganizationName, JobTitle
204 0         0 map { $request{"$contact$_"} = $params->{$contact}{$_} } keys %{$params->{$contact}};
  0         0  
  0         0  
205             }
206              
207 0         0 my $xml = $self->api->request(%request);
208              
209 0 0       0 return unless $xml;
210              
211 0         0 return $xml->{CommandResponse}->{DomainCreateResult};
212             }
213              
214             =head2 $domain->getinfo(DomainName => 'example.com')
215              
216             Returns a hashref containing information about the requested domain.
217              
218             =cut
219              
220             sub getinfo {
221 0     0 1 0 my $self = shift;
222              
223 0         0 my $params = _argparse(@_);
224              
225 0 0       0 return unless $params->{'DomainName'};
226              
227 0         0 my %request = (
228             Command => 'namecheap.domains.getinfo',
229             %$params,
230             );
231              
232 0         0 my $xml = $self->api->request(%request);
233              
234 0 0 0     0 return unless ($xml && $xml->{Status} eq 'OK');
235              
236 0         0 return $xml->{CommandResponse}->{DomainGetInfoResult};
237             }
238              
239             =head2 $domain->list(%hash)
240              
241             Get a list of domains in your account. Automatically handles the Namecheap
242             "paging" to get a full list. May be optionally restricted:
243              
244             my $domains = $domain->list(
245             ListType => 'ALL', # or EXPIRING or EXPIRED
246             SearchTerm => 'foo', # keyword search
247             SortBy => 'NAME', # or EXPIREDATE, CREATEDATE, or *_DESC
248             );
249              
250             Returns an arrayref of hashrefs:
251              
252             $domains = [
253             {
254             ID => '123',
255             Name => 'example.com',
256             User => 'owner',
257             Created => 'MM/DD/YYYY',
258             Expires => 'MM/DD/YYYY',
259             IsExpired => 'false',
260             IsLocked => 'true',
261             AutoRenew => 'false',
262             WhoisGuard => 'ENABLED',
263             },
264             ...
265             ];
266              
267             =cut
268              
269             sub list {
270 0     0 1 0 my $self = shift;
271              
272 0         0 my $params = _argparse(@_);
273              
274             my %request = (
275             Command => 'namecheap.domains.getList',
276             ClientIp => $params->{'ClientIp'},
277             UserName => $params->{'UserName'},
278             PageSize => 100,
279             Page => 1,
280             ListType => $params->{'ListType'},
281 0         0 SearchTerm => $params->{'SearchTerm'},
282             );
283              
284 0         0 my @domains;
285              
286 0         0 my $break = 0;
287 0         0 while (1) {
288 0         0 my $xml = $self->api->request(%request);
289              
290 0 0       0 last unless $xml;
291              
292 0 0       0 if (ref($xml->{CommandResponse}->{DomainGetListResult}->{Domain}) eq 'ARRAY') {
    0          
293 0         0 push(@domains, @{$xml->{CommandResponse}->{DomainGetListResult}->{Domain}});
  0         0  
294             } elsif (ref($xml->{CommandResponse}->{DomainGetListResult}->{Domain}) eq 'HASH') {
295 0         0 push(@domains, $xml->{CommandResponse}->{DomainGetListResult}->{Domain});
296             } else {
297 0         0 Carp::carp('Unexpected XML in CommandResponse->DomainGetListResult->Domain!');
298             }
299 0 0       0 if ($xml->{CommandResponse}->{Paging}->{TotalItems} <= ($request{Page} * $request{PageSize})) {
300 0         0 last;
301             } else {
302 0         0 $request{Page}++;
303             }
304             }
305              
306 0         0 return \@domains;
307             }
308              
309             =head2 $domain->getcontacts(DomainName => 'example.com')
310              
311             Get the contacts on file for the provided DomainName. Returns a big
312             ol' data structure:
313              
314             $contacts = {
315             Domain => 'example.com',
316             domainnameid => '12345',
317             Registrant => {
318             ReadOnly => 'false',
319             ... all contact fields from create ...
320             },
321             Tech => {
322             ... ditto ...
323             },
324             Admin => {
325             ... ditto ...
326             },
327             AuxBilling => {
328             ... ditto ...
329             },
330             WhoisGuardContact => {
331             ... same contacts as outside, except the actual published
332             WhoisGuard info, ReadOnly => 'true' ...
333             },
334             };
335              
336             =cut
337              
338             sub getcontacts {
339 0     0 1 0 my $self = shift;
340              
341 0         0 my $params = _argparse(@_);
342              
343 0 0       0 return unless $params->{'DomainName'};
344              
345 0         0 my %request = (
346             Command => 'namecheap.domains.getContacts',
347             %$params,
348             );
349              
350 0         0 my $xml = $self->api->request(%request);
351              
352 0 0       0 return unless $xml;
353              
354 0         0 return $xml->{CommandResponse}->{DomainContactsResult};
355             }
356              
357             =head2 $domain->setcontacts(%hash)
358              
359             Set contacts for a domain name.
360              
361             Example:
362              
363             my $result = $domain->create(
364             UserName => 'username', # optional if DefaultUser specified in $api
365             ClientIp => '1.2.3.4', # optional if DefaultIp specified in $api
366             DomainName => 'example.com',
367             Registrant => {
368             OrganizationName => 'Example Dot Com', # optional
369             FirstName => 'Domain',
370             LastName => 'Manager',
371             Address1 => '123 Fake Street',
372             Address2 => 'Suite 555', # optional
373             City => 'Univille',
374             StateProvince => 'SD',
375             StateProvinceChoice => 'S', # for 'State' or 'P' for 'Province'
376             PostalCode => '12345',
377             Country => 'USA',
378             Phone => '+1.2025551212',
379             Fax => '+1.2025551212', # optional
380             EmailAddress => 'foo@example.com',
381             },
382             Tech => {
383             # same fields as Registrant
384             },
385             Admin => {
386             # same fields as Registrant
387             },
388             AuxBilling => {
389             # same fields as Registrant
390             },
391             );
392              
393             Unspecified contacts will be automatically copied from the registrant, which
394             must be provided.
395              
396             $result is a small hashref confirming back the domain that was modified
397             and whether the operation was successful or not:
398              
399             $result = {
400             Domain => 'example.com',
401             IsSuccess => 'true',
402             };
403              
404             =cut
405              
406             sub setcontacts {
407 0     0 1 0 my $self = shift;
408              
409 0         0 my $params = _argparse(@_);
410              
411 0 0       0 return unless $params->{'DomainName'};
412              
413             my %request = (
414             Command => 'namecheap.domains.setContacts',
415             ClientIp => $params->{'ClientIp'},
416             UserName => $params->{'UserName'},
417 0         0 DomainName => $params->{'DomainName'},
418             );
419              
420 0         0 foreach my $contact (qw(Registrant Tech Admin AuxBilling)) {
421 0   0     0 $params->{$contact} ||= $params->{Registrant};
422 0         0 map { $request{"$contact$_"} = $params->{$contact}{$_} } keys %{$params->{$contact}};
  0         0  
  0         0  
423             }
424              
425 0         0 my $xml = $self->api->request(%request);
426              
427 0 0       0 return unless $xml;
428              
429 0         0 return $xml->{CommandResponse}->{DomainSetContactResult};
430             }
431              
432             =head2 $domain->gettldlist()
433              
434             Get a list of all TLDs available for registration, along with various
435             attributes for each TLD. Results are automatically cached for one
436             hour to avoid excessive API load.
437              
438             =cut
439              
440             sub gettldlist {
441 0     0 1 0 my $self = shift;
442              
443 0         0 my $params = _argparse(@_);
444              
445 0         0 my %request = (
446             Command => 'namecheap.domains.getTldList',
447             %$params,
448             );
449              
450 0 0 0     0 if (!$self->{_tldlist_cachetime} || time() - $self->{_tldlist_cachetime} > 3600) {
451 0         0 my $xml = $self->api->request(%request);
452 0         0 $self->{_tldlist_cache} = $xml->{CommandResponse}->{Tlds}->{Tld};
453 0         0 $self->{_tldlist_cachetime} = time();
454             }
455              
456 0         0 return $self->{_tldlist_cache};
457             }
458              
459             =head2 $domain->transfer(%hash)
460              
461             Initiate a transfer in request to Namecheap from another registrar.
462             Request should look something like:
463              
464             my $transfer = $domain->transfer(
465             DomainName => 'example.com',
466             Years => 1,
467             EPPCode => 'foobarbaz',
468             );
469              
470             The response will be a hashref:
471              
472             $transfer = {
473             Transfer => 'true',
474             TransferID => '15',
475             StatusID => '-1',
476             OrderID => '1234',
477             TransactionID => '1234',
478             ChargedAmount => '10.10',
479             };
480              
481             For transfer status code details, see the Namecheap API documentation:
482              
483             L
484              
485             =cut
486              
487             sub transfer {
488 0     0 1 0 my $self = shift;
489              
490 0         0 my $params = _argparse(@_);
491              
492 0         0 my $b64epp;
493 0 0 0     0 if ($params->{EPPCode} && $params->{EPPCode} !~ /^base64:/) {
494 0         0 $b64epp = MIME::Base64::encode($params->{EPPCode});
495 0         0 $params->{EPPCode} = "base64:$b64epp";
496             }
497 0         0 my %request = (
498             Command => 'namecheap.domains.transfer.create',
499             %$params,
500             );
501              
502 0         0 my $xml = $self->api->request(%request);
503              
504 0 0       0 return unless $xml;
505              
506 0         0 return $xml->{CommandResponse}->{DomainTransferCreateResult};
507             }
508              
509             =head2 $domain->transferstatus(TransferID => '1234')
510              
511             Check the current status of a particular transfer. The TransferID
512             is the TransferID returned by the transfer() call, or included in
513             the transferlist(). Returns a hashref:
514              
515             $result = {
516             TransferID => '1234',
517             Status => 'String',
518             StatusID => '-1',
519             };
520              
521             =cut
522              
523             sub transferstatus {
524 0     0 1 0 my $self = shift;
525              
526 0         0 my $params = _argparse(@_);
527              
528 0         0 my %request = (
529             Command => 'namecheap.domains.transfer.getStatus',
530             %$params,
531             );
532              
533 0         0 my $xml = $self->api->request(%request);
534              
535 0 0       0 return unless $xml;
536              
537 0         0 return $xml->{CommandResponse}->{DomainTransferGetStatusResult};
538             }
539              
540             =head2 $domain->transferlist()
541              
542             Retrieve a list of transfers associated with the connected API account.
543             Automatically handles the Namecheap "paging" to get a full list. May
544             be optionally restricted:
545              
546             my $transfers = $domain->transferlist(
547             ListType => 'ALL', # or INPROGRESS, CANCELLED, COMPLETED
548             SearchTerm => 'foo', # keyword search
549             SortBy => 'DOMAINNAME', # or TRANSFERDATE, STATUSDATE, *_DESC
550             );
551              
552             Returns an arrayref of hashrefs:
553              
554             $domains = [
555             {
556             ID => '123',
557             DomainName => 'example.com',
558             User => 'apiuser',
559             TransferDate => 'MM/DD/YYYY',
560             OrderID => 12345,
561             StatusID => 20
562             Status => 'Cancelled',
563             StatusDate => 'MM/DD/YYYY',
564             StatusDescription => 'String',
565             }
566             ...
567             ];
568              
569             =cut
570              
571             sub transferlist {
572 0     0 1 0 my $self = shift;
573              
574 0         0 my $params = _argparse(@_);
575              
576             my %request = (
577             Command => 'namecheap.domains.transfer.getList',
578             ClientIp => $params->{'ClientIp'},
579             UserName => $params->{'UserName'},
580             PageSize => 100,
581             Page => 1,
582             ListType => $params->{'ListType'},
583 0         0 SearchTerm => $params->{'SearchTerm'},
584             );
585              
586 0         0 my @transfers;
587              
588 0         0 my $break = 0;
589 0         0 while (1) {
590 0         0 my $xml = $self->api->request(%request);
591              
592 0 0       0 last unless $xml;
593              
594 0         0 push(@transfers, @{$xml->{CommandResponse}->{TransferGetListResult}->{Transfer}});
  0         0  
595 0 0       0 if ($xml->{CommandResponse}->{Paging}->{TotalItems} <= ($request{Page} * $request{PageSize})) {
596 0         0 last;
597             } else {
598 0         0 $request{Page}++;
599             }
600             }
601              
602 0         0 return \@transfers;
603             }
604              
605             =head2 $domain->api()
606              
607             Accessor for internal API object.
608              
609             =cut
610              
611             sub api {
612 1     1 1 230 return $_[0]->{api};
613             }
614              
615             sub _argparse {
616 2     2   3 my $hashref;
617 2 50       4 if (@_ % 2 == 0) {
    0          
618 2         4 $hashref = { @_ }
619             } elsif (ref($_[0]) eq 'HASH') {
620 0         0 $hashref = \%{$_[0]};
  0         0  
621             }
622 2         3 return $hashref;
623             }
624              
625             =head1 AUTHOR
626              
627             Tim Wilde, C<< >>
628              
629             =head1 BUGS
630              
631             Please report any bugs or feature requests to C, or through
632             the web interface at L. I will be notified, and then you'll
633             automatically be notified of progress on your bug as I make changes.
634              
635              
636              
637             =head1 SUPPORT
638              
639             You can find documentation for this module with the perldoc command.
640              
641             perldoc WWW::Namecheap::Domain
642              
643              
644             You can also look for information at:
645              
646             =over 4
647              
648             =item * RT: CPAN's request tracker (report bugs here)
649              
650             L
651              
652             =item * AnnoCPAN: Annotated CPAN documentation
653              
654             L
655              
656             =item * CPAN Ratings
657              
658             L
659              
660             =item * Search CPAN
661              
662             L
663              
664             =back
665              
666              
667             =head1 ACKNOWLEDGEMENTS
668              
669              
670             =head1 LICENSE AND COPYRIGHT
671              
672             Copyright 2011 Tim Wilde.
673              
674             This program is free software; you can redistribute it and/or modify it
675             under the terms of either: the GNU General Public License as published
676             by the Free Software Foundation; or the Artistic License.
677              
678             See http://dev.perl.org/licenses/ for more information.
679              
680              
681             =cut
682              
683             1; # End of WWW::Namecheap::Domain