dnsimple 2.0.0.a

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.
Files changed (61) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +8 -0
  3. data/.rspec +1 -0
  4. data/.ruby-gemset +1 -0
  5. data/.ruby-version +1 -0
  6. data/.travis.yml +7 -0
  7. data/CHANGELOG.markdown +50 -0
  8. data/Gemfile +3 -0
  9. data/LICENSE +22 -0
  10. data/README.markdown +60 -0
  11. data/Rakefile +33 -0
  12. data/dnsimple-ruby.gemspec +26 -0
  13. data/lib/dnsimple-ruby.rb +1 -0
  14. data/lib/dnsimple.rb +33 -0
  15. data/lib/dnsimple/base.rb +10 -0
  16. data/lib/dnsimple/certificate.rb +129 -0
  17. data/lib/dnsimple/client.rb +144 -0
  18. data/lib/dnsimple/contact.rb +154 -0
  19. data/lib/dnsimple/domain.rb +217 -0
  20. data/lib/dnsimple/error.rb +21 -0
  21. data/lib/dnsimple/extended_attribute.rb +52 -0
  22. data/lib/dnsimple/record.rb +94 -0
  23. data/lib/dnsimple/service.rb +42 -0
  24. data/lib/dnsimple/template.rb +63 -0
  25. data/lib/dnsimple/template_record.rb +80 -0
  26. data/lib/dnsimple/transfer_order.rb +34 -0
  27. data/lib/dnsimple/user.rb +26 -0
  28. data/lib/dnsimple/version.rb +3 -0
  29. data/spec/ci/.dnsimple.test +3 -0
  30. data/spec/dnsimple/certificate_spec.rb +56 -0
  31. data/spec/dnsimple/client_spec.rb +107 -0
  32. data/spec/dnsimple/contact_spec.rb +45 -0
  33. data/spec/dnsimple/domain_spec.rb +133 -0
  34. data/spec/dnsimple/extended_attributes_spec.rb +54 -0
  35. data/spec/dnsimple/record_spec.rb +51 -0
  36. data/spec/dnsimple/template_spec.rb +31 -0
  37. data/spec/dnsimple/user_spec.rb +31 -0
  38. data/spec/files/account/user/success.http +19 -0
  39. data/spec/files/certificates/index/success.http +19 -0
  40. data/spec/files/certificates/show/notfound.http +17 -0
  41. data/spec/files/certificates/show/success.http +19 -0
  42. data/spec/files/contacts/show/notfound.http +17 -0
  43. data/spec/files/contacts/show/success.http +19 -0
  44. data/spec/files/domains/auto_renewal_disable/notfound.http +21 -0
  45. data/spec/files/domains/auto_renewal_disable/success.http +23 -0
  46. data/spec/files/domains/auto_renewal_enable/notfound.http +21 -0
  47. data/spec/files/domains/auto_renewal_enable/success.http +23 -0
  48. data/spec/files/domains/show/notfound.http +17 -0
  49. data/spec/files/domains/show/success.http +19 -0
  50. data/spec/files/extended_attributes/ca.http +19 -0
  51. data/spec/files/extended_attributes/com.http +19 -0
  52. data/spec/files/extended_attributes/success.http +19 -0
  53. data/spec/files/records/index/success.http +19 -0
  54. data/spec/files/records/show/notfound.http +17 -0
  55. data/spec/files/records/show/success.http +19 -0
  56. data/spec/files/templates/show/notfound.http +17 -0
  57. data/spec/files/templates/show/success.http +19 -0
  58. data/spec/spec_helper.rb +34 -0
  59. data/spec/support/helpers.rb +15 -0
  60. data/spec/support/webmock.rb +11 -0
  61. metadata +224 -0
@@ -0,0 +1,154 @@
1
+ module DNSimple
2
+
3
+ # Represents a contact.
4
+ class Contact < Base
5
+
6
+ Aliases = {
7
+ 'first' => 'first_name',
8
+ 'last' => 'last_name',
9
+ 'state' => 'state_province',
10
+ 'province' => 'state_province',
11
+ 'state_or_province' => 'state_province',
12
+ 'email' => 'email_address',
13
+ }
14
+
15
+ # The contact ID in DNSimple
16
+ attr_accessor :id
17
+
18
+ # The contact first name
19
+ attr_accessor :first_name
20
+
21
+ # The contact last name
22
+ attr_accessor :last_name
23
+
24
+ # The contact's job title
25
+ attr_accessor :job_title
26
+
27
+ # The name of the organization in which the contact works
28
+ attr_accessor :organization_name
29
+
30
+ # The contact email address
31
+ attr_accessor :email_address
32
+
33
+ # The contact phone number
34
+ attr_accessor :phone
35
+
36
+ # The contact phone extension (may be omitted)
37
+ attr_accessor :phone_ext
38
+
39
+ # The contact fax number (may be omitted)
40
+ attr_accessor :fax
41
+
42
+ # The contact street address
43
+ attr_accessor :address1
44
+
45
+ # Apartment or suite number
46
+ attr_accessor :address2
47
+
48
+ # The city name
49
+ attr_accessor :city
50
+
51
+ # The state or province name
52
+ attr_accessor :state_province
53
+
54
+ # The contact postal code
55
+ attr_accessor :postal_code
56
+
57
+ # The contact country (as a 2-character country code)
58
+ attr_accessor :country
59
+
60
+ # When the contact was created in DNSimple
61
+ attr_accessor :created_at
62
+
63
+ # When the contact was last updated in DNSimple
64
+ attr_accessor :updated_at
65
+
66
+
67
+ # Map an aliased field name to it's real name. For example, if you
68
+ # pass "first" it will be resolved to "first_name", "email" is resolved
69
+ # to "email_address" and so on.
70
+ def self.resolve(name)
71
+ DNSimple::Contact::Aliases[name.to_s] || name
72
+ end
73
+
74
+ def self.resolve_attributes(attributes)
75
+ resolved_attributes = {}
76
+ attributes.each do |k, v|
77
+ resolved_attributes[resolve(k)] = v
78
+ end
79
+ resolved_attributes
80
+ end
81
+
82
+ # Create the contact with the given attributes in DNSimple.
83
+ # This method returns a Contact instance of the contact is created
84
+ # and raises an error otherwise.
85
+ def self.create(attributes, options={})
86
+ contact_hash = resolve_attributes(attributes)
87
+
88
+ options.merge!({:body => {:contact => contact_hash}})
89
+ response = DNSimple::Client.post("/v1/contacts", options)
90
+
91
+ case response.code
92
+ when 201
93
+ new(response["contact"])
94
+ else
95
+ raise RequestError.new("Error creating contact", response)
96
+ end
97
+ end
98
+
99
+ def self.find(id, options={})
100
+ response = DNSimple::Client.get("/v1/contacts/#{id}", options)
101
+
102
+ case response.code
103
+ when 200
104
+ new(response["contact"])
105
+ when 404
106
+ raise RecordNotFound, "Could not find contact #{id}"
107
+ else
108
+ raise RequestError.new("Error finding contact", response)
109
+ end
110
+ end
111
+
112
+ def self.all(options={})
113
+ response = DNSimple::Client.get("/v1/contacts", options)
114
+
115
+ case response.code
116
+ when 200
117
+ response.map { |r| new(r["contact"]) }
118
+ else
119
+ raise RequestError.new("Error listing contacts", response)
120
+ end
121
+ end
122
+
123
+
124
+ def name
125
+ [first_name, last_name].join(' ')
126
+ end
127
+
128
+ def save(options={})
129
+ contact_hash = {}
130
+ %w(first_name last_name organization_name job_title address1 address2 city
131
+ state_province postal_code country email_address phone phone_ext fax).each do |attribute|
132
+ contact_hash[DNSimple::Contact.resolve(attribute)] = self.send(attribute)
133
+ end
134
+
135
+ options.merge!({:body => {:contact => contact_hash}})
136
+
137
+ response = DNSimple::Client.put("/v1/contacts/#{id}", options)
138
+
139
+ case response.code
140
+ when 200
141
+ return self
142
+ else
143
+ raise RequestError.new("Error updating contact", response)
144
+ end
145
+ end
146
+
147
+ # Delete the contact from DNSimple. WARNING: this cannot be undone.
148
+ def delete(options={})
149
+ DNSimple::Client.delete("/v1/contacts/#{id}", options)
150
+ end
151
+ alias :destroy :delete
152
+
153
+ end
154
+ end
@@ -0,0 +1,217 @@
1
+ module DNSimple
2
+ class Domain < Base
3
+
4
+ # The domain ID in DNSimple
5
+ attr_accessor :id
6
+
7
+ # The domain name
8
+ attr_accessor :name
9
+
10
+ # When the domain was created in DNSimple
11
+ attr_accessor :created_at
12
+
13
+ # When the domain was last update in DNSimple
14
+ attr_accessor :updated_at
15
+
16
+ # The current known name server status
17
+ attr_accessor :name_server_status
18
+
19
+ # When the domain is due to expire
20
+ attr_accessor :expires_on
21
+
22
+ # The state of the domain in DNSimple
23
+ attr_accessor :state
24
+
25
+ # ID of the registrant in DNSimple
26
+ attr_accessor :registrant_id
27
+
28
+ # User ID in DNSimple
29
+ attr_accessor :user_id
30
+
31
+ # Is the domain lockable
32
+ attr_accessor :lockable
33
+
34
+ # Is the domain set to autorenew
35
+ attr_accessor :auto_renew
36
+
37
+ # Is the whois information protected
38
+ attr_accessor :whois_protected
39
+
40
+
41
+ # Check the availability of a name
42
+ def self.check(name, options={})
43
+ response = DNSimple::Client.get("/v1/domains/#{name}/check", options)
44
+
45
+ case response.code
46
+ when 200
47
+ "registered"
48
+ when 404
49
+ "available"
50
+ else
51
+ raise RequestError.new("Error checking availability", response)
52
+ end
53
+ end
54
+
55
+ # Create the domain with the given name in DNSimple. This
56
+ # method returns a Domain instance if the name is created
57
+ # and raises an error otherwise.
58
+ def self.create(name, options={})
59
+ options.merge!({:body => {:domain => {:name => name}}})
60
+
61
+ response = DNSimple::Client.post("/v1/domains", options)
62
+
63
+ case response.code
64
+ when 201
65
+ new(response["domain"])
66
+ else
67
+ raise RequestError.new("Error creating domain", response)
68
+ end
69
+ end
70
+
71
+ # Purchase a domain name.
72
+ def self.register(name, registrant={}, extended_attributes={}, options={})
73
+ body = {:domain => {:name => name}}
74
+ if registrant
75
+ if registrant[:id]
76
+ body[:domain][:registrant_id] = registrant[:id]
77
+ else
78
+ body.merge!(:contact => DNSimple::Contact.resolve_attributes(registrant))
79
+ end
80
+ end
81
+ body.merge!(:extended_attribute => extended_attributes)
82
+ options.merge!({:body => body})
83
+
84
+ response = DNSimple::Client.post("/v1/domain_registrations", options)
85
+
86
+ case response.code
87
+ when 201
88
+ return DNSimple::Domain.new(response["domain"])
89
+ else
90
+ raise RequestError.new("Error registering domain", response)
91
+ end
92
+ end
93
+
94
+ # Find a specific domain in the account either by the numeric ID
95
+ # or by the fully-qualified domain name.
96
+ def self.find(id, options={})
97
+ response = DNSimple::Client.get("/v1/domains/#{id}", options)
98
+
99
+ case response.code
100
+ when 200
101
+ new(response["domain"])
102
+ when 404
103
+ raise RecordNotFound, "Could not find domain #{id}"
104
+ else
105
+ raise RequestError.new("Error finding domain", response)
106
+ end
107
+ end
108
+
109
+ # Get all domains for the account.
110
+ def self.all(options={})
111
+ response = DNSimple::Client.get("/v1/domains", options)
112
+
113
+ case response.code
114
+ when 200
115
+ response.map { |r| new(r["domain"]) }
116
+ else
117
+ raise RequestError.new("Error listing domains", response)
118
+ end
119
+ end
120
+
121
+ # Enable auto_renew on the domain
122
+ def enable_auto_renew
123
+ return if auto_renew
124
+ auto_renew!(:post)
125
+ end
126
+
127
+ # Disable auto_renew on the domain
128
+ def disable_auto_renew
129
+ return unless auto_renew
130
+ auto_renew!(:delete)
131
+ end
132
+
133
+ # Delete the domain from DNSimple. WARNING: this cannot
134
+ # be undone.
135
+ def delete(options={})
136
+ DNSimple::Client.delete("/v1/domains/#{name}", options)
137
+ end
138
+ alias :destroy :delete
139
+
140
+ # Apply the given named template to the domain. This will add
141
+ # all of the records in the template to the domain.
142
+ def apply(template, options={})
143
+ options.merge!(:body => {})
144
+ template = resolve_template(template)
145
+
146
+ DNSimple::Client.post("/v1/domains/#{name}/templates/#{template.id}/apply", options)
147
+ end
148
+
149
+ def resolve_template(template)
150
+ case template
151
+ when DNSimple::Template
152
+ template
153
+ else
154
+ DNSimple::Template.find(template)
155
+ end
156
+ end
157
+
158
+ def applied_services(options={})
159
+ response = DNSimple::Client.get("/v1/domains/#{name}/applied_services", options)
160
+
161
+ case response.code
162
+ when 200
163
+ response.map { |r| DNSimple::Service.new(r["service"]) }
164
+ else
165
+ raise RequestError.new("Error listing applied services", response)
166
+ end
167
+ end
168
+
169
+ def available_services(options={})
170
+ response = DNSimple::Client.get("/v1/domains/#{name}/available_services", options)
171
+
172
+ case response.code
173
+ when 200
174
+ response.map { |r| DNSimple::Service.new(r["service"]) }
175
+ else
176
+ raise RequestError.new("Error listing available services", response)
177
+ end
178
+ end
179
+
180
+ def add_service(id_or_short_name, options={})
181
+ options.merge!(:body => {:service => {:id => id_or_short_name}})
182
+ response = DNSimple::Client.post("/v1/domains/#{name}/applied_services", options)
183
+
184
+ case response.code
185
+ when 200
186
+ true
187
+ else
188
+ raise RequestError.new("Error adding service", response)
189
+ end
190
+ end
191
+
192
+ def remove_service(id, options={})
193
+ response = DNSimple::Client.delete("/v1/domains/#{name}/applied_services/#{id}", options)
194
+
195
+ case response.code
196
+ when 200
197
+ true
198
+ else
199
+ raise RequestError.new("Error removing service", response)
200
+ end
201
+ end
202
+
203
+
204
+ private
205
+
206
+ def auto_renew!(method)
207
+ response = DNSimple::Client.send(method, "/v1/domains/#{name}/auto_renewal")
208
+ case response.code
209
+ when 200
210
+ self.auto_renew = response['domain']['auto_renew']
211
+ else
212
+ raise RequestError.new("Error setting auto_renew", response)
213
+ end
214
+ end
215
+
216
+ end
217
+ end
@@ -0,0 +1,21 @@
1
+ module DNSimple
2
+
3
+ class Error < StandardError
4
+ end
5
+
6
+ class RecordExists < Error
7
+ end
8
+
9
+ class RecordNotFound < Error
10
+ end
11
+
12
+ class RequestError < Error
13
+ def initialize(description, response)
14
+ super("#{description}: #{response["error"]}")
15
+ end
16
+ end
17
+
18
+ class AuthenticationFailed < Error
19
+ end
20
+
21
+ end
@@ -0,0 +1,52 @@
1
+ module DNSimple
2
+
3
+ # Used for domains that require extended attributes.
4
+ class ExtendedAttribute < Base
5
+
6
+ # An option for an extended attribute
7
+ class Option < Base
8
+ # The option name
9
+ attr_accessor :title
10
+
11
+ # The option value
12
+ attr_accessor :value
13
+
14
+ # A long description of the option
15
+ attr_accessor :description
16
+ end
17
+
18
+ # The extended attribute name
19
+ attr_accessor :name
20
+
21
+ # A description of the extended attribute
22
+ attr_accessor :description
23
+
24
+ # Boolean indicating if the extended attribute is required
25
+ attr_accessor :required
26
+
27
+ # An array of options for the extended attribute
28
+ def options
29
+ @options ||= []
30
+ end
31
+
32
+ def options=(opts)
33
+ @options = []
34
+ opts.each do |opt|
35
+ @options << DNSimple::ExtendedAttribute::Option.new(opt)
36
+ end
37
+ end
38
+
39
+ # Find the extended attributes for the given TLD
40
+ def self.find(tld, options={})
41
+ response = DNSimple::Client.get("/v1/extended_attributes/#{tld}", options)
42
+
43
+ case response.code
44
+ when 200
45
+ response.map { |r| new(r) }
46
+ else
47
+ raise RequestError.new("Error finding extended attributes", response)
48
+ end
49
+ end
50
+
51
+ end
52
+ end
@@ -0,0 +1,94 @@
1
+ module DNSimple
2
+
3
+ class Record < Base
4
+ Aliases = {
5
+ 'priority' => 'prio',
6
+ 'time-to-live' => 'ttl'
7
+ }
8
+
9
+ attr_accessor :id
10
+ attr_accessor :domain
11
+ attr_accessor :name
12
+ attr_accessor :content
13
+ attr_accessor :ttl
14
+ attr_accessor :prio
15
+ attr_accessor :record_type
16
+
17
+
18
+ def fqdn
19
+ [name, domain.name].delete_if { |v| v !~ DNSimple::BLANK_REGEX }.join(".")
20
+ end
21
+
22
+ def save(options={})
23
+ record_hash = {}
24
+ %w(name content ttl prio).each do |attribute|
25
+ record_hash[DNSimple::Record.resolve(attribute)] = self.send(attribute)
26
+ end
27
+
28
+ options.merge!(:body => {:record => record_hash})
29
+
30
+ response = DNSimple::Client.put("/v1/domains/#{domain.id}/records/#{id}", options)
31
+
32
+ case response.code
33
+ when 200
34
+ self
35
+ else
36
+ raise RequestError.new("Error updating record", response)
37
+ end
38
+ end
39
+
40
+ def delete(options={})
41
+ DNSimple::Client.delete("/v1/domains/#{domain.id}/records/#{id}", options)
42
+ end
43
+ alias :destroy :delete
44
+
45
+ def self.resolve(name)
46
+ DNSimple::Record::Aliases[name] || name
47
+ end
48
+
49
+ def self.create(domain, name, record_type, content, options={})
50
+ record_hash = {:name => name, :record_type => record_type, :content => content}
51
+ record_hash[:ttl] = options.delete(:ttl) || 3600
52
+ record_hash[:prio] = options.delete(:priority)
53
+ record_hash[:prio] = options.delete(:prio) || ''
54
+
55
+ options.merge!({:body => {:record => record_hash}})
56
+
57
+ response = DNSimple::Client.post("/v1/domains/#{domain.name}/records", options)
58
+
59
+ case response.code
60
+ when 201
61
+ new({:domain => domain}.merge(response["record"]))
62
+ when 406
63
+ raise RecordExists, "Record #{name}.#{domain.name} already exists"
64
+ else
65
+ raise RequestError.new("Error creating record", response)
66
+ end
67
+ end
68
+
69
+ def self.find(domain, id, options={})
70
+ response = DNSimple::Client.get("/v1/domains/#{domain.name}/records/#{id}", options)
71
+
72
+ case response.code
73
+ when 200
74
+ new({:domain => domain}.merge(response["record"]))
75
+ when 404
76
+ raise RecordNotFound, "Could not find record #{id} for domain #{domain.name}"
77
+ else
78
+ raise RequestError.new("Error finding record", response)
79
+ end
80
+ end
81
+
82
+ def self.all(domain, options={})
83
+ response = DNSimple::Client.get("/v1/domains/#{domain.name}/records", options)
84
+
85
+ case response.code
86
+ when 200
87
+ response.map { |r| new({:domain => domain}.merge(r["record"])) }
88
+ else
89
+ raise RequestError.new("Error listing records", response)
90
+ end
91
+ end
92
+
93
+ end
94
+ end