From 1808ddbe5708366f618485eb8650361c22033e08 Mon Sep 17 00:00:00 2001 From: Simone Carletti Date: Thu, 7 Jan 2016 17:00:15 +0100 Subject: [PATCH 1/4] Add the DomainRecord result type --- lib/dnsimple/struct/domain_record.rb | 40 ++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 lib/dnsimple/struct/domain_record.rb diff --git a/lib/dnsimple/struct/domain_record.rb b/lib/dnsimple/struct/domain_record.rb new file mode 100644 index 00000000..8fdbd6ef --- /dev/null +++ b/lib/dnsimple/struct/domain_record.rb @@ -0,0 +1,40 @@ +module Dnsimple + module Struct + + class DomainRecord < Base + # @return [Fixnum] The record ID in DNSimple. + attr_accessor :id + + # @return [Fixnum] The associated domain ID. + attr_accessor :domain_id + + # @return [Fixnum] The ID of the parent record, if this record is dependent on another record. + attr_accessor :parent_id + + # @return [String] The type of record, in uppercase. + attr_accessor :type + + # @return [String] The record name (without the domain name). + attr_accessor :name + + # @return [String] The plain-text record content. + attr_accessor :content + + # @return [Fixnum] The TTL value. + attr_accessor :ttl + + # @return [Fixnum] The priority value, if the type of record accepts a priority. + attr_accessor :priority + + # @return [Bool] True if this is a system record created by DNSimple. System records are read-only. + attr_accessor :system_record + + # @return [String] When the domain was created in DNSimple. + attr_accessor :created_at + + # @return [String] When the domain was last updated in DNSimple. + attr_accessor :updated_at + end + + end +end From e9846f86f52e42cd3e787990010f02698be946aa Mon Sep 17 00:00:00 2001 From: Simone Carletti Date: Thu, 7 Jan 2016 17:01:12 +0100 Subject: [PATCH 2/4] It's a zone Record. Let's just call it record for now --- lib/dnsimple/struct/{domain_record.rb => record.rb} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename lib/dnsimple/struct/{domain_record.rb => record.rb} (97%) diff --git a/lib/dnsimple/struct/domain_record.rb b/lib/dnsimple/struct/record.rb similarity index 97% rename from lib/dnsimple/struct/domain_record.rb rename to lib/dnsimple/struct/record.rb index 8fdbd6ef..2710544d 100644 --- a/lib/dnsimple/struct/domain_record.rb +++ b/lib/dnsimple/struct/record.rb @@ -1,7 +1,7 @@ module Dnsimple module Struct - class DomainRecord < Base + class Record < Base # @return [Fixnum] The record ID in DNSimple. attr_accessor :id From c0e7a1ec3a94155243075308dddae4dc8e8a73f4 Mon Sep 17 00:00:00 2001 From: Simone Carletti Date: Thu, 7 Jan 2016 17:04:59 +0100 Subject: [PATCH 3/4] Add client.zones -> record service --- lib/dnsimple/client/clients.rb | 12 ++++++++++++ lib/dnsimple/client/zones_records.rb | 6 ++++++ spec/dnsimple/client/zones_records_spec.rb | 7 +++++++ 3 files changed, 25 insertions(+) create mode 100644 lib/dnsimple/client/zones_records.rb create mode 100644 spec/dnsimple/client/zones_records_spec.rb diff --git a/lib/dnsimple/client/clients.rb b/lib/dnsimple/client/clients.rb index 832bd292..97239396 100644 --- a/lib/dnsimple/client/clients.rb +++ b/lib/dnsimple/client/clients.rb @@ -11,6 +11,11 @@ def misc @services[:misc] ||= Client::MiscService.new(self) end + # @return [Dnsimple::Client::ZonesService] The zone-related API proxy. + def zones + @services[:zones] ||= Client::ZonesService.new(self) + end + class ClientService < ::Struct.new(:client) @@ -56,5 +61,12 @@ class MiscService < ClientService include Client::Misc end + + require_relative 'zones_records' + + class ZonesService < ClientService + include Client::ZonesRecords + end + end end diff --git a/lib/dnsimple/client/zones_records.rb b/lib/dnsimple/client/zones_records.rb new file mode 100644 index 00000000..a78d4a50 --- /dev/null +++ b/lib/dnsimple/client/zones_records.rb @@ -0,0 +1,6 @@ +module Dnsimple + class Client + module ZonesRecords + end + end +end diff --git a/spec/dnsimple/client/zones_records_spec.rb b/spec/dnsimple/client/zones_records_spec.rb new file mode 100644 index 00000000..66602925 --- /dev/null +++ b/spec/dnsimple/client/zones_records_spec.rb @@ -0,0 +1,7 @@ +require 'spec_helper' + +describe Dnsimple::Client, ".zones" do + + subject { described_class.new(api_endpoint: "https://api.dnsimple.test", access_token: "a1b2c3").zones } + +end From 8008ef96996b1b8fa17462c44915df015b5299ff Mon Sep 17 00:00:00 2001 From: Simone Carletti Date: Thu, 7 Jan 2016 17:47:01 +0100 Subject: [PATCH 4/4] Add listZoneRecords() and allZoneRecords() --- lib/dnsimple/client/domains.rb | 4 +- lib/dnsimple/client/zones_records.rb | 44 +++++++++++++ lib/dnsimple/struct.rb | 1 + spec/dnsimple/client/domains_spec.rb | 10 ++- spec/dnsimple/client/zones_records_spec.rb | 63 +++++++++++++++++++ spec/files/{domains => }/notfound-domain.http | 22 +++---- spec/files/notfound-zone.http | 12 ++++ spec/files/zones/records/success.http | 17 +++++ 8 files changed, 158 insertions(+), 15 deletions(-) rename spec/files/{domains => }/notfound-domain.http (96%) create mode 100644 spec/files/notfound-zone.http create mode 100644 spec/files/zones/records/success.http diff --git a/lib/dnsimple/client/domains.rb b/lib/dnsimple/client/domains.rb index 1d15ecb7..fc36c1fa 100644 --- a/lib/dnsimple/client/domains.rb +++ b/lib/dnsimple/client/domains.rb @@ -8,10 +8,10 @@ module Domains # @see #all_domains # # @example List domains in the first page - # client.domains(1010) + # client.domains.list(1010) # # @example List domains, provide a specific page - # client.domains(1010, query: { page: 2 }) + # client.domains.list(1010, query: { page: 2 }) # # @param [Fixnum] account_id the account ID # @param [Hash] options the filtering and sorting option diff --git a/lib/dnsimple/client/zones_records.rb b/lib/dnsimple/client/zones_records.rb index a78d4a50..cc20b000 100644 --- a/lib/dnsimple/client/zones_records.rb +++ b/lib/dnsimple/client/zones_records.rb @@ -1,6 +1,50 @@ module Dnsimple class Client module ZonesRecords + + # Lists the zone records in the account. + # + # @see https://developer.dnsimple.com/v2/zones/records/#list + # @see #all_records + # + # @example List records for the zone "example.com" in the first page + # client.zones.records(1010, "example.com") + # + # @example List records for the zone "example.com", provide a specific page + # client.zones.records(1010, "example.com", query: { page: 2 }) + # + # @param [Fixnum, Dnsimple::Client::WILDCARD_ACCOUNT] account_id the account ID or wildcard + # @param [String] zone_id the zone name + # @param [Hash] options the filtering and sorting option + # @return [Dnsimple::PaginatedResponse] + # @raise [Dnsimple::RequestError] + def records(account_id, zone_id, options = {}) + response = client.get(Client.versioned("/%s/zones/%s/records" % [account_id, zone_id]), options) + + Dnsimple::PaginatedResponse.new(response, response["data"].map { |r| Struct::Record.new(r) }) + end + alias :list_records :records + + # Lists ALL the zone records in the account. + # + # This method is similar to {#records}, but instead of returning the results of a specific page + # it iterates all the pages and returns the entire collection. + # + # Please use this method carefully, as fetching the entire collection will increase the number of requests + # you send to the API server and you may eventually risk to hit the throttle limit. + # + # @see https://developer.dnsimple.com/v2/zones/records/#list + # @see #records + # + # @param [Fixnum] account_id the account ID + # @param [String] zone_id the zone name + # @param [Hash] options the filtering and sorting option + # @return [Dnsimple::CollectionResponse] + # @raise [Dnsimple::RequestError] + def all_records(account_id, zone_id, options = {}) + paginate(:records, account_id, zone_id, options) + end + end end end diff --git a/lib/dnsimple/struct.rb b/lib/dnsimple/struct.rb index feb21bfe..bfa03f27 100644 --- a/lib/dnsimple/struct.rb +++ b/lib/dnsimple/struct.rb @@ -15,4 +15,5 @@ def initialize(attributes = {}) require_relative 'struct/account' require_relative 'struct/domain' +require_relative 'struct/record' require_relative 'struct/user' diff --git a/spec/dnsimple/client/domains_spec.rb b/spec/dnsimple/client/domains_spec.rb index 2d25e903..11da75f9 100644 --- a/spec/dnsimple/client/domains_spec.rb +++ b/spec/dnsimple/client/domains_spec.rb @@ -26,6 +26,12 @@ expect(WebMock).to have_requested(:get, "https://api.dnsimple.test/v2/#{account_id}/domains?page=2") end + it "supports extra request options" do + subject.domains(account_id, query: { foo: "bar" }) + + expect(WebMock).to have_requested(:get, "https://api.dnsimple.test/v2/#{account_id}/domains?foo=bar") + end + it "returns the domains" do response = subject.domains(account_id) @@ -123,7 +129,7 @@ context "when something does not exist" do it "raises NotFoundError" do stub_request(:get, %r[/v2]) - .to_return(read_fixture("domains/notfound-domain.http")) + .to_return(read_fixture("notfound-domain.http")) expect { subject.domain(account_id, "example.com") @@ -158,7 +164,7 @@ context "when something does not exist" do it "raises NotFoundError" do stub_request(:delete, %r[/v2]) - .to_return(read_fixture("domains/notfound-domain.http")) + .to_return(read_fixture("notfound-domain.http")) expect { subject.delete_domain(account_id, "example.com") diff --git a/spec/dnsimple/client/zones_records_spec.rb b/spec/dnsimple/client/zones_records_spec.rb index 66602925..d3a33eaf 100644 --- a/spec/dnsimple/client/zones_records_spec.rb +++ b/spec/dnsimple/client/zones_records_spec.rb @@ -4,4 +4,67 @@ subject { described_class.new(api_endpoint: "https://api.dnsimple.test", access_token: "a1b2c3").zones } + + describe "#records" do + let(:account_id) { 1010 } + let(:zone_id) { "example.com" } + + before do + stub_request(:get, %r[/v2/#{account_id}/zones/#{zone_id}/records]) + .to_return(read_fixture("zones/records/success.http")) + end + + it "builds the correct request" do + subject.records(account_id, zone_id) + + expect(WebMock).to have_requested(:get, "https://api.dnsimple.test/v2/#{account_id}/zones/#{zone_id}/records") + .with(headers: { 'Accept' => 'application/json' }) + end + + it "supports pagination" do + subject.records(account_id, zone_id, query: { page: 2 }) + + expect(WebMock).to have_requested(:get, "https://api.dnsimple.test/v2/#{account_id}/zones/#{zone_id}/records?page=2") + end + + it "supports extra request options" do + subject.records(account_id, zone_id, query: { foo: "bar" }) + + expect(WebMock).to have_requested(:get, "https://api.dnsimple.test/v2/#{account_id}/zones/#{zone_id}/records?foo=bar") + end + + it "returns the records" do + response = subject.records(account_id, zone_id) + + expect(response).to be_a(Dnsimple::PaginatedResponse) + expect(response.data).to be_a(Array) + expect(response.data.size).to eq(5) + + response.data.each do |result| + expect(result).to be_a(Dnsimple::Struct::Record) + expect(result.id).to be_a(Fixnum) + end + end + + it "exposes the pagination information" do + response = subject.records(account_id, zone_id) + + expect(response.respond_to?(:page)).to be_truthy + expect(response.page).to eq(1) + expect(response.per_page).to be_a(Fixnum) + expect(response.total_entries).to be_a(Fixnum) + expect(response.total_pages).to be_a(Fixnum) + end + end + + describe "#all_records" do + let(:account_id) { 1010 } + let(:zone_id) { "example.com" } + + it "delegates to client.paginate" do + expect(subject).to receive(:paginate).with(:records, account_id, zone_id, { foo: "bar" }) + subject.all_records(account_id, zone_id, { foo: "bar" }) + end + end + end diff --git a/spec/files/domains/notfound-domain.http b/spec/files/notfound-domain.http similarity index 96% rename from spec/files/domains/notfound-domain.http rename to spec/files/notfound-domain.http index ea415de6..5acaf7bc 100644 --- a/spec/files/domains/notfound-domain.http +++ b/spec/files/notfound-domain.http @@ -1,12 +1,12 @@ -HTTP/1.1 404 Not Found -Server: nginx -Date: Wed, 16 Dec 2015 22:07:20 GMT -Content-Type: application/json; charset=utf-8 -Transfer-Encoding: chunked -Connection: keep-alive -Strict-Transport-Security: max-age=31536000 -Cache-Control: no-cache -X-Request-Id: bc587ea7-bcd5-4c10-a940-a9b4c8339824 -X-Runtime: 0.059966 - +HTTP/1.1 404 Not Found +Server: nginx +Date: Wed, 16 Dec 2015 22:07:20 GMT +Content-Type: application/json; charset=utf-8 +Transfer-Encoding: chunked +Connection: keep-alive +Strict-Transport-Security: max-age=31536000 +Cache-Control: no-cache +X-Request-Id: bc587ea7-bcd5-4c10-a940-a9b4c8339824 +X-Runtime: 0.059966 + {"message":"Domain `0' not found"} \ No newline at end of file diff --git a/spec/files/notfound-zone.http b/spec/files/notfound-zone.http new file mode 100644 index 00000000..84dd9af1 --- /dev/null +++ b/spec/files/notfound-zone.http @@ -0,0 +1,12 @@ +HTTP/1.1 500 Internal Server Error +Server: nginx +Date: Thu, 07 Jan 2016 16:35:37 GMT +Content-Type: application/json; charset=utf-8 +Transfer-Encoding: chunked +Connection: keep-alive +Status: 500 Internal Server Error +Cache-Control: no-cache +X-Request-Id: 0de115b1-2143-44e5-b117-c7f9c51ea2ff +X-Runtime: 0.022304 + +{"message":"Internal Server Error"} \ No newline at end of file diff --git a/spec/files/zones/records/success.http b/spec/files/zones/records/success.http new file mode 100644 index 00000000..31fc420a --- /dev/null +++ b/spec/files/zones/records/success.http @@ -0,0 +1,17 @@ +HTTP/1.1 200 OK +Server: nginx +Date: Thu, 07 Jan 2016 16:33:47 GMT +Content-Type: application/json; charset=utf-8 +Transfer-Encoding: chunked +Connection: keep-alive +Status: 200 OK +X-RateLimit-Limit: 4000 +X-RateLimit-Remaining: 3994 +X-RateLimit-Reset: 1452184426 +ETag: W/"1ae3e2e65dbcc2c2a7237e3e564129dd" +Cache-Control: max-age=0, private, must-revalidate +X-Request-Id: 9b361b57-43e2-47df-9f00-e7c252bc4d41 +X-Runtime: 0.107990 +Strict-Transport-Security: max-age=31536000 + +{"data":[{"id":64779,"domain_id":5841,"parent_id":null,"name":"","content":"ns1.dnsimple.com admin.dnsimple.com 1452184205 86400 7200 604800 300","ttl":3600,"priority":null,"type":"SOA","system_record":true,"created_at":"2016-01-07T16:30:05.379Z","updated_at":"2016-01-07T16:30:05.379Z"},{"id":64780,"domain_id":5841,"parent_id":null,"name":"","content":"ns1.dnsimple.com","ttl":3600,"priority":null,"type":"NS","system_record":true,"created_at":"2016-01-07T16:30:05.422Z","updated_at":"2016-01-07T16:30:05.422Z"},{"id":64781,"domain_id":5841,"parent_id":null,"name":"","content":"ns2.dnsimple.com","ttl":3600,"priority":null,"type":"NS","system_record":true,"created_at":"2016-01-07T16:30:05.433Z","updated_at":"2016-01-07T16:30:05.433Z"},{"id":64782,"domain_id":5841,"parent_id":null,"name":"","content":"ns3.dnsimple.com","ttl":3600,"priority":null,"type":"NS","system_record":true,"created_at":"2016-01-07T16:30:05.445Z","updated_at":"2016-01-07T16:30:05.445Z"},{"id":64783,"domain_id":5841,"parent_id":null,"name":"","content":"ns4.dnsimple.com","ttl":3600,"priority":null,"type":"NS","system_record":true,"created_at":"2016-01-07T16:30:05.457Z","updated_at":"2016-01-07T16:30:05.457Z"}],"pagination":{"current_page":1,"per_page":30,"total_entries":5,"total_pages":1}} \ No newline at end of file