mirror of
https://github.com/internetee/registry.git
synced 2025-06-12 07:34:45 +02:00
parent
0ac3a43613
commit
8c915164c5
8 changed files with 51 additions and 38 deletions
|
@ -5,29 +5,33 @@ module Repp
|
||||||
resource :domains do
|
resource :domains do
|
||||||
resource :contacts do
|
resource :contacts do
|
||||||
patch '/' do
|
patch '/' do
|
||||||
predecessor = current_user.registrar.contacts.find_by(code: params[:predecessor])
|
current_contact = current_user.registrar.contacts
|
||||||
successor = current_user.registrar.contacts.find_by(code: params[:successor])
|
.find_by(code: params[:current_contact_id])
|
||||||
|
new_contact = current_user.registrar.contacts.find_by(code: params[:new_contact_id])
|
||||||
|
|
||||||
unless predecessor
|
unless current_contact
|
||||||
error!({ error: { type: 'invalid_request_error',
|
error!({ error: { type: 'invalid_request_error',
|
||||||
param: 'predecessor',
|
param: 'current_contact_id',
|
||||||
message: "No such contact: #{params[:predecessor]}" } }, :bad_request)
|
message: "No such contact: #{params[:current_contact_id]}"} },
|
||||||
|
:bad_request)
|
||||||
end
|
end
|
||||||
|
|
||||||
unless successor
|
unless new_contact
|
||||||
error!({ error: { type: 'invalid_request_error',
|
error!({ error: { type: 'invalid_request_error',
|
||||||
param: 'successor',
|
param: 'new_contact_id',
|
||||||
message: "No such contact: #{params[:successor]}" } }, :bad_request)
|
message: "No such contact: #{params[:new_contact_id]}" } },
|
||||||
|
:bad_request)
|
||||||
end
|
end
|
||||||
|
|
||||||
if predecessor == successor
|
if current_contact == new_contact
|
||||||
error!({ error: { type: 'invalid_request_error',
|
error!({ error: { type: 'invalid_request_error',
|
||||||
message: 'New contact ID must be different from current' \
|
message: 'New contact ID must be different from current' \
|
||||||
' contact ID' } },
|
' contact ID' } },
|
||||||
:bad_request)
|
:bad_request)
|
||||||
end
|
end
|
||||||
|
|
||||||
affected_domains, skipped_domains = TechDomainContact.replace(predecessor, successor)
|
affected_domains, skipped_domains = TechDomainContact
|
||||||
|
.replace(current_contact, new_contact)
|
||||||
@response = { affected_domains: affected_domains, skipped_domains: skipped_domains }
|
@response = { affected_domains: affected_domains, skipped_domains: skipped_domains }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -6,7 +6,8 @@ class Registrar
|
||||||
uri = URI.parse("#{ENV['repp_url']}domains/contacts")
|
uri = URI.parse("#{ENV['repp_url']}domains/contacts")
|
||||||
|
|
||||||
request = Net::HTTP::Patch.new(uri)
|
request = Net::HTTP::Patch.new(uri)
|
||||||
request.set_form_data(predecessor: params[:predecessor], successor: params[:successor])
|
request.set_form_data(current_contact_id: params[:current_contact_id],
|
||||||
|
new_contact_id: params[:new_contact_id])
|
||||||
request.basic_auth(current_user.username, current_user.password)
|
request.basic_auth(current_user.username, current_user.password)
|
||||||
|
|
||||||
if Rails.env.test?
|
if Rails.env.test?
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
class TechDomainContact < DomainContact
|
class TechDomainContact < DomainContact
|
||||||
# Audit log is needed, therefore no raw SQL
|
# Audit log is needed, therefore no raw SQL
|
||||||
def self.replace(predecessor, successor)
|
def self.replace(current_contact, new_contact)
|
||||||
affected_domains = []
|
affected_domains = []
|
||||||
skipped_domains = []
|
skipped_domains = []
|
||||||
tech_contacts = where(contact: predecessor)
|
tech_contacts = where(contact: current_contact)
|
||||||
|
|
||||||
transaction do
|
transaction do
|
||||||
tech_contacts.each do |tech_contact|
|
tech_contacts.each do |tech_contact|
|
||||||
|
@ -12,7 +12,7 @@ class TechDomainContact < DomainContact
|
||||||
next
|
next
|
||||||
end
|
end
|
||||||
|
|
||||||
tech_contact.contact = successor
|
tech_contact.contact = new_contact
|
||||||
tech_contact.save!
|
tech_contact.save!
|
||||||
affected_domains << tech_contact.domain.name
|
affected_domains << tech_contact.domain.name
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,11 +7,11 @@
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="col-md-2 control-label">
|
<div class="col-md-2 control-label">
|
||||||
<%= label_tag :predecessor, t('.predecessor') %>
|
<%= label_tag :current_contact_id %>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-md-4">
|
<div class="col-md-4">
|
||||||
<%= text_field_tag :predecessor, params[:predecessor],
|
<%= text_field_tag :current_contact_id, params[:current_contact_id],
|
||||||
list: :contacts,
|
list: :contacts,
|
||||||
required: true,
|
required: true,
|
||||||
autofocus: true,
|
autofocus: true,
|
||||||
|
@ -21,11 +21,11 @@
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="col-md-2 control-label">
|
<div class="col-md-2 control-label">
|
||||||
<%= label_tag :successor, t('.successor') %>
|
<%= label_tag :new_contact_id %>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-md-4">
|
<div class="col-md-4">
|
||||||
<%= text_field_tag :successor, params[:successor],
|
<%= text_field_tag :new_contact_id, params[:new_contact_id],
|
||||||
list: :contacts,
|
list: :contacts,
|
||||||
required: true,
|
required: true,
|
||||||
class: 'form-control' %>
|
class: 'form-control' %>
|
||||||
|
|
|
@ -8,8 +8,6 @@ en:
|
||||||
bulk_transfer: Bulk transfer
|
bulk_transfer: Bulk transfer
|
||||||
|
|
||||||
tech_contact_form:
|
tech_contact_form:
|
||||||
predecessor: Current contact ID
|
|
||||||
successor: New contact ID
|
|
||||||
submit_btn: Replace technical contacts
|
submit_btn: Replace technical contacts
|
||||||
help_btn: Toggle help
|
help_btn: Toggle help
|
||||||
help: >-
|
help: >-
|
||||||
|
|
|
@ -8,8 +8,8 @@ Replaces all domain contacts of the current registrar.
|
||||||
$ curl https://repp.internet.ee/v1/domains/contacts \
|
$ curl https://repp.internet.ee/v1/domains/contacts \
|
||||||
-X PATCH \
|
-X PATCH \
|
||||||
-u username:password \
|
-u username:password \
|
||||||
-d predecessor=foo \
|
-d current_contact_id=foo \
|
||||||
-d successor=bar
|
-d new_contact_id=bar
|
||||||
```
|
```
|
||||||
### Example response
|
### Example response
|
||||||
```
|
```
|
||||||
|
|
|
@ -2,7 +2,8 @@ require 'test_helper'
|
||||||
|
|
||||||
class APIDomainContactsTest < ActionDispatch::IntegrationTest
|
class APIDomainContactsTest < ActionDispatch::IntegrationTest
|
||||||
def test_replace_all_tech_contacts_of_the_current_registrar
|
def test_replace_all_tech_contacts_of_the_current_registrar
|
||||||
patch '/repp/v1/domains/contacts', { predecessor: 'william-001', successor: 'john-001' },
|
patch '/repp/v1/domains/contacts', { current_contact_id: 'william-001',
|
||||||
|
new_contact_id: 'john-001' },
|
||||||
{ 'HTTP_AUTHORIZATION' => http_auth_key }
|
{ 'HTTP_AUTHORIZATION' => http_auth_key }
|
||||||
|
|
||||||
assert_nil domains(:shop).tech_contacts.find_by(code: 'william-001')
|
assert_nil domains(:shop).tech_contacts.find_by(code: 'william-001')
|
||||||
|
@ -13,14 +14,16 @@ class APIDomainContactsTest < ActionDispatch::IntegrationTest
|
||||||
def test_skip_discarded_domains
|
def test_skip_discarded_domains
|
||||||
domains(:airport).update!(statuses: [DomainStatus::DELETE_CANDIDATE])
|
domains(:airport).update!(statuses: [DomainStatus::DELETE_CANDIDATE])
|
||||||
|
|
||||||
patch '/repp/v1/domains/contacts', { predecessor: 'william-001', successor: 'john-001' },
|
patch '/repp/v1/domains/contacts', { current_contact_id: 'william-001',
|
||||||
|
new_contact_id: 'john-001' },
|
||||||
{ 'HTTP_AUTHORIZATION' => http_auth_key }
|
{ 'HTTP_AUTHORIZATION' => http_auth_key }
|
||||||
|
|
||||||
assert domains(:airport).tech_contacts.find_by(code: 'william-001')
|
assert domains(:airport).tech_contacts.find_by(code: 'william-001')
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_return_affected_domains_in_alphabetical_order
|
def test_return_affected_domains_in_alphabetical_order
|
||||||
patch '/repp/v1/domains/contacts', { predecessor: 'william-001', successor: 'john-001' },
|
patch '/repp/v1/domains/contacts', { current_contact_id: 'william-001',
|
||||||
|
new_contact_id: 'john-001' },
|
||||||
{ 'HTTP_AUTHORIZATION' => http_auth_key }
|
{ 'HTTP_AUTHORIZATION' => http_auth_key }
|
||||||
|
|
||||||
assert_response :ok
|
assert_response :ok
|
||||||
|
@ -33,7 +36,8 @@ class APIDomainContactsTest < ActionDispatch::IntegrationTest
|
||||||
domains(:shop).update!(statuses: [DomainStatus::DELETE_CANDIDATE])
|
domains(:shop).update!(statuses: [DomainStatus::DELETE_CANDIDATE])
|
||||||
domains(:airport).update!(statuses: [DomainStatus::DELETE_CANDIDATE])
|
domains(:airport).update!(statuses: [DomainStatus::DELETE_CANDIDATE])
|
||||||
|
|
||||||
patch '/repp/v1/domains/contacts', { predecessor: 'william-001', successor: 'john-001' },
|
patch '/repp/v1/domains/contacts', { current_contact_id: 'william-001',
|
||||||
|
new_contact_id: 'john-001' },
|
||||||
{ 'HTTP_AUTHORIZATION' => http_auth_key }
|
{ 'HTTP_AUTHORIZATION' => http_auth_key }
|
||||||
|
|
||||||
assert_response :ok
|
assert_response :ok
|
||||||
|
@ -42,52 +46,58 @@ class APIDomainContactsTest < ActionDispatch::IntegrationTest
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_keep_other_tech_contacts_intact
|
def test_keep_other_tech_contacts_intact
|
||||||
patch '/repp/v1/domains/contacts', { predecessor: 'william-001', successor: 'john-001' },
|
patch '/repp/v1/domains/contacts', { current_contact_id: 'william-001',
|
||||||
|
new_contact_id: 'john-001' },
|
||||||
{ 'HTTP_AUTHORIZATION' => http_auth_key }
|
{ 'HTTP_AUTHORIZATION' => http_auth_key }
|
||||||
|
|
||||||
assert domains(:shop).tech_contacts.find_by(code: 'acme-ltd-001')
|
assert domains(:shop).tech_contacts.find_by(code: 'acme-ltd-001')
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_keep_admin_contacts_intact
|
def test_keep_admin_contacts_intact
|
||||||
patch '/repp/v1/domains/contacts', { predecessor: 'william-001', successor: 'john-001' },
|
patch '/repp/v1/domains/contacts', { current_contact_id: 'william-001',
|
||||||
|
new_contact_id: 'john-001' },
|
||||||
{ 'HTTP_AUTHORIZATION' => http_auth_key }
|
{ 'HTTP_AUTHORIZATION' => http_auth_key }
|
||||||
|
|
||||||
assert domains(:airport).admin_contacts.find_by(code: 'william-001')
|
assert domains(:airport).admin_contacts.find_by(code: 'william-001')
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_restrict_contacts_to_the_current_registrar
|
def test_restrict_contacts_to_the_current_registrar
|
||||||
patch '/repp/v1/domains/contacts', { predecessor: 'jack-001', successor: 'william-002' },
|
patch '/repp/v1/domains/contacts', { current_contact_id: 'jack-001',
|
||||||
|
new_contact_id: 'william-002' },
|
||||||
{ 'HTTP_AUTHORIZATION' => http_auth_key }
|
{ 'HTTP_AUTHORIZATION' => http_auth_key }
|
||||||
|
|
||||||
assert_response :bad_request
|
assert_response :bad_request
|
||||||
assert_equal ({ error: { type: 'invalid_request_error',
|
assert_equal ({ error: { type: 'invalid_request_error',
|
||||||
param: 'predecessor',
|
param: 'current_contact_id',
|
||||||
message: 'No such contact: jack-001' } }),
|
message: 'No such contact: jack-001' } }),
|
||||||
JSON.parse(response.body, symbolize_names: true)
|
JSON.parse(response.body, symbolize_names: true)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_non_existent_predecessor
|
def test_non_existent_current_contact
|
||||||
patch '/repp/v1/domains/contacts', { predecessor: 'non-existent', successor: 'john-001' },
|
patch '/repp/v1/domains/contacts', { current_contact_id: 'non-existent',
|
||||||
|
new_contact_id: 'john-001' },
|
||||||
{ 'HTTP_AUTHORIZATION' => http_auth_key }
|
{ 'HTTP_AUTHORIZATION' => http_auth_key }
|
||||||
assert_response :bad_request
|
assert_response :bad_request
|
||||||
assert_equal ({ error: { type: 'invalid_request_error',
|
assert_equal ({ error: { type: 'invalid_request_error',
|
||||||
param: 'predecessor',
|
param: 'current_contact_id',
|
||||||
message: 'No such contact: non-existent' } }),
|
message: 'No such contact: non-existent' } }),
|
||||||
JSON.parse(response.body, symbolize_names: true)
|
JSON.parse(response.body, symbolize_names: true)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_non_existent_successor
|
def test_non_existent_new_contact
|
||||||
patch '/repp/v1/domains/contacts', { predecessor: 'william-001', successor: 'non-existent' },
|
patch '/repp/v1/domains/contacts', { current_contact_id: 'william-001',
|
||||||
|
new_contact_id: 'non-existent' },
|
||||||
{ 'HTTP_AUTHORIZATION' => http_auth_key }
|
{ 'HTTP_AUTHORIZATION' => http_auth_key }
|
||||||
assert_response :bad_request
|
assert_response :bad_request
|
||||||
assert_equal ({ error: { type: 'invalid_request_error',
|
assert_equal ({ error: { type: 'invalid_request_error',
|
||||||
param: 'successor',
|
param: 'new_contact_id',
|
||||||
message: 'No such contact: non-existent' } }),
|
message: 'No such contact: non-existent' } }),
|
||||||
JSON.parse(response.body, symbolize_names: true)
|
JSON.parse(response.body, symbolize_names: true)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_disallow_self_replacement
|
def test_disallow_self_replacement
|
||||||
patch '/repp/v1/domains/contacts', { predecessor: 'william-001', successor: 'william-001' },
|
patch '/repp/v1/domains/contacts', { current_contact_id: 'william-001',
|
||||||
|
new_contact_id: 'william-001' },
|
||||||
{ 'HTTP_AUTHORIZATION' => http_auth_key }
|
{ 'HTTP_AUTHORIZATION' => http_auth_key }
|
||||||
assert_response :bad_request
|
assert_response :bad_request
|
||||||
assert_equal ({ error: { type: 'invalid_request_error',
|
assert_equal ({ error: { type: 'invalid_request_error',
|
||||||
|
|
|
@ -7,7 +7,7 @@ class RegistrarAreaTechContactBulkChangeTest < ActionDispatch::IntegrationTest
|
||||||
|
|
||||||
def test_replace_domain_contacts_of_current_registrar
|
def test_replace_domain_contacts_of_current_registrar
|
||||||
request_stub = stub_request(:patch, /domains\/contacts/)
|
request_stub = stub_request(:patch, /domains\/contacts/)
|
||||||
.with(body: { predecessor: 'william-001', successor: 'john-001' },
|
.with(body: { current_contact_id: 'william-001', new_contact_id: 'john-001' },
|
||||||
basic_auth: ['test_bestnames', 'testtest'])
|
basic_auth: ['test_bestnames', 'testtest'])
|
||||||
.to_return(body: { affected_domains: %w[foo.test bar.test],
|
.to_return(body: { affected_domains: %w[foo.test bar.test],
|
||||||
skipped_domains: %w[baz.test qux.test] }.to_json,
|
skipped_domains: %w[baz.test qux.test] }.to_json,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue