dnsimple 2.0.0.a

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