Merge pull request #1817 from internetee/1764-registrar-bulk-admin-change

Domain admin contacts bulk change feature
This commit is contained in:
Timo Võhmar 2021-02-10 17:01:54 +02:00 committed by GitHub
commit a46b04856f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 524 additions and 136 deletions

View file

@ -16,8 +16,10 @@ plugins:
enabled: true enabled: true
config: config:
languages: languages:
- ruby ruby:
- javascript mass_threshold: 100
javascript:
mass_threshold: 100
eslint: eslint:
enabled: true enabled: true
channel: eslint-5 channel: eslint-5

View file

@ -0,0 +1,18 @@
class Registrar
class AdminContactsController < BulkChangeController
BASE_URL = URI.parse("#{ENV['repp_url']}domains/admin_contacts").freeze
ACTIVE_TAB = :admin_contact
def update
authorize! :manage, :repp
uri = BASE_URL
request = form_request(uri)
response = do_request(request, uri)
start_notice = t('.replaced')
process_response(response: response,
start_notice: start_notice,
active_tab: ACTIVE_TAB)
end
end
end

View file

@ -26,6 +26,84 @@ class Registrar
private private
def form_request(uri)
request = Net::HTTP::Patch.new(uri)
request.set_form_data(current_contact_id: params[:current_contact_id],
new_contact_id: params[:new_contact_id])
request.basic_auth(current_registrar_user.username,
current_registrar_user.plain_text_password)
request
end
def process_response(response:, start_notice: '', active_tab:)
parsed_response = JSON.parse(response.body, symbolize_names: true)
if response.code == '200'
notices = success_notices(parsed_response, start_notice)
flash[:notice] = notices.join(', ')
redirect_to registrar_domains_url
else
@error = response.code == '404' ? 'Contact(s) not found' : parsed_response[:message]
render file: 'registrar/bulk_change/new', locals: { active_tab: active_tab }
end
end
def success_notices(parsed_response, start_notice)
notices = [start_notice]
notices << "#{t('.affected_domains')}: " \
"#{parsed_response[:data][:affected_domains].join(', ')}"
if parsed_response[:data][:skipped_domains]
notices << "#{t('.skipped_domains')}: " \
"#{parsed_response[:data][:skipped_domains].join(', ')}"
end
notices
end
def do_request(request, uri)
response = if Rails.env.test?
do_test_request(request, uri)
elsif Rails.env.development?
do_dev_request(request, uri)
else
do_live_request(request, uri)
end
response
end
def do_live_request(request, uri)
client_cert = File.read(ENV['cert_path'])
client_key = File.read(ENV['key_path'])
Net::HTTP.start(uri.hostname, uri.port,
use_ssl: (uri.scheme == 'https'),
cert: OpenSSL::X509::Certificate.new(client_cert),
key: OpenSSL::PKey::RSA.new(client_key)) do |http|
http.request(request)
end
end
def do_dev_request(request, uri)
client_cert = File.read(ENV['cert_path'])
client_key = File.read(ENV['key_path'])
Net::HTTP.start(uri.hostname, uri.port,
use_ssl: (uri.scheme == 'https'),
verify_mode: OpenSSL::SSL::VERIFY_NONE,
cert: OpenSSL::X509::Certificate.new(client_cert),
key: OpenSSL::PKey::RSA.new(client_key)) do |http|
http.request(request)
end
end
def do_test_request(request, uri)
Net::HTTP.start(uri.hostname, uri.port,
use_ssl: (uri.scheme == 'https'),
verify_mode: OpenSSL::SSL::VERIFY_NONE) do |http|
http.request(request)
end
end
def ready_to_renew? def ready_to_renew?
domain_ids_for_bulk_renew.present? && params[:renew].present? domain_ids_for_bulk_renew.present? && params[:renew].present?
end end

View file

@ -25,32 +25,7 @@ class Registrar
current_registrar_user.plain_text_password) current_registrar_user.plain_text_password)
if Rails.env.test? response = do_request(request, uri)
response = Net::HTTP.start(uri.hostname, uri.port,
use_ssl: (uri.scheme == 'https'),
verify_mode: OpenSSL::SSL::VERIFY_NONE) do |http|
http.request(request)
end
elsif Rails.env.development?
client_cert = File.read(ENV['cert_path'])
client_key = File.read(ENV['key_path'])
response = Net::HTTP.start(uri.hostname, uri.port,
use_ssl: (uri.scheme == 'https'),
verify_mode: OpenSSL::SSL::VERIFY_NONE,
cert: OpenSSL::X509::Certificate.new(client_cert),
key: OpenSSL::PKey::RSA.new(client_key)) do |http|
http.request(request)
end
else
client_cert = File.read(ENV['cert_path'])
client_key = File.read(ENV['key_path'])
response = Net::HTTP.start(uri.hostname, uri.port,
use_ssl: (uri.scheme == 'https'),
cert: OpenSSL::X509::Certificate.new(client_cert),
key: OpenSSL::PKey::RSA.new(client_key)) do |http|
http.request(request)
end
end
parsed_response = JSON.parse(response.body, symbolize_names: true) parsed_response = JSON.parse(response.body, symbolize_names: true)

View file

@ -18,32 +18,7 @@ class Registrar
request.basic_auth(current_registrar_user.username, request.basic_auth(current_registrar_user.username,
current_registrar_user.plain_text_password) current_registrar_user.plain_text_password)
if Rails.env.test? response = do_request(request, uri)
response = Net::HTTP.start(uri.hostname, uri.port,
use_ssl: (uri.scheme == 'https'),
verify_mode: OpenSSL::SSL::VERIFY_NONE) do |http|
http.request(request)
end
elsif Rails.env.development?
client_cert = File.read(ENV['cert_path'])
client_key = File.read(ENV['key_path'])
response = Net::HTTP.start(uri.hostname, uri.port,
use_ssl: (uri.scheme == 'https'),
verify_mode: OpenSSL::SSL::VERIFY_NONE,
cert: OpenSSL::X509::Certificate.new(client_cert),
key: OpenSSL::PKey::RSA.new(client_key)) do |http|
http.request(request)
end
else
client_cert = File.read(ENV['cert_path'])
client_key = File.read(ENV['key_path'])
response = Net::HTTP.start(uri.hostname, uri.port,
use_ssl: (uri.scheme == 'https'),
cert: OpenSSL::X509::Certificate.new(client_cert),
key: OpenSSL::PKey::RSA.new(client_key)) do |http|
http.request(request)
end
end
parsed_response = JSON.parse(response.body, symbolize_names: true) parsed_response = JSON.parse(response.body, symbolize_names: true)

View file

@ -1,62 +1,19 @@
class Registrar class Registrar
class TechContactsController < BulkChangeController class TechContactsController < BulkChangeController
BASE_URL = URI.parse("#{ENV['repp_url']}domains/contacts").freeze
ACTIVE_TAB = :technical_contact
def update def update
authorize! :manage, :repp authorize! :manage, :repp
uri = URI.parse("#{ENV['repp_url']}domains/contacts") uri = BASE_URL
request = form_request(uri)
response = do_request(request, uri)
start_notice = t('.replaced')
request = Net::HTTP::Patch.new(uri) process_response(response: response,
request.set_form_data(current_contact_id: params[:current_contact_id], start_notice: start_notice,
new_contact_id: params[:new_contact_id]) active_tab: ACTIVE_TAB)
request.basic_auth(current_registrar_user.username,
current_registrar_user.plain_text_password)
if Rails.env.test?
response = Net::HTTP.start(uri.hostname, uri.port,
use_ssl: (uri.scheme == 'https'),
verify_mode: OpenSSL::SSL::VERIFY_NONE) do |http|
http.request(request)
end
elsif Rails.env.development?
client_cert = File.read(ENV['cert_path'])
client_key = File.read(ENV['key_path'])
response = Net::HTTP.start(uri.hostname, uri.port,
use_ssl: (uri.scheme == 'https'),
verify_mode: OpenSSL::SSL::VERIFY_NONE,
cert: OpenSSL::X509::Certificate.new(client_cert),
key: OpenSSL::PKey::RSA.new(client_key)) do |http|
http.request(request)
end
else
client_cert = File.read(ENV['cert_path'])
client_key = File.read(ENV['key_path'])
response = Net::HTTP.start(uri.hostname, uri.port,
use_ssl: (uri.scheme == 'https'),
cert: OpenSSL::X509::Certificate.new(client_cert),
key: OpenSSL::PKey::RSA.new(client_key)) do |http|
http.request(request)
end
end
parsed_response = JSON.parse(response.body, symbolize_names: true)
if response.code == '200'
notices = [t('.replaced')]
notices << "#{t('.affected_domains')}: " \
"#{parsed_response[:data][:affected_domains].join(', ')}"
if parsed_response[:data][:skipped_domains]
notices << "#{t('.skipped_domains')}: " \
"#{parsed_response[:data][:skipped_domains].join(', ')}"
end
flash[:notice] = notices.join(', ')
redirect_to registrar_domains_url
else
@error = response.code == '404' ? 'Contact(s) not found' : parsed_response[:message]
render file: 'registrar/bulk_change/new', locals: { active_tab: :technical_contact }
end
end end
end end
end end

View file

@ -0,0 +1,21 @@
module Repp
module V1
module Domains
class AdminContactsController < BaseContactsController
def update
super
unless @new_contact.identical_to?(@current_contact)
@epp_errors << { code: 2304, msg: 'Admin contacts must be identical' }
end
return handle_errors if @epp_errors.any?
affected, skipped = AdminDomainContact.replace(@current_contact, @new_contact)
@response = { affected_domains: affected, skipped_domains: skipped }
render_success(data: @response)
end
end
end
end
end

View file

@ -0,0 +1,31 @@
module Repp
module V1
module Domains
class BaseContactsController < BaseController
before_action :set_current_contact, only: [:update]
before_action :set_new_contact, only: [:update]
def set_current_contact
@current_contact = current_user.registrar.contacts
.find_by!(code: contact_params[:current_contact_id])
end
def set_new_contact
@new_contact = current_user.registrar.contacts.find_by!(code: params[:new_contact_id])
end
def update
@epp_errors ||= []
@epp_errors << { code: 2304, msg: 'New contact must be valid' } if @new_contact.invalid?
end
private
def contact_params
params.require(%i[current_contact_id new_contact_id])
params.permit(:current_contact_id, :new_contact_id)
end
end
end
end
end

View file

@ -1,23 +1,9 @@
module Repp module Repp
module V1 module V1
module Domains module Domains
class ContactsController < BaseController class ContactsController < BaseContactsController
before_action :set_current_contact, only: [:update]
before_action :set_new_contact, only: [:update]
def set_current_contact
@current_contact = current_user.registrar.contacts.find_by!(
code: contact_params[:current_contact_id]
)
end
def set_new_contact
@new_contact = current_user.registrar.contacts.find_by!(code: params[:new_contact_id])
end
def update def update
@epp_errors ||= [] super
@epp_errors << { code: 2304, msg: 'New contact must be valid' } if @new_contact.invalid?
if @new_contact == @current_contact if @new_contact == @current_contact
@epp_errors << { code: 2304, msg: 'New contact must be different from current' } @epp_errors << { code: 2304, msg: 'New contact must be different from current' }
@ -29,13 +15,6 @@ module Repp
@response = { affected_domains: affected, skipped_domains: skipped } @response = { affected_domains: affected, skipped_domains: skipped }
render_success(data: @response) render_success(data: @response)
end end
private
def contact_params
params.require(%i[current_contact_id new_contact_id])
params.permit(:current_contact_id, :new_contact_id)
end
end end
end end
end end

View file

@ -1,2 +1,26 @@
class AdminDomainContact < DomainContact class AdminDomainContact < DomainContact
# rubocop:disable Metrics/AbcSize
# rubocop:disable Metrics/MethodLength
def self.replace(current_contact, new_contact)
affected_domains = []
skipped_domains = []
admin_contacts = where(contact: current_contact)
admin_contacts.each do |admin_contact|
if admin_contact.domain.bulk_update_prohibited?
skipped_domains << admin_contact.domain.name
next
end
begin
admin_contact.contact = new_contact
admin_contact.save!
affected_domains << admin_contact.domain.name
rescue ActiveRecord::RecordNotUnique
skipped_domains << admin_contact.domain.name
end
end
[affected_domains.sort, skipped_domains.sort]
end
# rubocop:enable Metrics/AbcSize
# rubocop:enable Metrics/MethodLength
end end

View file

@ -11,6 +11,13 @@ module Concerns::Contact::Identical
ident_country_code ident_country_code
org_name org_name
] ]
IDENTICAL_ATTRIBUTES = %w[
ident
ident_type
ident_country_code
].freeze
private_constant :IDENTIFIABLE_ATTRIBUTES private_constant :IDENTIFIABLE_ATTRIBUTES
def identical(registrar) def identical(registrar)
@ -20,6 +27,12 @@ module Concerns::Contact::Identical
.where.not(id: id).take .where.not(id: id).take
end end
def identical_to?(contact)
IDENTICAL_ATTRIBUTES.all? do |attribute|
attributes[attribute] == contact.attributes[attribute]
end
end
private private
def identifiable_hash def identifiable_hash

View file

@ -0,0 +1,65 @@
<%= form_tag registrar_admin_contacts_path, method: :patch, class: 'form-horizontal' do %>
<% if @error %>
<div class="alert alert-danger">
<%= @error %>
</div>
<% end %>
<div class="form-group">
<div class="row">
<div class="col-md-6 control-label">
<p><%= t '.comment' %></p>
</div>
</div>
<div class="col-md-2 control-label">
<%= label_tag :current_contact_id, t('.current_contact_id') %>
</div>
<div class="col-md-4 current_admin_contact">
<%= text_field_tag :current_contact_id, params[:current_contact_id],
list: :contacts,
required: true,
autofocus: true,
class: 'form-control' %>
</div>
</div>
<div class="form-group">
<div class="col-md-2 control-label">
<%= label_tag :new_contact_id, t('.new_contact_id') %>
</div>
<div class="col-md-4 new_admin_contact">
<%= text_field_tag :new_contact_id, params[:new_contact_id],
list: :contacts,
required: true,
class: 'form-control' %>
</div>
</div>
<div class="form-group">
<div class="col-md-4 col-md-offset-2 text-right">
<button class="btn btn-warning">
<%= t '.submit_btn' %>
</button>
</div>
</div>
<div class="form-group">
<div class="col-md-6">
<a class="btn btn-default btn-xs" role="button" data-toggle="collapse"
href="#bulk_change_tech_contact_help"><%= t '.help_btn' %></a>
<div class="collapse" id="bulk_change_tech_contact_help">
<div class="well">
<%= t '.help' %>
</div>
</div>
</div>
</div>
<% end %>
<datalist id="contacts">
<% available_contacts.each do |data| %>
<option value="<%= data.second %>"><%= data.first %></option>
<% end %>
</datalist>

View file

@ -10,7 +10,7 @@
<%= label_tag :current_contact_id, t('.current_contact_id') %> <%= label_tag :current_contact_id, t('.current_contact_id') %>
</div> </div>
<div class="col-md-4"> <div class="col-md-4 current_tech_contact">
<%= text_field_tag :current_contact_id, params[:current_contact_id], <%= text_field_tag :current_contact_id, params[:current_contact_id],
list: :contacts, list: :contacts,
required: true, required: true,
@ -24,7 +24,7 @@
<%= label_tag :new_contact_id, t('.new_contact_id') %> <%= label_tag :new_contact_id, t('.new_contact_id') %>
</div> </div>
<div class="col-md-4"> <div class="col-md-4 new_tech_contact">
<%= text_field_tag :new_contact_id, params[:new_contact_id], <%= text_field_tag :new_contact_id, params[:new_contact_id],
list: :contacts, list: :contacts,
required: true, required: true,

View file

@ -12,6 +12,10 @@
<a href="#technical_contact" data-toggle="tab"><%= t '.technical_contact' %></a> <a href="#technical_contact" data-toggle="tab"><%= t '.technical_contact' %></a>
</li> </li>
<li class="<%= 'active' if active_tab == :admin_contact %>">
<a href="#admin_contact" data-toggle="tab"><%= t '.admin_contact' %></a>
</li>
<li class="<%= 'active' if active_tab == :nameserver %>"> <li class="<%= 'active' if active_tab == :nameserver %>">
<a href="#nameserver" data-toggle="tab"><%= t '.nameserver' %></a> <a href="#nameserver" data-toggle="tab"><%= t '.nameserver' %></a>
</li> </li>
@ -31,6 +35,11 @@
<%= render 'tech_contact_form', available_contacts: available_contacts %> <%= render 'tech_contact_form', available_contacts: available_contacts %>
</div> </div>
<div class="tab-pane<%= ' active' if active_tab == :admin_contact %>"
id="admin_contact">
<%= render 'admin_contact_form', available_contacts: available_contacts %>
</div>
<div class="tab-pane<%= ' active' if active_tab == :nameserver %>" id="nameserver"> <div class="tab-pane<%= ' active' if active_tab == :nameserver %>" id="nameserver">
<%= render 'nameserver_form' %> <%= render 'nameserver_form' %>
</div> </div>

View file

@ -0,0 +1,6 @@
en:
registrar:
admin_contacts:
update:
replaced: Admin contacts have been successfully replaced.
replaced: Technical contacts have been successfully replaced.

View file

@ -0,0 +1,11 @@
en:
registrar:
admin_contacts:
update:
replaced: Admin contacts have been successfully replaced.
affected_domains: Affected domains
skipped_domains: Skipped domains
process_request:
affected_domains: Affected domains
skipped_domains: Skipped domains
replaced: Admin contacts have been successfully replaced.

View file

@ -4,6 +4,7 @@ en:
new: new:
header: Bulk change header: Bulk change
technical_contact: Technical contact technical_contact: Technical contact
admin_contact: Admin contact
nameserver: Nameserver nameserver: Nameserver
bulk_transfer: Bulk transfer bulk_transfer: Bulk transfer
bulk_renew: Bulk renew bulk_renew: Bulk renew
@ -17,6 +18,19 @@ en:
Replace technical contact specified in "current contact ID" with the one in "new Replace technical contact specified in "current contact ID" with the one in "new
contact ID" on any domain registered under this registrar contact ID" on any domain registered under this registrar
admin_contact_form:
current_contact_id: Current admin contact ID
new_contact_id: New admin contact ID
submit_btn: Replace admin contacts
help_btn: Toggle help
help: >-
Replace admin contact specified in "current contact ID" with the one in "new
contact ID" on any domain registered under this registrar. Contact idents must
be the same
comment: >-
Bulk admin change is only allowed in case of old and new contact are sharing identical
ident data ie for updating contact information.
nameserver_form: nameserver_form:
ip_hint: One IP per line ip_hint: One IP per line
replace_btn: Replace nameserver replace_btn: Replace nameserver
@ -38,3 +52,5 @@ en:
domain_ids: Domains for bulk renewal domain_ids: Domains for bulk renewal
current_balance: Current balance current_balance: Current balance
period: Period period: Period
affected_domains: Affected domains
skipped_domains: Skipped domains

View file

@ -5,3 +5,7 @@ en:
replaced: Technical contacts have been successfully replaced. replaced: Technical contacts have been successfully replaced.
affected_domains: Affected domains affected_domains: Affected domains
skipped_domains: Skipped domains skipped_domains: Skipped domains
process_request:
affected_domains: Affected domains
skipped_domains: Skipped domains
replaced: Technical contacts have been successfully replaced.

View file

@ -64,6 +64,7 @@ Rails.application.routes.draw do
get ':id/transfer_info', to: 'domains#transfer_info', constraints: { id: /.*/ } get ':id/transfer_info', to: 'domains#transfer_info', constraints: { id: /.*/ }
post 'transfer', to: 'domains#transfer' post 'transfer', to: 'domains#transfer'
patch 'contacts', to: 'domains/contacts#update' patch 'contacts', to: 'domains/contacts#update'
patch 'admin_contacts', to: 'domains/admin_contacts#update'
post 'renew/bulk', to: 'domains/renews#bulk_renew' post 'renew/bulk', to: 'domains/renews#bulk_renew'
end end
end end
@ -137,6 +138,7 @@ Rails.application.routes.draw do
resource :bulk_change, controller: :bulk_change, only: :new resource :bulk_change, controller: :bulk_change, only: :new
post '/bulk_renew/new', to: 'bulk_change#bulk_renew', as: :bulk_renew post '/bulk_renew/new', to: 'bulk_change#bulk_renew', as: :bulk_renew
resource :tech_contacts, only: :update resource :tech_contacts, only: :update
resource :admin_contacts, only: :update
resource :nameservers, only: :update resource :nameservers, only: :update
resources :contacts, constraints: {:id => /[^\/]+(?=#{ ActionController::Renderers::RENDERERS.map{|e| "\\.#{e}\\z"}.join("|") })|[^\/]+/} do resources :contacts, constraints: {:id => /[^\/]+(?=#{ ActionController::Renderers::RENDERERS.map{|e| "\\.#{e}\\z"}.join("|") })|[^\/]+/} do
member do member do

View file

@ -0,0 +1,153 @@
require 'test_helper'
class APIDomainAdminContactsTest < ApplicationIntegrationTest
setup do
@admin_current = domains(:shop).admin_contacts.find_by(code: 'jane-001')
domain = domains(:airport)
domain.admin_contacts << @admin_current
@admin_new = contacts(:william)
@admin_new.update(ident: @admin_current.ident,
ident_type: @admin_current.ident_type,
ident_country_code: @admin_current.ident_country_code)
end
def test_replace_all_admin_contacts_when_ident_data_doesnt_match
@admin_new.update(ident: '777' ,
ident_type: 'priv',
ident_country_code: 'LV')
patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: @admin_current.code,
new_contact_id: @admin_new.code },
headers: { 'HTTP_AUTHORIZATION' => http_auth_key }
assert_response :bad_request
assert_equal ({ code: 2304, message: 'Admin contacts must be identical', data: {} }),
JSON.parse(response.body, symbolize_names: true)
end
def test_replace_all_admin_contacts_of_the_current_registrar
assert @admin_new.identical_to?(@admin_current)
patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: @admin_current.code,
new_contact_id: @admin_new.code },
headers: { 'HTTP_AUTHORIZATION' => http_auth_key }
assert_nil domains(:shop).admin_contacts.find_by(code: @admin_current.code)
assert domains(:shop).admin_contacts.find_by(code: @admin_new.code)
assert domains(:airport).admin_contacts.find_by(code: @admin_new.code)
end
def test_skip_discarded_domains
domains(:airport).update!(statuses: [DomainStatus::DELETE_CANDIDATE])
patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: @admin_current.code,
new_contact_id: @admin_new.code },
headers: { 'HTTP_AUTHORIZATION' => http_auth_key }
assert domains(:airport).admin_contacts.find_by(code: @admin_current.code)
end
def test_return_affected_domains_in_alphabetical_order
domain = domains(:airport)
domain.admin_contacts = [@admin_current]
patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: @admin_current.code,
new_contact_id: @admin_new.code },
headers: { 'HTTP_AUTHORIZATION' => http_auth_key }
assert_response :ok
assert_equal ({ code: 1000, message: 'Command completed successfully', data: { affected_domains: %w[airport.test shop.test],
skipped_domains: [] }}),
JSON.parse(response.body, symbolize_names: true)
end
def test_return_skipped_domains_in_alphabetical_order
domains(:shop).update!(statuses: [DomainStatus::DELETE_CANDIDATE])
domains(:airport).update!(statuses: [DomainStatus::DELETE_CANDIDATE])
patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: @admin_current.code,
new_contact_id: @admin_new.code },
headers: { 'HTTP_AUTHORIZATION' => http_auth_key }
assert_response :ok
assert_equal %w[airport.test shop.test], JSON.parse(response.body,
symbolize_names: true)[:data][:skipped_domains]
end
def test_keep_other_admin_contacts_intact
patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: @admin_current.code,
new_contact_id: @admin_new.code },
headers: { 'HTTP_AUTHORIZATION' => http_auth_key }
assert domains(:airport).admin_contacts.find_by(code: 'john-001')
end
def test_keep_tech_contacts_intact
patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: @admin_current.code,
new_contact_id: @admin_new.code },
headers: { 'HTTP_AUTHORIZATION' => http_auth_key }
assert domains(:airport).tech_contacts.find_by(code: 'william-001')
end
def test_restrict_contacts_to_the_current_registrar
patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: @admin_current.code,
new_contact_id: 'william-002' },
headers: { 'HTTP_AUTHORIZATION' => http_auth_key }
assert_response :not_found
assert_equal ({ code: 2303, message: 'Object does not exist' }),
JSON.parse(response.body, symbolize_names: true)
end
def test_non_existent_current_contact
patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: 'non-existent',
new_contact_id: @admin_new.code},
headers: { 'HTTP_AUTHORIZATION' => http_auth_key }
assert_response :not_found
assert_equal ({ code: 2303, message: 'Object does not exist' }),
JSON.parse(response.body, symbolize_names: true)
end
def test_non_existent_new_contact
patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: @admin_current.code,
new_contact_id: 'non-existent' },
headers: { 'HTTP_AUTHORIZATION' => http_auth_key }
assert_response :not_found
assert_equal ({code: 2303, message: 'Object does not exist'}),
JSON.parse(response.body, symbolize_names: true)
end
def test_disallow_invalid_new_contact
patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: @admin_current.code,
new_contact_id: 'invalid' },
headers: { 'HTTP_AUTHORIZATION' => http_auth_key }
assert_response :bad_request
assert_equal ({ code: 2304, message: 'New contact must be valid', data: {} }),
JSON.parse(response.body, symbolize_names: true)
end
def test_admin_bulk_changed_when_domain_update_prohibited
domains(:shop).update!(statuses: [DomainStatus::SERVER_UPDATE_PROHIBITED])
domains(:airport).admin_contacts = [@admin_current]
shop_admin_contact = Contact.find_by(code: 'jane-001')
assert domains(:shop).admin_contacts.include?(shop_admin_contact)
patch '/repp/v1/domains/admin_contacts', params: { current_contact_id: @admin_current.code,
new_contact_id: @admin_new.code },
headers: { 'HTTP_AUTHORIZATION' => http_auth_key }
assert_response :ok
assert_equal ({ code: 1000,
message: 'Command completed successfully',
data: { affected_domains: ["airport.test"],
skipped_domains: ["shop.test"] }}),
JSON.parse(response.body, symbolize_names: true)
end
private
def http_auth_key
ActionController::HttpAuthentication::Basic.encode_credentials('test_bestnames', 'testtest')
end
end

View file

@ -0,0 +1,49 @@
require 'application_system_test_case'
class RegistrarAreaAdminContactBulkChangeTest < ApplicationSystemTestCase
setup do
sign_in users(:api_bestnames)
end
def test_replace_domain_contacts_of_current_registrar
request_stub = stub_request(:patch, /domains\/admin_contacts/)
.with(body: { current_contact_id: 'william-001', new_contact_id: 'john-001' },
basic_auth: ['test_bestnames', 'testtest'])
.to_return(body: { data: { affected_domains: %w[foo.test bar.test],
skipped_domains: %w[baz.test qux.test] } }.to_json,
status: 200)
visit registrar_domains_url
click_link 'Bulk change'
click_link 'Admin contact'
find('.current_admin_contact').fill_in 'Current contact ID', with: 'william-001'
find('.new_admin_contact').fill_in 'New contact ID', with: 'john-001'
click_on 'Replace admin contacts'
assert_requested request_stub
assert_current_path registrar_domains_path
assert_text 'Admin contacts have been successfully replaced'
assert_text 'Affected domains: foo.test, bar.test'
assert_text 'Skipped domains: baz.test, qux.test'
end
def test_fails_gracefully
stub_request(:patch, /domains\/admin_contacts/)
.to_return(status: 400,
body: { message: 'epic fail' }.to_json,
headers: { 'Content-type' => Mime[:json] })
visit registrar_domains_url
click_link 'Bulk change'
click_link 'Admin contact'
find('.current_admin_contact').fill_in 'Current contact ID', with: 'william-001'
find('.new_admin_contact').fill_in 'New contact ID', with: 'john-001'
click_on 'Replace admin contacts'
assert_text 'epic fail'
assert_field 'Current contact ID', with: 'william-001'
assert_field 'New contact ID', with: 'john-001'
end
end

View file

@ -16,8 +16,8 @@ class RegistrarAreaTechContactBulkChangeTest < ApplicationSystemTestCase
visit registrar_domains_url visit registrar_domains_url
click_link 'Bulk change' click_link 'Bulk change'
fill_in 'Current contact ID', with: 'william-001' find('.current_tech_contact').fill_in 'Current contact ID', with: 'william-001'
fill_in 'New contact ID', with: 'john-001' find('.new_tech_contact').fill_in 'New contact ID', with: 'john-001'
click_on 'Replace technical contacts' click_on 'Replace technical contacts'
assert_requested request_stub assert_requested request_stub
@ -36,8 +36,8 @@ class RegistrarAreaTechContactBulkChangeTest < ApplicationSystemTestCase
visit registrar_domains_url visit registrar_domains_url
click_link 'Bulk change' click_link 'Bulk change'
fill_in 'Current contact ID', with: 'william-001' find('.current_tech_contact').fill_in 'Current contact ID', with: 'william-001'
fill_in 'New contact ID', with: 'john-001' find('.new_tech_contact').fill_in 'New contact ID', with: 'john-001'
click_on 'Replace technical contacts' click_on 'Replace technical contacts'
assert_text 'epic fail' assert_text 'epic fail'