enom 0.0.1 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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