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,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,3 @@
1
+ module DNSimple
2
+ VERSION = '2.0.0.a'
3
+ end
@@ -0,0 +1,3 @@
1
+ username: username
2
+ password: password
3
+ base_uri: https://api.ci.dnsimple.com
@@ -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