diff --git a/app/api/repp/nameservers_v1.rb b/app/api/repp/nameservers_v1.rb index cbc58eece..d653adf7f 100644 --- a/app/api/repp/nameservers_v1.rb +++ b/app/api/repp/nameservers_v1.rb @@ -5,10 +5,10 @@ module Repp resource 'registrar/nameservers' do put '/' do params do - requires :data, type: Hash do + requires :data, type: Hash, allow_blank: false do requires :type, type: String, allow_blank: false requires :id, type: String, allow_blank: false - requires :attributes, type: Hash do + requires :attributes, type: Hash, allow_blank: false do requires :hostname, type: String, allow_blank: false requires :ipv4, type: Array requires :ipv6, type: Array @@ -16,21 +16,28 @@ module Repp end end - old_nameserver = current_user.registrar.nameservers.find_by(hostname: params[:data][:id]) - error!({ errors: [{ title: "Hostname #{params[:data][:id]} does not exist" }] }, 404) unless old_nameserver + hostname = params[:data][:id] - new_nameserver = old_nameserver.dup - new_nameserver.hostname = params[:data][:attributes][:hostname] - new_nameserver.ipv4 = params[:data][:attributes][:ipv4] - new_nameserver.ipv6 = params[:data][:attributes][:ipv6] + unless current_user.registrar.nameservers.exists?(hostname: hostname) + error!({ errors: [{ title: "Hostname #{hostname} does not exist" }] }, 404) + end - error!({ errors: [{ title: 'Invalid params' }] }, 400) unless new_nameserver.valid? + new_attributes = { + hostname: params[:data][:attributes][:hostname], + ipv4: params[:data][:attributes][:ipv4], + ipv6: params[:data][:attributes][:ipv6], + } - current_user.registrar.replace_nameserver(old_nameserver, new_nameserver) + begin + current_user.registrar.replace_nameservers(hostname, new_attributes) + rescue ActiveRecord::RecordInvalid => e + error!({ errors: e.record.errors.full_messages.map { |error| { title: error } } }, 400) + end status 200 @response = { data: { type: 'nameserver', - id: new_nameserver.hostname, attributes: params[:data][:attributes] } } + id: params[:data][:attributes][:hostname], + attributes: params[:data][:attributes] } } end end end diff --git a/app/models/registrar.rb b/app/models/registrar.rb index 4bfb191e1..6a10983d2 100644 --- a/app/models/registrar.rb +++ b/app/models/registrar.rb @@ -158,12 +158,16 @@ class Registrar < ActiveRecord::Base white_ips.api.pluck(:ipv4, :ipv6).flatten.include?(ip) end - def replace_nameserver(old_nameserver, new_nameserver) + # Audit log is needed, therefore no raw SQL + def replace_nameservers(hostname, new_attributes) transaction do - nameservers.where(hostname: old_nameserver.hostname).find_each do |nameserver| - nameserver.update!(hostname: new_nameserver.hostname, - ipv4: new_nameserver.ipv4, - ipv6: new_nameserver.ipv6) # Audit log is needed, therefore no raw SQL + nameservers.where(hostname: hostname).find_each do |original_nameserver| + new_nameserver = Nameserver.new + new_nameserver.domain = original_nameserver.domain + new_nameserver.attributes = new_attributes + new_nameserver.save! + + original_nameserver.destroy! end end end diff --git a/test/fixtures/contacts.yml b/test/fixtures/contacts.yml index eaf4401b7..fe11968b9 100644 --- a/test/fixtures/contacts.yml +++ b/test/fixtures/contacts.yml @@ -42,6 +42,17 @@ acme_ltd: code: acme-ltd-001 auth_info: 720b3c +jack: + name: Jack + email: jack@inbox.test + phone: '+555.555' + ident: 1234 + ident_type: org + registrar: goodnames + ident_country_code: US + code: jack-001 + auth_info: e2c440 + invalid: name: any code: any diff --git a/test/fixtures/domains.yml b/test/fixtures/domains.yml index 7c0844d97..b2b2a24b5 100644 --- a/test/fixtures/domains.yml +++ b/test/fixtures/domains.yml @@ -28,6 +28,16 @@ library: period: 1 period_unit: m +metro: + name: metro.test + name_dirty: metro.test + registrar: goodnames + registrant: jack + transfer_code: 1071ad + valid_to: 2010-07-05 + period: 1 + period_unit: m + invalid: name: invalid.test transfer_code: any diff --git a/test/fixtures/nameservers.yml b/test/fixtures/nameservers.yml index 870e678ad..a03dc8cc9 100644 --- a/test/fixtures/nameservers.yml +++ b/test/fixtures/nameservers.yml @@ -13,3 +13,11 @@ ns2: ipv6: - 2001:db8::2 domain: shop + +airport_ns1: + hostname: ns1.bestnames.test + domain: airport + +metro_ns1: + hostname: ns1.bestnames.test + domain: metro diff --git a/test/integration/api/nameservers/put_test.rb b/test/integration/api/nameservers/put_test.rb index d048c29fe..034c885b7 100644 --- a/test/integration/api/nameservers/put_test.rb +++ b/test/integration/api/nameservers/put_test.rb @@ -1,17 +1,55 @@ require 'test_helper' class APINameserversPutTest < ActionDispatch::IntegrationTest - def test_replaces_current_registrar_nameservers + def setup + @registrar = registrars(:bestnames) + end + + def test_deletes_old_nameservers + previous_nameserver_ids = @registrar.nameservers.where(hostname: 'ns1.bestnames.test').ids + request_params = { format: :json, data: { type: 'nameserver', id: 'ns1.bestnames.test', + attributes: { hostname: 'ns55.bestnames.test' } } } + + put '/repp/v1/registrar/nameservers', request_params, { 'HTTP_AUTHORIZATION' => http_auth_key } + refute @registrar.nameservers(true).where(id: previous_nameserver_ids).exists? + end + + def test_creates_new_nameservers + request_params = { format: :json, data: { type: 'nameserver', id: 'ns1.bestnames.test', + attributes: { hostname: 'ns55.bestnames.test' } } } + put '/repp/v1/registrar/nameservers', request_params, { 'HTTP_AUTHORIZATION' => http_auth_key } + assert_equal 2, @registrar.nameservers.where(hostname: 'ns55.bestnames.test').size + end + + def test_saves_all_attributes request_params = { format: :json, data: { type: 'nameserver', id: 'ns1.bestnames.test', attributes: { hostname: 'ns55.bestnames.test', ipv4: ['192.0.2.55'], ipv6: ['2001:db8::55'] } } } put '/repp/v1/registrar/nameservers', request_params, { 'HTTP_AUTHORIZATION' => http_auth_key } - new_nameserver = registrars(:bestnames).nameservers.find_by(hostname: 'ns55.bestnames.test') - assert_nil registrars(:bestnames).nameservers.find_by(hostname: 'ns1.bestnames.test') + new_nameserver = domains(:shop).nameservers.find_by(hostname: 'ns55.bestnames.test') assert_equal ['192.0.2.55'], new_nameserver.ipv4 assert_equal ['2001:DB8::55'], new_nameserver.ipv6 + end + + def test_keeps_other_registrar_nameservers_intact + request_params = { format: :json, data: { type: 'nameserver', id: 'ns1.bestnames.test', + attributes: { hostname: 'ns55.bestnames.test' } } } + + other_registrar_nameserver_ids = registrars(:goodnames).nameservers.ids + assert other_registrar_nameserver_ids.any? + put '/repp/v1/registrar/nameservers', request_params, { 'HTTP_AUTHORIZATION' => http_auth_key } + assert_equal other_registrar_nameserver_ids, registrars(:goodnames).nameservers(true).ids + end + + def test_returns_new_nameserver_record + request_params = { format: :json, data: { type: 'nameserver', id: 'ns1.bestnames.test', + attributes: { hostname: 'ns55.bestnames.test', + ipv4: ['192.0.2.55'], + ipv6: ['2001:db8::55'] } } } + put '/repp/v1/registrar/nameservers', request_params, { 'HTTP_AUTHORIZATION' => http_auth_key } + assert_response 200 assert_equal ({ data: { type: 'nameserver', id: 'ns55.bestnames.test', @@ -21,7 +59,7 @@ class APINameserversPutTest < ActionDispatch::IntegrationTest JSON.parse(response.body, symbolize_names: true) end - def test_honors_optional_params + def test_optional_params request_params = { format: :json, data: { type: 'nameserver', id: 'ns1.bestnames.test', attributes: { hostname: 'ns55.bestnames.test' } } } put '/repp/v1/registrar/nameservers', request_params, { 'HTTP_AUTHORIZATION' => http_auth_key } @@ -44,7 +82,7 @@ class APINameserversPutTest < ActionDispatch::IntegrationTest put '/repp/v1/registrar/nameservers', request_params, { 'HTTP_AUTHORIZATION' => http_auth_key } assert_response 400 - assert_equal ({ errors: [{ title: 'Invalid params' }] }), + assert_equal ({ errors: [{ title: 'Hostname is missing' }] }), JSON.parse(response.body, symbolize_names: true) end