enom 0.0.1 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,9 +1,8 @@
1
- require 'rest_client'
2
- require 'crack/xml'
3
- require File.expand_path(File.dirname(__FILE__) + '/enom/client')
4
- require File.expand_path(File.dirname(__FILE__) + '/enom/domain')
1
+ require 'httparty'
5
2
 
6
- module Enom
7
- class InterfaceError < StandardError; end
8
- class InvalidNameServerCount < StandardError; end
9
- end
3
+ require 'enom/client'
4
+ require 'enom/domain'
5
+ require 'enom/account'
6
+ require 'enom/error'
7
+
8
+ module Enom; end
@@ -0,0 +1,9 @@
1
+ module Enom
2
+ class Account
3
+
4
+ def self.balance
5
+ Client.request('Command' => 'GetBalance')['interface_response']['AvailableBalance'].gsub(',', '').to_f
6
+ end
7
+
8
+ end
9
+ end
@@ -0,0 +1,50 @@
1
+ require 'yaml'
2
+ module Enom
3
+
4
+ class CommandNotFound < RuntimeError; end
5
+
6
+ class CLI
7
+
8
+ def initialize
9
+ Client.username = "test"
10
+ Client.password = "password"
11
+ end
12
+
13
+ def execute(command_name, args, options={})
14
+ command = commands[command_name]
15
+ if command
16
+ begin
17
+ command.new.execute(args, options)
18
+ rescue Enom::Error => e
19
+ puts "An error occurred: #{e.message}"
20
+ rescue RuntimeError => e
21
+ puts "An error occurred: #{e.message}"
22
+ end
23
+ else
24
+ raise CommandNotFound, "Unknown command: #{command_name}"
25
+ end
26
+ end
27
+
28
+ def commands
29
+ {
30
+ 'info' => Enom::Commands::DescribeAccount,
31
+ 'check' => Enom::Commands::CheckDomain,
32
+ 'register' => Enom::Commands::RegisterDomain,
33
+ # 'renew' => Enom::Commands::RenewDomain,
34
+ # 'transfer' => Enom::Commands::TransferDomain,
35
+ # 'describe' => Enom::Commands::DescribeDomain,
36
+ 'list' => Enom::Commands::ListDomains,
37
+ # 'lock' => Enom::Commands::LockDomain,
38
+ # 'unlock' => Enom::Commands::UnlockDomain,
39
+ # 'nameservers:list' => Enom::Commands::ListNameservers,
40
+ # 'nameservers:set' => Enom::Commands::SetNameservers
41
+ }
42
+ end
43
+
44
+ require 'enom/commands/describe_account'
45
+ require 'enom/commands/check_domain'
46
+ require 'enom/commands/register_domain'
47
+ require 'enom/commands/list_domains'
48
+
49
+ end
50
+ end
@@ -1,43 +1,40 @@
1
- require 'cgi'
2
1
  module Enom
3
2
 
4
3
  class Client
4
+ include HTTParty
5
5
 
6
- def initialize(username, password, ssl = true, test = false)
7
- @@username = username
8
- @@password = password
9
- @@protocol = ssl == true ? "https" : "http"
10
- @@endpoint = test == true ? "resellertest.enom.com" : "reseller.enom.com"
11
- end
12
-
13
- def find_domain(name)
14
- sld, tld = name.split('.')
15
- payload = get('Command' => 'GetDomainInfo', 'SLD' => sld, 'TLD' => tld)
16
- Domain.new(payload)
17
- end
18
-
19
- def get_balance
20
- get('Command' => 'GetBalance')
21
- end
6
+ class << self
7
+ attr_accessor :username, :password, :test
8
+ alias_method :test?, :test
22
9
 
23
- private
10
+ # All requests must contain the UID, PW, and ResponseType query parameters
11
+ def default_params
12
+ { 'UID' => self.username, 'PW' => self.password, 'ResponseType' => 'xml'}
13
+ end
24
14
 
25
- def get(params = {})
26
- params.merge!(default_params)
27
- payload = Crack::XML.parse(RestClient.get(url, {:params => params }))
28
- if payload['interface_response']['ErrCount'] == '0'
29
- return payload
30
- else
31
- raise InterfaceError
15
+ # Enom has a test platform and a production platform. Both are configured to use
16
+ # HTTPS at all times. Don't forget to configure permitted IPs (in both environments)
17
+ # or you'll get InterfaceErrors.
18
+ def base_uri
19
+ @base_uri = test? ? "https://resellertest.enom.com/interface.asp" : "https://reseller.enom.com/interface.asp"
32
20
  end
33
- end
34
21
 
35
- def url
36
- @@protocol + "://" + @@endpoint + "/interface.asp"
37
- end
22
+ # All requests to Enom are GET requests, even when we're changing data. Unfortunately,
23
+ # Enom also does not provide HTTP status codes to alert for authentication failures
24
+ # or other helpful statuses -- everything comes back as a 200.
25
+ def request(params = {})
26
+ params.merge!(default_params)
27
+ response = get(base_uri, :query => params)
28
+ case response.code
29
+ when 200
30
+ if response['interface_response']['ErrCount'] == '0'
31
+ return response
32
+ else
33
+ raise InterfaceError
34
+ end
35
+ end
36
+ end
38
37
 
39
- def default_params
40
- { 'UID' => @@username, 'PW' => @@password, 'ResponseType' => 'xml'}
41
38
  end
42
39
 
43
40
  end
@@ -1,32 +1,108 @@
1
1
  module Enom
2
- class Domain < Client
3
2
 
4
- attr_reader :name, :sld, :tld
3
+ class Domain
4
+ include HTTParty
5
5
 
6
- def initialize(payload)
7
- @name = payload['interface_response']['GetDomainInfo']['domainname']
8
- @sld, @tld = @name.split('.')
9
- @domain_payload = payload
6
+ # The domain name on Enom
7
+ attr_reader :name
8
+
9
+ # Second-level and first-level domain on Enom
10
+ attr_reader :sld, :tld
11
+
12
+ # Domain expiration date (currently returns a string - 11/9/2010 11:57:39 AM)
13
+ attr_reader :expiration_date
14
+
15
+
16
+ def initialize(attributes)
17
+ @name = attributes["DomainName"] || attributes["domainname"]
18
+ @sld, @tld = @name.split('.')
19
+ expiration_string = attributes["expiration_date"] || attributes["status"]["expiration"]
20
+ @expiration_date = Date.parse(expiration_string.split(' ').first)
21
+
22
+ # If we have more attributes for the domain from running GetDomainInfo
23
+ # (as opposed to GetAllDomains), we should save it to the instance to
24
+ # save on future API calls
25
+ if attributes["services"] && attributes["status"]
26
+ set_extended_domain_attributes(attributes)
27
+ end
28
+ end
29
+
30
+ # Find the domain (must be in your account) on Enom
31
+ def self.find(name)
32
+ sld, tld = name.split('.')
33
+ response = Client.request('Command' => 'GetDomainInfo', 'SLD' => sld, 'TLD' => tld)["interface_response"]["GetDomainInfo"]
34
+ p response if Client.test?
35
+ Domain.new(response)
36
+ end
37
+
38
+ # Determine if the domain is available for purchase
39
+ # def self.check(name)
40
+ # sld, tld = name.split('.')
41
+ # response = self.get("#{Client.base_uri}/domains/#{name}/check.json", options)
42
+ #
43
+ # p response if Client.test?
44
+ #
45
+ # # return "registered" or "available"
46
+ # end
47
+
48
+ # Find and return all domains in the account
49
+ def self.all(options = {})
50
+ response = Client.request("Command" => "GetAllDomains")["interface_response"]["GetAllDomains"]["DomainDetail"]
51
+
52
+ p response if Client.test?
53
+
54
+ domains = []
55
+ response.each {|d| domains << Domain.new(d) }
56
+ return domains
57
+ end
58
+
59
+ # Purchase the domain
60
+ def self.register!(name, options = {})
61
+ sld, tld = name.split('.')
62
+ opts = {}
63
+ if options[:nameservers]
64
+ count = 1
65
+ options[:nameservers].each do |nameserver|
66
+ opts.merge!("NS#{count}" => nameserver)
67
+ count += 1
68
+ end
69
+ end
70
+ opts.merge!('NumYears' => options[:years]) if options[:years]
71
+ purchase = get({'Command' => 'Purchase', 'SLD' => sld, 'TLD' => tld}.merge(opts))
72
+ self.find(name)
10
73
  end
11
74
 
75
+ # Lock the domain at the registrar so it can't be transferred
12
76
  def lock
13
- get('Command' => 'SetRegLock', 'SLD' => sld, 'TLD' => tld, 'UnlockRegistrar' => '0')
77
+ Client.request('Command' => 'SetRegLock', 'SLD' => sld, 'TLD' => tld, 'UnlockRegistrar' => '0')
78
+ @locked = true
79
+ return self
14
80
  end
15
81
 
82
+ # Unlock the domain at the registrar to permit transfers
16
83
  def unlock
17
- get('Command' => 'SetRegLock', 'SLD' => sld, 'TLD' => tld, 'UnlockRegistrar' => '1')
84
+ Client.request('Command' => 'SetRegLock', 'SLD' => sld, 'TLD' => tld, 'UnlockRegistrar' => '1')
85
+ @locked = false
86
+ return self
18
87
  end
19
88
 
20
- def locked?
21
- payload = get('Command' => 'GetRegLock', 'SLD' => sld, 'TLD' => tld)
22
- payload['interface_response']['reg_lock'] == '1' ? true : false
89
+ # Check if the domain is currently locked. locked? helper method also available
90
+ def locked
91
+ unless @locked
92
+ response = Client.request('Command' => 'GetRegLock', 'SLD' => sld, 'TLD' => tld)['interface_response']['reg_lock']
93
+ @locked = response == '1'
94
+ end
95
+ return @locked
23
96
  end
97
+ alias_method :locked?, :locked
24
98
 
99
+ # Return the DNS nameservers that are currently used for the domain
25
100
  def nameservers
26
- @domain_payload['interface_response']['GetDomainInfo']['services']['entry'].first['configuration']['dns']
101
+ get_extended_domain_attributes unless @nameservers
102
+ return @nameservers
27
103
  end
28
104
 
29
- def update_nameservers(nameservers)
105
+ def update_nameservers(nameservers = [])
30
106
  count = 1
31
107
  ns = {}
32
108
  if (2..12).include?(nameservers.size)
@@ -34,24 +110,52 @@ module Enom
34
110
  ns.merge!("NS#{count}" => nameserver)
35
111
  count += 1
36
112
  end
37
- get({'Command' => 'ModifyNS', 'SLD' => sld, 'TLD' => tld}.merge(ns))
113
+ Client.request({'Command' => 'ModifyNS', 'SLD' => sld, 'TLD' => tld}.merge(ns))
114
+ @nameservers = ns.values
115
+ return self
38
116
  else
39
- raise InvalidNameServerCount, "A minimum of 2 and maximum of 12 nameservers are required"
117
+ raise InvalidNameServerCount
40
118
  end
41
119
  end
42
120
 
43
121
  def expiration_date
44
- @domain_payload['interface_response']['GetDomainInfo']['status']['expiration']
122
+ date_string = @domain_payload['interface_response']['GetDomainInfo']['status']['expiration']
123
+ Date.parse(date_string.split(' ').first)
124
+ end
125
+
126
+ def registration_status
127
+ get_extended_domain_attributes unless @registration_status
128
+ return @registration_status
129
+ end
130
+
131
+ def active?
132
+ registration_status == "Registered"
45
133
  end
46
134
 
47
135
  def expired?
136
+ registration_status == "Expired"
48
137
  end
49
138
 
50
- def registration_status
51
- @domain_payload['interface_response']['GetDomainInfo']['status']['registrationstatus']
139
+ def renew!(years = 1)
140
+ # get('Command' => 'Renew', 'SLD' => sld, 'TLD' => tld)
141
+ raise NotImplementedError
142
+ end
143
+
144
+ private
145
+
146
+ # Make another API call to get all domain info. Often necessary when domains are
147
+ # found using Domain.all instead of Domain.find.
148
+ def get_extended_domain_attributes
149
+ sld, tld = name.split('.')
150
+ attributes = Client.request('Command' => 'GetDomainInfo', 'SLD' => sld, 'TLD' => tld)["interface_response"]["GetDomainInfo"]
151
+ set_extended_domain_attributes(attributes)
52
152
  end
53
153
 
54
- def renew
154
+ # Set any more attributes that we have to work with to instance variables
155
+ def set_extended_domain_attributes(attributes)
156
+ @nameservers = attributes['services']['entry'].first['configuration']['dns']
157
+ @registration_status = attributes['status']['registrationstatus']
158
+ return self
55
159
  end
56
160
 
57
161
  end
@@ -0,0 +1,25 @@
1
+ module Enom
2
+
3
+ class InterfaceError < StandardError
4
+ def initialize(message = nil)
5
+ if message
6
+ super message
7
+ else
8
+ super "An unknown error occurred. Check your username, password, and make sure your IP address is permitted to access the Enom API"
9
+ end
10
+ end
11
+ end
12
+
13
+ class NotImplementedError < StandardError
14
+ def initialize
15
+ super "The command you tried is not yet implemented, but we're planning on it! Feel free to fork the project and contribute!"
16
+ end
17
+ end
18
+
19
+ class InvalidNameServerCount < StandardError
20
+ def initialize
21
+ super "A minimum of 2 and maximum of 12 nameservers are required"
22
+ end
23
+ end
24
+
25
+ end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: enom
3
3
  version: !ruby/object:Gem::Version
4
- hash: 29
4
+ hash: 59
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
+ - 9
8
9
  - 0
9
- - 1
10
- version: 0.0.1
10
+ version: 0.9.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - James Miller
@@ -15,44 +15,29 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-09-13 00:00:00 -07:00
18
+ date: 2010-11-13 00:00:00 -06:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
22
- name: rest-client
22
+ name: httparty
23
23
  prerelease: false
24
24
  requirement: &id001 !ruby/object:Gem::Requirement
25
25
  none: false
26
26
  requirements:
27
27
  - - ~>
28
28
  - !ruby/object:Gem::Version
29
- hash: 15
30
- segments:
31
- - 1
32
- - 6
33
- - 0
34
- version: 1.6.0
35
- type: :runtime
36
- version_requirements: *id001
37
- - !ruby/object:Gem::Dependency
38
- name: crack
39
- prerelease: false
40
- requirement: &id002 !ruby/object:Gem::Requirement
41
- none: false
42
- requirements:
43
- - - ~>
44
- - !ruby/object:Gem::Version
45
- hash: 9
29
+ hash: 5
46
30
  segments:
47
31
  - 0
32
+ - 6
48
33
  - 1
49
- version: "0.1"
34
+ version: 0.6.1
50
35
  type: :runtime
51
- version_requirements: *id002
36
+ version_requirements: *id001
52
37
  - !ruby/object:Gem::Dependency
53
38
  name: shoulda
54
39
  prerelease: false
55
- requirement: &id003 !ruby/object:Gem::Requirement
40
+ requirement: &id002 !ruby/object:Gem::Requirement
56
41
  none: false
57
42
  requirements:
58
43
  - - ">="
@@ -62,8 +47,8 @@ dependencies:
62
47
  - 0
63
48
  version: "0"
64
49
  type: :development
65
- version_requirements: *id003
66
- description: Enom is a simple Ruby wrapper for a small portion of the Enom domain reseller API.
50
+ version_requirements: *id002
51
+ description: Enom is a simple Ruby wrapper for portions of the Enom domain reseller API.
67
52
  email: bensie@gmail.com
68
53
  executables: []
69
54
 
@@ -76,8 +61,11 @@ files:
76
61
  - Rakefile
77
62
  - LICENSE
78
63
  - lib/enom.rb
64
+ - lib/enom/account.rb
65
+ - lib/enom/cli.rb
79
66
  - lib/enom/client.rb
80
67
  - lib/enom/domain.rb
68
+ - lib/enom/error.rb
81
69
  - test/enom_test.rb
82
70
  - test/test_helper.rb
83
71
  has_rdoc: true