Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

General Improvements #28

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
201 changes: 162 additions & 39 deletions domain.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,46 +2,54 @@ package namecheap

import (
"errors"
"fmt"
"net/url"
"strconv"
"strings"
"time"
)

const (
domainsGetList = "namecheap.domains.getList"
domainsGetInfo = "namecheap.domains.getInfo"
domainsCheck = "namecheap.domains.check"
domainsCreate = "namecheap.domains.create"
domainsTLDList = "namecheap.domains.getTldList"
domainsRenew = "namecheap.domains.renew"
domainsSetContacts = "namecheap.domains.setContacts"
domainsGetList = "namecheap.domains.getList"
domainsGetInfo = "namecheap.domains.getInfo"
domainsCheck = "namecheap.domains.check"
domainsCreate = "namecheap.domains.create"
domainsTLDList = "namecheap.domains.getTldList"
domainsRenew = "namecheap.domains.renew"
domainsSetContacts = "namecheap.domains.setContacts"
domainsGetRegistrarLock = "namecheap.domains.getRegistrarLock"
domainsSetRegistrarLock = "namecheap.domains.setRegistrarLock"
)

// DomainGetListResult represents the data returned by 'domains.getList'
type DomainGetListResult struct {
ID int `xml:"ID,attr"`
Name string `xml:"Name,attr"`
User string `xml:"User,attr"`
Created string `xml:"Created,attr"`
Expires string `xml:"Expires,attr"`
IsExpired bool `xml:"IsExpired,attr"`
IsLocked bool `xml:"IsLocked,attr"`
AutoRenew bool `xml:"AutoRenew,attr"`
WhoisGuard string `xml:"WhoisGuard,attr"`
ID int `xml:"ID,attr"`
Name string `xml:"Name,attr"`
User string `xml:"User,attr"`
Created time.Time `xml:"-"`
CreatedString string `xml:"Created,attr"`
Expires time.Time `xml:"-"`
ExpiresString string `xml:"Expires,attr"`
IsExpired bool `xml:"IsExpired,attr"`
IsLocked bool `xml:"IsLocked,attr"`
AutoRenew bool `xml:"AutoRenew,attr"`
WhoisGuard string `xml:"WhoisGuard,attr"`
}

// DomainInfo represents the data returned by 'domains.getInfo'
type DomainInfo struct {
ID int `xml:"ID,attr"`
Name string `xml:"DomainName,attr"`
Owner string `xml:"OwnerName,attr"`
Created string `xml:"DomainDetails>CreatedDate"`
Expires string `xml:"DomainDetails>ExpiredDate"`
IsExpired bool `xml:"IsExpired,attr"`
IsLocked bool `xml:"IsLocked,attr"`
AutoRenew bool `xml:"AutoRenew,attr"`
DNSDetails DNSDetails `xml:"DnsDetails"`
Whoisguard Whoisguard `xml:"Whoisguard"`
ID int `xml:"ID,attr"`
Name string `xml:"DomainName,attr"`
Owner string `xml:"OwnerName,attr"`
Created time.Time `xml:"-"`
CreatedString string `xml:"DomainDetails>CreatedDate"`
Expires time.Time `xml:"-"`
ExpiresString string `xml:"DomainDetails>ExpiredDate"`
IsExpired bool `xml:"IsExpired,attr"`
IsLocked bool `xml:"IsLocked,attr"`
AutoRenew bool `xml:"AutoRenew,attr"`
DNSDetails DNSDetails `xml:"DnsDetails"`
Whoisguard Whoisguard `xml:"Whoisguard"`
}

type DNSDetails struct {
Expand All @@ -50,11 +58,19 @@ type DNSDetails struct {
Nameservers []string `xml:"Nameserver"`
}

type WhoisguardEmailDetails struct {
Email string `xml:"WhoisGuardEmail,attr"`
ForwardedTo string `xml:"ForwardedTo,attr"`
LastAutoEmailChangeDate string `xml:"LastAutoEmailChangeDate,attr"`
AutoEmailChangeFrequencyDays int `xml:"AutoEmailChangeFrequencyDays,attr"`
}
type Whoisguard struct {
RawEnabled string `xml:"Enabled,attr"`
Enabled bool `xml:"-"`
ID int64 `xml:"ID"`
ExpiredDate string `xml:"ExpiredDate"`
RawEnabled string `xml:"Enabled,attr"`
Enabled bool `xml:"-"`
ID int64 `xml:"ID"`
ExpiredDate time.Time `xml:"-"`
ExpiredDateString string `xml:"ExpiredDate"`
EmailDetails WhoisguardEmailDetails `xml:"EmailDetails"`
}

type DomainCheckResult struct {
Expand Down Expand Up @@ -84,20 +100,30 @@ type DomainCreateResult struct {
}

type DomainRenewResult struct {
DomainID int `xml:"DomainID,attr"`
Name string `xml:"DomainName,attr"`
Renewed bool `xml:"Renew,attr"`
ChargedAmount float64 `xml:"ChargedAmount,attr"`
OrderID int `xml:"OrderID,attr"`
TransactionID int `xml:"TransactionID,attr"`
ExpireDate string `xml:"DomainDetails>ExpiredDate"`
DomainID int `xml:"DomainID,attr"`
Name string `xml:"DomainName,attr"`
Renewed bool `xml:"Renew,attr"`
ChargedAmount float64 `xml:"ChargedAmount,attr"`
OrderID int `xml:"OrderID,attr"`
TransactionID int `xml:"TransactionID,attr"`
ExpireDate time.Time
ExpireDateString string `xml:"DomainDetails>ExpiredDate"`
}

type DomainSetContactsResult struct {
Name string `xml:"Domain,attr"`
IsSuccess bool `xml:"IsSuccess,attr"`
}

type DomainRegistrarLockStatusResult struct {
Name string `xml:"Domain,attr"`
IsLocked bool `xml:"RegistrarLockStatus,attr"`
}

type DomainSetRegistrarLockResult struct {
Name string `xml:"Domain,attr"`
IsSuccess bool `xml:"IsSuccess,attr"`
}
type DomainCreateOption struct {
AddFreeWhoisguard bool
WGEnabled bool
Expand All @@ -111,11 +137,33 @@ func (client *Client) DomainsGetList() ([]DomainGetListResult, error) {
params: url.Values{},
}

requestInfo.params.Set("PageSize", "100")

resp, err := client.do(requestInfo)
if err != nil {
return nil, err
}

for _, domain := range resp.Domains {
if domain.CreatedString != "" {
created, createdErr := resp.ParseDate(domain.CreatedString)
if createdErr != nil {
return nil, fmt.Errorf("error when parsing Created date to time.Time: %w", createdErr)
}

domain.Created = created
}

if domain.ExpiresString != "" {
expires, expiresErr := resp.ParseDate(domain.ExpiresString)
if expiresErr != nil {
return nil, fmt.Errorf("error when parsing Expires date to time.Time: %w", expiresErr)
}

domain.Expires = expires
}
}

return resp.Domains, nil
}

Expand All @@ -133,9 +181,40 @@ func (client *Client) DomainGetInfo(domainName string) (*DomainInfo, error) {
return nil, err
}

if resp.DomainInfo != nil && strings.EqualFold(resp.DomainInfo.Whoisguard.RawEnabled, "true") {
resp.DomainInfo.Whoisguard.Enabled = true
if resp.DomainInfo != nil {
if strings.EqualFold(resp.DomainInfo.Whoisguard.RawEnabled, "true") {
resp.DomainInfo.Whoisguard.Enabled = true
}

if resp.DomainInfo.CreatedString != "" {
created, createdErr := resp.ParseDate(resp.DomainInfo.CreatedString)
if createdErr != nil {
return nil, fmt.Errorf("error when parsing domain Created date to time.Time: %w", createdErr)
}

resp.DomainInfo.Created = created
}

if resp.DomainInfo.ExpiresString != "" {
expires, expiresErr := resp.ParseDate(resp.DomainInfo.ExpiresString)
if expiresErr != nil {
return nil, fmt.Errorf("error when parsing domain Expires date to time.Time: %w", expiresErr)
}

resp.DomainInfo.Expires = expires
}

if resp.DomainInfo.Whoisguard.ExpiredDateString != "" {
expired, expiredErr := resp.ParseDate(resp.DomainInfo.Whoisguard.ExpiredDateString)
if expiredErr != nil {
return nil, fmt.Errorf("error when parsing WhoisGuard Expired date to time.Time: %w", expiredErr)
}

resp.DomainInfo.Whoisguard.ExpiredDate = expired
}

}

return resp.DomainInfo, nil
}

Expand Down Expand Up @@ -220,6 +299,15 @@ func (client *Client) DomainRenew(domainName string, years int) (*DomainRenewRes
return nil, err
}

if resp.DomainRenew.ExpireDateString != "" {
expired, expiredErr := resp.ParseDate(resp.DomainRenew.ExpireDateString)
if expiredErr != nil {
return nil, fmt.Errorf("error when parsing Expired date to time.Time: %w", expiredErr)
}

resp.DomainRenew.ExpireDate = expired
}

return resp.DomainRenew, nil
}

Expand All @@ -241,3 +329,38 @@ func (client *Client) DomainSetContacts(domainName string) (*DomainSetContactsRe

return resp.DomainSetContacts, nil
}

func (client *Client) DomainGetRegistrarLock(domainName string) (*DomainRegistrarLockStatusResult, error) {
requestInfo := &ApiRequest{
command: domainsGetRegistrarLock,
method: "POST",
params: url.Values{},
}
requestInfo.params.Set("DomainName", domainName)

resp, err := client.do(requestInfo)
if err != nil {
return nil, err
}

return resp.DomainRegistrarLockStatus, nil
}

func (client *Client) DomainSetRegistrarLock(domainName string, lock bool) (*DomainSetRegistrarLockResult, error) {
requestInfo := &ApiRequest{
command: domainsSetRegistrarLock,
method: "POST",
params: url.Values{},
}
requestInfo.params.Set("DomainName", domainName)
if !lock {
requestInfo.params.Set("LockAction", "UNLOCK")
}

resp, err := client.do(requestInfo)
if err != nil {
return nil, err
}

return resp.DomainSetRegistrarLock, nil
}
93 changes: 71 additions & 22 deletions namecheap.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@ import (
"io/ioutil"
"net/http"
"net/url"
"regexp"
"strconv"
"strings"
"time"
)

const defaultBaseURL = "https://api.namecheap.com/xml.response"
Expand All @@ -38,29 +40,76 @@ type ApiRequest struct {
params url.Values
}

type NamecheapTimeLocation struct {
*time.Location
}

// could be like --4:00, +5, +5:30, +2:50
var gmtOffsetRegex = regexp.MustCompile(`([\-+])(\d+):?(\d+)?`)

func (n *NamecheapTimeLocation) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
var offsetStr string
if decodeErr := d.DecodeElement(&offsetStr, &start); decodeErr != nil {
return decodeErr
}

pieces := gmtOffsetRegex.FindStringSubmatch(offsetStr)

if len(pieces) == 0 {
return fmt.Errorf("GMTTimeDifference was not of expected format")
}

sign := pieces[1]
hours := pieces[2]
minutes := pieces[3]

if minutes == "" {
minutes = "00"
}

dur, durErr := time.ParseDuration(fmt.Sprintf("%s%sh%sm", sign, hours, minutes))
if durErr != nil {
return fmt.Errorf("error when converting parsed GMTTimeDifference to time.Duration: %w", durErr)
}

n.Location = time.FixedZone("Namecheap", int(dur.Seconds()))
return nil
}

type ApiResponse struct {
Status string `xml:"Status,attr"`
Command string `xml:"RequestedCommand"`
TLDList []TLDListResult `xml:"CommandResponse>Tlds>Tld"`
Domains []DomainGetListResult `xml:"CommandResponse>DomainGetListResult>Domain"`
DomainInfo *DomainInfo `xml:"CommandResponse>DomainGetInfoResult"`
DomainDNSHosts *DomainDNSGetHostsResult `xml:"CommandResponse>DomainDNSGetHostsResult"`
DomainDNSSetHosts *DomainDNSSetHostsResult `xml:"CommandResponse>DomainDNSSetHostsResult"`
DomainCreate *DomainCreateResult `xml:"CommandResponse>DomainCreateResult"`
DomainRenew *DomainRenewResult `xml:"CommandResponse>DomainRenewResult"`
DomainsCheck []DomainCheckResult `xml:"CommandResponse>DomainCheckResult"`
DomainNSInfo *DomainNSInfoResult `xml:"CommandResponse>DomainNSInfoResult"`
DomainDNSSetCustom *DomainDNSSetCustomResult `xml:"CommandResponse>DomainDNSSetCustomResult"`
DomainSetContacts *DomainSetContactsResult `xml:"CommandResponse>DomainSetContactResult"`
SslActivate *SslActivateResult `xml:"CommandResponse>SSLActivateResult"`
SslCreate *SslCreateResult `xml:"CommandResponse>SSLCreateResult"`
SslCertificates []SslGetListResult `xml:"CommandResponse>SSLListResult>SSL"`
UsersGetPricing []UsersGetPricingResult `xml:"CommandResponse>UserGetPricingResult>ProductType"`
WhoisguardList []WhoisguardGetListResult `xml:"CommandResponse>WhoisguardGetListResult>Whoisguard"`
WhoisguardEnable whoisguardEnableResult `xml:"CommandResponse>WhoisguardEnableResult"`
WhoisguardDisable whoisguardDisableResult `xml:"CommandResponse>WhoisguardDisableResult"`
WhoisguardRenew *WhoisguardRenewResult `xml:"CommandResponse>WhoisguardRenewResult"`
Errors ApiErrors `xml:"Errors>Error"`
Status string `xml:"Status,attr"`
Command string `xml:"RequestedCommand"`
TLDList []TLDListResult `xml:"CommandResponse>Tlds>Tld"`
Domains []DomainGetListResult `xml:"CommandResponse>DomainGetListResult>Domain"`
DomainInfo *DomainInfo `xml:"CommandResponse>DomainGetInfoResult"`
DomainDNSHosts *DomainDNSGetHostsResult `xml:"CommandResponse>DomainDNSGetHostsResult"`
DomainDNSSetHosts *DomainDNSSetHostsResult `xml:"CommandResponse>DomainDNSSetHostsResult"`
DomainCreate *DomainCreateResult `xml:"CommandResponse>DomainCreateResult"`
DomainRenew *DomainRenewResult `xml:"CommandResponse>DomainRenewResult"`
DomainsCheck []DomainCheckResult `xml:"CommandResponse>DomainCheckResult"`
DomainNSInfo *DomainNSInfoResult `xml:"CommandResponse>DomainNSInfoResult"`
DomainDNSSetCustom *DomainDNSSetCustomResult `xml:"CommandResponse>DomainDNSSetCustomResult"`
DomainSetContacts *DomainSetContactsResult `xml:"CommandResponse>DomainSetContactResult"`
DomainRegistrarLockStatus *DomainRegistrarLockStatusResult `xml:"CommandResponse>DomainGetRegistrarLockResult"`
DomainSetRegistrarLock *DomainSetRegistrarLockResult `xml:"CommandResponse>DomainSetRegistrarLockResult"`
SslActivate *SslActivateResult `xml:"CommandResponse>SSLActivateResult"`
SslCreate *SslCreateResult `xml:"CommandResponse>SSLCreateResult"`
SslCertificates []SslGetListResult `xml:"CommandResponse>SSLListResult>SSL"`
UsersGetPricing []UsersGetPricingResult `xml:"CommandResponse>UserGetPricingResult>ProductType"`
WhoisguardList []WhoisguardGetListResult `xml:"CommandResponse>WhoisguardGetListResult>Whoisguard"`
WhoisguardEnable whoisguardEnableResult `xml:"CommandResponse>WhoisguardEnableResult"`
WhoisguardDisable whoisguardDisableResult `xml:"CommandResponse>WhoisguardDisableResult"`
WhoisguardRenew *WhoisguardRenewResult `xml:"CommandResponse>WhoisguardRenewResult"`
Errors ApiErrors `xml:"Errors>Error"`
GMTTimeDifference NamecheapTimeLocation `xml:"GMTTimeDifference"`
}

func (a *ApiResponse) ParseTime(layout, value string) (time.Time, error) {
return time.ParseInLocation(layout, value, a.GMTTimeDifference.Location)
}

func (a *ApiResponse) ParseDate(value string) (time.Time, error) {
return time.ParseInLocation("01/02/2006", value, a.GMTTimeDifference.Location)
}

// ApiError is the format of the error returned in the api responses.
Expand Down
2 changes: 2 additions & 0 deletions whoisguard.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ func (client *Client) WhoisguardGetList() ([]WhoisguardGetListResult, error) {
params: url.Values{},
}

requestInfo.params.Set("PageSize", "100")

resp, err := client.do(requestInfo)
if err != nil {
return nil, err
Expand Down