From 228078a84e42dc7114f1129645fde30f5db6a1fa Mon Sep 17 00:00:00 2001 From: Artur Beljajev Date: Mon, 19 Mar 2018 00:55:35 +0200 Subject: [PATCH 01/11] Add bulk replace to registrar area #662 --- app/api/repp/api.rb | 1 + app/api/repp/domain_contacts_v1.rb | 35 ++++++ .../registrar/bulk_change_controller.rb | 20 ++++ ...ontroller.rb => nameservers_controller.rb} | 8 +- .../registrar/tech_contacts_controller.rb | 58 ++++++++++ app/models/tech_domain_contact.rb | 21 ++++ .../_flash_messages.html.erb | 6 +- app/views/layouts/registrar/base.html.erb | 2 +- .../_nameserver_form.html.erb} | 7 +- .../bulk_change/_tech_contact_form.html.erb | 48 ++++++++ app/views/registrar/bulk_change/new.html.erb | 32 ++++++ app/views/registrar/domains/index.html.erb | 32 +++--- .../registrar_nameservers/edit.html.erb | 11 -- config/locales/registrar/bulk_change.en.yml | 14 +++ config/locales/registrar/domains.en.yml | 2 +- config/locales/registrar/nameservers.en.yml | 5 + .../registrar/registrar_nameservers.en.yml | 13 --- config/locales/registrar/tech_contacts.en.yml | 7 ++ config/routes.rb | 6 +- doc/repp/v1/domain_contacts.md | 19 ++++ test/fixtures/domain_contacts.yml | 15 +++ test/fixtures/nameservers.yml | 4 + test/integration/api/domain_contacts_test.rb | 103 ++++++++++++++++++ test/integration/api/domain_transfers_test.rb | 2 +- .../epp/domain/transfer/request_test.rb | 2 +- .../nameserver_test.rb} | 11 +- .../bulk_change/tech_contact_test.rb | 47 ++++++++ .../registrar/domain_transfers_test.rb | 3 +- test/models/domain_transfer_test.rb | 2 +- test/models/nameserver_test.rb | 4 +- 30 files changed, 474 insertions(+), 66 deletions(-) create mode 100644 app/api/repp/domain_contacts_v1.rb create mode 100644 app/controllers/registrar/bulk_change_controller.rb rename app/controllers/registrar/{registrar_nameservers_controller.rb => nameservers_controller.rb} (94%) create mode 100644 app/controllers/registrar/tech_contacts_controller.rb rename app/views/{admin/base => application}/_flash_messages.html.erb (77%) rename app/views/registrar/{registrar_nameservers/_form.html.erb => bulk_change/_nameserver_form.html.erb} (89%) create mode 100644 app/views/registrar/bulk_change/_tech_contact_form.html.erb create mode 100644 app/views/registrar/bulk_change/new.html.erb delete mode 100644 app/views/registrar/registrar_nameservers/edit.html.erb create mode 100644 config/locales/registrar/bulk_change.en.yml create mode 100644 config/locales/registrar/nameservers.en.yml delete mode 100644 config/locales/registrar/registrar_nameservers.en.yml create mode 100644 config/locales/registrar/tech_contacts.en.yml create mode 100644 doc/repp/v1/domain_contacts.md create mode 100644 test/integration/api/domain_contacts_test.rb rename test/integration/registrar/{nameserver_replacement_test.rb => bulk_change/nameserver_test.rb} (91%) create mode 100644 test/integration/registrar/bulk_change/tech_contact_test.rb diff --git a/app/api/repp/api.rb b/app/api/repp/api.rb index 9c12470a0..7858cd625 100644 --- a/app/api/repp/api.rb +++ b/app/api/repp/api.rb @@ -59,5 +59,6 @@ module Repp mount Repp::AccountV1 mount Repp::DomainTransfersV1 mount Repp::NameserversV1 + mount Repp::DomainContactsV1 end end diff --git a/app/api/repp/domain_contacts_v1.rb b/app/api/repp/domain_contacts_v1.rb new file mode 100644 index 000000000..2d2cc4dbb --- /dev/null +++ b/app/api/repp/domain_contacts_v1.rb @@ -0,0 +1,35 @@ +module Repp + class DomainContactsV1 < Grape::API + version 'v1', using: :path + + resource :domains do + resource :contacts do + patch '/' do + predecessor = current_user.registrar.contacts.find_by(code: params[:predecessor]) + successor = current_user.registrar.contacts.find_by(code: params[:successor]) + + unless predecessor + error!({ error: { type: 'invalid_request_error', + param: 'predecessor', + message: "No such contact: #{params[:predecessor]}" } }, :bad_request) + end + + unless successor + error!({ error: { type: 'invalid_request_error', + param: 'successor', + message: "No such contact: #{params[:successor]}" } }, :bad_request) + end + + if predecessor == successor + error!({ error: { type: 'invalid_request_error', + message: 'Successor contact must be different from predecessor' } }, + :bad_request) + end + + affected_domains, skipped_domains = TechDomainContact.replace(predecessor, successor) + @response = { affected_domains: affected_domains, skipped_domains: skipped_domains } + end + end + end + end +end diff --git a/app/controllers/registrar/bulk_change_controller.rb b/app/controllers/registrar/bulk_change_controller.rb new file mode 100644 index 000000000..562344a46 --- /dev/null +++ b/app/controllers/registrar/bulk_change_controller.rb @@ -0,0 +1,20 @@ +class Registrar + class BulkChangeController < DeppController + helper_method :available_contacts + + def new + authorize! :manage, :repp + render file: 'registrar/bulk_change/new', locals: { active_tab: default_tab } + end + + private + + def available_contacts + current_user.registrar.contacts.order(:name).pluck(:name, :code) + end + + def default_tab + :technical_contact + end + end +end diff --git a/app/controllers/registrar/registrar_nameservers_controller.rb b/app/controllers/registrar/nameservers_controller.rb similarity index 94% rename from app/controllers/registrar/registrar_nameservers_controller.rb rename to app/controllers/registrar/nameservers_controller.rb index 1af3cde64..b6f7af829 100644 --- a/app/controllers/registrar/registrar_nameservers_controller.rb +++ b/app/controllers/registrar/nameservers_controller.rb @@ -1,9 +1,5 @@ class Registrar - class RegistrarNameserversController < DeppController - def edit - authorize! :manage, :repp - end - + class NameserversController < BulkChangeController def update authorize! :manage, :repp @@ -52,7 +48,7 @@ class Registrar redirect_to registrar_domains_url else @api_errors = parsed_response[:errors] - render :edit + render file: 'registrar/bulk_change/new', locals: { active_tab: :nameserver } end end end diff --git a/app/controllers/registrar/tech_contacts_controller.rb b/app/controllers/registrar/tech_contacts_controller.rb new file mode 100644 index 000000000..fccb10f78 --- /dev/null +++ b/app/controllers/registrar/tech_contacts_controller.rb @@ -0,0 +1,58 @@ +class Registrar + class TechContactsController < BulkChangeController + def update + authorize! :manage, :repp + + uri = URI.parse("#{ENV['repp_url']}domains/contacts") + + request = Net::HTTP::Patch.new(uri) + request.set_form_data(predecessor: params[:predecessor], successor: params[:successor]) + request.basic_auth(current_user.username, current_user.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[:affected_domains].join(', ')}" + + if parsed_response[:skipped_domains] + notices << "#{t('.skipped_domains')}: #{parsed_response[:skipped_domains].join(', ')}" + end + + flash[:notice] = notices + redirect_to registrar_domains_url + else + @error = parsed_response[:error] + render file: 'registrar/bulk_change/new', locals: { active_tab: :technical_contact } + end + end + end +end diff --git a/app/models/tech_domain_contact.rb b/app/models/tech_domain_contact.rb index 68ae35dde..55cc45aed 100644 --- a/app/models/tech_domain_contact.rb +++ b/app/models/tech_domain_contact.rb @@ -1,2 +1,23 @@ class TechDomainContact < DomainContact + # Audit log is needed, therefore no raw SQL + def self.replace(predecessor, successor) + affected_domains = [] + skipped_domains = [] + tech_contacts = where(contact: predecessor) + + transaction do + tech_contacts.each do |tech_contact| + if tech_contact.domain.discarded? + skipped_domains << tech_contact.domain.name + next + end + + tech_contact.contact = successor + tech_contact.save! + affected_domains << tech_contact.domain.name + end + end + + return affected_domains.sort, skipped_domains.sort + end end diff --git a/app/views/admin/base/_flash_messages.html.erb b/app/views/application/_flash_messages.html.erb similarity index 77% rename from app/views/admin/base/_flash_messages.html.erb rename to app/views/application/_flash_messages.html.erb index 4a10df304..9b31f0d3f 100644 --- a/app/views/admin/base/_flash_messages.html.erb +++ b/app/views/application/_flash_messages.html.erb @@ -1,7 +1,11 @@ <% if flash[:notice] %>
-

<%= flash[:notice] %>

+ <% if flash[:notice].respond_to?(:join) %> +

<%= flash[:notice].join('
').html_safe %>

+ <% else %> +

<%= flash[:notice] %>

+ <% end %>
<% end %> diff --git a/app/views/layouts/registrar/base.html.erb b/app/views/layouts/registrar/base.html.erb index 6116c7a26..c1b67673e 100644 --- a/app/views/layouts/registrar/base.html.erb +++ b/app/views/layouts/registrar/base.html.erb @@ -39,7 +39,7 @@
- <%= render 'shared/flash' %> + <%= render 'flash_messages' %> <% if depp_controller? %> <%= render 'registrar/shared/epp_results' %> <% end %> diff --git a/app/views/registrar/registrar_nameservers/_form.html.erb b/app/views/registrar/bulk_change/_nameserver_form.html.erb similarity index 89% rename from app/views/registrar/registrar_nameservers/_form.html.erb rename to app/views/registrar/bulk_change/_nameserver_form.html.erb index 3aca3e0e1..1b1900314 100644 --- a/app/views/registrar/registrar_nameservers/_form.html.erb +++ b/app/views/registrar/bulk_change/_nameserver_form.html.erb @@ -1,12 +1,13 @@ -<%= form_tag registrar_update_registrar_nameserver_path, method: :put, class: 'form-horizontal' do %> +<%= form_tag registrar_nameservers_path, method: :patch, class: 'form-horizontal' do %> + <%= render 'registrar/domain_transfers/form/api_errors' %> +
<%= label_tag :old_hostname %>
- <%= text_field_tag :old_hostname, params[:old_hostname], autofocus: true, - required: true, + <%= text_field_tag :old_hostname, params[:old_hostname], required: true, class: 'form-control' %>
diff --git a/app/views/registrar/bulk_change/_tech_contact_form.html.erb b/app/views/registrar/bulk_change/_tech_contact_form.html.erb new file mode 100644 index 000000000..24e7ff27f --- /dev/null +++ b/app/views/registrar/bulk_change/_tech_contact_form.html.erb @@ -0,0 +1,48 @@ +<%= form_tag registrar_tech_contacts_path, method: :patch, class: 'form-horizontal' do %> + <% if @error %> +
+ <%= @error[:message] %> +
+ <% end %> + +
+
+ <%= label_tag :predecessor %> +
+ +
+ <%= text_field_tag :predecessor, params[:predecessor], + list: :contacts, + required: true, + autofocus: true, + class: 'form-control' %> +
+
+ +
+
+ <%= label_tag :successor %> +
+ +
+ <%= text_field_tag :successor, params[:successor], + list: :contacts, + required: true, + class: 'form-control' %> +
+
+ +
+
+ +
+
+<% end %> + + + <% available_contacts.each do |data| %> + + <% end %> + diff --git a/app/views/registrar/bulk_change/new.html.erb b/app/views/registrar/bulk_change/new.html.erb new file mode 100644 index 000000000..77cc2d20a --- /dev/null +++ b/app/views/registrar/bulk_change/new.html.erb @@ -0,0 +1,32 @@ + + + + +
+
+ + +
+
+ <%= render 'tech_contact_form', available_contacts: available_contacts %> +
+ +
+ <%= render 'nameserver_form' %> +
+
+
+
diff --git a/app/views/registrar/domains/index.html.erb b/app/views/registrar/domains/index.html.erb index 319f0d04f..cbc048697 100644 --- a/app/views/registrar/domains/index.html.erb +++ b/app/views/registrar/domains/index.html.erb @@ -1,13 +1,13 @@