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.
- checksums.yaml +7 -0
- data/.gitignore +8 -0
- data/.rspec +1 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +7 -0
- data/CHANGELOG.markdown +50 -0
- data/Gemfile +3 -0
- data/LICENSE +22 -0
- data/README.markdown +60 -0
- data/Rakefile +33 -0
- data/dnsimple-ruby.gemspec +26 -0
- data/lib/dnsimple-ruby.rb +1 -0
- data/lib/dnsimple.rb +33 -0
- data/lib/dnsimple/base.rb +10 -0
- data/lib/dnsimple/certificate.rb +129 -0
- data/lib/dnsimple/client.rb +144 -0
- data/lib/dnsimple/contact.rb +154 -0
- data/lib/dnsimple/domain.rb +217 -0
- data/lib/dnsimple/error.rb +21 -0
- data/lib/dnsimple/extended_attribute.rb +52 -0
- data/lib/dnsimple/record.rb +94 -0
- data/lib/dnsimple/service.rb +42 -0
- data/lib/dnsimple/template.rb +63 -0
- data/lib/dnsimple/template_record.rb +80 -0
- data/lib/dnsimple/transfer_order.rb +34 -0
- data/lib/dnsimple/user.rb +26 -0
- data/lib/dnsimple/version.rb +3 -0
- data/spec/ci/.dnsimple.test +3 -0
- data/spec/dnsimple/certificate_spec.rb +56 -0
- data/spec/dnsimple/client_spec.rb +107 -0
- data/spec/dnsimple/contact_spec.rb +45 -0
- data/spec/dnsimple/domain_spec.rb +133 -0
- data/spec/dnsimple/extended_attributes_spec.rb +54 -0
- data/spec/dnsimple/record_spec.rb +51 -0
- data/spec/dnsimple/template_spec.rb +31 -0
- data/spec/dnsimple/user_spec.rb +31 -0
- data/spec/files/account/user/success.http +19 -0
- data/spec/files/certificates/index/success.http +19 -0
- data/spec/files/certificates/show/notfound.http +17 -0
- data/spec/files/certificates/show/success.http +19 -0
- data/spec/files/contacts/show/notfound.http +17 -0
- data/spec/files/contacts/show/success.http +19 -0
- data/spec/files/domains/auto_renewal_disable/notfound.http +21 -0
- data/spec/files/domains/auto_renewal_disable/success.http +23 -0
- data/spec/files/domains/auto_renewal_enable/notfound.http +21 -0
- data/spec/files/domains/auto_renewal_enable/success.http +23 -0
- data/spec/files/domains/show/notfound.http +17 -0
- data/spec/files/domains/show/success.http +19 -0
- data/spec/files/extended_attributes/ca.http +19 -0
- data/spec/files/extended_attributes/com.http +19 -0
- data/spec/files/extended_attributes/success.http +19 -0
- data/spec/files/records/index/success.http +19 -0
- data/spec/files/records/show/notfound.http +17 -0
- data/spec/files/records/show/success.http +19 -0
- data/spec/files/templates/show/notfound.http +17 -0
- data/spec/files/templates/show/success.http +19 -0
- data/spec/spec_helper.rb +34 -0
- data/spec/support/helpers.rb +15 -0
- data/spec/support/webmock.rb +11 -0
- metadata +224 -0
@@ -0,0 +1,42 @@
|
|
1
|
+
module DNSimple
|
2
|
+
|
3
|
+
# Represents a service that can be applied to a domain.
|
4
|
+
class Service < Base
|
5
|
+
|
6
|
+
attr_accessor :id
|
7
|
+
|
8
|
+
attr_accessor :name
|
9
|
+
|
10
|
+
attr_accessor :short_name
|
11
|
+
|
12
|
+
attr_accessor :description
|
13
|
+
|
14
|
+
# Find a service by its ID or short name
|
15
|
+
def self.find(id_or_short_name, options={})
|
16
|
+
id = id_or_short_name
|
17
|
+
response = DNSimple::Client.get("/v1/services/#{id}", options)
|
18
|
+
|
19
|
+
case response.code
|
20
|
+
when 200
|
21
|
+
new(response["service"])
|
22
|
+
when 404
|
23
|
+
raise RecordNotFound, "Could not find service #{id}"
|
24
|
+
else
|
25
|
+
raise RequestError.new("Error finding service", response)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# Get all of the services that can be applied to a domain
|
30
|
+
def self.all(options={})
|
31
|
+
response = DNSimple::Client.get("/v1/services", options)
|
32
|
+
|
33
|
+
case response.code
|
34
|
+
when 200
|
35
|
+
response.map { |r| new(r["service"]) }
|
36
|
+
else
|
37
|
+
raise RequestError.new("Error listing services", response)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module DNSimple
|
2
|
+
class Template < Base
|
3
|
+
|
4
|
+
attr_accessor :id
|
5
|
+
attr_accessor :name
|
6
|
+
attr_accessor :short_name
|
7
|
+
attr_accessor :description
|
8
|
+
|
9
|
+
|
10
|
+
def self.create(name, short_name, description=nil, options={})
|
11
|
+
template_hash = {
|
12
|
+
:name => name,
|
13
|
+
:short_name => short_name,
|
14
|
+
:description => description
|
15
|
+
}
|
16
|
+
|
17
|
+
options.merge!(:body => {:dns_template => template_hash})
|
18
|
+
|
19
|
+
response = DNSimple::Client.post("/v1/templates", options)
|
20
|
+
|
21
|
+
case response.code
|
22
|
+
when 201
|
23
|
+
new(response["dns_template"])
|
24
|
+
else
|
25
|
+
raise RequestError.new("Error creating template", response)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.find(id_or_short_name, options={})
|
30
|
+
id = id_or_short_name
|
31
|
+
response = DNSimple::Client.get("/v1/templates/#{id}", options)
|
32
|
+
|
33
|
+
case response.code
|
34
|
+
when 200
|
35
|
+
new(response["dns_template"])
|
36
|
+
when 404
|
37
|
+
raise RecordNotFound, "Could not find template #{id}"
|
38
|
+
else
|
39
|
+
raise RequestError.new("Error finding template", response)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.all(options={})
|
44
|
+
response = DNSimple::Client.get("/v1/templates", options)
|
45
|
+
|
46
|
+
case response.code
|
47
|
+
when 200
|
48
|
+
response.map { |r| new(r["dns_template"]) }
|
49
|
+
else
|
50
|
+
raise RequestError.new("Error listing templates", response)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
# Delete the template from DNSimple.
|
56
|
+
# WARNING: this cannot be undone.
|
57
|
+
def delete(options={})
|
58
|
+
DNSimple::Client.delete("/v1/templates/#{id}", options)
|
59
|
+
end
|
60
|
+
alias :destroy :delete
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module DNSimple
|
2
|
+
|
3
|
+
# A single record in a template.
|
4
|
+
class TemplateRecord < Base
|
5
|
+
|
6
|
+
# The id of the template record
|
7
|
+
attr_accessor :id
|
8
|
+
|
9
|
+
# The template the record belongs to
|
10
|
+
attr_accessor :template
|
11
|
+
|
12
|
+
# The name the record points to. This may be blank.
|
13
|
+
attr_accessor :name
|
14
|
+
|
15
|
+
# The content for the record.
|
16
|
+
attr_accessor :content
|
17
|
+
|
18
|
+
# The record type
|
19
|
+
attr_accessor :record_type
|
20
|
+
|
21
|
+
# The time-to-live
|
22
|
+
attr_accessor :ttl
|
23
|
+
|
24
|
+
# The priority (only for MX records)
|
25
|
+
attr_accessor :prio
|
26
|
+
|
27
|
+
def delete(options={})
|
28
|
+
DNSimple::Client.delete("/v1/templates/#{template.id}/template_records/#{id}", options)
|
29
|
+
end
|
30
|
+
alias :destroy :delete
|
31
|
+
|
32
|
+
def self.create(short_name, name, record_type, content, options={})
|
33
|
+
template = DNSimple::Template.find(short_name)
|
34
|
+
|
35
|
+
record_hash = {:name => name, :record_type => record_type, :content => content}
|
36
|
+
record_hash[:ttl] = options.delete(:ttl) || 3600
|
37
|
+
record_hash[:prio] = options.delete(:prio) || ''
|
38
|
+
|
39
|
+
options.merge!({:query => {:dns_template_record => record_hash}})
|
40
|
+
|
41
|
+
response = DNSimple::Client.post("/v1/templates/#{template.id}/template_records", options)
|
42
|
+
|
43
|
+
case response.code
|
44
|
+
when 201
|
45
|
+
new({:template => template}.merge(response["dns_template_record"]))
|
46
|
+
else
|
47
|
+
raise RequestError.new("Error creating template record", response)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.find(short_name, id, options={})
|
52
|
+
template = DNSimple::Template.find(short_name)
|
53
|
+
response = DNSimple::Client.get("/v1/templates/#{template.id}/template_records/#{id}", options)
|
54
|
+
|
55
|
+
case response.code
|
56
|
+
when 200
|
57
|
+
new({:template => template}.merge(response["dns_template_record"]))
|
58
|
+
when 404
|
59
|
+
raise RecordNotFound, "Could not find template record #{id} for template #{template.id}"
|
60
|
+
else
|
61
|
+
raise RequestError.new("Error finding template record", response)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# Get all of the template records for the template with the
|
66
|
+
# given short name.
|
67
|
+
def self.all(short_name, options={})
|
68
|
+
template = DNSimple::Template.find(short_name)
|
69
|
+
response = DNSimple::Client.get("/v1/templates/#{template.id}/template_records", options)
|
70
|
+
|
71
|
+
case response.code
|
72
|
+
when 200
|
73
|
+
response.map { |r| new({:template => template}.merge(r["dns_template_record"])) }
|
74
|
+
else
|
75
|
+
raise RequestError.new("Error listing template records", response)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module DNSimple
|
2
|
+
|
3
|
+
# Represents a transfer order.
|
4
|
+
class TransferOrder < Base
|
5
|
+
|
6
|
+
attr_accessor :id
|
7
|
+
|
8
|
+
attr_accessor :status
|
9
|
+
|
10
|
+
def self.create(name, authinfo='', registrant={}, extended_attributes={}, options={})
|
11
|
+
body = {:domain => {:name => name}, :transfer_order => {:authinfo => authinfo}}
|
12
|
+
|
13
|
+
if registrant[:id]
|
14
|
+
body[:domain][:registrant_id] = registrant[:id]
|
15
|
+
else
|
16
|
+
body.merge!(:contact => Contact.resolve_attributes(registrant))
|
17
|
+
end
|
18
|
+
|
19
|
+
body.merge!(:extended_attribute => extended_attributes)
|
20
|
+
|
21
|
+
options.merge!({:body => body})
|
22
|
+
|
23
|
+
response = DNSimple::Client.post("/v1/domain_transfers", options)
|
24
|
+
|
25
|
+
case response.code
|
26
|
+
when 201
|
27
|
+
new(response["transfer_order"])
|
28
|
+
else
|
29
|
+
raise RequestError.new("Error creating transfer order", response)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module DNSimple
|
2
|
+
class User < Base
|
3
|
+
|
4
|
+
attr_accessor :id
|
5
|
+
attr_accessor :email
|
6
|
+
attr_accessor :domain_count
|
7
|
+
attr_accessor :domain_limit
|
8
|
+
attr_accessor :login_count
|
9
|
+
attr_accessor :failed_login_count
|
10
|
+
attr_accessor :created_at
|
11
|
+
attr_accessor :updated_at
|
12
|
+
|
13
|
+
|
14
|
+
def self.me
|
15
|
+
response = DNSimple::Client.get("/v1/user")
|
16
|
+
|
17
|
+
case response.code
|
18
|
+
when 200
|
19
|
+
new(response["user"])
|
20
|
+
else
|
21
|
+
raise RequestError.new("Error finding account", response)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe DNSimple::Certificate do
|
4
|
+
|
5
|
+
let(:domain) { DNSimple::Domain.new(:name => "example.com") }
|
6
|
+
|
7
|
+
|
8
|
+
describe ".find" do
|
9
|
+
before do
|
10
|
+
stub_request(:get, %r[/v1/domains/example.com/certificates/2]).
|
11
|
+
to_return(read_fixture("certificates/show/success.http"))
|
12
|
+
end
|
13
|
+
|
14
|
+
it "builds the correct request" do
|
15
|
+
described_class.find(domain, "2")
|
16
|
+
|
17
|
+
expect(WebMock).to have_requested(:get, "https://#{CONFIG['username']}:#{CONFIG['password']}@#{CONFIG['host']}/v1/domains/example.com/certificates/2").
|
18
|
+
with(:headers => { 'Accept' => 'application/json' })
|
19
|
+
end
|
20
|
+
|
21
|
+
context "when the certificate exists" do
|
22
|
+
it "returns the certificate" do
|
23
|
+
result = described_class.find(domain, "2")
|
24
|
+
|
25
|
+
expect(result.id).to eq(4576)
|
26
|
+
expect(result.domain).to eq(domain)
|
27
|
+
expect(result.name).to eq("www")
|
28
|
+
expect(result.csr).to eq("-----BEGIN NEW CERTIFICATE REQUEST-----\nRHr2akB4KMba6FMAsvlStnO/2ika16hNx+d3smPNsER+HA==\n-----END NEW CERTIFICATE REQUEST-----\n")
|
29
|
+
expect(result.ssl_certificate).to eq("-----BEGIN CERTIFICATE-----\nXwTkw5UCPpaVyUYcwHlvaprOe9ZbwIyEHm2AT1rW+70=\n-----END CERTIFICATE-----\n")
|
30
|
+
expect(result.private_key).to eq("-----BEGIN RSA PRIVATE KEY-----\nUeXbFi7o+nuPfRhpBFQEKwacKFc3Hnc1hH6UsnC0KY25cUif7yz38A==\n-----END RSA PRIVATE KEY-----\n")
|
31
|
+
expect(result.approver_email).to eq("example@example.net")
|
32
|
+
expect(result.created_at).to eq("2013-09-17T21:54:42Z")
|
33
|
+
expect(result.updated_at).to eq("2013-09-17T22:25:36Z")
|
34
|
+
|
35
|
+
expect(result.available_approver_emails).to be_nil
|
36
|
+
expect(result.certificate_status).to be_nil
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
describe "#fqdn" do
|
43
|
+
it "joins the name and domain name" do
|
44
|
+
certificate = described_class.new(:name => 'www')
|
45
|
+
certificate.domain = domain
|
46
|
+
expect(certificate.fqdn).to eq("www.#{domain.name}")
|
47
|
+
end
|
48
|
+
|
49
|
+
it "strips blank parts from name" do
|
50
|
+
certificate = described_class.new(:name => '')
|
51
|
+
certificate.domain = domain
|
52
|
+
expect(certificate.fqdn).to eq(domain.name)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe DNSimple::Client do
|
4
|
+
|
5
|
+
let(:klass) { described_class }
|
6
|
+
let(:response) { stub('response', :code => 200) }
|
7
|
+
|
8
|
+
before do
|
9
|
+
@_username = described_class.username
|
10
|
+
@_password = described_class.password
|
11
|
+
@_api_token = described_class.api_token
|
12
|
+
@_base_uri = described_class.base_uri
|
13
|
+
end
|
14
|
+
|
15
|
+
after do
|
16
|
+
described_class.username = @_username
|
17
|
+
described_class.password = @_password
|
18
|
+
described_class.api_token = @_api_token
|
19
|
+
described_class.base_uri = @_base_uri
|
20
|
+
end
|
21
|
+
|
22
|
+
[:get, :post, :put, :delete].each do |method|
|
23
|
+
describe ".#{method}" do
|
24
|
+
it "delegates to .request" do
|
25
|
+
described_class.expects(:request).with(method, '/domains', { :foo => 'bar' })
|
26
|
+
described_class.send(method, '/domains', { :foo => 'bar' })
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe ".request" do
|
32
|
+
it "uses HTTP authentication if there's a password provided" do
|
33
|
+
described_class.username = 'user'
|
34
|
+
described_class.password = 'pass'
|
35
|
+
described_class.api_token = nil
|
36
|
+
described_class.base_uri = 'https://api.example.com/'
|
37
|
+
|
38
|
+
HTTParty.expects(:get).
|
39
|
+
with('https://api.example.com/domains', has_entries(:basic_auth => { :username => 'user', :password => 'pass' })).
|
40
|
+
returns(response)
|
41
|
+
|
42
|
+
described_class.request(:get, '/domains', {})
|
43
|
+
end
|
44
|
+
|
45
|
+
it "uses header authentication if there's an api token provided" do
|
46
|
+
described_class.username = 'user'
|
47
|
+
described_class.password = nil
|
48
|
+
described_class.api_token = 'token'
|
49
|
+
described_class.base_uri = 'https://api.example.com/'
|
50
|
+
|
51
|
+
HTTParty.expects(:get).
|
52
|
+
with('https://api.example.com/domains', has_entries(:headers => has_entries({ 'X-DNSimple-Token' => 'user:token' }))).
|
53
|
+
returns(response)
|
54
|
+
|
55
|
+
described_class.request(:get, '/domains', {})
|
56
|
+
end
|
57
|
+
|
58
|
+
it "raises an error if there's no password or api token provided" do
|
59
|
+
described_class.username = 'user'
|
60
|
+
described_class.password = nil
|
61
|
+
described_class.api_token = nil
|
62
|
+
described_class.base_uri = 'https://api.example.com/'
|
63
|
+
|
64
|
+
expect {
|
65
|
+
described_class.request(:get, '/domains', {})
|
66
|
+
}.to raise_error(DNSimple::Error, 'A password or API token is required for all API requests.')
|
67
|
+
end
|
68
|
+
|
69
|
+
it "adds a custom user-agent" do
|
70
|
+
HTTParty.expects(:get).
|
71
|
+
with(is_a(String), has_entries(:headers => has_entries({ 'User-Agent' => "dnsimple-ruby/#{DNSimple::VERSION}" }))).
|
72
|
+
returns(response)
|
73
|
+
|
74
|
+
described_class.request(:get, '/foo', {})
|
75
|
+
end
|
76
|
+
|
77
|
+
it "performs a request" do
|
78
|
+
HTTParty.expects(:get).
|
79
|
+
with("#{described_class.base_uri}/foo",
|
80
|
+
:format => :json,
|
81
|
+
:basic_auth => { :username => described_class.username, :password => described_class.password },
|
82
|
+
:headers => { 'Accept' => 'application/json', 'User-Agent' => "dnsimple-ruby/#{DNSimple::VERSION}" }
|
83
|
+
).
|
84
|
+
returns(response)
|
85
|
+
|
86
|
+
described_class.request(:get, '/foo', {})
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
|
91
|
+
describe ".base_uri" do
|
92
|
+
it "returns the qualified API uri" do
|
93
|
+
klass.base_uri = "http://api.dnsimple.com"
|
94
|
+
expect(klass.base_uri).to eq("http://api.dnsimple.com")
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
describe ".base_uri=" do
|
99
|
+
it "sets the base_uri" do
|
100
|
+
klass.base_uri = "http://api1.dnsimple.com/"
|
101
|
+
expect(klass.base_uri).to eq("http://api1.dnsimple.com")
|
102
|
+
klass.base_uri = "http://api2.dnsimple.com"
|
103
|
+
expect(klass.base_uri).to eq("http://api2.dnsimple.com")
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe DNSimple::Contact do
|
4
|
+
|
5
|
+
describe ".find" do
|
6
|
+
before do
|
7
|
+
stub_request(:get, %r[/v1/contacts/2]).
|
8
|
+
to_return(read_fixture("contacts/show/success.http"))
|
9
|
+
end
|
10
|
+
|
11
|
+
it "builds the correct request" do
|
12
|
+
described_class.find("2")
|
13
|
+
|
14
|
+
expect(WebMock).to have_requested(:get, "https://#{CONFIG['username']}:#{CONFIG['password']}@#{CONFIG['host']}/v1/contacts/2").
|
15
|
+
with(:headers => { 'Accept' => 'application/json' })
|
16
|
+
end
|
17
|
+
|
18
|
+
context "when the contact exists" do
|
19
|
+
it "returns the contact" do
|
20
|
+
result = described_class.find("2")
|
21
|
+
|
22
|
+
expect(result).to be_a(described_class)
|
23
|
+
expect(result.id).to eq(2)
|
24
|
+
expect(result.first_name).to eq("Simone")
|
25
|
+
expect(result.last_name).to eq("Carletti")
|
26
|
+
expect(result.job_title).to eq("Underwater Programmer")
|
27
|
+
expect(result.organization_name).to eq("DNSimple")
|
28
|
+
expect(result.email_address).to eq("example@example.com")
|
29
|
+
expect(result.phone).to eq("+1 111 000000")
|
30
|
+
expect(result.fax).to eq("+1 222 000000")
|
31
|
+
expect(result.address1).to eq("Awesome Street")
|
32
|
+
expect(result.address2).to eq("c/o Someone")
|
33
|
+
expect(result.city).to eq("Rome")
|
34
|
+
expect(result.state_province).to eq("RM")
|
35
|
+
expect(result.postal_code).to eq("00171")
|
36
|
+
expect(result.country).to eq("IT")
|
37
|
+
expect(result.created_at).to eq("2013-11-08T17:23:15Z")
|
38
|
+
expect(result.updated_at).to eq("2013-11-08T17:23:15Z")
|
39
|
+
|
40
|
+
expect(result.phone_ext).to be_nil
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|