mirror of
https://github.com/internetee/registry.git
synced 2025-07-20 09:46:09 +02:00
Merge pull request #1774 from internetee/repp-domains
REPP: Domain management
This commit is contained in:
commit
d073656448
66 changed files with 2700 additions and 605 deletions
|
@ -15,6 +15,7 @@ plugins:
|
||||||
duplication:
|
duplication:
|
||||||
enabled: true
|
enabled: true
|
||||||
config:
|
config:
|
||||||
|
count_threshold: 3
|
||||||
languages:
|
languages:
|
||||||
ruby:
|
ruby:
|
||||||
mass_threshold: 100
|
mass_threshold: 100
|
||||||
|
@ -38,6 +39,9 @@ checks:
|
||||||
method-lines:
|
method-lines:
|
||||||
config:
|
config:
|
||||||
threshold: 40
|
threshold: 40
|
||||||
|
method-count:
|
||||||
|
config:
|
||||||
|
threshold: 25
|
||||||
exclude_patterns:
|
exclude_patterns:
|
||||||
- "app/models/version/"
|
- "app/models/version/"
|
||||||
- "bin/"
|
- "bin/"
|
||||||
|
|
2
Gemfile
2
Gemfile
|
@ -2,6 +2,7 @@ source 'https://rubygems.org'
|
||||||
|
|
||||||
# core
|
# core
|
||||||
gem 'active_interaction', '~> 3.8'
|
gem 'active_interaction', '~> 3.8'
|
||||||
|
gem 'apipie-rails', '~> 0.5.18'
|
||||||
gem 'bootsnap', '>= 1.1.0', require: false
|
gem 'bootsnap', '>= 1.1.0', require: false
|
||||||
gem 'iso8601', '0.12.1' # for dates and times
|
gem 'iso8601', '0.12.1' # for dates and times
|
||||||
gem 'rails', '~> 6.0'
|
gem 'rails', '~> 6.0'
|
||||||
|
@ -78,7 +79,6 @@ gem 'wkhtmltopdf-binary', '~> 0.12.5.1'
|
||||||
|
|
||||||
gem 'directo', github: 'internetee/directo', branch: 'master'
|
gem 'directo', github: 'internetee/directo', branch: 'master'
|
||||||
|
|
||||||
|
|
||||||
group :development, :test do
|
group :development, :test do
|
||||||
gem 'pry', '0.10.1'
|
gem 'pry', '0.10.1'
|
||||||
gem 'puma'
|
gem 'puma'
|
||||||
|
|
|
@ -145,6 +145,8 @@ GEM
|
||||||
akami (1.3.1)
|
akami (1.3.1)
|
||||||
gyoku (>= 0.4.0)
|
gyoku (>= 0.4.0)
|
||||||
nokogiri
|
nokogiri
|
||||||
|
apipie-rails (0.5.18)
|
||||||
|
rails (>= 4.1)
|
||||||
attr_required (1.0.1)
|
attr_required (1.0.1)
|
||||||
autoprefixer-rails (10.2.4.0)
|
autoprefixer-rails (10.2.4.0)
|
||||||
execjs
|
execjs
|
||||||
|
@ -495,11 +497,13 @@ GEM
|
||||||
|
|
||||||
PLATFORMS
|
PLATFORMS
|
||||||
ruby
|
ruby
|
||||||
|
x86_64-linux
|
||||||
|
|
||||||
DEPENDENCIES
|
DEPENDENCIES
|
||||||
active_interaction (~> 3.8)
|
active_interaction (~> 3.8)
|
||||||
activerecord-import
|
activerecord-import
|
||||||
airbrake
|
airbrake
|
||||||
|
apipie-rails (~> 0.5.18)
|
||||||
aws-sdk-sesv2 (~> 1.16)
|
aws-sdk-sesv2 (~> 1.16)
|
||||||
bootsnap (>= 1.1.0)
|
bootsnap (>= 1.1.0)
|
||||||
bootstrap-sass (~> 3.4)
|
bootstrap-sass (~> 3.4)
|
||||||
|
@ -558,4 +562,4 @@ DEPENDENCIES
|
||||||
wkhtmltopdf-binary (~> 0.12.5.1)
|
wkhtmltopdf-binary (~> 0.12.5.1)
|
||||||
|
|
||||||
BUNDLED WITH
|
BUNDLED WITH
|
||||||
2.1.4
|
2.2.2
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
require 'deserializers/xml/domain_delete'
|
||||||
module Epp
|
module Epp
|
||||||
class DomainsController < BaseController
|
class DomainsController < BaseController
|
||||||
before_action :find_domain, only: %i[info renew update transfer delete]
|
before_action :find_domain, only: %i[info renew update transfer delete]
|
||||||
|
@ -26,104 +27,39 @@ module Epp
|
||||||
end
|
end
|
||||||
|
|
||||||
def create
|
def create
|
||||||
authorize! :create, Epp::Domain
|
authorize!(:create, Epp::Domain)
|
||||||
|
|
||||||
if Domain.release_to_auction
|
registrar_id = current_user.registrar.id
|
||||||
request_domain_name = params[:parsed_frame].css('name').text.strip.downcase
|
@domain = Epp::Domain.new
|
||||||
domain_name = DNS::DomainName.new(SimpleIDN.to_unicode(request_domain_name))
|
data = ::Deserializers::Xml::DomainCreate.new(params[:parsed_frame], registrar_id).call
|
||||||
|
action = Actions::DomainCreate.new(@domain, data)
|
||||||
|
|
||||||
if domain_name.at_auction?
|
action.call ? render_epp_response('/epp/domains/create') : handle_errors(@domain)
|
||||||
epp_errors << {
|
|
||||||
code: '2306',
|
|
||||||
msg: 'Parameter value policy error: domain is at auction',
|
|
||||||
}
|
|
||||||
handle_errors
|
|
||||||
return
|
|
||||||
elsif domain_name.awaiting_payment?
|
|
||||||
epp_errors << {
|
|
||||||
code: '2003',
|
|
||||||
msg: 'Required parameter missing; reserved>pw element required for reserved domains',
|
|
||||||
}
|
|
||||||
handle_errors
|
|
||||||
return
|
|
||||||
elsif domain_name.pending_registration?
|
|
||||||
registration_code = params[:parsed_frame].css('reserved > pw').text
|
|
||||||
|
|
||||||
if registration_code.empty?
|
|
||||||
epp_errors << {
|
|
||||||
code: '2003',
|
|
||||||
msg: 'Required parameter missing; reserved>pw element is required',
|
|
||||||
}
|
|
||||||
handle_errors
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
unless domain_name.available_with_code?(registration_code)
|
|
||||||
epp_errors << {
|
|
||||||
code: '2202',
|
|
||||||
msg: 'Invalid authorization information; invalid reserved>pw value',
|
|
||||||
}
|
|
||||||
handle_errors
|
|
||||||
return
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
@domain = Epp::Domain.new_from_epp(params[:parsed_frame], current_user)
|
|
||||||
handle_errors(@domain) and return if @domain.errors.any?
|
|
||||||
@domain.valid?
|
|
||||||
@domain.errors.delete(:name_dirty) if @domain.errors[:puny_label].any?
|
|
||||||
handle_errors(@domain) and return if @domain.errors.any?
|
|
||||||
handle_errors and return unless balance_ok?('create') # loads pricelist in this method
|
|
||||||
|
|
||||||
ActiveRecord::Base.transaction do
|
|
||||||
@domain.add_legal_file_to_new(params[:parsed_frame])
|
|
||||||
|
|
||||||
if @domain.save # TODO: Maybe use validate: false here because we have already validated the domain?
|
|
||||||
current_user.registrar.debit!({
|
|
||||||
sum: @domain_pricelist.price.amount,
|
|
||||||
description: "#{I18n.t('create')} #{@domain.name}",
|
|
||||||
activity_type: AccountActivity::CREATE,
|
|
||||||
price: @domain_pricelist
|
|
||||||
})
|
|
||||||
|
|
||||||
if Domain.release_to_auction && domain_name.pending_registration?
|
|
||||||
active_auction = Auction.find_by(domain: domain_name.to_s,
|
|
||||||
status: Auction.statuses[:payment_received])
|
|
||||||
active_auction.domain_registered!
|
|
||||||
end
|
|
||||||
Dispute.close_by_domain(@domain.name)
|
|
||||||
render_epp_response '/epp/domains/create'
|
|
||||||
else
|
|
||||||
handle_errors(@domain)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def update
|
def update
|
||||||
authorize! :update, @domain, @password
|
authorize!(:update, @domain, @password)
|
||||||
|
|
||||||
updated = @domain.update(params[:parsed_frame], current_user)
|
registrar_id = current_user.registrar.id
|
||||||
(handle_errors(@domain) && return) unless updated
|
update_params = ::Deserializers::Xml::DomainUpdate.new(params[:parsed_frame],
|
||||||
|
registrar_id).call
|
||||||
|
action = Actions::DomainUpdate.new(@domain, update_params, false)
|
||||||
|
(handle_errors(@domain) and return) unless action.call
|
||||||
|
|
||||||
pending = @domain.epp_pending_update.present?
|
pending = @domain.epp_pending_update.present?
|
||||||
render_epp_response "/epp/domains/success#{'_pending' if pending}"
|
render_epp_response("/epp/domains/success#{'_pending' if pending}")
|
||||||
end
|
end
|
||||||
|
|
||||||
def delete
|
def delete
|
||||||
authorize! :delete, @domain, @password
|
authorize!(:delete, @domain, @password)
|
||||||
|
frame = params[:parsed_frame]
|
||||||
|
delete_params = ::Deserializers::Xml::DomainDelete.new(frame).call
|
||||||
|
action = Actions::DomainDelete.new(@domain, delete_params, current_user.registrar)
|
||||||
|
|
||||||
(handle_errors(@domain) && return) unless @domain.can_be_deleted?
|
(handle_errors(@domain) and return) unless action.call
|
||||||
|
|
||||||
if @domain.epp_destroy(params[:parsed_frame], current_user.id)
|
pending = @domain.epp_pending_delete.present?
|
||||||
if @domain.epp_pending_delete.present?
|
render_epp_response("/epp/domains/success#{'_pending' if pending}")
|
||||||
render_epp_response '/epp/domains/success_pending'
|
|
||||||
else
|
|
||||||
render_epp_response '/epp/domains/success'
|
|
||||||
end
|
|
||||||
else
|
|
||||||
handle_errors(@domain)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def check
|
def check
|
||||||
|
@ -137,44 +73,17 @@ module Epp
|
||||||
def renew
|
def renew
|
||||||
authorize! :renew, @domain
|
authorize! :renew, @domain
|
||||||
|
|
||||||
period_element = params[:parsed_frame].css('period').text
|
registrar_id = current_user.registrar.id
|
||||||
period = (period_element.to_i == 0) ? 1 : period_element.to_i
|
renew_params = ::Deserializers::Xml::Domain.new(params[:parsed_frame],
|
||||||
period_unit = Epp::Domain.parse_period_unit_from_frame(params[:parsed_frame]) || 'y'
|
registrar_id).call
|
||||||
|
|
||||||
balance_ok?('renew', period, period_unit) # loading pricelist
|
|
||||||
|
|
||||||
begin
|
|
||||||
ActiveRecord::Base.transaction(isolation: :serializable) do
|
|
||||||
@domain.reload
|
|
||||||
|
|
||||||
success = @domain.renew(
|
|
||||||
params[:parsed_frame].css('curExpDate').text,
|
|
||||||
period, period_unit
|
|
||||||
)
|
|
||||||
|
|
||||||
if success
|
|
||||||
unless balance_ok?('renew', period, period_unit)
|
|
||||||
handle_errors
|
|
||||||
fail ActiveRecord::Rollback
|
|
||||||
end
|
|
||||||
|
|
||||||
current_user.registrar.debit!({
|
|
||||||
sum: @domain_pricelist.price.amount,
|
|
||||||
description: "#{I18n.t('renew')} #{@domain.name}",
|
|
||||||
activity_type: AccountActivity::RENEW,
|
|
||||||
price: @domain_pricelist
|
|
||||||
})
|
|
||||||
|
|
||||||
|
action = Actions::DomainRenew.new(@domain, renew_params, current_user.registrar)
|
||||||
|
if action.call
|
||||||
render_epp_response '/epp/domains/renew'
|
render_epp_response '/epp/domains/renew'
|
||||||
else
|
else
|
||||||
handle_errors(@domain)
|
handle_errors(@domain)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
rescue ActiveRecord::StatementInvalid => e
|
|
||||||
sleep rand / 100
|
|
||||||
retry
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def transfer
|
def transfer
|
||||||
authorize! :transfer, @domain
|
authorize! :transfer, @domain
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
module Repp
|
module Repp
|
||||||
module V1
|
module V1
|
||||||
class AccountsController < BaseController
|
class AccountsController < BaseController
|
||||||
|
api :GET, '/repp/v1/accounts/balance'
|
||||||
|
desc "Get account's balance"
|
||||||
def balance
|
def balance
|
||||||
resp = { balance: current_user.registrar.cash_account.balance,
|
resp = { balance: current_user.registrar.cash_account.balance,
|
||||||
currency: current_user.registrar.cash_account.currency }
|
currency: current_user.registrar.cash_account.currency }
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
module Repp
|
module Repp
|
||||||
module V1
|
module V1
|
||||||
class BaseController < ActionController::API
|
class BaseController < ActionController::API # rubocop:disable Metrics/ClassLength
|
||||||
around_action :log_request
|
around_action :log_request
|
||||||
before_action :authenticate_user
|
before_action :authenticate_user
|
||||||
before_action :validate_webclient_ca
|
before_action :validate_webclient_ca
|
||||||
|
@ -16,9 +16,12 @@ module Repp
|
||||||
rescue ActiveRecord::RecordNotFound
|
rescue ActiveRecord::RecordNotFound
|
||||||
@response = { code: 2303, message: 'Object does not exist' }
|
@response = { code: 2303, message: 'Object does not exist' }
|
||||||
render(json: @response, status: :not_found)
|
render(json: @response, status: :not_found)
|
||||||
rescue ActionController::ParameterMissing => e
|
rescue ActionController::ParameterMissing, Apipie::ParamMissing => e
|
||||||
@response = { code: 2003, message: e }
|
@response = { code: 2003, message: e }
|
||||||
render(json: @response, status: :bad_request)
|
render(json: @response, status: :bad_request)
|
||||||
|
rescue Apipie::ParamInvalid => e
|
||||||
|
@response = { code: 2005, message: e }
|
||||||
|
render(json: @response, status: :bad_request)
|
||||||
ensure
|
ensure
|
||||||
create_repp_log
|
create_repp_log
|
||||||
end
|
end
|
||||||
|
@ -35,6 +38,16 @@ module Repp
|
||||||
end
|
end
|
||||||
# rubocop:enable Metrics/AbcSize
|
# rubocop:enable Metrics/AbcSize
|
||||||
|
|
||||||
|
def set_domain
|
||||||
|
registrar = current_user.registrar
|
||||||
|
@domain = Epp::Domain.find_by(registrar: registrar, name: params[:domain_id])
|
||||||
|
@domain ||= Epp::Domain.find_by!(registrar: registrar, name_puny: params[:domain_id])
|
||||||
|
|
||||||
|
return @domain if @domain
|
||||||
|
|
||||||
|
raise ActiveRecord::RecordNotFound
|
||||||
|
end
|
||||||
|
|
||||||
def set_paper_trail_whodunnit
|
def set_paper_trail_whodunnit
|
||||||
::PaperTrail.request.whodunnit = current_user
|
::PaperTrail.request.whodunnit = current_user
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
require 'serializers/repp/contact'
|
require 'serializers/repp/contact'
|
||||||
module Repp
|
module Repp
|
||||||
module V1
|
module V1
|
||||||
class ContactsController < BaseController
|
class ContactsController < BaseController # rubocop:disable Metrics/ClassLength
|
||||||
before_action :find_contact, only: %i[show update destroy]
|
before_action :find_contact, only: %i[show update destroy]
|
||||||
|
|
||||||
## GET /repp/v1/contacts
|
api :get, '/repp/v1/contacts'
|
||||||
|
desc 'Get all existing contacts'
|
||||||
def index
|
def index
|
||||||
record_count = current_user.registrar.contacts.count
|
record_count = current_user.registrar.contacts.count
|
||||||
contacts = showable_contacts(params[:details], params[:limit] || 200,
|
contacts = showable_contacts(params[:details], params[:limit] || 200,
|
||||||
|
@ -13,14 +14,16 @@ module Repp
|
||||||
render(json: @response, status: :ok)
|
render(json: @response, status: :ok)
|
||||||
end
|
end
|
||||||
|
|
||||||
## GET /repp/v1/contacts/1
|
api :get, '/repp/v1/contacts/:contact_code'
|
||||||
|
desc 'Get a specific contact'
|
||||||
def show
|
def show
|
||||||
serializer = ::Serializers::Repp::Contact.new(@contact,
|
serializer = ::Serializers::Repp::Contact.new(@contact,
|
||||||
show_address: Contact.address_processing?)
|
show_address: Contact.address_processing?)
|
||||||
render_success(data: serializer.to_json)
|
render_success(data: serializer.to_json)
|
||||||
end
|
end
|
||||||
|
|
||||||
## GET /repp/v1/contacts/check/1
|
api :get, '/repp/v1/contacts/check/:contact_code'
|
||||||
|
desc 'Check contact code availability'
|
||||||
def check
|
def check
|
||||||
contact = Epp::Contact.find_by(code: params[:id])
|
contact = Epp::Contact.find_by(code: params[:id])
|
||||||
data = { contact: { id: params[:id], available: contact.nil? } }
|
data = { contact: { id: params[:id], available: contact.nil? } }
|
||||||
|
@ -28,7 +31,8 @@ module Repp
|
||||||
render_success(data: data)
|
render_success(data: data)
|
||||||
end
|
end
|
||||||
|
|
||||||
## POST /repp/v1/contacts
|
api :POST, '/repp/v1/contacts'
|
||||||
|
desc 'Create a new contact'
|
||||||
def create
|
def create
|
||||||
@contact = Epp::Contact.new(contact_params_with_address, current_user.registrar, epp: false)
|
@contact = Epp::Contact.new(contact_params_with_address, current_user.registrar, epp: false)
|
||||||
action = Actions::ContactCreate.new(@contact, params[:legal_document],
|
action = Actions::ContactCreate.new(@contact, params[:legal_document],
|
||||||
|
@ -42,7 +46,8 @@ module Repp
|
||||||
render_success(create_update_success_body)
|
render_success(create_update_success_body)
|
||||||
end
|
end
|
||||||
|
|
||||||
## PUT /repp/v1/contacts/1
|
api :PUT, '/repp/v1/contacts/:contact_code'
|
||||||
|
desc 'Update existing contact'
|
||||||
def update
|
def update
|
||||||
action = Actions::ContactUpdate.new(@contact, contact_params_with_address(required: false),
|
action = Actions::ContactUpdate.new(@contact, contact_params_with_address(required: false),
|
||||||
params[:legal_document],
|
params[:legal_document],
|
||||||
|
@ -56,6 +61,8 @@ module Repp
|
||||||
render_success(create_update_success_body)
|
render_success(create_update_success_body)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
api :DELETE, '/repp/v1/contacts/:contact_code'
|
||||||
|
desc 'Delete a specific contact'
|
||||||
def destroy
|
def destroy
|
||||||
action = Actions::ContactDelete.new(@contact, params[:legal_document])
|
action = Actions::ContactDelete.new(@contact, params[:legal_document])
|
||||||
unless action.call
|
unless action.call
|
||||||
|
|
|
@ -2,6 +2,50 @@ module Repp
|
||||||
module V1
|
module V1
|
||||||
module Domains
|
module Domains
|
||||||
class ContactsController < BaseContactsController
|
class ContactsController < BaseContactsController
|
||||||
|
before_action :set_domain, only: %i[index create destroy]
|
||||||
|
|
||||||
|
def_param_group :contacts_apidoc do
|
||||||
|
param :contacts, Array, required: true, desc: 'Array of new linked contacts' do
|
||||||
|
param :code, String, required: true, desc: 'Contact code'
|
||||||
|
param :type, String, required: true, desc: 'Role of contact (admin/tech)'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
api :GET, '/repp/v1/domains/:domain_name/contacts'
|
||||||
|
desc "View domain's admin and tech contacts"
|
||||||
|
def index
|
||||||
|
admin_contacts = @domain.admin_domain_contacts.pluck(:contact_code_cache)
|
||||||
|
tech_contacts = @domain.tech_domain_contacts.pluck(:contact_code_cache)
|
||||||
|
|
||||||
|
data = { admin_contacts: admin_contacts, tech_contacts: tech_contacts }
|
||||||
|
render_success(data: data)
|
||||||
|
end
|
||||||
|
|
||||||
|
api :POST, '/repp/v1/domains/:domain_name/contacts'
|
||||||
|
desc 'Link new contact(s) to domain'
|
||||||
|
param_group :contacts_apidoc
|
||||||
|
def create
|
||||||
|
cta('add')
|
||||||
|
end
|
||||||
|
|
||||||
|
api :DELETE, '/repp/v1/domains/:domain_name/contacts'
|
||||||
|
desc 'Remove contact(s) from domain'
|
||||||
|
param_group :contacts_apidoc
|
||||||
|
def destroy
|
||||||
|
cta('rem')
|
||||||
|
end
|
||||||
|
|
||||||
|
def cta(action = 'add')
|
||||||
|
params[:contacts].each { |c| c[:action] = action }
|
||||||
|
action = Actions::DomainUpdate.new(@domain, contact_create_params, false)
|
||||||
|
|
||||||
|
# rubocop:disable Style/AndOr
|
||||||
|
handle_errors(@domain) and return unless action.call
|
||||||
|
# rubocop:enable Style/AndOr
|
||||||
|
|
||||||
|
render_success(data: { domain: { name: @domain.name } })
|
||||||
|
end
|
||||||
|
|
||||||
def update
|
def update
|
||||||
super
|
super
|
||||||
|
|
||||||
|
@ -15,6 +59,12 @@ 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_create_params
|
||||||
|
params.permit(:domain_id, contacts: [%i[action code type]])
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
58
app/controllers/repp/v1/domains/dnssec_controller.rb
Normal file
58
app/controllers/repp/v1/domains/dnssec_controller.rb
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
module Repp
|
||||||
|
module V1
|
||||||
|
module Domains
|
||||||
|
class DnssecController < BaseController
|
||||||
|
before_action :set_domain, only: %i[index create destroy]
|
||||||
|
|
||||||
|
def_param_group :dns_keys_apidoc do
|
||||||
|
param :flags, String, required: true, desc: '256 (KSK) or 257 (ZSK)'
|
||||||
|
param :protocol, String, required: true, desc: 'Key protocol (3)'
|
||||||
|
param :alg, String, required: true, desc: 'DNSSEC key algorithm (3,5,6,7,8,10,13,14)'
|
||||||
|
param :public_key, String, required: true, desc: 'DNSSEC public key'
|
||||||
|
end
|
||||||
|
|
||||||
|
api :GET, '/repp/v1/domains/:domain_name/dnssec'
|
||||||
|
desc "View specific domain's DNSSEC keys"
|
||||||
|
def index
|
||||||
|
dnssec_keys = @domain.dnskeys
|
||||||
|
data = { dns_keys: dnssec_keys.as_json(only: %i[flags alg protocol public_key]) }
|
||||||
|
render_success(data: data)
|
||||||
|
end
|
||||||
|
|
||||||
|
api :POST, '/repp/v1/domains/:domain_name/dnssec'
|
||||||
|
desc 'Create a new DNSSEC key(s) for domain'
|
||||||
|
param :dns_keys, Array, required: true, desc: 'Array of new DNSSEC keys' do
|
||||||
|
param_group :dns_keys_apidoc, DnssecController
|
||||||
|
end
|
||||||
|
def create
|
||||||
|
cta('add')
|
||||||
|
end
|
||||||
|
|
||||||
|
api :DELETE, 'repp/v1/domains/:domain_name/dnssec'
|
||||||
|
param :dns_keys, Array, required: true, desc: 'Array of new DNSSEC keys' do
|
||||||
|
param_group :dns_keys_apidoc, DnssecController
|
||||||
|
end
|
||||||
|
def destroy
|
||||||
|
cta('rem')
|
||||||
|
end
|
||||||
|
|
||||||
|
def cta(action = 'add')
|
||||||
|
params[:dns_keys].each { |n| n[:action] = action }
|
||||||
|
action = Actions::DomainUpdate.new(@domain, dnssec_params, false)
|
||||||
|
|
||||||
|
# rubocop:disable Style/AndOr
|
||||||
|
(handle_errors(@domain) and return) unless action.call
|
||||||
|
# rubocop:enable Style/AndOr
|
||||||
|
|
||||||
|
render_success(data: { domain: { name: @domain.name } })
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def dnssec_params
|
||||||
|
params.permit(:domain_id, dns_keys: [%i[action flags protocol alg public_key]])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
61
app/controllers/repp/v1/domains/nameservers_controller.rb
Normal file
61
app/controllers/repp/v1/domains/nameservers_controller.rb
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
module Repp
|
||||||
|
module V1
|
||||||
|
module Domains
|
||||||
|
class NameserversController < BaseController
|
||||||
|
before_action :set_domain, only: %i[index create destroy]
|
||||||
|
before_action :set_nameserver, only: %i[destroy]
|
||||||
|
|
||||||
|
api :GET, '/repp/v1/domains/:domain_name/nameservers'
|
||||||
|
desc "Get domain's nameservers"
|
||||||
|
def index
|
||||||
|
nameservers = @domain.nameservers
|
||||||
|
data = { nameservers: nameservers.as_json(only: %i[hostname ipv4 ipv6]) }
|
||||||
|
render_success(data: data)
|
||||||
|
end
|
||||||
|
|
||||||
|
api :POST, '/repp/v1/domains/:domain_name/nameservers'
|
||||||
|
desc 'Create new nameserver for domain'
|
||||||
|
param :nameservers, Array, required: true, desc: 'Array of new nameservers' do
|
||||||
|
param :hostname, String, required: true, desc: 'Nameserver hostname'
|
||||||
|
param :ipv4, Array, required: false, desc: 'Array of IPv4 values'
|
||||||
|
param :ipv6, Array, required: false, desc: 'Array of IPv6 values'
|
||||||
|
end
|
||||||
|
def create
|
||||||
|
params[:nameservers].each { |n| n[:action] = 'add' }
|
||||||
|
action = Actions::DomainUpdate.new(@domain, nameserver_params, current_user)
|
||||||
|
|
||||||
|
unless action.call
|
||||||
|
handle_errors(@domain)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
render_success(data: { domain: { name: @domain.name } })
|
||||||
|
end
|
||||||
|
|
||||||
|
api :DELETE, '/repp/v1/domains/:domain/nameservers/:nameserver'
|
||||||
|
desc 'Delete specific nameserver from domain'
|
||||||
|
def destroy
|
||||||
|
nameserver = { nameservers: [{ hostname: params[:id], action: 'rem' }] }
|
||||||
|
action = Actions::DomainUpdate.new(@domain, nameserver, false)
|
||||||
|
|
||||||
|
unless action.call
|
||||||
|
handle_errors(@domain)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
render_success(data: { domain: { name: @domain.name } })
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def set_nameserver
|
||||||
|
@nameserver = @domain.nameservers.find_by!(hostname: params[:id])
|
||||||
|
end
|
||||||
|
|
||||||
|
def nameserver_params
|
||||||
|
params.permit(:domain_id, nameservers: [[:hostname, :action, ipv4: [], ipv6: []]])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -4,6 +4,26 @@ module Repp
|
||||||
class RenewsController < BaseController
|
class RenewsController < BaseController
|
||||||
before_action :validate_renew_period, only: [:bulk_renew]
|
before_action :validate_renew_period, only: [:bulk_renew]
|
||||||
before_action :select_renewable_domains, only: [:bulk_renew]
|
before_action :select_renewable_domains, only: [:bulk_renew]
|
||||||
|
before_action :set_domain, only: [:create]
|
||||||
|
|
||||||
|
api :POST, 'repp/v1/domains/:domain_name/renew'
|
||||||
|
desc 'Renew domain'
|
||||||
|
param :renew, Hash, required: true, desc: 'Renew parameters' do
|
||||||
|
param :period, Integer, required: true, desc: 'Renew period. Month (m) or year (y)'
|
||||||
|
param :period_unit, String, required: true, desc: 'For how many months or years to renew'
|
||||||
|
param :exp_date, String, required: true, desc: 'Current expiry date for domain'
|
||||||
|
end
|
||||||
|
def create
|
||||||
|
authorize!(:renew, @domain)
|
||||||
|
action = Actions::DomainRenew.new(@domain, renew_params[:renew], current_user.registrar)
|
||||||
|
|
||||||
|
unless action.call
|
||||||
|
handle_errors(@domain)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
render_success(data: { domain: { name: @domain.name } })
|
||||||
|
end
|
||||||
|
|
||||||
def bulk_renew
|
def bulk_renew
|
||||||
renew = run_bulk_renew_task(@domains, bulk_renew_params[:renew_period])
|
renew = run_bulk_renew_task(@domains, bulk_renew_params[:renew_period])
|
||||||
|
@ -16,6 +36,10 @@ module Repp
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def renew_params
|
||||||
|
params.permit(:domain_id, renew: %i[period period_unit exp_date])
|
||||||
|
end
|
||||||
|
|
||||||
def validate_renew_period
|
def validate_renew_period
|
||||||
@epp_errors ||= []
|
@epp_errors ||= []
|
||||||
periods = Depp::Domain::PERIODS.map { |p| p[1] }
|
periods = Depp::Domain::PERIODS.map { |p| p[1] }
|
||||||
|
|
65
app/controllers/repp/v1/domains/statuses_controller.rb
Normal file
65
app/controllers/repp/v1/domains/statuses_controller.rb
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
module Repp
|
||||||
|
module V1
|
||||||
|
module Domains
|
||||||
|
class StatusesController < BaseController
|
||||||
|
before_action :set_domain, only: %i[update destroy]
|
||||||
|
before_action :verify_status
|
||||||
|
|
||||||
|
api :DELETE, '/repp/v1/domains/:domain_name/statuses/:status'
|
||||||
|
param :domain_name, String, desc: 'Domain name'
|
||||||
|
param :status, String, desc: 'Status to be removed'
|
||||||
|
desc 'Remove status from specific domain'
|
||||||
|
def destroy
|
||||||
|
return editing_failed unless domain_with_status?(params[:id])
|
||||||
|
|
||||||
|
@domain.statuses = @domain.statuses.delete(params[:id])
|
||||||
|
if @domain.save
|
||||||
|
render_success
|
||||||
|
else
|
||||||
|
handle_errors(@domain)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
api :PUT, '/repp/v1/domains/:domain_name/statuses/:status'
|
||||||
|
param :domain_name, String, desc: 'Domain name'
|
||||||
|
param :status, String, desc: 'Status to be added'
|
||||||
|
desc 'Add status to specific domain'
|
||||||
|
def update
|
||||||
|
return editing_failed if domain_with_status?(params[:id])
|
||||||
|
|
||||||
|
@domain.statuses << params[:id]
|
||||||
|
if @domain.save
|
||||||
|
render_success(data: { domain: @domain.name, status: params[:id] })
|
||||||
|
else
|
||||||
|
handle_errors(@domain)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def domain_with_status?(status)
|
||||||
|
@domain.statuses.include?(status)
|
||||||
|
end
|
||||||
|
|
||||||
|
def verify_status
|
||||||
|
allowed_statuses = [DomainStatus::CLIENT_HOLD].freeze
|
||||||
|
stat = params[:id]
|
||||||
|
|
||||||
|
return if allowed_statuses.include?(stat)
|
||||||
|
|
||||||
|
@domain.add_epp_error('2306', nil, nil,
|
||||||
|
"#{I18n.t(:client_side_status_editing_error)}: status #{stat}")
|
||||||
|
handle_errors(@domain)
|
||||||
|
end
|
||||||
|
|
||||||
|
def editing_failed
|
||||||
|
stat = params[:id]
|
||||||
|
|
||||||
|
@domain.add_epp_error('2306', nil, nil,
|
||||||
|
"#{I18n.t(:client_side_status_editing_error)}: status #{stat}")
|
||||||
|
handle_errors(@domain)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
39
app/controllers/repp/v1/domains/transfers_controller.rb
Normal file
39
app/controllers/repp/v1/domains/transfers_controller.rb
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
module Repp
|
||||||
|
module V1
|
||||||
|
module Domains
|
||||||
|
class TransfersController < BaseController
|
||||||
|
before_action :set_domain, only: [:create]
|
||||||
|
|
||||||
|
api :POST, 'repp/v1/domains/:domain_name/transfer'
|
||||||
|
desc 'Transfer a specific domain'
|
||||||
|
param :transfer, Hash, required: true, desc: 'Renew parameters' do
|
||||||
|
param :transfer_code, String, required: true, desc: 'Renew period. Month (m) or year (y)'
|
||||||
|
end
|
||||||
|
def create
|
||||||
|
action = Actions::DomainTransfer.new(@domain, transfer_params[:transfer][:transfer_code],
|
||||||
|
current_user.registrar)
|
||||||
|
|
||||||
|
unless action.call
|
||||||
|
handle_errors(@domain)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
render_success(data: { domain: { name: @domain.name, type: 'domain_transfer' } })
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def set_domain
|
||||||
|
domain_id = transfer_params[:domain_id]
|
||||||
|
h = {}
|
||||||
|
h[domain_id.match?(/\A[0-9]+\z/) ? :id : :name] = domain_id
|
||||||
|
@domain = Epp::Domain.find_by!(h)
|
||||||
|
end
|
||||||
|
|
||||||
|
def transfer_params
|
||||||
|
params.permit(:domain_id, transfer: [:transfer_code])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,16 +1,96 @@
|
||||||
|
require 'serializers/repp/domain'
|
||||||
module Repp
|
module Repp
|
||||||
module V1
|
module V1
|
||||||
class DomainsController < BaseController
|
class DomainsController < BaseController # rubocop:disable Metrics/ClassLength
|
||||||
before_action :set_authorized_domain, only: [:transfer_info]
|
before_action :set_authorized_domain, only: %i[transfer_info destroy]
|
||||||
|
before_action :validate_registrar_authorization, only: %i[transfer_info destroy]
|
||||||
|
before_action :forward_registrar_id, only: %i[create update destroy]
|
||||||
|
before_action :set_domain, only: %i[update]
|
||||||
|
|
||||||
|
api :GET, '/repp/v1/domains'
|
||||||
|
desc 'Get all existing domains'
|
||||||
def index
|
def index
|
||||||
records = current_user.registrar.domains
|
records = current_user.registrar.domains
|
||||||
domains = records.limit(limit).offset(offset)
|
domains = records.limit(limit).offset(offset)
|
||||||
domains = domains.pluck(:name) unless index_params[:details] == 'true'
|
|
||||||
|
|
||||||
render_success(data: { domains: domains, total_number_of_records: records.count })
|
render_success(data: { domains: serialized_domains(domains),
|
||||||
|
total_number_of_records: records.count })
|
||||||
end
|
end
|
||||||
|
|
||||||
|
api :GET, '/repp/v1/domains/:domain_name'
|
||||||
|
desc 'Get a specific domain'
|
||||||
|
def show
|
||||||
|
@domain = Epp::Domain.find_by!(name: params[:id])
|
||||||
|
sponsor = @domain.registrar == current_user.registrar
|
||||||
|
render_success(data: { domain: Serializers::Repp::Domain.new(@domain,
|
||||||
|
sponsored: sponsor).to_json })
|
||||||
|
end
|
||||||
|
|
||||||
|
api :POST, '/repp/v1/domains'
|
||||||
|
desc 'Create a new domain'
|
||||||
|
param :domain, Hash, required: true, desc: 'Parameters for new domain' do
|
||||||
|
param :name, String, required: true, desc: 'Domain name to be registered'
|
||||||
|
param :registrant, String, required: true, desc: 'Registrant contact code'
|
||||||
|
param :reserved_pw, String, required: false, desc: 'Reserved password for domain'
|
||||||
|
param :transfer_code, String, required: false, desc: 'Desired transfer code for domain'
|
||||||
|
param :period, Integer, required: true, desc: 'Registration period in months or years'
|
||||||
|
param :period_unit, String, required: true, desc: 'Period type (month m) or (year y)'
|
||||||
|
param :nameservers_attributes, Array, required: false, desc: 'Domain nameservers' do
|
||||||
|
param :hostname, String, required: true, desc: 'Nameserver hostname'
|
||||||
|
param :ipv4, Array, desc: 'Array of IPv4 addresses'
|
||||||
|
param :ipv6, Array, desc: 'Array of IPv4 addresses'
|
||||||
|
end
|
||||||
|
param :admin_contacts, Array, required: false, desc: 'Admin domain contacts codes'
|
||||||
|
param :tech_contacts, Array, required: false, desc: 'Tech domain contacts codes'
|
||||||
|
param :dnskeys_attributes, Array, required: false, desc: 'DNSSEC keys for domain' do
|
||||||
|
param_group :dns_keys_apidoc, Repp::V1::Domains::DnssecController
|
||||||
|
end
|
||||||
|
end
|
||||||
|
returns code: 200, desc: 'Successful domain registration response' do
|
||||||
|
property :code, Integer, desc: 'EPP code'
|
||||||
|
property :message, String, desc: 'EPP code explanation'
|
||||||
|
property :data, Hash do
|
||||||
|
property :domain, Hash do
|
||||||
|
property :name, String, 'Domain name'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
def create
|
||||||
|
authorize!(:create, Epp::Domain)
|
||||||
|
@domain = Epp::Domain.new
|
||||||
|
action = Actions::DomainCreate.new(@domain, domain_create_params)
|
||||||
|
|
||||||
|
# rubocop:disable Style/AndOr
|
||||||
|
handle_errors(@domain) and return unless action.call
|
||||||
|
# rubocop:enable Style/AndOr
|
||||||
|
|
||||||
|
render_success(data: { domain: { name: @domain.name } })
|
||||||
|
end
|
||||||
|
|
||||||
|
api :PUT, '/repp/v1/domains/:domain_name'
|
||||||
|
desc 'Update existing domain'
|
||||||
|
param :id, String, desc: 'Domain name in IDN / Puny format'
|
||||||
|
param :domain, Hash, required: true, desc: 'Changes of domain object' do
|
||||||
|
param :registrant, Hash, required: false, desc: 'New registrant object' do
|
||||||
|
param :code, String, required: true, desc: 'New registrant contact code'
|
||||||
|
param :verified, [true, false], required: false,
|
||||||
|
desc: 'Registrant change is already verified'
|
||||||
|
end
|
||||||
|
param :transfer_code, String, required: false, desc: 'New authorization code'
|
||||||
|
end
|
||||||
|
def update
|
||||||
|
action = Actions::DomainUpdate.new(@domain, params[:domain], false)
|
||||||
|
|
||||||
|
unless action.call
|
||||||
|
handle_errors(@domain)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
render_success(data: { domain: { name: @domain.name } })
|
||||||
|
end
|
||||||
|
|
||||||
|
api :GET, '/repp/v1/domains/:domain_name/transfer_info'
|
||||||
|
desc "Retrieve specific domain's transfer info"
|
||||||
def transfer_info
|
def transfer_info
|
||||||
contact_fields = %i[code name ident ident_type ident_country_code phone email street city
|
contact_fields = %i[code name ident ident_type ident_country_code phone email street city
|
||||||
zip country_code statuses]
|
zip country_code statuses]
|
||||||
|
@ -25,6 +105,8 @@ module Repp
|
||||||
render_success(data: data)
|
render_success(data: data)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
api :POST, '/repp/v1/domains/transfer'
|
||||||
|
desc 'Transfer multiple domains'
|
||||||
def transfer
|
def transfer
|
||||||
@errors ||= []
|
@errors ||= []
|
||||||
@successful = []
|
@successful = []
|
||||||
|
@ -36,6 +118,30 @@ module Repp
|
||||||
render_success(data: { success: @successful, failed: @errors })
|
render_success(data: { success: @successful, failed: @errors })
|
||||||
end
|
end
|
||||||
|
|
||||||
|
api :DELETE, '/repp/v1/domains/:domain_name'
|
||||||
|
desc 'Delete specific domain'
|
||||||
|
param :delete, Hash, required: true, desc: 'Object holding verified key' do
|
||||||
|
param :verified, [true, false], required: true,
|
||||||
|
desc: 'Whether to ask registrant verification or not'
|
||||||
|
end
|
||||||
|
def destroy
|
||||||
|
action = Actions::DomainDelete.new(@domain, params, current_user.registrar)
|
||||||
|
|
||||||
|
# rubocop:disable Style/AndOr
|
||||||
|
handle_errors(@domain) and return unless action.call
|
||||||
|
# rubocop:enable Style/AndOr
|
||||||
|
|
||||||
|
render_success(data: { domain: { name: @domain.name } })
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def serialized_domains(domains)
|
||||||
|
return domains.pluck(:name) unless index_params[:details] == 'true'
|
||||||
|
|
||||||
|
domains.map { |d| Serializers::Repp::Domain.new(d).to_json }
|
||||||
|
end
|
||||||
|
|
||||||
def initiate_transfer(transfer)
|
def initiate_transfer(transfer)
|
||||||
domain = Epp::Domain.find_or_initialize_by(name: transfer[:domain_name])
|
domain = Epp::Domain.find_or_initialize_by(name: transfer[:domain_name])
|
||||||
action = Actions::DomainTransfer.new(domain, transfer[:transfer_code],
|
action = Actions::DomainTransfer.new(domain, transfer[:transfer_code],
|
||||||
|
@ -49,8 +155,6 @@ module Repp
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def transfer_params
|
def transfer_params
|
||||||
params.require(:data).require(:domain_transfers).each do |t|
|
params.require(:data).require(:domain_transfers).each do |t|
|
||||||
t.require(:domain_name)
|
t.require(:domain_name)
|
||||||
|
@ -66,10 +170,29 @@ module Repp
|
||||||
params.permit(:id)
|
params.permit(:id)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def forward_registrar_id
|
||||||
|
return unless params[:domain]
|
||||||
|
|
||||||
|
params[:domain][:registrar] = current_user.registrar.id
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_domain
|
||||||
|
registrar = current_user.registrar
|
||||||
|
@domain = Epp::Domain.find_by(registrar: registrar, name: params[:id])
|
||||||
|
@domain ||= Epp::Domain.find_by!(registrar: registrar, name_puny: params[:id])
|
||||||
|
|
||||||
|
return @domain if @domain
|
||||||
|
|
||||||
|
raise ActiveRecord::RecordNotFound
|
||||||
|
end
|
||||||
|
|
||||||
def set_authorized_domain
|
def set_authorized_domain
|
||||||
@epp_errors ||= []
|
@epp_errors ||= []
|
||||||
@domain = domain_from_url_hash
|
@domain = domain_from_url_hash
|
||||||
|
end
|
||||||
|
|
||||||
|
def validate_registrar_authorization
|
||||||
|
return if @domain.registrar == current_user.registrar
|
||||||
return if @domain.transfer_code.eql?(request.headers['Auth-Code'])
|
return if @domain.transfer_code.eql?(request.headers['Auth-Code'])
|
||||||
|
|
||||||
@epp_errors << { code: 2202, msg: I18n.t('errors.messages.epp_authorization_error') }
|
@epp_errors << { code: 2202, msg: I18n.t('errors.messages.epp_authorization_error') }
|
||||||
|
@ -78,9 +201,9 @@ module Repp
|
||||||
|
|
||||||
def domain_from_url_hash
|
def domain_from_url_hash
|
||||||
entry = transfer_info_params[:id]
|
entry = transfer_info_params[:id]
|
||||||
return Domain.find(entry) if entry.match?(/\A[0-9]+\z/)
|
return Epp::Domain.find(entry) if entry.match?(/\A[0-9]+\z/)
|
||||||
|
|
||||||
Domain.find_by!('name = ? OR name_puny = ?', entry, entry)
|
Epp::Domain.find_by!('name = ? OR name_puny = ?', entry, entry)
|
||||||
end
|
end
|
||||||
|
|
||||||
def limit
|
def limit
|
||||||
|
@ -94,6 +217,14 @@ module Repp
|
||||||
def index_params
|
def index_params
|
||||||
params.permit(:limit, :offset, :details)
|
params.permit(:limit, :offset, :details)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def domain_create_params
|
||||||
|
params.require(:domain).permit(:name, :registrant, :period, :period_unit, :registrar,
|
||||||
|
:transfer_code, :reserved_pw,
|
||||||
|
dnskeys_attributes: [%i[flags alg protocol public_key]],
|
||||||
|
nameservers_attributes: [[:hostname, ipv4: [], ipv6: []]],
|
||||||
|
admin_contacts: [], tech_contacts: [])
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,6 +4,19 @@ module Repp
|
||||||
class NameserversController < BaseController
|
class NameserversController < BaseController
|
||||||
before_action :verify_nameserver_existance, only: %i[update]
|
before_action :verify_nameserver_existance, only: %i[update]
|
||||||
|
|
||||||
|
api :PUT, 'repp/v1/registrar/nameservers'
|
||||||
|
desc 'bulk nameserver change'
|
||||||
|
param :data, Hash, required: true, desc: 'Object holding nameserver changes' do
|
||||||
|
param :type, String, required: true, desc: 'Always set as "nameserver"'
|
||||||
|
param :id, String, required: true, desc: 'Hostname of replacable nameserver'
|
||||||
|
param :domains, Array, required: false, desc: 'Array of domain names qualified for ' \
|
||||||
|
'nameserver replacement'
|
||||||
|
param :attributes, Hash, required: true, desc: 'Object holding new nameserver values' do
|
||||||
|
param :hostname, String, required: true, desc: 'New hostname of nameserver'
|
||||||
|
param :ipv4, Array, of: String, required: false, desc: 'Array of fixed IPv4 addresses'
|
||||||
|
param :ipv6, Array, of: String, required: false, desc: 'Array of fixed IPv6 addresses'
|
||||||
|
end
|
||||||
|
end
|
||||||
def update
|
def update
|
||||||
affected, errored = current_user.registrar
|
affected, errored = current_user.registrar
|
||||||
.replace_nameservers(hostname,
|
.replace_nameservers(hostname,
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
module Repp
|
||||||
|
module V1
|
||||||
|
module Registrar
|
||||||
|
class NotificationsController < BaseController
|
||||||
|
before_action :set_notification, only: [:update]
|
||||||
|
|
||||||
|
api :GET, '/repp/v1/registrar/notifications'
|
||||||
|
desc 'Get the latest unread poll message'
|
||||||
|
def index
|
||||||
|
@notification = current_user.unread_notifications.order('created_at DESC').take
|
||||||
|
|
||||||
|
# rubocop:disable Style/AndOr
|
||||||
|
render_success(data: nil) and return unless @notification
|
||||||
|
# rubocop:enable Style/AndOr
|
||||||
|
|
||||||
|
data = @notification.as_json(only: %i[id text attached_obj_id attached_obj_type])
|
||||||
|
|
||||||
|
render_success(data: data)
|
||||||
|
end
|
||||||
|
|
||||||
|
api :GET, '/repp/v1/registrar/notifications/:notification_id'
|
||||||
|
desc 'Get a specific poll message'
|
||||||
|
def show
|
||||||
|
@notification = current_user.registrar.notifications.find(params[:id])
|
||||||
|
data = @notification.as_json(only: %i[id text attached_obj_id attached_obj_type read])
|
||||||
|
|
||||||
|
render_success(data: data)
|
||||||
|
end
|
||||||
|
|
||||||
|
api :PUT, '/repp/v1/registrar/notifications'
|
||||||
|
desc 'Mark poll message as read'
|
||||||
|
param :notification, Hash, required: true do
|
||||||
|
param :read, [true], required: true, desc: 'Set as true to mark as read'
|
||||||
|
end
|
||||||
|
def update
|
||||||
|
# rubocop:disable Style/AndOr
|
||||||
|
handle_errors(@notification) and return unless @notification.mark_as_read
|
||||||
|
# rubocop:enable Style/AndOr
|
||||||
|
|
||||||
|
render_success(data: { notification_id: @notification.id, read: true })
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def set_notification
|
||||||
|
@notification = current_user.unread_notifications.find(params[:id])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
24
app/interactions/actions/base_action.rb
Normal file
24
app/interactions/actions/base_action.rb
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
module Actions
|
||||||
|
class BaseAction
|
||||||
|
def self.maybe_attach_legal_doc(entity, legal_doc)
|
||||||
|
return unless legal_doc
|
||||||
|
return if legal_doc[:body].starts_with?(ENV['legal_documents_dir'])
|
||||||
|
|
||||||
|
entity.legal_documents.create(
|
||||||
|
document_type: legal_doc[:type],
|
||||||
|
body: legal_doc[:body]
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.attach_legal_doc_to_new(entity, legal_doc, domain: true)
|
||||||
|
return unless legal_doc
|
||||||
|
|
||||||
|
doc = LegalDocument.create(
|
||||||
|
documentable_type: domain ? Domain : Contact,
|
||||||
|
document_type: legal_doc[:type],
|
||||||
|
body: legal_doc[:body]
|
||||||
|
)
|
||||||
|
entity.legal_documents = [doc]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -59,15 +59,7 @@ module Actions
|
||||||
end
|
end
|
||||||
|
|
||||||
def maybe_attach_legal_doc
|
def maybe_attach_legal_doc
|
||||||
return unless legal_document
|
::Actions::BaseAction.attach_legal_doc_to_new(contact, legal_document, domain: false)
|
||||||
|
|
||||||
doc = LegalDocument.create(
|
|
||||||
documentable_type: Contact,
|
|
||||||
document_type: legal_document[:type], body: legal_document[:body]
|
|
||||||
)
|
|
||||||
|
|
||||||
contact.legal_documents = [doc]
|
|
||||||
contact.legal_document_id = doc.id
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def commit
|
def commit
|
|
@ -28,15 +28,7 @@ module Actions
|
||||||
end
|
end
|
||||||
|
|
||||||
def maybe_attach_legal_doc
|
def maybe_attach_legal_doc
|
||||||
return unless legal_document
|
::Actions::BaseAction.maybe_attach_legal_doc(contact, legal_document)
|
||||||
|
|
||||||
document = contact.legal_documents.create(
|
|
||||||
document_type: legal_document[:type],
|
|
||||||
body: legal_document[:body]
|
|
||||||
)
|
|
||||||
|
|
||||||
contact.legal_document_id = document.id
|
|
||||||
contact.save
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def commit
|
def commit
|
|
@ -42,14 +42,7 @@ module Actions
|
||||||
end
|
end
|
||||||
|
|
||||||
def maybe_attach_legal_doc
|
def maybe_attach_legal_doc
|
||||||
return unless legal_document
|
::Actions::BaseAction.maybe_attach_legal_doc(contact, legal_document)
|
||||||
|
|
||||||
document = contact.legal_documents.create(
|
|
||||||
document_type: legal_document[:type],
|
|
||||||
body: legal_document[:body]
|
|
||||||
)
|
|
||||||
|
|
||||||
contact.legal_document_id = document.id
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def maybe_update_ident
|
def maybe_update_ident
|
214
app/interactions/actions/domain_create.rb
Normal file
214
app/interactions/actions/domain_create.rb
Normal file
|
@ -0,0 +1,214 @@
|
||||||
|
module Actions
|
||||||
|
class DomainCreate # rubocop:disable Metrics/ClassLength
|
||||||
|
attr_reader :domain, :params
|
||||||
|
|
||||||
|
def initialize(domain, params)
|
||||||
|
@domain = domain
|
||||||
|
@params = params
|
||||||
|
end
|
||||||
|
|
||||||
|
def call
|
||||||
|
assign_domain_attributes
|
||||||
|
validate_domain_integrity
|
||||||
|
return false if domain.errors[:epp_errors].any?
|
||||||
|
|
||||||
|
assign_registrant
|
||||||
|
assign_nameservers
|
||||||
|
assign_domain_contacts
|
||||||
|
domain.attach_default_contacts
|
||||||
|
assign_expiry_time
|
||||||
|
maybe_attach_legal_doc
|
||||||
|
|
||||||
|
commit
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_contact_duplications
|
||||||
|
if check_for_same_contacts(@admin_contacts, 'admin') &&
|
||||||
|
check_for_same_contacts(@tech_contacts, 'tech')
|
||||||
|
true
|
||||||
|
else
|
||||||
|
false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_for_same_contacts(contacts, contact_type)
|
||||||
|
return true unless contacts.uniq.count != contacts.count
|
||||||
|
|
||||||
|
domain.add_epp_error('2306', contact_type, nil, %i[domain_contacts invalid])
|
||||||
|
false
|
||||||
|
end
|
||||||
|
|
||||||
|
# Check if domain is eligible for new registration
|
||||||
|
def validate_domain_integrity
|
||||||
|
return unless Domain.release_to_auction
|
||||||
|
|
||||||
|
dn = DNS::DomainName.new(domain.name)
|
||||||
|
if dn.at_auction?
|
||||||
|
domain.add_epp_error('2306', nil, nil, 'Parameter value policy error: domain is at auction')
|
||||||
|
elsif dn.awaiting_payment?
|
||||||
|
domain.add_epp_error('2003', nil, nil, 'Required parameter missing; reserved>pw element' \
|
||||||
|
' required for reserved domains')
|
||||||
|
elsif dn.pending_registration?
|
||||||
|
validate_reserved_password(dn)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def validate_reserved_password(domain_name)
|
||||||
|
if params[:reserved_pw].blank?
|
||||||
|
domain.add_epp_error('2003', nil, nil, 'Required parameter missing; reserved>pw ' \
|
||||||
|
'element is required')
|
||||||
|
else
|
||||||
|
unless domain_name.available_with_code?(params[:reserved_pw])
|
||||||
|
domain.add_epp_error('2202', nil, nil, 'Invalid authorization information; invalid ' \
|
||||||
|
'reserved>pw value')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def assign_registrant
|
||||||
|
unless params[:registrant]
|
||||||
|
domain.add_epp_error('2306', nil, nil, %i[registrant cannot_be_missing])
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
regt = Registrant.find_by(code: params[:registrant])
|
||||||
|
if regt
|
||||||
|
domain.registrant = regt
|
||||||
|
else
|
||||||
|
domain.add_epp_error('2303', 'registrant', params[:registrant], %i[registrant not_found])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def assign_domain_attributes
|
||||||
|
domain.name = params[:name].strip.downcase
|
||||||
|
domain.registrar = current_registrar
|
||||||
|
assign_domain_period
|
||||||
|
assign_domain_auth_codes
|
||||||
|
assign_dnskeys
|
||||||
|
end
|
||||||
|
|
||||||
|
def assign_dnskeys
|
||||||
|
return unless params[:dnskeys_attributes]&.any?
|
||||||
|
|
||||||
|
params[:dnskeys_attributes].each { |dk| verify_public_key_integrity(dk[:public_key]) }
|
||||||
|
domain.dnskeys_attributes = params[:dnskeys_attributes]
|
||||||
|
end
|
||||||
|
|
||||||
|
def verify_public_key_integrity(pub)
|
||||||
|
return if Dnskey.pub_key_base64?(pub)
|
||||||
|
|
||||||
|
domain.add_epp_error(2005, nil, nil, %i[dnskeys invalid])
|
||||||
|
end
|
||||||
|
|
||||||
|
def assign_domain_auth_codes
|
||||||
|
domain.transfer_code = params[:transfer_code] if params[:transfer_code].present?
|
||||||
|
domain.reserved_pw = params[:reserved_pw] if params[:reserved_pw].present?
|
||||||
|
end
|
||||||
|
|
||||||
|
def assign_domain_period
|
||||||
|
domain.period = params[:period]
|
||||||
|
domain.period_unit = params[:period_unit]
|
||||||
|
end
|
||||||
|
|
||||||
|
def assign_nameservers
|
||||||
|
return unless params[:nameservers_attributes]
|
||||||
|
|
||||||
|
domain.nameservers_attributes = params[:nameservers_attributes]
|
||||||
|
end
|
||||||
|
|
||||||
|
def assign_contact(contact_code, admin: true)
|
||||||
|
contact = Contact.find_by(code: contact_code)
|
||||||
|
arr = admin ? @admin_contacts : @tech_contacts
|
||||||
|
if contact
|
||||||
|
arr << { contact_id: contact.id, contact_code_cache: contact.code }
|
||||||
|
else
|
||||||
|
domain.add_epp_error('2303', 'contact', contact_code, %i[domain_contacts not_found])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def assign_domain_contacts
|
||||||
|
@admin_contacts = []
|
||||||
|
@tech_contacts = []
|
||||||
|
params[:admin_contacts]&.each { |c| assign_contact(c) }
|
||||||
|
params[:tech_contacts]&.each { |c| assign_contact(c, admin: false) }
|
||||||
|
|
||||||
|
domain.admin_domain_contacts_attributes = @admin_contacts
|
||||||
|
domain.tech_domain_contacts_attributes = @tech_contacts
|
||||||
|
check_contact_duplications
|
||||||
|
end
|
||||||
|
|
||||||
|
def assign_expiry_time
|
||||||
|
return unless domain.period
|
||||||
|
|
||||||
|
period = Integer(domain.period)
|
||||||
|
domain.expire_time = calculate_expiry(period)
|
||||||
|
end
|
||||||
|
|
||||||
|
def calculate_expiry(period)
|
||||||
|
plural_period_unit_name = (domain.period_unit == 'm' ? 'months' : 'years').to_sym
|
||||||
|
(Time.zone.now.advance(plural_period_unit_name => period) + 1.day).beginning_of_day
|
||||||
|
end
|
||||||
|
|
||||||
|
def action_billable?
|
||||||
|
unless domain_pricelist&.price
|
||||||
|
domain.add_epp_error(2104, nil, nil, I18n.t(:active_price_missing_for_this_operation))
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
if domain.registrar.balance < domain_pricelist.price.amount
|
||||||
|
domain.add_epp_error(2104, nil, nil, I18n.t('billing_failure_credit_balance_low'))
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
true
|
||||||
|
end
|
||||||
|
|
||||||
|
def debit_registrar
|
||||||
|
return unless action_billable?
|
||||||
|
|
||||||
|
domain.registrar.debit!(sum: domain_pricelist.price.amount, price: domain_pricelist,
|
||||||
|
description: "#{I18n.t('create')} #{domain.name}",
|
||||||
|
activity_type: AccountActivity::CREATE)
|
||||||
|
end
|
||||||
|
|
||||||
|
def domain_pricelist
|
||||||
|
@domain_pricelist ||= domain.pricelist('create', domain.period.try(:to_i), domain.period_unit)
|
||||||
|
|
||||||
|
@domain_pricelist
|
||||||
|
end
|
||||||
|
|
||||||
|
def maybe_attach_legal_doc
|
||||||
|
::Actions::BaseAction.attach_legal_doc_to_new(domain, params[:legal_document], domain: true)
|
||||||
|
end
|
||||||
|
|
||||||
|
def process_auction_and_disputes
|
||||||
|
dn = DNS::DomainName.new(domain.name)
|
||||||
|
Dispute.close_by_domain(domain.name)
|
||||||
|
return unless Domain.release_to_auction && dn.pending_registration?
|
||||||
|
|
||||||
|
Auction.find_by(domain: domain.name,
|
||||||
|
status: Auction.statuses[:payment_received])&.domain_registered!
|
||||||
|
end
|
||||||
|
|
||||||
|
def commit
|
||||||
|
return false if domain.errors[:epp_errors].any? || validation_process_errored?
|
||||||
|
|
||||||
|
debit_registrar
|
||||||
|
return false if domain.errors.any?
|
||||||
|
|
||||||
|
process_auction_and_disputes
|
||||||
|
domain.save
|
||||||
|
end
|
||||||
|
|
||||||
|
def validation_process_errored?
|
||||||
|
return if domain.valid?
|
||||||
|
|
||||||
|
domain.errors.delete(:name_dirty) if domain.errors[:puny_label].any?
|
||||||
|
domain.errors.any?
|
||||||
|
end
|
||||||
|
|
||||||
|
def current_registrar
|
||||||
|
Registrar.find(params[:registrar])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
57
app/interactions/actions/domain_delete.rb
Normal file
57
app/interactions/actions/domain_delete.rb
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
module Actions
|
||||||
|
class DomainDelete
|
||||||
|
attr_reader :domain
|
||||||
|
attr_reader :params
|
||||||
|
attr_reader :user
|
||||||
|
|
||||||
|
def initialize(domain, params, user)
|
||||||
|
@domain = domain
|
||||||
|
@params = params
|
||||||
|
@user = user
|
||||||
|
end
|
||||||
|
|
||||||
|
def call
|
||||||
|
return false unless @domain.can_be_deleted?
|
||||||
|
|
||||||
|
verify_not_discarded
|
||||||
|
maybe_attach_legal_doc
|
||||||
|
|
||||||
|
return false if domain.errors.any?
|
||||||
|
return false if domain.errors[:epp_errors].any?
|
||||||
|
|
||||||
|
destroy
|
||||||
|
end
|
||||||
|
|
||||||
|
def maybe_attach_legal_doc
|
||||||
|
::Actions::BaseAction.attach_legal_doc_to_new(domain, params[:legal_document], domain: true)
|
||||||
|
end
|
||||||
|
|
||||||
|
def verify_not_discarded
|
||||||
|
return unless domain.discarded?
|
||||||
|
|
||||||
|
domain.add_epp_error('2304', nil, nil, 'Object status prohibits operation')
|
||||||
|
end
|
||||||
|
|
||||||
|
def verify?
|
||||||
|
return false unless Setting.request_confirmation_on_domain_deletion_enabled
|
||||||
|
return false if params[:delete][:verified] == true
|
||||||
|
|
||||||
|
true
|
||||||
|
end
|
||||||
|
|
||||||
|
def ask_delete_verification
|
||||||
|
domain.registrant_verification_asked!(params, user.id)
|
||||||
|
domain.pending_delete!
|
||||||
|
domain.manage_automatic_statuses
|
||||||
|
end
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
if verify?
|
||||||
|
ask_delete_verification
|
||||||
|
else
|
||||||
|
domain.set_pending_delete!
|
||||||
|
end
|
||||||
|
true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
34
app/interactions/actions/domain_renew.rb
Normal file
34
app/interactions/actions/domain_renew.rb
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
module Actions
|
||||||
|
class DomainRenew
|
||||||
|
attr_reader :domain
|
||||||
|
attr_reader :params
|
||||||
|
attr_reader :user
|
||||||
|
|
||||||
|
def initialize(domain, params, user)
|
||||||
|
@domain = domain
|
||||||
|
@params = params
|
||||||
|
@user = user
|
||||||
|
end
|
||||||
|
|
||||||
|
def call
|
||||||
|
domain.is_renewal = true
|
||||||
|
if !domain.renewable? || domain.invalid?
|
||||||
|
domain.add_renew_epp_errors
|
||||||
|
false
|
||||||
|
else
|
||||||
|
domain.validate_exp_dates(params[:exp_date])
|
||||||
|
renew
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def renew
|
||||||
|
return false if domain.errors[:epp_errors].any?
|
||||||
|
|
||||||
|
task = Domains::BulkRenew::SingleDomainRenew.run(domain: domain,
|
||||||
|
period: params[:period],
|
||||||
|
unit: params[:period_unit],
|
||||||
|
registrar: user)
|
||||||
|
task.valid?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
256
app/interactions/actions/domain_update.rb
Normal file
256
app/interactions/actions/domain_update.rb
Normal file
|
@ -0,0 +1,256 @@
|
||||||
|
module Actions
|
||||||
|
class DomainUpdate # rubocop:disable Metrics/ClassLength
|
||||||
|
attr_reader :domain, :params, :bypass_verify
|
||||||
|
|
||||||
|
def initialize(domain, params, bypass_verify)
|
||||||
|
@domain = domain
|
||||||
|
@params = params
|
||||||
|
@bypass_verify = bypass_verify
|
||||||
|
@changes_registrant = false
|
||||||
|
end
|
||||||
|
|
||||||
|
def call
|
||||||
|
validate_domain_integrity
|
||||||
|
assign_new_registrant if params[:registrant]
|
||||||
|
assign_relational_modifications
|
||||||
|
assign_requested_statuses
|
||||||
|
::Actions::BaseAction.maybe_attach_legal_doc(domain, params[:legal_document])
|
||||||
|
|
||||||
|
commit
|
||||||
|
end
|
||||||
|
|
||||||
|
def assign_relational_modifications
|
||||||
|
assign_nameserver_modifications if params[:nameservers]
|
||||||
|
assign_dnssec_modifications if params[:dns_keys]
|
||||||
|
return unless params[:contacts]
|
||||||
|
|
||||||
|
assign_admin_contact_changes
|
||||||
|
assign_tech_contact_changes
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_for_same_contacts(contacts, contact_type)
|
||||||
|
return unless contacts.uniq.count != contacts.count
|
||||||
|
|
||||||
|
domain.add_epp_error('2306', contact_type, nil, %i[domain_contacts invalid])
|
||||||
|
end
|
||||||
|
|
||||||
|
def validate_domain_integrity
|
||||||
|
domain.auth_info = params[:transfer_code] if params[:transfer_code]
|
||||||
|
|
||||||
|
return unless domain.discarded?
|
||||||
|
|
||||||
|
domain.add_epp_error('2304', nil, nil, 'Object status prohibits operation')
|
||||||
|
end
|
||||||
|
|
||||||
|
def assign_new_registrant
|
||||||
|
unless params[:registrant][:code]
|
||||||
|
domain.add_epp_error('2306', nil, nil, %i[registrant cannot_be_missing])
|
||||||
|
end
|
||||||
|
|
||||||
|
regt = Registrant.find_by(code: params[:registrant][:code])
|
||||||
|
unless regt
|
||||||
|
domain.add_epp_error('2303', 'registrant', params[:registrant], %i[registrant not_found])
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
replace_domain_registrant(regt)
|
||||||
|
end
|
||||||
|
|
||||||
|
def replace_domain_registrant(new_registrant)
|
||||||
|
return if domain.registrant == new_registrant
|
||||||
|
|
||||||
|
@changes_registrant = true if domain.registrant.ident != new_registrant.ident
|
||||||
|
if @changes_registrant && domain.registrant_change_prohibited?
|
||||||
|
domain.add_epp_error(2304, 'status', DomainStatus::SERVER_REGISTRANT_CHANGE_PROHIBITED,
|
||||||
|
I18n.t(:object_status_prohibits_operation))
|
||||||
|
else
|
||||||
|
domain.registrant = new_registrant
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def assign_nameserver_modifications
|
||||||
|
@nameservers = []
|
||||||
|
params[:nameservers].each do |ns_attr|
|
||||||
|
case ns_attr[:action]
|
||||||
|
when 'rem'
|
||||||
|
validate_ns_integrity(ns_attr)
|
||||||
|
when 'add'
|
||||||
|
@nameservers << ns_attr.except(:action)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
domain.nameservers_attributes = @nameservers if @nameservers.present?
|
||||||
|
end
|
||||||
|
|
||||||
|
def validate_ns_integrity(ns_attr)
|
||||||
|
ns = domain.nameservers.from_hash_params(ns_attr.except(:action)).first
|
||||||
|
if ns
|
||||||
|
@nameservers << { id: ns.id, _destroy: 1 }
|
||||||
|
else
|
||||||
|
domain.add_epp_error('2303', 'hostAttr', ns_attr[:hostname], %i[nameservers not_found])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def assign_dnssec_modifications
|
||||||
|
@dnskeys = []
|
||||||
|
params[:dns_keys].each do |key|
|
||||||
|
case key[:action]
|
||||||
|
when 'add'
|
||||||
|
validate_dnskey_integrity(key)
|
||||||
|
when 'rem'
|
||||||
|
assign_removable_dnskey(key)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
domain.dnskeys_attributes = @dnskeys.uniq
|
||||||
|
end
|
||||||
|
|
||||||
|
def validate_dnskey_integrity(key)
|
||||||
|
if key[:public_key] && !Setting.key_data_allowed
|
||||||
|
domain.add_epp_error('2306', nil, nil, %i[dnskeys key_data_not_allowed])
|
||||||
|
elsif Dnskey.pub_key_base64?(key[:public_key])
|
||||||
|
@dnskeys << key.except(:action)
|
||||||
|
else
|
||||||
|
domain.add_epp_error(2005, nil, nil, %i[dnskeys invalid])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def assign_removable_dnskey(key)
|
||||||
|
dnkey = domain.dnskeys.find_by(key.except(:action))
|
||||||
|
domain.add_epp_error(2303, nil, nil, %i[dnskeys not_found]) unless dnkey
|
||||||
|
|
||||||
|
@dnskeys << { id: dnkey.id, _destroy: 1 } if dnkey
|
||||||
|
end
|
||||||
|
|
||||||
|
def assign_admin_contact_changes
|
||||||
|
props = gather_domain_contacts(params[:contacts].select { |c| c[:type] == 'admin' })
|
||||||
|
|
||||||
|
if props.any? && domain.admin_change_prohibited?
|
||||||
|
domain.add_epp_error('2304', 'admin', DomainStatus::SERVER_ADMIN_CHANGE_PROHIBITED,
|
||||||
|
I18n.t(:object_status_prohibits_operation))
|
||||||
|
elsif props.present?
|
||||||
|
domain.admin_domain_contacts_attributes = props
|
||||||
|
check_for_same_contacts(props, 'admin')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def assign_tech_contact_changes
|
||||||
|
props = gather_domain_contacts(params[:contacts].select { |c| c[:type] == 'tech' },
|
||||||
|
admin: false)
|
||||||
|
|
||||||
|
if props.any? && domain.tech_change_prohibited?
|
||||||
|
domain.add_epp_error('2304', 'tech', DomainStatus::SERVER_TECH_CHANGE_PROHIBITED,
|
||||||
|
I18n.t(:object_status_prohibits_operation))
|
||||||
|
elsif props.present?
|
||||||
|
domain.tech_domain_contacts_attributes = props
|
||||||
|
check_for_same_contacts(props, 'tech')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def gather_domain_contacts(contacts, admin: true)
|
||||||
|
props = []
|
||||||
|
|
||||||
|
contacts.each do |c|
|
||||||
|
contact = contact_for_action(action: c[:action], method: admin ? 'admin' : 'tech',
|
||||||
|
code: c[:code])
|
||||||
|
entry = assign_contact(contact, add: c[:action] == 'add', admin: admin, code: c[:code])
|
||||||
|
props << entry if entry.is_a?(Hash)
|
||||||
|
end
|
||||||
|
|
||||||
|
props
|
||||||
|
end
|
||||||
|
|
||||||
|
def contact_for_action(action:, method:, code:)
|
||||||
|
contact = Epp::Contact.find_by(code: code)
|
||||||
|
return contact if action == 'add' || !contact
|
||||||
|
return domain.admin_domain_contacts.find_by(contact_id: contact.id) if method == 'admin'
|
||||||
|
|
||||||
|
domain.tech_domain_contacts.find_by(contact_id: contact.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
def assign_contact(obj, add: false, admin: true, code:)
|
||||||
|
if obj.blank?
|
||||||
|
domain.add_epp_error('2303', 'contact', code, %i[domain_contacts not_found])
|
||||||
|
elsif obj.try(:org?) && admin && add
|
||||||
|
domain.add_epp_error('2306', 'contact', code,
|
||||||
|
%i[domain_contacts admin_contact_can_be_only_private_person])
|
||||||
|
else
|
||||||
|
add ? { contact_id: obj.id, contact_code_cache: obj.code } : { id: obj.id, _destroy: 1 }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def assign_requested_statuses
|
||||||
|
return unless params[:statuses]
|
||||||
|
|
||||||
|
@rem = []
|
||||||
|
@add = []
|
||||||
|
@failed = false
|
||||||
|
|
||||||
|
params[:statuses].each { |s| verify_status_eligiblity(s) }
|
||||||
|
domain.statuses = (domain.statuses - @rem + @add) unless @failed
|
||||||
|
end
|
||||||
|
|
||||||
|
def verify_status_eligiblity(status_entry)
|
||||||
|
status, action = status_entry.select_keys(:status, :action)
|
||||||
|
return unless permitted_status?(status, action)
|
||||||
|
|
||||||
|
action == 'add' ? @add << status : @rem << status
|
||||||
|
end
|
||||||
|
|
||||||
|
def permitted_status?(status, action)
|
||||||
|
if DomainStatus::CLIENT_STATUSES.include?(status) &&
|
||||||
|
(domain.statuses.include?(status) || action == 'add')
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
domain.add_epp_error('2303', 'status', status, %i[statuses not_found])
|
||||||
|
@failed = true
|
||||||
|
false
|
||||||
|
end
|
||||||
|
|
||||||
|
def verify_registrant_change?
|
||||||
|
return if !@changes_registrant || params[:registrant][:verified] == true
|
||||||
|
return true unless domain.disputed?
|
||||||
|
return validate_dispute_case if params[:reserved_pw]
|
||||||
|
|
||||||
|
domain.add_epp_error('2304', nil, nil, 'Required parameter missing; reservedpw element ' \
|
||||||
|
'required for dispute domains')
|
||||||
|
|
||||||
|
true
|
||||||
|
end
|
||||||
|
|
||||||
|
def validate_dispute_case
|
||||||
|
dispute = Dispute.active.find_by(domain_name: domain.name, password: params[:reserved_pw])
|
||||||
|
if dispute
|
||||||
|
Dispute.close_by_domain(domain.name)
|
||||||
|
false
|
||||||
|
else
|
||||||
|
domain.add_epp_error('2202', nil, nil,
|
||||||
|
'Invalid authorization information; invalid reserved>pw value')
|
||||||
|
true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def ask_registrant_verification
|
||||||
|
if verify_registrant_change? && !bypass_verify &&
|
||||||
|
Setting.request_confirmation_on_registrant_change_enabled
|
||||||
|
domain.registrant_verification_asked!(params, params[:registrar])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def commit
|
||||||
|
return false if any_errors?
|
||||||
|
|
||||||
|
ask_registrant_verification
|
||||||
|
return false if any_errors?
|
||||||
|
|
||||||
|
domain.save
|
||||||
|
end
|
||||||
|
|
||||||
|
def any_errors?
|
||||||
|
return true if domain.errors[:epp_errors].any? || domain.invalid?
|
||||||
|
|
||||||
|
false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -9,6 +9,7 @@ module Domains
|
||||||
|
|
||||||
def execute
|
def execute
|
||||||
in_transaction_with_retries do
|
in_transaction_with_retries do
|
||||||
|
check_balance
|
||||||
success = domain.renew(domain.valid_to, period, unit)
|
success = domain.renew(domain.valid_to, period, unit)
|
||||||
if success
|
if success
|
||||||
check_balance
|
check_balance
|
||||||
|
@ -55,6 +56,7 @@ module Domains
|
||||||
private
|
private
|
||||||
|
|
||||||
def add_error
|
def add_error
|
||||||
|
domain.add_epp_error(2104, nil, nil, I18n.t(:domain_renew_error_for_domain))
|
||||||
errors.add(:domain, I18n.t('domain_renew_error_for_domain', domain: domain.name))
|
errors.add(:domain, I18n.t('domain_renew_error_for_domain', domain: domain.name))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -9,15 +9,30 @@ module Domains
|
||||||
string :unit
|
string :unit
|
||||||
|
|
||||||
def execute
|
def execute
|
||||||
return domain_pricelist.price.amount if domain_pricelist.try(:price)
|
if domain_pricelist.try(:price)
|
||||||
|
price = domain_pricelist.price.amount
|
||||||
|
return price if balance_ok?(price)
|
||||||
|
else
|
||||||
|
domain.add_epp_error(2104, nil, nil, I18n.t(:active_price_missing_for_this_operation))
|
||||||
errors.add(:domain, I18n.t(:active_price_missing_for_operation_with_domain,
|
errors.add(:domain, I18n.t(:active_price_missing_for_operation_with_domain,
|
||||||
domain: domain.name))
|
domain: domain.name))
|
||||||
|
end
|
||||||
|
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def balance_ok?(price)
|
||||||
|
if domain.registrar.cash_account.balance >= price
|
||||||
|
true
|
||||||
|
else
|
||||||
|
domain.add_epp_error(2104, nil, nil, I18n.t(:not_enough_funds))
|
||||||
|
errors.add(:domain, I18n.t(:billing_failure_credit_balance_low, domain: domain.name))
|
||||||
|
false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def domain_pricelist
|
def domain_pricelist
|
||||||
domain.pricelist(operation, period.try(:to_i), unit)
|
domain.pricelist(operation, period.try(:to_i), unit)
|
||||||
end
|
end
|
||||||
|
|
|
@ -20,15 +20,20 @@ module Domains
|
||||||
WhoisRecord.find_by(domain_id: domain.id).save # need to reload model
|
WhoisRecord.find_by(domain_id: domain.id).save # need to reload model
|
||||||
end
|
end
|
||||||
|
|
||||||
# rubocop:disable Metrics/AbcSize
|
|
||||||
def update_domain
|
def update_domain
|
||||||
|
frame_json = domain.pending_json['frame']
|
||||||
|
frame = frame_json ? frame_json.with_indifferent_access : {}
|
||||||
|
assign_domain_update_meta
|
||||||
|
|
||||||
|
Actions::DomainUpdate.new(domain, frame, true).call
|
||||||
|
end
|
||||||
|
|
||||||
|
def assign_domain_update_meta
|
||||||
user = ApiUser.find(domain.pending_json['current_user_id'])
|
user = ApiUser.find(domain.pending_json['current_user_id'])
|
||||||
frame = Nokogiri::XML(domain.pending_json['frame'])
|
|
||||||
domain.upid = user.registrar.id if user.registrar
|
domain.upid = user.registrar.id if user.registrar
|
||||||
domain.up_date = Time.zone.now
|
domain.up_date = Time.zone.now
|
||||||
domain.update(frame, user, false)
|
end
|
||||||
end
|
|
||||||
# rubocop:enable Metrics/AbcSize
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -60,7 +60,10 @@ module Billing
|
||||||
def self.price_for(zone, operation_category, duration)
|
def self.price_for(zone, operation_category, duration)
|
||||||
lists = valid.where(zone: zone, operation_category: operation_category, duration: duration)
|
lists = valid.where(zone: zone, operation_category: operation_category, duration: duration)
|
||||||
return lists.first if lists.count == 1
|
return lists.first if lists.count == 1
|
||||||
|
|
||||||
lists.order(valid_from: :desc).first
|
lists.order(valid_from: :desc).first
|
||||||
|
rescue ActiveRecord::StatementInvalid
|
||||||
|
nil
|
||||||
end
|
end
|
||||||
|
|
||||||
def name
|
def name
|
||||||
|
|
|
@ -86,6 +86,8 @@ module EppErrors
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
nil
|
nil
|
||||||
|
rescue NameError
|
||||||
|
nil
|
||||||
end
|
end
|
||||||
|
|
||||||
def construct_msg_args_and_value(epp_error_args)
|
def construct_msg_args_and_value(epp_error_args)
|
||||||
|
|
|
@ -8,6 +8,7 @@ class Dnskey < ApplicationRecord
|
||||||
validate :validate_algorithm
|
validate :validate_algorithm
|
||||||
validate :validate_protocol
|
validate :validate_protocol
|
||||||
validate :validate_flags
|
validate :validate_flags
|
||||||
|
validate :validate_public_key
|
||||||
|
|
||||||
before_save lambda {
|
before_save lambda {
|
||||||
generate_digest if will_save_change_to_public_key? && !will_save_change_to_ds_digest?
|
generate_digest if will_save_change_to_public_key? && !will_save_change_to_ds_digest?
|
||||||
|
@ -115,6 +116,12 @@ class Dnskey < ApplicationRecord
|
||||||
self.ds_key_tag = ((c & 0xFFFF) + (c >> 16)) & 0xFFFF
|
self.ds_key_tag = ((c & 0xFFFF) + (c >> 16)) & 0xFFFF
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def validate_public_key
|
||||||
|
return if Dnskey.pub_key_base64?(public_key)
|
||||||
|
|
||||||
|
errors.add(:public_key, :invalid)
|
||||||
|
end
|
||||||
|
|
||||||
class << self
|
class << self
|
||||||
def int_to_hex(s)
|
def int_to_hex(s)
|
||||||
s = s.to_s(16)
|
s = s.to_s(16)
|
||||||
|
@ -128,5 +135,13 @@ class Dnskey < ApplicationRecord
|
||||||
def bin_to_hex(s)
|
def bin_to_hex(s)
|
||||||
s.each_byte.map { |b| format('%02X', b) }.join
|
s.each_byte.map { |b| format('%02X', b) }.join
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def pub_key_base64?(pub)
|
||||||
|
return unless pub&.is_a?(String)
|
||||||
|
|
||||||
|
Base64.strict_encode64(Base64.strict_decode64(pub)) == pub
|
||||||
|
rescue ArgumentError
|
||||||
|
false
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -513,7 +513,7 @@ class Domain < ApplicationRecord
|
||||||
|
|
||||||
# depricated not used, not valid
|
# depricated not used, not valid
|
||||||
def update_prohibited?
|
def update_prohibited?
|
||||||
pending_update_prohibited? && pending_delete_prohibited?
|
(statuses & DomainStatus::UPDATE_PROHIBIT_STATES).present?
|
||||||
end
|
end
|
||||||
|
|
||||||
# public api
|
# public api
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
require 'deserializers/xml/legal_document'
|
require 'deserializers/xml/legal_document'
|
||||||
|
require 'deserializers/xml/nameserver'
|
||||||
|
require 'deserializers/xml/domain_create'
|
||||||
|
require 'deserializers/xml/domain_update'
|
||||||
class Epp::Domain < Domain
|
class Epp::Domain < Domain
|
||||||
include EppErrors
|
include EppErrors
|
||||||
|
|
||||||
|
@ -27,30 +29,15 @@ class Epp::Domain < Domain
|
||||||
active_techs = tech_domain_contacts.select { |x| !x.marked_for_destruction? }
|
active_techs = tech_domain_contacts.select { |x| !x.marked_for_destruction? }
|
||||||
|
|
||||||
# validate registrant here as well
|
# validate registrant here as well
|
||||||
([Contact.find_by(code: registrant.code)] + active_admins + active_techs).each do |x|
|
([Contact.find(registrant.id)] + active_admins + active_techs).each do |x|
|
||||||
unless x.valid?
|
unless x.valid?
|
||||||
add_epp_error('2304', nil, nil, I18n.t(:contact_is_not_valid, value: x.code))
|
add_epp_error('2304', nil, nil, I18n.t(:contact_is_not_valid, value: x.try(:code)))
|
||||||
ok = false
|
ok = false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
ok
|
ok
|
||||||
end
|
end
|
||||||
|
|
||||||
class << self
|
|
||||||
def new_from_epp(frame, current_user)
|
|
||||||
domain = Epp::Domain.new
|
|
||||||
domain.attributes = domain.attrs_from(frame, current_user)
|
|
||||||
domain.attach_default_contacts
|
|
||||||
|
|
||||||
period = domain.period.to_i
|
|
||||||
plural_period_unit_name = (domain.period_unit == 'm' ? 'months' : 'years').to_sym
|
|
||||||
expire_time = (Time.zone.now.advance(plural_period_unit_name => period) + 1.day).beginning_of_day
|
|
||||||
domain.expire_time = expire_time
|
|
||||||
|
|
||||||
domain
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def epp_code_map
|
def epp_code_map
|
||||||
{
|
{
|
||||||
'2002' => [ # Command use error
|
'2002' => [ # Command use error
|
||||||
|
@ -123,408 +110,10 @@ class Epp::Domain < Domain
|
||||||
|
|
||||||
def attach_default_contacts
|
def attach_default_contacts
|
||||||
return if registrant.blank?
|
return if registrant.blank?
|
||||||
tech_contacts << registrant if tech_domain_contacts.blank?
|
registrant_obj = Contact.find_by(code: registrant.code)
|
||||||
admin_contacts << registrant if admin_domain_contacts.blank? && !registrant.org?
|
|
||||||
end
|
|
||||||
|
|
||||||
def attrs_from(frame, current_user, action = nil)
|
tech_contacts << registrant_obj if tech_domain_contacts.blank?
|
||||||
at = {}.with_indifferent_access
|
admin_contacts << registrant_obj if admin_domain_contacts.blank? && !registrant.org?
|
||||||
|
|
||||||
registrant_frame = frame.css('registrant').first
|
|
||||||
code = registrant_frame.try(:text)
|
|
||||||
if code.present?
|
|
||||||
if action == 'chg' && registrant_change_prohibited?
|
|
||||||
add_epp_error('2304', "status", DomainStatus::SERVER_REGISTRANT_CHANGE_PROHIBITED, I18n.t(:object_status_prohibits_operation))
|
|
||||||
end
|
|
||||||
regt = Registrant.find_by(code: code)
|
|
||||||
if regt
|
|
||||||
at[:registrant_id] = regt.id
|
|
||||||
else
|
|
||||||
add_epp_error('2303', 'registrant', code, [:registrant, :not_found])
|
|
||||||
end
|
|
||||||
else
|
|
||||||
add_epp_error('2306', nil, nil, [:registrant, :cannot_be_missing])
|
|
||||||
end if registrant_frame
|
|
||||||
|
|
||||||
|
|
||||||
at[:name] = frame.css('name').text if new_record?
|
|
||||||
at[:registrar_id] = current_user.registrar.try(:id)
|
|
||||||
|
|
||||||
period = frame.css('period').text
|
|
||||||
at[:period] = (period.to_i == 0) ? 1 : period.to_i
|
|
||||||
|
|
||||||
at[:period_unit] = Epp::Domain.parse_period_unit_from_frame(frame) || 'y'
|
|
||||||
|
|
||||||
at[:reserved_pw] = frame.css('reserved > pw').text
|
|
||||||
|
|
||||||
# at[:statuses] = domain_statuses_attrs(frame, action)
|
|
||||||
at[:nameservers_attributes] = nameservers_attrs(frame, action)
|
|
||||||
at[:admin_domain_contacts_attributes] = admin_domain_contacts_attrs(frame, action)
|
|
||||||
at[:tech_domain_contacts_attributes] = tech_domain_contacts_attrs(frame, action)
|
|
||||||
|
|
||||||
check_for_same_contacts(at[:admin_domain_contacts_attributes], 'admin')
|
|
||||||
check_for_same_contacts(at[:tech_domain_contacts_attributes], 'tech')
|
|
||||||
|
|
||||||
pw = frame.css('authInfo > pw').text
|
|
||||||
at[:transfer_code] = pw if pw.present?
|
|
||||||
|
|
||||||
if new_record?
|
|
||||||
dnskey_frame = frame.css('extension create')
|
|
||||||
else
|
|
||||||
dnskey_frame = frame
|
|
||||||
end
|
|
||||||
|
|
||||||
at[:dnskeys_attributes] = dnskeys_attrs(dnskey_frame, action)
|
|
||||||
|
|
||||||
at
|
|
||||||
end
|
|
||||||
|
|
||||||
def check_for_same_contacts(contacts, contact_type)
|
|
||||||
return unless contacts.uniq.count != contacts.count
|
|
||||||
|
|
||||||
add_epp_error('2306', contact_type, nil, %i[domain_contacts invalid])
|
|
||||||
end
|
|
||||||
|
|
||||||
# Adding legal doc to domain and
|
|
||||||
# if something goes wrong - raise Rollback error
|
|
||||||
def add_legal_file_to_new frame
|
|
||||||
legal_document_data = ::Deserializers::Xml::LegalDocument.new(frame).call
|
|
||||||
return unless legal_document_data
|
|
||||||
return if legal_document_data[:body].starts_with?(ENV['legal_documents_dir'])
|
|
||||||
|
|
||||||
doc = LegalDocument.create(documentable_type: Domain, document_type: legal_document_data[:type],
|
|
||||||
body: legal_document_data[:body])
|
|
||||||
self.legal_documents = [doc]
|
|
||||||
|
|
||||||
frame.css("legalDocument").first.content = doc.path if doc&.persisted?
|
|
||||||
self.legal_document_id = doc.id
|
|
||||||
end
|
|
||||||
|
|
||||||
def nameservers_attrs(frame, action)
|
|
||||||
ns_list = nameservers_from(frame)
|
|
||||||
|
|
||||||
if action == 'rem'
|
|
||||||
to_destroy = []
|
|
||||||
ns_list.each do |ns_attrs|
|
|
||||||
nameserver = nameservers.find_by_hash_params(ns_attrs).first
|
|
||||||
if nameserver.blank?
|
|
||||||
add_epp_error('2303', 'hostAttr', ns_attrs[:hostname], [:nameservers, :not_found])
|
|
||||||
else
|
|
||||||
to_destroy << {
|
|
||||||
id: nameserver.id,
|
|
||||||
_destroy: 1
|
|
||||||
}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return to_destroy
|
|
||||||
else
|
|
||||||
return ns_list
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def nameservers_from(frame)
|
|
||||||
res = []
|
|
||||||
frame.css('hostAttr').each do |x|
|
|
||||||
host_attr = {
|
|
||||||
hostname: x.css('hostName').first.try(:text),
|
|
||||||
ipv4: x.css('hostAddr[ip="v4"]').map(&:text).compact,
|
|
||||||
ipv6: x.css('hostAddr[ip="v6"]').map(&:text).compact
|
|
||||||
}
|
|
||||||
|
|
||||||
res << host_attr.delete_if { |_k, v| v.blank? }
|
|
||||||
end
|
|
||||||
|
|
||||||
res
|
|
||||||
end
|
|
||||||
|
|
||||||
def admin_domain_contacts_attrs(frame, action)
|
|
||||||
admin_attrs = domain_contact_attrs_from(frame, action, 'admin')
|
|
||||||
|
|
||||||
if admin_attrs.present? && admin_change_prohibited?
|
|
||||||
add_epp_error('2304', 'admin', DomainStatus::SERVER_ADMIN_CHANGE_PROHIBITED, I18n.t(:object_status_prohibits_operation))
|
|
||||||
return []
|
|
||||||
end
|
|
||||||
|
|
||||||
case action
|
|
||||||
when 'rem'
|
|
||||||
return destroy_attrs(admin_attrs, admin_domain_contacts)
|
|
||||||
else
|
|
||||||
return admin_attrs
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def tech_domain_contacts_attrs(frame, action)
|
|
||||||
tech_attrs = domain_contact_attrs_from(frame, action, 'tech')
|
|
||||||
|
|
||||||
if tech_attrs.present? && tech_change_prohibited?
|
|
||||||
add_epp_error('2304', 'tech', DomainStatus::SERVER_TECH_CHANGE_PROHIBITED, I18n.t(:object_status_prohibits_operation))
|
|
||||||
return []
|
|
||||||
end
|
|
||||||
|
|
||||||
case action
|
|
||||||
when 'rem'
|
|
||||||
return destroy_attrs(tech_attrs, tech_domain_contacts)
|
|
||||||
else
|
|
||||||
return tech_attrs
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def destroy_attrs(attrs, dcontacts)
|
|
||||||
destroy_attrs = []
|
|
||||||
attrs.each do |at|
|
|
||||||
domain_contact_id = dcontacts.find_by(contact_id: at[:contact_id]).try(:id)
|
|
||||||
|
|
||||||
unless domain_contact_id
|
|
||||||
add_epp_error('2303', 'contact', at[:contact_code_cache], [:domain_contacts, :not_found])
|
|
||||||
next
|
|
||||||
end
|
|
||||||
|
|
||||||
destroy_attrs << {
|
|
||||||
id: domain_contact_id,
|
|
||||||
_destroy: 1
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
destroy_attrs
|
|
||||||
end
|
|
||||||
|
|
||||||
def domain_contact_attrs_from(frame, action, type)
|
|
||||||
attrs = []
|
|
||||||
frame.css('contact').each do |x|
|
|
||||||
next if x['type'] != type
|
|
||||||
|
|
||||||
c = Epp::Contact.find_by_epp_code(x.text)
|
|
||||||
unless c
|
|
||||||
add_epp_error('2303', 'contact', x.text, [:domain_contacts, :not_found])
|
|
||||||
next
|
|
||||||
end
|
|
||||||
|
|
||||||
if action != 'rem'
|
|
||||||
if x['type'] == 'admin' && c.org?
|
|
||||||
add_epp_error('2306', 'contact', x.text, [:domain_contacts, :admin_contact_can_be_only_private_person])
|
|
||||||
next
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
attrs << {
|
|
||||||
contact_id: c.id,
|
|
||||||
contact_code_cache: c.code
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
attrs
|
|
||||||
end
|
|
||||||
|
|
||||||
def dnskeys_attrs(frame, action)
|
|
||||||
keys = []
|
|
||||||
return keys if frame.blank?
|
|
||||||
inf_data = DnsSecKeys.new(frame)
|
|
||||||
add_epp_error('2005', nil, nil, %i[dnskeys invalid]) if not_base64?(inf_data)
|
|
||||||
|
|
||||||
if action == 'rem' &&
|
|
||||||
frame.css('rem > all').first.try(:text) == 'true'
|
|
||||||
keys = inf_data.mark_destroy_all dnskeys
|
|
||||||
else
|
|
||||||
if Setting.key_data_allowed
|
|
||||||
errors.add(:base, :ds_data_not_allowed) if inf_data.ds_data.present?
|
|
||||||
keys = inf_data.key_data
|
|
||||||
end
|
|
||||||
if Setting.ds_data_allowed
|
|
||||||
errors.add(:base, :key_data_not_allowed) if inf_data.key_data.present?
|
|
||||||
keys = inf_data.ds_data
|
|
||||||
end
|
|
||||||
if action == 'rem'
|
|
||||||
keys = inf_data.mark_destroy(dnskeys)
|
|
||||||
add_epp_error('2303', nil, nil, [:dnskeys, :not_found]) if keys.include? nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
errors.any? ? [] : keys
|
|
||||||
end
|
|
||||||
|
|
||||||
def not_base64?(inf_data)
|
|
||||||
inf_data.key_data.any? do |key|
|
|
||||||
value = key[:public_key]
|
|
||||||
|
|
||||||
!value.is_a?(String) || Base64.strict_encode64(Base64.strict_decode64(value)) != value
|
|
||||||
end
|
|
||||||
rescue ArgumentError
|
|
||||||
true
|
|
||||||
end
|
|
||||||
|
|
||||||
class DnsSecKeys
|
|
||||||
def initialize(frame)
|
|
||||||
@key_data = []
|
|
||||||
@ds_data = []
|
|
||||||
# schema validation prevents both in the same parent node
|
|
||||||
if frame.css('dsData').present?
|
|
||||||
ds_data_from frame
|
|
||||||
else
|
|
||||||
frame.css('keyData').each do |key|
|
|
||||||
@key_data.append key_data_from(key)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
attr_reader :key_data
|
|
||||||
attr_reader :ds_data
|
|
||||||
|
|
||||||
def mark_destroy_all(dns_keys)
|
|
||||||
# if transition support required mark_destroy dns_keys when has ds/key values otherwise ...
|
|
||||||
dns_keys.map { |inf_data| mark inf_data }
|
|
||||||
end
|
|
||||||
|
|
||||||
def mark_destroy(dns_keys)
|
|
||||||
(ds_data.present? ? ds_filter(dns_keys) : kd_filter(dns_keys)).map do |inf_data|
|
|
||||||
inf_data.blank? ? nil : mark(inf_data)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
KEY_INTERFACE = {flags: 'flags', protocol: 'protocol', alg: 'alg', public_key: 'pubKey' }
|
|
||||||
DS_INTERFACE =
|
|
||||||
{ ds_key_tag: 'keyTag',
|
|
||||||
ds_alg: 'alg',
|
|
||||||
ds_digest_type: 'digestType',
|
|
||||||
ds_digest: 'digest'
|
|
||||||
}
|
|
||||||
|
|
||||||
def xm_copy(frame, map)
|
|
||||||
result = {}
|
|
||||||
map.each do |key, elem|
|
|
||||||
result[key] = frame.css(elem).first.try(:text)
|
|
||||||
end
|
|
||||||
result
|
|
||||||
end
|
|
||||||
|
|
||||||
def key_data_from(frame)
|
|
||||||
xm_copy frame, KEY_INTERFACE
|
|
||||||
end
|
|
||||||
|
|
||||||
def ds_data_from(frame)
|
|
||||||
frame.css('dsData').each do |ds_data|
|
|
||||||
key = ds_data.css('keyData')
|
|
||||||
ds = xm_copy ds_data, DS_INTERFACE
|
|
||||||
ds.merge(key_data_from key) if key.present?
|
|
||||||
@ds_data << ds
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def ds_filter(dns_keys)
|
|
||||||
@ds_data.map do |ds|
|
|
||||||
dns_keys.find_by(ds.slice(*DS_INTERFACE.keys))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def kd_filter(dns_keys)
|
|
||||||
@key_data.map do |key|
|
|
||||||
dns_keys.find_by(key)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def mark(inf_data)
|
|
||||||
{ id: inf_data.id, _destroy: 1 }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def domain_statuses_attrs(frame, action)
|
|
||||||
status_list = domain_status_list_from(frame)
|
|
||||||
if action == 'rem'
|
|
||||||
to_destroy = []
|
|
||||||
status_list.each do |x|
|
|
||||||
if statuses.include?(x)
|
|
||||||
to_destroy << x
|
|
||||||
else
|
|
||||||
add_epp_error('2303', 'status', x, %i[statuses not_found])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return to_destroy
|
|
||||||
else
|
|
||||||
return status_list
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def domain_status_list_from(frame)
|
|
||||||
status_list = []
|
|
||||||
|
|
||||||
frame.css('status').each do |x|
|
|
||||||
unless DomainStatus::CLIENT_STATUSES.include?(x['s'])
|
|
||||||
add_epp_error('2303', 'status', x['s'], %i[statuses not_found])
|
|
||||||
next
|
|
||||||
end
|
|
||||||
|
|
||||||
status_list << x['s']
|
|
||||||
end
|
|
||||||
|
|
||||||
status_list
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
def update(frame, current_user, verify = true)
|
|
||||||
return super if frame.blank?
|
|
||||||
|
|
||||||
if discarded? || statuses_blocks_update?
|
|
||||||
add_epp_error('2304', nil, nil, 'Object status prohibits operation')
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
at = {}.with_indifferent_access
|
|
||||||
at.deep_merge!(attrs_from(frame.css('chg'), current_user, 'chg'))
|
|
||||||
at.deep_merge!(attrs_from(frame.css('rem'), current_user, 'rem'))
|
|
||||||
|
|
||||||
if doc = attach_legal_document(::Deserializers::Xml::LegalDocument.new(frame).call)
|
|
||||||
frame.css("legalDocument").first.content = doc.path if doc&.persisted?
|
|
||||||
self.legal_document_id = doc.id
|
|
||||||
end
|
|
||||||
|
|
||||||
at_add = attrs_from(frame.css('add'), current_user, 'add')
|
|
||||||
at[:nameservers_attributes] += at_add[:nameservers_attributes]
|
|
||||||
at[:admin_domain_contacts_attributes] += at_add[:admin_domain_contacts_attributes]
|
|
||||||
at[:tech_domain_contacts_attributes] += at_add[:tech_domain_contacts_attributes]
|
|
||||||
at[:dnskeys_attributes] += at_add[:dnskeys_attributes]
|
|
||||||
at[:statuses] =
|
|
||||||
statuses - domain_statuses_attrs(frame.css('rem'), 'rem') + domain_statuses_attrs(frame.css('add'), 'add')
|
|
||||||
|
|
||||||
if errors.empty? && verify
|
|
||||||
self.upid = current_user.registrar.id if current_user.registrar
|
|
||||||
self.up_date = Time.zone.now
|
|
||||||
end
|
|
||||||
|
|
||||||
registrant_verification_needed = false
|
|
||||||
# registrant block may not be present, so we need this to rule out false positives
|
|
||||||
if frame.css('registrant').text.present?
|
|
||||||
registrant_verification_needed = verification_needed?(code: frame.css('registrant').text)
|
|
||||||
end
|
|
||||||
|
|
||||||
if registrant_verification_needed && disputed?
|
|
||||||
disputed_pw = frame.css('reserved > pw').text
|
|
||||||
if disputed_pw.blank?
|
|
||||||
add_epp_error('2304', nil, nil, 'Required parameter missing; reserved' \
|
|
||||||
'pw element required for dispute domains')
|
|
||||||
else
|
|
||||||
dispute = Dispute.active.find_by(domain_name: name, password: disputed_pw)
|
|
||||||
if dispute
|
|
||||||
Dispute.close_by_domain(name)
|
|
||||||
registrant_verification_needed = false # Prevent asking current registrant confirmation
|
|
||||||
else
|
|
||||||
add_epp_error('2202', nil, nil, 'Invalid authorization information; '\
|
|
||||||
'invalid reserved>pw value')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
unverified_registrant_params = frame.css('registrant').present? &&
|
|
||||||
frame.css('registrant').attr('verified').to_s.downcase != 'yes'
|
|
||||||
|
|
||||||
if registrant_verification_needed && errors.empty? && verify &&
|
|
||||||
Setting.request_confirmation_on_registrant_change_enabled &&
|
|
||||||
unverified_registrant_params
|
|
||||||
registrant_verification_asked!(frame.to_s, current_user.id) unless disputed?
|
|
||||||
end
|
|
||||||
|
|
||||||
errors.empty? && super(at)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def apply_pending_delete!
|
def apply_pending_delete!
|
||||||
|
@ -618,7 +207,7 @@ class Epp::Domain < Domain
|
||||||
end
|
end
|
||||||
|
|
||||||
def add_renew_epp_errors
|
def add_renew_epp_errors
|
||||||
if renew_blocking_statuses.any? && !renewable?
|
if renew_blocking_statuses.any? || !renewable?
|
||||||
add_epp_error('2304', 'status', renew_blocking_statuses,
|
add_epp_error('2304', 'status', renew_blocking_statuses,
|
||||||
I18n.t('object_status_prohibits_operation'))
|
I18n.t('object_status_prohibits_operation'))
|
||||||
end
|
end
|
||||||
|
|
|
@ -63,7 +63,7 @@ class Nameserver < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
class << self
|
class << self
|
||||||
def find_by_hash_params params
|
def from_hash_params params
|
||||||
params = params.with_indifferent_access
|
params = params.with_indifferent_access
|
||||||
rel = all
|
rel = all
|
||||||
rel = rel.where(hostname: params[:hostname])
|
rel = rel.where(hostname: params[:hostname])
|
||||||
|
|
|
@ -6,7 +6,7 @@ class TechDomainContact < DomainContact
|
||||||
tech_contacts = where(contact: current_contact)
|
tech_contacts = where(contact: current_contact)
|
||||||
|
|
||||||
tech_contacts.each do |tech_contact|
|
tech_contacts.each do |tech_contact|
|
||||||
if tech_contact.domain.bulk_update_prohibited?
|
if irreplaceable?(tech_contact)
|
||||||
skipped_domains << tech_contact.domain.name
|
skipped_domains << tech_contact.domain.name
|
||||||
next
|
next
|
||||||
end
|
end
|
||||||
|
@ -20,4 +20,9 @@ class TechDomainContact < DomainContact
|
||||||
end
|
end
|
||||||
[affected_domains.sort, skipped_domains.sort]
|
[affected_domains.sort, skipped_domains.sort]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.irreplaceable?(tech_contact)
|
||||||
|
dn = tech_contact.domain
|
||||||
|
dn.bulk_update_prohibited? || dn.update_prohibited? || dn.tech_change_prohibited?
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
10
config/initializers/apipie.rb
Normal file
10
config/initializers/apipie.rb
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
Apipie.configure do |config|
|
||||||
|
config.app_name = "Estonian Internet Foundation's REST EPP"
|
||||||
|
config.validate = true
|
||||||
|
config.translate = false
|
||||||
|
config.api_base_url = "/api"
|
||||||
|
config.doc_base_url = "/apipie"
|
||||||
|
config.swagger_content_type_input = :json
|
||||||
|
# where is your API defined?
|
||||||
|
config.api_controllers_matcher = "#{Rails.root}/app/controllers/**/*.rb"
|
||||||
|
end
|
|
@ -1,4 +1,5 @@
|
||||||
require 'core_monkey_patches/array'
|
require 'core_monkey_patches/array'
|
||||||
|
require 'core_monkey_patches/hash'
|
||||||
require 'gem_monkey_patches/builder'
|
require 'gem_monkey_patches/builder'
|
||||||
require 'gem_monkey_patches/i18n'
|
require 'gem_monkey_patches/i18n'
|
||||||
require 'gem_monkey_patches/paper_trail'
|
require 'gem_monkey_patches/paper_trail'
|
||||||
|
|
|
@ -6,4 +6,3 @@ en:
|
||||||
reset_btn: Reset
|
reset_btn: Reset
|
||||||
show:
|
show:
|
||||||
title: REPP log
|
title: REPP log
|
||||||
|
|
||||||
|
|
|
@ -53,13 +53,22 @@ Rails.application.routes.draw do
|
||||||
resources :auctions, only: %i[index]
|
resources :auctions, only: %i[index]
|
||||||
resources :retained_domains, only: %i[index]
|
resources :retained_domains, only: %i[index]
|
||||||
namespace :registrar do
|
namespace :registrar do
|
||||||
|
resources :notifications, only: [:index, :show, :update]
|
||||||
resources :nameservers do
|
resources :nameservers do
|
||||||
collection do
|
collection do
|
||||||
put '/', to: 'nameservers#update'
|
put '/', to: 'nameservers#update'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
resources :domains do
|
resources :domains, constraints: { id: /.*/ } do
|
||||||
|
resources :nameservers, only: %i[index create destroy], constraints: { id: /.*/ }, controller: 'domains/nameservers'
|
||||||
|
resources :dnssec, only: %i[index create], constraints: { id: /.*/ }, controller: 'domains/dnssec'
|
||||||
|
resources :contacts, only: %i[index create], constraints: { id: /.*/ }, controller: 'domains/contacts'
|
||||||
|
resources :renew, only: %i[create], constraints: { id: /.*/ }, controller: 'domains/renews'
|
||||||
|
resources :transfer, only: %i[create], constraints: { id: /.*/ }, controller: 'domains/transfers'
|
||||||
|
resources :statuses, only: %i[update destroy], constraints: { id: /.*/ }, controller: 'domains/statuses'
|
||||||
|
match "dnssec", to: "domains/dnssec#destroy", via: "delete", defaults: { id: nil }
|
||||||
|
match "contacts", to: "domains/contacts#destroy", via: "delete", defaults: { id: nil }
|
||||||
collection do
|
collection 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'
|
||||||
|
|
5
lib/core_monkey_patches/hash.rb
Normal file
5
lib/core_monkey_patches/hash.rb
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
class Hash
|
||||||
|
def select_keys(*args)
|
||||||
|
select { |k, _| args.include?(k) }.map { |_k, v| v }
|
||||||
|
end
|
||||||
|
end
|
95
lib/deserializers/xml/dnssec.rb
Normal file
95
lib/deserializers/xml/dnssec.rb
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
module Deserializers
|
||||||
|
module Xml
|
||||||
|
class DnssecKey
|
||||||
|
attr_reader :frame, :dsa
|
||||||
|
|
||||||
|
KEY_INTERFACE = { flags: 'flags', protocol: 'protocol', alg: 'alg',
|
||||||
|
public_key: 'pubKey' }.freeze
|
||||||
|
DS_INTERFACE = { ds_key_tag: 'keyTag', ds_alg: 'alg', ds_digest_type: 'digestType',
|
||||||
|
ds_digest: 'digest' }.freeze
|
||||||
|
|
||||||
|
def initialize(frame, dsa)
|
||||||
|
@frame = frame
|
||||||
|
@dsa = dsa
|
||||||
|
end
|
||||||
|
|
||||||
|
def call
|
||||||
|
dsa ? ds_alg_output : xm_copy(frame, KEY_INTERFACE)
|
||||||
|
end
|
||||||
|
|
||||||
|
def ds_alg_output
|
||||||
|
ds_key = xm_copy(frame, DS_INTERFACE)
|
||||||
|
ds_key.merge(xm_copy(frame.css('keyData'), KEY_INTERFACE)) if frame.css('keyData').present?
|
||||||
|
ds_key
|
||||||
|
end
|
||||||
|
|
||||||
|
def other_alg_output
|
||||||
|
xm_copy(frame, KEY_INTERFACE)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def xm_copy(entry, map)
|
||||||
|
result = {}
|
||||||
|
map.each do |key, elem|
|
||||||
|
result[key] = entry.css(elem).first.try(:text)
|
||||||
|
end
|
||||||
|
result
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class DnssecKeys
|
||||||
|
attr_reader :frame, :key_data, :ds_data
|
||||||
|
|
||||||
|
def initialize(frame)
|
||||||
|
@key_data = []
|
||||||
|
@ds_data = []
|
||||||
|
|
||||||
|
# schema validation prevents both in the same parent node
|
||||||
|
if frame.css('dsData').present?
|
||||||
|
frame.css('dsData').each { |k| @ds_data << key_from_params(k, dsa: true) }
|
||||||
|
end
|
||||||
|
|
||||||
|
return if frame.css('keyData').blank?
|
||||||
|
|
||||||
|
frame.css('keyData').each { |k| @key_data << key_from_params(k, dsa: false) }
|
||||||
|
end
|
||||||
|
|
||||||
|
def key_from_params(obj, dsa: false)
|
||||||
|
Deserializers::Xml::DnssecKey.new(obj, dsa).call
|
||||||
|
end
|
||||||
|
|
||||||
|
def call
|
||||||
|
key_data + ds_data
|
||||||
|
end
|
||||||
|
|
||||||
|
def mark_destroy_all(dns_keys)
|
||||||
|
# if transition support required mark_destroy dns_keys when has ds/key values otherwise ...
|
||||||
|
dns_keys.map { |inf_data| mark(inf_data) }
|
||||||
|
end
|
||||||
|
|
||||||
|
def mark_destroy(dns_keys)
|
||||||
|
data = ds_data.present? ? ds_filter(dns_keys) : kd_filter(dns_keys)
|
||||||
|
data.each { |inf_data| inf_data.blank? ? nil : mark(inf_data) }
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def ds_filter(dns_keys)
|
||||||
|
@ds_data.map do |ds|
|
||||||
|
dns_keys.find_by(ds.slice(*DS_INTERFACE.keys))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def kd_filter(dns_keys)
|
||||||
|
@key_data.map do |key|
|
||||||
|
dns_keys.find_by(key)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def mark(inf_data)
|
||||||
|
{ id: inf_data.id, _destroy: 1 }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
61
lib/deserializers/xml/domain.rb
Normal file
61
lib/deserializers/xml/domain.rb
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
module Deserializers
|
||||||
|
module Xml
|
||||||
|
class Domain
|
||||||
|
attr_reader :frame, :registrar
|
||||||
|
|
||||||
|
def initialize(frame, registrar)
|
||||||
|
@frame = frame
|
||||||
|
@registrar = registrar
|
||||||
|
end
|
||||||
|
|
||||||
|
def call
|
||||||
|
attributes = {
|
||||||
|
name: if_present('name'),
|
||||||
|
registrar: registrar,
|
||||||
|
registrant: if_present('registrant'),
|
||||||
|
reserved_pw: if_present('reserved > pw'),
|
||||||
|
}
|
||||||
|
|
||||||
|
attributes.merge!(assign_period_attributes)
|
||||||
|
|
||||||
|
pw = frame.css('authInfo > pw').text
|
||||||
|
attributes[:transfer_code] = pw if pw.present?
|
||||||
|
attributes.compact
|
||||||
|
end
|
||||||
|
|
||||||
|
def assign_period_attributes
|
||||||
|
period = frame.css('period')
|
||||||
|
|
||||||
|
{
|
||||||
|
period: period.text.present? ? Integer(period.text) : 1,
|
||||||
|
period_unit: period.first ? period.first[:unit] : 'y',
|
||||||
|
exp_date: if_present('curExpDate'),
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def if_present(css_path)
|
||||||
|
return if frame.css(css_path).blank?
|
||||||
|
|
||||||
|
frame.css(css_path).text
|
||||||
|
end
|
||||||
|
|
||||||
|
def statuses_to_add
|
||||||
|
statuses_frame = frame.css('add')
|
||||||
|
return if statuses_frame.blank?
|
||||||
|
|
||||||
|
statuses_frame.css('status').map do |status|
|
||||||
|
status['s']
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def statuses_to_remove
|
||||||
|
statuses_frame = frame.css('rem')
|
||||||
|
return if statuses_frame.blank?
|
||||||
|
|
||||||
|
statuses_frame.css('status').map do |status|
|
||||||
|
status['s']
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
52
lib/deserializers/xml/domain_create.rb
Normal file
52
lib/deserializers/xml/domain_create.rb
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
require 'deserializers/xml/legal_document'
|
||||||
|
require 'deserializers/xml/domain'
|
||||||
|
require 'deserializers/xml/nameserver'
|
||||||
|
require 'deserializers/xml/dnssec'
|
||||||
|
module Deserializers
|
||||||
|
module Xml
|
||||||
|
class DomainCreate
|
||||||
|
attr_reader :frame
|
||||||
|
attr_reader :registrar
|
||||||
|
|
||||||
|
def initialize(frame, registrar)
|
||||||
|
@frame = frame
|
||||||
|
@registrar = registrar
|
||||||
|
end
|
||||||
|
|
||||||
|
def call
|
||||||
|
obj = domain
|
||||||
|
obj[:admin_contacts] = admin_contacts
|
||||||
|
obj[:tech_contacts] = tech_contacts
|
||||||
|
obj[:nameservers_attributes] = nameservers
|
||||||
|
obj[:dnskeys_attributes] = dns_keys
|
||||||
|
obj[:legal_document] = legal_document
|
||||||
|
|
||||||
|
obj
|
||||||
|
end
|
||||||
|
|
||||||
|
def domain
|
||||||
|
@domain ||= ::Deserializers::Xml::Domain.new(frame, registrar).call
|
||||||
|
end
|
||||||
|
|
||||||
|
def nameservers
|
||||||
|
@nameservers ||= ::Deserializers::Xml::Nameservers.new(frame).call
|
||||||
|
end
|
||||||
|
|
||||||
|
def admin_contacts
|
||||||
|
frame.css('contact').select { |c| c['type'] == 'admin' }.map(&:text)
|
||||||
|
end
|
||||||
|
|
||||||
|
def tech_contacts
|
||||||
|
frame.css('contact').select { |c| c['type'] == 'tech' }.map(&:text)
|
||||||
|
end
|
||||||
|
|
||||||
|
def dns_keys
|
||||||
|
@dns_keys ||= ::Deserializers::Xml::DnssecKeys.new(frame).key_data
|
||||||
|
end
|
||||||
|
|
||||||
|
def legal_document
|
||||||
|
@legal_document ||= ::Deserializers::Xml::LegalDocument.new(frame).call
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
20
lib/deserializers/xml/domain_delete.rb
Normal file
20
lib/deserializers/xml/domain_delete.rb
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
module Deserializers
|
||||||
|
module Xml
|
||||||
|
class DomainDelete
|
||||||
|
attr_reader :frame
|
||||||
|
|
||||||
|
def initialize(frame)
|
||||||
|
@frame = frame
|
||||||
|
end
|
||||||
|
|
||||||
|
def call
|
||||||
|
obj = {}
|
||||||
|
obj[:name] = frame.css('name')&.text
|
||||||
|
verify = frame.css('delete').children.css('delete').attr('verified').to_s.downcase == 'yes'
|
||||||
|
obj[:delete] = { verified: verify }
|
||||||
|
|
||||||
|
obj
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
89
lib/deserializers/xml/domain_update.rb
Normal file
89
lib/deserializers/xml/domain_update.rb
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
require 'deserializers/xml/legal_document'
|
||||||
|
require 'deserializers/xml/domain'
|
||||||
|
require 'deserializers/xml/nameserver'
|
||||||
|
require 'deserializers/xml/dnssec'
|
||||||
|
module Deserializers
|
||||||
|
module Xml
|
||||||
|
class DomainUpdate
|
||||||
|
attr_reader :frame, :registrar
|
||||||
|
|
||||||
|
def initialize(frame, registrar)
|
||||||
|
@frame = frame
|
||||||
|
@registrar = registrar
|
||||||
|
@legal_document ||= ::Deserializers::Xml::LegalDocument.new(frame).call
|
||||||
|
end
|
||||||
|
|
||||||
|
def call
|
||||||
|
obj = { domain: frame.css('name')&.text, registrant: registrant, contacts: contacts,
|
||||||
|
transfer_code: if_present('authInfo > pw'), nameservers: nameservers,
|
||||||
|
registrar_id: registrar, statuses: statuses, dns_keys: dns_keys,
|
||||||
|
reserved_pw: if_present('reserved > pw'), legal_document: @legal_document }
|
||||||
|
|
||||||
|
obj.reject { |_key, val| val.blank? }
|
||||||
|
end
|
||||||
|
|
||||||
|
def registrant
|
||||||
|
return if frame.css('chg > registrant').blank?
|
||||||
|
|
||||||
|
{ code: frame.css('chg > registrant').text,
|
||||||
|
verified: frame.css('chg > registrant').attr('verified').to_s.downcase == 'yes' }
|
||||||
|
end
|
||||||
|
|
||||||
|
def contacts
|
||||||
|
contacts = []
|
||||||
|
frame.css('add > contact').each do |c|
|
||||||
|
contacts << { code: c.text, type: c['type'], action: 'add' }
|
||||||
|
end
|
||||||
|
|
||||||
|
frame.css('rem > contact').each do |c|
|
||||||
|
contacts << { code: c.text, type: c['type'], action: 'rem' }
|
||||||
|
end
|
||||||
|
|
||||||
|
contacts.presence
|
||||||
|
end
|
||||||
|
|
||||||
|
def nameservers
|
||||||
|
@nameservers = []
|
||||||
|
|
||||||
|
frame.css('add > ns > hostAttr').each { |ns| assign_ns(ns) }
|
||||||
|
frame.css('rem > ns > hostAttr').each { |ns| assign_ns(ns, add: false) }
|
||||||
|
|
||||||
|
@nameservers.presence
|
||||||
|
end
|
||||||
|
|
||||||
|
def assign_ns(nameserver, add: true)
|
||||||
|
nsrv = Deserializers::Xml::Nameserver.new(nameserver).call
|
||||||
|
nsrv[:action] = add ? 'add' : 'rem'
|
||||||
|
@nameservers << nsrv
|
||||||
|
end
|
||||||
|
|
||||||
|
def dns_keys
|
||||||
|
added = ::Deserializers::Xml::DnssecKeys.new(frame.css('add')).call
|
||||||
|
added.each { |k| k[:action] = 'add' }
|
||||||
|
removed = ::Deserializers::Xml::DnssecKeys.new(frame.css('rem')).call
|
||||||
|
removed.each { |k| k[:action] = 'rem' }
|
||||||
|
|
||||||
|
return if (added + removed).blank?
|
||||||
|
|
||||||
|
added + removed
|
||||||
|
end
|
||||||
|
|
||||||
|
def statuses
|
||||||
|
return if frame.css('status').blank?
|
||||||
|
|
||||||
|
s = []
|
||||||
|
|
||||||
|
frame.css('add > status').each { |e| s << { status: e.attr('s'), action: 'add' } }
|
||||||
|
frame.css('rem > status').each { |e| s << { status: e.attr('s'), action: 'rem' } }
|
||||||
|
|
||||||
|
s
|
||||||
|
end
|
||||||
|
|
||||||
|
def if_present(css_path)
|
||||||
|
return if frame.css(css_path).blank?
|
||||||
|
|
||||||
|
frame.css(css_path).text
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
37
lib/deserializers/xml/nameserver.rb
Normal file
37
lib/deserializers/xml/nameserver.rb
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
module Deserializers
|
||||||
|
module Xml
|
||||||
|
class Nameserver
|
||||||
|
attr_reader :frame
|
||||||
|
|
||||||
|
def initialize(frame)
|
||||||
|
@frame = frame
|
||||||
|
end
|
||||||
|
|
||||||
|
def call
|
||||||
|
{
|
||||||
|
hostname: frame.css('hostName').text,
|
||||||
|
ipv4: frame.css('hostAddr[ip="v4"]').map(&:text).compact,
|
||||||
|
ipv6: frame.css('hostAddr[ip="v6"]').map(&:text).compact,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class Nameservers
|
||||||
|
attr_reader :frame
|
||||||
|
|
||||||
|
def initialize(frame)
|
||||||
|
@frame = frame
|
||||||
|
end
|
||||||
|
|
||||||
|
def call
|
||||||
|
res = []
|
||||||
|
frame.css('hostAttr').each do |ns|
|
||||||
|
ns = Deserializers::Xml::Nameserver.new(ns).call
|
||||||
|
res << ns.delete_if { |_k, v| v.blank? }
|
||||||
|
end
|
||||||
|
|
||||||
|
res
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -10,7 +10,7 @@ module Serializers
|
||||||
|
|
||||||
def to_json(obj = contact)
|
def to_json(obj = contact)
|
||||||
json = { id: obj.code, name: obj.name, ident: ident,
|
json = { id: obj.code, name: obj.name, ident: ident,
|
||||||
email: obj.email, phone: obj.phone, fax: obj.fax,
|
email: obj.email, phone: obj.phone,
|
||||||
auth_info: obj.auth_info, statuses: obj.statuses,
|
auth_info: obj.auth_info, statuses: obj.statuses,
|
||||||
disclosed_attributes: obj.disclosed_attributes }
|
disclosed_attributes: obj.disclosed_attributes }
|
||||||
|
|
||||||
|
|
45
lib/serializers/repp/domain.rb
Normal file
45
lib/serializers/repp/domain.rb
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
module Serializers
|
||||||
|
module Repp
|
||||||
|
class Domain
|
||||||
|
attr_reader :domain
|
||||||
|
|
||||||
|
def initialize(domain, sponsored: true)
|
||||||
|
@domain = domain
|
||||||
|
@sponsored = sponsored
|
||||||
|
end
|
||||||
|
|
||||||
|
# rubocop:disable Metrics/AbcSize
|
||||||
|
def to_json(obj = domain)
|
||||||
|
json = {
|
||||||
|
name: obj.name, registrant: obj.registrant.code, created_at: obj.created_at,
|
||||||
|
updated_at: obj.updated_at, expire_time: obj.expire_time, outzone_at: obj.outzone_at,
|
||||||
|
delete_date: obj.delete_date, force_delete_date: obj.force_delete_date,
|
||||||
|
contacts: contacts, nameservers: nameservers, dnssec_keys: dnssec_keys,
|
||||||
|
statuses: obj.statuses, registrar: registrar
|
||||||
|
}
|
||||||
|
json[:transfer_code] = obj.auth_info if @sponsored
|
||||||
|
json
|
||||||
|
end
|
||||||
|
# rubocop:enable Metrics/AbcSize
|
||||||
|
|
||||||
|
def contacts
|
||||||
|
domain.domain_contacts.map { |c| { code: c.contact_code_cache, type: c.type } }
|
||||||
|
end
|
||||||
|
|
||||||
|
def nameservers
|
||||||
|
domain.nameservers.map { |ns| { hostname: ns.hostname, ipv4: ns.ipv4, ipv6: ns.ipv6 } }
|
||||||
|
end
|
||||||
|
|
||||||
|
def dnssec_keys
|
||||||
|
domain.dnskeys.map do |nssec|
|
||||||
|
{ flags: nssec.flags, protocol: nssec.protocol, alg: nssec.alg,
|
||||||
|
public_key: nssec.public_key }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def registrar
|
||||||
|
{ name: domain.registrar.name, website: domain.registrar.website }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
80
test/integration/admin_area/domain_update_confirms_test.rb
Normal file
80
test/integration/admin_area/domain_update_confirms_test.rb
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
require 'test_helper'
|
||||||
|
require 'application_system_test_case'
|
||||||
|
|
||||||
|
class AdminAreaBlockedDomainsIntegrationTest < JavaScriptApplicationSystemTestCase
|
||||||
|
setup do
|
||||||
|
WebMock.allow_net_connect!
|
||||||
|
sign_in users(:admin)
|
||||||
|
@domain = domains(:shop)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_t
|
||||||
|
new_registrant = contacts(:william)
|
||||||
|
assert_not_equal new_registrant, @domain.registrant
|
||||||
|
|
||||||
|
puts new_registrant.name
|
||||||
|
request_xml = <<-XML
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<epp xmlns="https://epp.tld.ee/schema/epp-ee-1.0.xsd">
|
||||||
|
<command>
|
||||||
|
<update>
|
||||||
|
<domain:update xmlns:domain="https://epp.tld.ee/schema/domain-eis-1.0.xsd">
|
||||||
|
<domain:name>#{@domain.name}</domain:name>
|
||||||
|
<domain:chg>
|
||||||
|
<domain:registrant>#{new_registrant.code}</domain:registrant>
|
||||||
|
</domain:chg>
|
||||||
|
</domain:update>
|
||||||
|
</update>
|
||||||
|
<extension>
|
||||||
|
<eis:extdata xmlns:eis="https://epp.tld.ee/schema/eis-1.0.xsd">
|
||||||
|
<eis:legalDocument type="pdf">#{'test' * 2000}</eis:legalDocument>
|
||||||
|
</eis:extdata>
|
||||||
|
</extension>
|
||||||
|
</command>
|
||||||
|
</epp>
|
||||||
|
XML
|
||||||
|
|
||||||
|
post epp_update_path, params: { frame: request_xml },
|
||||||
|
headers: { 'HTTP_COOKIE' => 'session=api_bestnames' }
|
||||||
|
@domain.reload
|
||||||
|
|
||||||
|
puts @domain.registrant
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def update_registrant_of_domain
|
||||||
|
new_registrant = contacts(:william)
|
||||||
|
assert_not_equal new_registrant, @domain.registrant
|
||||||
|
|
||||||
|
@domain.registrant
|
||||||
|
request_xml = <<-XML
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<epp xmlns="https://epp.tld.ee/schema/epp-ee-1.0.xsd">
|
||||||
|
<command>
|
||||||
|
<update>
|
||||||
|
<domain:update xmlns:domain="https://epp.tld.ee/schema/domain-eis-1.0.xsd">
|
||||||
|
<domain:name>#{@domain.name}</domain:name>
|
||||||
|
<domain:chg>
|
||||||
|
<domain:registrant>#{new_registrant.code}</domain:registrant>
|
||||||
|
</domain:chg>
|
||||||
|
</domain:update>
|
||||||
|
</update>
|
||||||
|
<extension>
|
||||||
|
<eis:extdata xmlns:eis="https://epp.tld.ee/schema/eis-1.0.xsd">
|
||||||
|
<eis:legalDocument type="pdf">#{'test' * 2000}</eis:legalDocument>
|
||||||
|
</eis:extdata>
|
||||||
|
</extension>
|
||||||
|
</command>
|
||||||
|
</epp>
|
||||||
|
XML
|
||||||
|
|
||||||
|
post epp_update_path, params: { frame: request_xml },
|
||||||
|
headers: { 'HTTP_COOKIE' => 'session=api_bestnames' }
|
||||||
|
@domain.reload
|
||||||
|
|
||||||
|
# puts response.body
|
||||||
|
puts @domain.registrant
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
68
test/integration/repp/v1/contacts/tech_replace_test.rb
Normal file
68
test/integration/repp/v1/contacts/tech_replace_test.rb
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
class ReppV1ContactsTechReplaceTest < ActionDispatch::IntegrationTest
|
||||||
|
def setup
|
||||||
|
@user = users(:api_bestnames)
|
||||||
|
token = Base64.encode64("#{@user.username}:#{@user.plain_text_password}")
|
||||||
|
token = "Basic #{token}"
|
||||||
|
|
||||||
|
@auth_headers = { 'Authorization' => token }
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_replaces_tech_contacts
|
||||||
|
old_contact = contacts(:john)
|
||||||
|
new_contact = contacts(:william)
|
||||||
|
|
||||||
|
assert DomainContact.where(contact: old_contact, type: 'TechDomainContact').any?
|
||||||
|
|
||||||
|
payload = { current_contact_id: old_contact.code, new_contact_id: new_contact.code}
|
||||||
|
patch "/repp/v1/domains/contacts", headers: @auth_headers, params: payload
|
||||||
|
json = JSON.parse(response.body, symbolize_names: true)
|
||||||
|
|
||||||
|
assert_response :ok
|
||||||
|
assert_equal 1000, json[:code]
|
||||||
|
assert_empty ["hospital.test", "library.test"] - json[:data][:affected_domains]
|
||||||
|
|
||||||
|
assert DomainContact.where(contact: old_contact, type: 'TechDomainContact').blank?
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_validates_contact_codes
|
||||||
|
payload = { current_contact_id: 'aaa', new_contact_id: 'bbb'}
|
||||||
|
patch "/repp/v1/domains/contacts", headers: @auth_headers, params: payload
|
||||||
|
json = JSON.parse(response.body, symbolize_names: true)
|
||||||
|
|
||||||
|
assert_response :not_found
|
||||||
|
assert_equal 2303, json[:code]
|
||||||
|
assert_equal 'Object does not exist', json[:message]
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_new_contact_must_be_different
|
||||||
|
old_contact = contacts(:john)
|
||||||
|
|
||||||
|
payload = { current_contact_id: old_contact.code, new_contact_id: old_contact.code }
|
||||||
|
patch "/repp/v1/domains/contacts", headers: @auth_headers, params: payload
|
||||||
|
json = JSON.parse(response.body, symbolize_names: true)
|
||||||
|
|
||||||
|
assert_response :bad_request
|
||||||
|
assert_equal 2304, json[:code]
|
||||||
|
assert_equal 'New contact must be different from current', json[:message]
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_domain_has_status_tech_change_prohibited
|
||||||
|
domain_shop = domains(:shop)
|
||||||
|
domain_shop_tech_contact_id = domain_shop.tech_domain_contacts[0][:contact_id]
|
||||||
|
old_contact = Contact.find_by(id: domain_shop_tech_contact_id)
|
||||||
|
new_contact = contacts(:john)
|
||||||
|
|
||||||
|
domain_shop.update(statuses: [DomainStatus::SERVER_TECH_CHANGE_PROHIBITED])
|
||||||
|
domain_shop.reload
|
||||||
|
assert domain_shop.statuses.include? DomainStatus::SERVER_TECH_CHANGE_PROHIBITED
|
||||||
|
|
||||||
|
payload = { current_contact_id: old_contact.code, new_contact_id: new_contact.code }
|
||||||
|
patch "/repp/v1/domains/contacts", headers: @auth_headers, params: payload
|
||||||
|
json = JSON.parse(response.body, symbolize_names: true)
|
||||||
|
|
||||||
|
assert_equal json[:data][:skipped_domains], ["shop.test"]
|
||||||
|
assert domain_shop.contacts.find_by(id: domain_shop_tech_contact_id).present?
|
||||||
|
end
|
||||||
|
end
|
|
@ -106,7 +106,7 @@ class ReppV1DomainsBulkRenewTest < ActionDispatch::IntegrationTest
|
||||||
|
|
||||||
assert_response :bad_request
|
assert_response :bad_request
|
||||||
assert_equal 2002, json[:code]
|
assert_equal 2002, json[:code]
|
||||||
assert_equal 'Not enough funds for renew domains', json[:message]
|
assert_equal 'Domain Billing failure - credit balance low', json[:message]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
100
test/integration/repp/v1/domains/contacts_test.rb
Normal file
100
test/integration/repp/v1/domains/contacts_test.rb
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
class ReppV1DomainsContactsTest < ActionDispatch::IntegrationTest
|
||||||
|
def setup
|
||||||
|
@user = users(:api_bestnames)
|
||||||
|
@domain = domains(:shop)
|
||||||
|
token = Base64.encode64("#{@user.username}:#{@user.plain_text_password}")
|
||||||
|
token = "Basic #{token}"
|
||||||
|
|
||||||
|
@auth_headers = { 'Authorization' => token }
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_shows_existing_domain_contacts
|
||||||
|
get "/repp/v1/domains/#{@domain.name}/contacts", headers: @auth_headers
|
||||||
|
json = JSON.parse(response.body, symbolize_names: true)
|
||||||
|
|
||||||
|
assert_response :ok
|
||||||
|
assert_equal 1000, json[:code]
|
||||||
|
assert_equal 'Command completed successfully', json[:message]
|
||||||
|
|
||||||
|
assert_equal @domain.admin_contacts.length, json[:data][:admin_contacts].length
|
||||||
|
assert_equal @domain.tech_contacts.length, json[:data][:tech_contacts].length
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_can_add_new_admin_contacts
|
||||||
|
new_contact = contacts(:john)
|
||||||
|
refute @domain.admin_contacts.find_by(code: new_contact.code).present?
|
||||||
|
|
||||||
|
payload = { contacts: [ { code: new_contact.code, type: 'admin' } ] }
|
||||||
|
post "/repp/v1/domains/#{@domain.name}/contacts", headers: @auth_headers, params: payload
|
||||||
|
json = JSON.parse(response.body, symbolize_names: true)
|
||||||
|
|
||||||
|
assert_response :ok
|
||||||
|
assert_equal 1000, json[:code]
|
||||||
|
|
||||||
|
assert @domain.admin_contacts.find_by(code: new_contact.code).present?
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_can_add_new_tech_contacts
|
||||||
|
new_contact = contacts(:john)
|
||||||
|
refute @domain.tech_contacts.find_by(code: new_contact.code).present?
|
||||||
|
|
||||||
|
payload = { contacts: [ { code: new_contact.code, type: 'tech' } ] }
|
||||||
|
post "/repp/v1/domains/#{@domain.name}/contacts", headers: @auth_headers, params: payload
|
||||||
|
json = JSON.parse(response.body, symbolize_names: true)
|
||||||
|
|
||||||
|
assert_response :ok
|
||||||
|
assert_equal 1000, json[:code]
|
||||||
|
@domain.reload
|
||||||
|
|
||||||
|
assert @domain.tech_contacts.find_by(code: new_contact.code).present?
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_can_remove_admin_contacts
|
||||||
|
contact = contacts(:john)
|
||||||
|
payload = { contacts: [ { code: contact.code, type: 'admin' } ] }
|
||||||
|
post "/repp/v1/domains/#{@domain.name}/contacts", headers: @auth_headers, params: payload
|
||||||
|
assert @domain.admin_contacts.find_by(code: contact.code).present?
|
||||||
|
|
||||||
|
# Actually delete the contact
|
||||||
|
delete "/repp/v1/domains/#{@domain.name}/contacts", headers: @auth_headers, params: payload
|
||||||
|
json = JSON.parse(response.body, symbolize_names: true)
|
||||||
|
|
||||||
|
assert_response :ok
|
||||||
|
assert_equal 1000, json[:code]
|
||||||
|
|
||||||
|
refute @domain.admin_contacts.find_by(code: contact.code).present?
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_can_remove_tech_contacts
|
||||||
|
contact = contacts(:john)
|
||||||
|
payload = { contacts: [ { code: contact.code, type: 'tech' } ] }
|
||||||
|
post "/repp/v1/domains/#{@domain.name}/contacts", headers: @auth_headers, params: payload
|
||||||
|
assert @domain.tech_contacts.find_by(code: contact.code).present?
|
||||||
|
|
||||||
|
# Actually delete the contact
|
||||||
|
delete "/repp/v1/domains/#{@domain.name}/contacts", headers: @auth_headers, params: payload
|
||||||
|
json = JSON.parse(response.body, symbolize_names: true)
|
||||||
|
|
||||||
|
assert_response :ok
|
||||||
|
assert_equal 1000, json[:code]
|
||||||
|
|
||||||
|
refute @domain.tech_contacts.find_by(code: contact.code).present?
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_can_not_remove_one_and_only_contact
|
||||||
|
contact = @domain.admin_contacts.last
|
||||||
|
|
||||||
|
payload = { contacts: [ { code: contact.code, type: 'admin' } ] }
|
||||||
|
delete "/repp/v1/domains/#{@domain.name}/contacts", headers: @auth_headers, params: payload
|
||||||
|
json = JSON.parse(response.body, symbolize_names: true)
|
||||||
|
|
||||||
|
@domain.reload
|
||||||
|
assert_response :bad_request
|
||||||
|
assert_equal 2004, json[:code]
|
||||||
|
|
||||||
|
assert @domain.admin_contacts.any?
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
137
test/integration/repp/v1/domains/create_test.rb
Normal file
137
test/integration/repp/v1/domains/create_test.rb
Normal file
|
@ -0,0 +1,137 @@
|
||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
class ReppV1DomainsCreateTest < ActionDispatch::IntegrationTest
|
||||||
|
def setup
|
||||||
|
@user = users(:api_bestnames)
|
||||||
|
@domain = domains(:shop)
|
||||||
|
token = Base64.encode64("#{@user.username}:#{@user.plain_text_password}")
|
||||||
|
token = "Basic #{token}"
|
||||||
|
|
||||||
|
@auth_headers = { 'Authorization' => token }
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_creates_new_domain_successfully
|
||||||
|
@auth_headers['Content-Type'] = 'application/json'
|
||||||
|
contact = contacts(:john)
|
||||||
|
|
||||||
|
payload = {
|
||||||
|
domain: {
|
||||||
|
name: 'domeener.test',
|
||||||
|
registrant: contact.code,
|
||||||
|
period: 1,
|
||||||
|
period_unit: 'y'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
post "/repp/v1/domains", headers: @auth_headers, params: payload.to_json
|
||||||
|
json = JSON.parse(response.body, symbolize_names: true)
|
||||||
|
assert_response :ok
|
||||||
|
assert_equal 1000, json[:code]
|
||||||
|
assert_equal 'Command completed successfully', json[:message]
|
||||||
|
|
||||||
|
assert @user.registrar.domains.find_by(name: 'domeener.test').present?
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_validates_price_on_domain_create
|
||||||
|
@auth_headers['Content-Type'] = 'application/json'
|
||||||
|
contact = contacts(:john)
|
||||||
|
|
||||||
|
payload = {
|
||||||
|
domain: {
|
||||||
|
name: 'domeener.test',
|
||||||
|
registrant: contact.code,
|
||||||
|
period: 3,
|
||||||
|
period_unit: 'y'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
post "/repp/v1/domains", headers: @auth_headers, params: payload.to_json
|
||||||
|
json = JSON.parse(response.body, symbolize_names: true)
|
||||||
|
assert_response :bad_request
|
||||||
|
assert_equal 2104, json[:code]
|
||||||
|
assert_equal 'Active price missing for this operation!', json[:message]
|
||||||
|
|
||||||
|
refute @user.registrar.domains.find_by(name: 'domeener.test').present?
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_creates_domain_with_predefined_nameservers
|
||||||
|
@auth_headers['Content-Type'] = 'application/json'
|
||||||
|
contact = contacts(:john)
|
||||||
|
|
||||||
|
payload = {
|
||||||
|
domain: {
|
||||||
|
name: 'domeener.test',
|
||||||
|
registrant: contact.code,
|
||||||
|
period: 1,
|
||||||
|
period_unit: 'y',
|
||||||
|
nameservers_attributes: [
|
||||||
|
{ hostname: 'ns1.domeener.ee' },
|
||||||
|
{ hostname: 'ns2.domeener.ee' }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
post "/repp/v1/domains", headers: @auth_headers, params: payload.to_json
|
||||||
|
json = JSON.parse(response.body, symbolize_names: true)
|
||||||
|
assert_response :ok
|
||||||
|
assert_equal 1000, json[:code]
|
||||||
|
assert_equal 'Command completed successfully', json[:message]
|
||||||
|
|
||||||
|
domain = @user.registrar.domains.find_by(name: 'domeener.test')
|
||||||
|
assert domain.present?
|
||||||
|
assert_empty ['ns1.domeener.ee', 'ns2.domeener.ee'] - domain.nameservers.collect(&:hostname)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_creates_domain_with_custom_contacts
|
||||||
|
@auth_headers['Content-Type'] = 'application/json'
|
||||||
|
contact = contacts(:john)
|
||||||
|
admin_contact = contacts(:william)
|
||||||
|
tech_contact = contacts(:jane)
|
||||||
|
|
||||||
|
payload = {
|
||||||
|
domain: {
|
||||||
|
name: 'domeener.test',
|
||||||
|
registrant: contact.code,
|
||||||
|
period: 1,
|
||||||
|
period_unit: 'y',
|
||||||
|
admin_contacts: [ admin_contact.code ],
|
||||||
|
tech_contacts: [ tech_contact.code ],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
post "/repp/v1/domains", headers: @auth_headers, params: payload.to_json
|
||||||
|
json = JSON.parse(response.body, symbolize_names: true)
|
||||||
|
assert_response :ok
|
||||||
|
assert_equal 1000, json[:code]
|
||||||
|
assert_equal 'Command completed successfully', json[:message]
|
||||||
|
|
||||||
|
domain = @user.registrar.domains.find_by(name: 'domeener.test')
|
||||||
|
assert domain.present?
|
||||||
|
assert_equal tech_contact, domain.tech_domain_contacts.first.contact
|
||||||
|
assert_equal admin_contact, domain.admin_domain_contacts.first.contact
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_creates_new_domain_with_desired_transfer_code
|
||||||
|
@auth_headers['Content-Type'] = 'application/json'
|
||||||
|
contact = contacts(:john)
|
||||||
|
|
||||||
|
payload = {
|
||||||
|
domain: {
|
||||||
|
name: 'domeener.test',
|
||||||
|
registrant: contact.code,
|
||||||
|
transfer_code: 'ABADIATS',
|
||||||
|
period: 1,
|
||||||
|
period_unit: 'y'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
post "/repp/v1/domains", headers: @auth_headers, params: payload.to_json
|
||||||
|
json = JSON.parse(response.body, symbolize_names: true)
|
||||||
|
assert_response :ok
|
||||||
|
assert_equal 1000, json[:code]
|
||||||
|
assert_equal 'Command completed successfully', json[:message]
|
||||||
|
|
||||||
|
assert @user.registrar.domains.find_by(name: 'domeener.test').present?
|
||||||
|
assert_equal 'ABADIATS', @user.registrar.domains.find_by(name: 'domeener.test').transfer_code
|
||||||
|
end
|
||||||
|
end
|
54
test/integration/repp/v1/domains/delete_test.rb
Normal file
54
test/integration/repp/v1/domains/delete_test.rb
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
class ReppV1DomainsDeleteTest < ActionDispatch::IntegrationTest
|
||||||
|
def setup
|
||||||
|
@user = users(:api_bestnames)
|
||||||
|
@domain = domains(:shop)
|
||||||
|
token = Base64.encode64("#{@user.username}:#{@user.plain_text_password}")
|
||||||
|
token = "Basic #{token}"
|
||||||
|
|
||||||
|
@auth_headers = { 'Authorization' => token }
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_domain_pending_delete_confirmation
|
||||||
|
Setting.request_confirmation_on_domain_deletion_enabled = true
|
||||||
|
@auth_headers['Content-Type'] = 'application/json'
|
||||||
|
|
||||||
|
payload = {
|
||||||
|
delete: {
|
||||||
|
verified: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delete "/repp/v1/domains/#{@domain.name}", headers: @auth_headers, params: payload.to_json
|
||||||
|
@domain.reload
|
||||||
|
json = JSON.parse(response.body, symbolize_names: true)
|
||||||
|
assert_response :ok
|
||||||
|
assert_equal 1000, json[:code]
|
||||||
|
assert_equal 'Command completed successfully', json[:message]
|
||||||
|
|
||||||
|
assert @domain.statuses.include? DomainStatus::PENDING_DELETE_CONFIRMATION
|
||||||
|
assert_not @domain.statuses.include? DomainStatus::PENDING_DELETE
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_domain_pending_delete_on_verified_delete
|
||||||
|
Setting.request_confirmation_on_domain_deletion_enabled = true
|
||||||
|
@auth_headers['Content-Type'] = 'application/json'
|
||||||
|
|
||||||
|
payload = {
|
||||||
|
delete: {
|
||||||
|
verified: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delete "/repp/v1/domains/#{@domain.name}", headers: @auth_headers, params: payload.to_json
|
||||||
|
@domain.reload
|
||||||
|
json = JSON.parse(response.body, symbolize_names: true)
|
||||||
|
assert_response :ok
|
||||||
|
assert_equal 1000, json[:code]
|
||||||
|
assert_equal 'Command completed successfully', json[:message]
|
||||||
|
|
||||||
|
refute @domain.statuses.include? DomainStatus::PENDING_DELETE_CONFIRMATION
|
||||||
|
assert @domain.statuses.include? DomainStatus::PENDING_DELETE
|
||||||
|
end
|
||||||
|
end
|
96
test/integration/repp/v1/domains/dnssec_test.rb
Normal file
96
test/integration/repp/v1/domains/dnssec_test.rb
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
class ReppV1DomainsDnssecTest < ActionDispatch::IntegrationTest
|
||||||
|
def setup
|
||||||
|
@user = users(:api_bestnames)
|
||||||
|
@domain = domains(:shop)
|
||||||
|
token = Base64.encode64("#{@user.username}:#{@user.plain_text_password}")
|
||||||
|
token = "Basic #{token}"
|
||||||
|
|
||||||
|
@auth_headers = { 'Authorization' => token }
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_shows_dnssec_keys_associated_with_domain
|
||||||
|
get "/repp/v1/domains/#{@domain.name}/dnssec", headers: @auth_headers
|
||||||
|
json = JSON.parse(response.body, symbolize_names: true)
|
||||||
|
|
||||||
|
assert_response :ok
|
||||||
|
assert_equal 1000, json[:code]
|
||||||
|
assert_equal 'Command completed successfully', json[:message]
|
||||||
|
assert_empty json[:data][:dns_keys]
|
||||||
|
|
||||||
|
payload = {
|
||||||
|
dns_keys: [
|
||||||
|
{ flags: '256',
|
||||||
|
alg: '14',
|
||||||
|
protocol: '3',
|
||||||
|
public_key: 'dGVzdA=='
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
post "/repp/v1/domains/#{@domain.name}/dnssec", params: payload, headers: @auth_headers
|
||||||
|
json = JSON.parse(response.body, symbolize_names: true)
|
||||||
|
|
||||||
|
get "/repp/v1/domains/#{@domain.name}/dnssec", headers: @auth_headers
|
||||||
|
json = JSON.parse(response.body, symbolize_names: true)
|
||||||
|
|
||||||
|
assert_equal 1, json[:data][:dns_keys].length
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_creates_dnssec_key_successfully
|
||||||
|
assert @domain.dnskeys.empty?
|
||||||
|
payload = {
|
||||||
|
dns_keys: [
|
||||||
|
{ flags: '256',
|
||||||
|
alg: '14',
|
||||||
|
protocol: '3',
|
||||||
|
public_key: 'dGVzdA=='
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
post "/repp/v1/domains/#{@domain.name}/dnssec", params: payload, headers: @auth_headers
|
||||||
|
json = JSON.parse(response.body, symbolize_names: true)
|
||||||
|
@domain.reload
|
||||||
|
|
||||||
|
assert_response :ok
|
||||||
|
assert_equal 1000, json[:code]
|
||||||
|
assert_equal 'Command completed successfully', json[:message]
|
||||||
|
|
||||||
|
assert @domain.dnskeys.present?
|
||||||
|
dnssec_key = @domain.dnskeys.last
|
||||||
|
assert_equal payload[:dns_keys][0][:flags].to_i, dnssec_key.flags
|
||||||
|
assert_equal payload[:dns_keys][0][:alg].to_i, dnssec_key.alg
|
||||||
|
assert_equal payload[:dns_keys][0][:protocol].to_i, dnssec_key.protocol
|
||||||
|
assert_equal payload[:dns_keys][0][:public_key], dnssec_key.public_key
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_removes_existing_dnssec_key_successfully
|
||||||
|
payload = {
|
||||||
|
dns_keys: [
|
||||||
|
{ flags: '256',
|
||||||
|
alg: '14',
|
||||||
|
protocol: '3',
|
||||||
|
public_key: 'dGVzdA=='
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
post "/repp/v1/domains/#{@domain.name}/dnssec", params: payload, headers: @auth_headers
|
||||||
|
json = JSON.parse(response.body, symbolize_names: true)
|
||||||
|
|
||||||
|
assert @domain.dnskeys.any?
|
||||||
|
|
||||||
|
# Real delete here
|
||||||
|
delete "/repp/v1/domains/#{@domain.name}/dnssec", params: payload, headers: @auth_headers
|
||||||
|
json = JSON.parse(response.body, symbolize_names: true)
|
||||||
|
@domain.reload
|
||||||
|
|
||||||
|
assert_response :ok
|
||||||
|
assert_equal 1000, json[:code]
|
||||||
|
assert_equal 'Command completed successfully', json[:message]
|
||||||
|
|
||||||
|
assert @domain.dnskeys.empty?
|
||||||
|
end
|
||||||
|
end
|
|
@ -51,4 +51,17 @@ class ReppV1DomainsListTest < ActionDispatch::IntegrationTest
|
||||||
|
|
||||||
assert_equal (@user.registrar.domains.count - offset), json[:data][:domains].length
|
assert_equal (@user.registrar.domains.count - offset), json[:data][:domains].length
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_returns_specific_domain_details_by_name
|
||||||
|
domain = domains(:shop)
|
||||||
|
get "/repp/v1/domains/#{domain.name}", headers: @auth_headers
|
||||||
|
json = JSON.parse(response.body, symbolize_names: true)
|
||||||
|
|
||||||
|
assert_response :ok
|
||||||
|
assert_equal 1000, json[:code]
|
||||||
|
assert_equal 'Command completed successfully', json[:message]
|
||||||
|
|
||||||
|
serialized_domain = Serializers::Repp::Domain.new(domain).to_json
|
||||||
|
assert_equal serialized_domain.as_json, json[:data][:domain].as_json
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
94
test/integration/repp/v1/domains/nameservers_test.rb
Normal file
94
test/integration/repp/v1/domains/nameservers_test.rb
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
class ReppV1DomainsNameserversTest < ActionDispatch::IntegrationTest
|
||||||
|
def setup
|
||||||
|
@user = users(:api_bestnames)
|
||||||
|
@domain = domains(:shop)
|
||||||
|
token = Base64.encode64("#{@user.username}:#{@user.plain_text_password}")
|
||||||
|
token = "Basic #{token}"
|
||||||
|
|
||||||
|
@auth_headers = { 'Authorization' => token }
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_can_add_new_nameserver
|
||||||
|
payload = {
|
||||||
|
nameservers: [
|
||||||
|
{ hostname: "ns1.domeener.ee",
|
||||||
|
ipv4: ["192.168.1.1"],
|
||||||
|
ipv6: ["FE80::AEDE:48FF:FE00:1122"]}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
post "/repp/v1/domains/#{@domain.name}/nameservers", params: payload, headers: @auth_headers
|
||||||
|
json = JSON.parse(response.body, symbolize_names: true)
|
||||||
|
|
||||||
|
assert_response :ok
|
||||||
|
assert_equal 1000, json[:code]
|
||||||
|
assert_equal 'Command completed successfully', json[:message]
|
||||||
|
assert_equal payload[:nameservers][0][:hostname], @domain.nameservers.last.hostname
|
||||||
|
assert_equal payload[:nameservers][0][:ipv4], @domain.nameservers.last.ipv4
|
||||||
|
assert_equal payload[:nameservers][0][:ipv6], @domain.nameservers.last.ipv6
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_can_remove_existing_nameserver
|
||||||
|
payload = {
|
||||||
|
nameservers: [
|
||||||
|
{ hostname: "ns1.domeener.ee",
|
||||||
|
ipv4: ["192.168.1.1"],
|
||||||
|
ipv6: ["FE80::AEDE:48FF:FE00:1122"]}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
post "/repp/v1/domains/#{@domain.name}/nameservers", params: payload, headers: @auth_headers
|
||||||
|
assert_response :ok
|
||||||
|
|
||||||
|
@domain.reload
|
||||||
|
assert @domain.nameservers.where(hostname: payload[:nameservers][0][:hostname]).any?
|
||||||
|
|
||||||
|
delete "/repp/v1/domains/#{@domain.name}/nameservers/#{payload[:nameservers][0][:hostname]}",
|
||||||
|
params: payload, headers: @auth_headers
|
||||||
|
json = JSON.parse(response.body, symbolize_names: true)
|
||||||
|
|
||||||
|
assert_response :ok
|
||||||
|
assert_equal 1000, json[:code]
|
||||||
|
assert_equal 'Command completed successfully', json[:message]
|
||||||
|
|
||||||
|
@domain.reload
|
||||||
|
refute @domain.nameservers.where(hostname: payload[:nameservers][0][:hostname]).any?
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_can_not_add_duplicate_nameserver
|
||||||
|
payload = {
|
||||||
|
nameservers: [
|
||||||
|
{ hostname: @domain.nameservers.last.hostname,
|
||||||
|
ipv4: @domain.nameservers.last.ipv4,
|
||||||
|
ipv6: @domain.nameservers.last.ipv6 }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
post "/repp/v1/domains/#{@domain.name}/nameservers", params: payload, headers: @auth_headers
|
||||||
|
json = JSON.parse(response.body, symbolize_names: true)
|
||||||
|
assert_response :bad_request
|
||||||
|
assert_equal 2302, json[:code]
|
||||||
|
assert_equal 'Nameserver already exists on this domain [hostname]', json[:message]
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_returns_errors_when_removing_unknown_nameserver
|
||||||
|
delete "/repp/v1/domains/#{@domain.name}/nameservers/ns.nonexistant.test", headers: @auth_headers
|
||||||
|
json = JSON.parse(response.body, symbolize_names: true)
|
||||||
|
|
||||||
|
assert_response :not_found
|
||||||
|
assert_equal 2303, json[:code]
|
||||||
|
assert_equal 'Object does not exist', json[:message]
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_returns_error_when_ns_count_too_low
|
||||||
|
delete "/repp/v1/domains/#{@domain.name}/nameservers/#{@domain.nameservers.last.hostname}", headers: @auth_headers
|
||||||
|
json = JSON.parse(response.body, symbolize_names: true)
|
||||||
|
|
||||||
|
assert_response :bad_request
|
||||||
|
assert_equal 2308, json[:code]
|
||||||
|
assert_equal 'Data management policy violation; Nameserver count must be between 2-11 for active ' \
|
||||||
|
'domains [nameservers]', json[:message]
|
||||||
|
end
|
||||||
|
end
|
66
test/integration/repp/v1/domains/renews_test.rb
Normal file
66
test/integration/repp/v1/domains/renews_test.rb
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
class ReppV1DomainsRenewsTest < ActionDispatch::IntegrationTest
|
||||||
|
def setup
|
||||||
|
@user = users(:api_bestnames)
|
||||||
|
@domain = domains(:shop)
|
||||||
|
token = Base64.encode64("#{@user.username}:#{@user.plain_text_password}")
|
||||||
|
token = "Basic #{token}"
|
||||||
|
|
||||||
|
@auth_headers = { 'Authorization' => token }
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_domain_can_be_renewed
|
||||||
|
original_valid_to = @domain.valid_to
|
||||||
|
travel_to Time.zone.parse('2010-07-05')
|
||||||
|
|
||||||
|
@auth_headers['Content-Type'] = 'application/json'
|
||||||
|
payload = { renew: { period: 1, period_unit: 'y', exp_date: original_valid_to } }
|
||||||
|
post "/repp/v1/domains/#{@domain.name}/renew", headers: @auth_headers, params: payload.to_json
|
||||||
|
json = JSON.parse(response.body, symbolize_names: true)
|
||||||
|
|
||||||
|
assert_response :ok
|
||||||
|
assert_equal 1000, json[:code]
|
||||||
|
assert_equal 'Command completed successfully', json[:message]
|
||||||
|
|
||||||
|
assert @domain.valid_to, original_valid_to + 1.year
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_domain_renew_pricing_error
|
||||||
|
original_valid_to = @domain.valid_to
|
||||||
|
travel_to Time.zone.parse('2010-07-05')
|
||||||
|
|
||||||
|
@auth_headers['Content-Type'] = 'application/json'
|
||||||
|
payload = { renew: { period: 100, period_unit: 'y', exp_date: original_valid_to } }
|
||||||
|
post "/repp/v1/domains/#{@domain.name}/renew", headers: @auth_headers, params: payload.to_json
|
||||||
|
json = JSON.parse(response.body, symbolize_names: true)
|
||||||
|
|
||||||
|
assert_response :bad_request
|
||||||
|
assert_equal 2104, json[:code]
|
||||||
|
assert_equal 'Active price missing for this operation!', json[:message]
|
||||||
|
|
||||||
|
assert @domain.valid_to, original_valid_to
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_some_test
|
||||||
|
days_to_renew_domain_before_expire = setting_entries(:days_to_renew_domain_before_expire)
|
||||||
|
days_to_renew_domain_before_expire.update(value: '1')
|
||||||
|
days_to_renew_domain_before_expire.reload
|
||||||
|
|
||||||
|
original_valid_to = @domain.valid_to
|
||||||
|
travel_to @domain.valid_to - 3.days
|
||||||
|
|
||||||
|
one_year = billing_prices(:renew_one_year)
|
||||||
|
one_year.update(valid_from: @domain.valid_to - 5.days)
|
||||||
|
one_year.reload
|
||||||
|
|
||||||
|
@auth_headers['Content-Type'] = 'application/json'
|
||||||
|
payload = { renew: { period: 1, period_unit: 'y', exp_date: original_valid_to } }
|
||||||
|
post "/repp/v1/domains/#{@domain.name}/renew", headers: @auth_headers, params: payload.to_json
|
||||||
|
json = JSON.parse(response.body, symbolize_names: true)
|
||||||
|
|
||||||
|
assert_response :bad_request
|
||||||
|
assert_equal 2304, json[:code]
|
||||||
|
assert_equal 'Object status prohibits operation', json[:message]
|
||||||
|
end
|
||||||
|
end
|
82
test/integration/repp/v1/domains/statuses_test.rb
Normal file
82
test/integration/repp/v1/domains/statuses_test.rb
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
class ReppV1DomainsStatusesTest < ActionDispatch::IntegrationTest
|
||||||
|
def setup
|
||||||
|
@user = users(:api_bestnames)
|
||||||
|
@domain = domains(:shop)
|
||||||
|
token = Base64.encode64("#{@user.username}:#{@user.plain_text_password}")
|
||||||
|
token = "Basic #{token}"
|
||||||
|
|
||||||
|
@auth_headers = { 'Authorization' => token }
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_client_hold_can_be_added
|
||||||
|
refute @domain.statuses.include?(DomainStatus::CLIENT_HOLD)
|
||||||
|
put repp_v1_domain_status_path(domain_id: @domain.name, id: DomainStatus::CLIENT_HOLD), headers: @auth_headers
|
||||||
|
json = JSON.parse(response.body, symbolize_names: true)
|
||||||
|
|
||||||
|
assert_response :ok
|
||||||
|
@domain.reload
|
||||||
|
|
||||||
|
assert @domain.statuses.include?(DomainStatus::CLIENT_HOLD)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_client_hold_can_be_removed
|
||||||
|
statuses = @domain.statuses << DomainStatus::CLIENT_HOLD
|
||||||
|
@domain.update(statuses: statuses)
|
||||||
|
delete repp_v1_domain_status_path(domain_id: @domain.name, id: DomainStatus::CLIENT_HOLD), headers: @auth_headers
|
||||||
|
|
||||||
|
assert_response :ok
|
||||||
|
@domain.reload
|
||||||
|
refute @domain.statuses.include?(DomainStatus::CLIENT_HOLD)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_can_not_remove_disallowed_statuses
|
||||||
|
statuses = @domain.statuses << DomainStatus::FORCE_DELETE
|
||||||
|
@domain.update(statuses: statuses)
|
||||||
|
|
||||||
|
delete repp_v1_domain_status_path(domain_id: @domain.name, id: DomainStatus::FORCE_DELETE), headers: @auth_headers
|
||||||
|
@domain.reload
|
||||||
|
json = JSON.parse(response.body, symbolize_names: true)
|
||||||
|
|
||||||
|
assert_response :bad_request
|
||||||
|
assert_equal 'Parameter value policy error. Client-side object status management not supported: status serverForceDelete', json[:message]
|
||||||
|
|
||||||
|
assert @domain.statuses.include?(DomainStatus::FORCE_DELETE)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_can_not_add_disallowed_statuses
|
||||||
|
put repp_v1_domain_status_path(domain_id: @domain.name, id: DomainStatus::DELETE_CANDIDATE), headers: @auth_headers
|
||||||
|
@domain.reload
|
||||||
|
json = JSON.parse(response.body, symbolize_names: true)
|
||||||
|
|
||||||
|
assert_response :bad_request
|
||||||
|
assert_equal 'Parameter value policy error. Client-side object status management not supported: status deleteCandidate', json[:message]
|
||||||
|
|
||||||
|
refute @domain.statuses.include?(DomainStatus::DELETE_CANDIDATE)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_can_not_remove_unexistant_status
|
||||||
|
refute @domain.statuses.include?(DomainStatus::CLIENT_HOLD)
|
||||||
|
delete repp_v1_domain_status_path(domain_id: @domain.name, id: DomainStatus::CLIENT_HOLD), headers: @auth_headers
|
||||||
|
json = JSON.parse(response.body, symbolize_names: true)
|
||||||
|
|
||||||
|
assert_response :bad_request
|
||||||
|
assert_equal 'Parameter value policy error. Client-side object status management not supported: status clientHold', json[:message]
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_returns_normal_error_when_action_fails
|
||||||
|
@invalid_domain = domains(:invalid)
|
||||||
|
|
||||||
|
put repp_v1_domain_status_path(domain_id: @invalid_domain.name, id: DomainStatus::CLIENT_HOLD), headers: @auth_headers
|
||||||
|
json = JSON.parse(response.body, symbolize_names: true)
|
||||||
|
assert_response :bad_request
|
||||||
|
assert_equal 2304, json[:code]
|
||||||
|
|
||||||
|
delete repp_v1_domain_status_path(domain_id: @invalid_domain.name, id: DomainStatus::FORCE_DELETE), headers: @auth_headers
|
||||||
|
json = JSON.parse(response.body, symbolize_names: true)
|
||||||
|
assert_response :bad_request
|
||||||
|
assert_equal 2306, json[:code]
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -28,6 +28,7 @@ class ReppV1DomainsTransferInfoTest < ActionDispatch::IntegrationTest
|
||||||
def test_respects_domain_authorization_code
|
def test_respects_domain_authorization_code
|
||||||
headers = @auth_headers
|
headers = @auth_headers
|
||||||
headers['Auth-Code'] = 'jhfgifhdg'
|
headers['Auth-Code'] = 'jhfgifhdg'
|
||||||
|
@domain.update!(registrar: registrars(:goodnames))
|
||||||
|
|
||||||
get "/repp/v1/domains/#{@domain.name}/transfer_info", headers: headers
|
get "/repp/v1/domains/#{@domain.name}/transfer_info", headers: headers
|
||||||
json = JSON.parse(response.body, symbolize_names: true)
|
json = JSON.parse(response.body, symbolize_names: true)
|
||||||
|
|
|
@ -10,6 +10,34 @@ class ReppV1DomainsTransferTest < ActionDispatch::IntegrationTest
|
||||||
@auth_headers = { 'Authorization' => token }
|
@auth_headers = { 'Authorization' => token }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_transfers_scoped_domain
|
||||||
|
refute @domain.registrar == @user.registrar
|
||||||
|
payload = { transfer: { transfer_code: @domain.transfer_code } }
|
||||||
|
post "/repp/v1/domains/#{@domain.name}/transfer", headers: @auth_headers, params: payload
|
||||||
|
json = JSON.parse(response.body, symbolize_names: true)
|
||||||
|
@domain.reload
|
||||||
|
|
||||||
|
assert_response :ok
|
||||||
|
assert_equal 1000, json[:code]
|
||||||
|
assert_equal 'Command completed successfully', json[:message]
|
||||||
|
|
||||||
|
assert_equal @domain.registrar, @user.registrar
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_does_not_transfer_scoped_domain_with_invalid_transfer_code
|
||||||
|
refute @domain.registrar == @user.registrar
|
||||||
|
payload = { transfer: { transfer_code: 'invalid' } }
|
||||||
|
post "/repp/v1/domains/#{@domain.name}/transfer", headers: @auth_headers, params: payload
|
||||||
|
json = JSON.parse(response.body, symbolize_names: true)
|
||||||
|
@domain.reload
|
||||||
|
|
||||||
|
assert_response :bad_request
|
||||||
|
assert_equal 2202, json[:code]
|
||||||
|
assert_equal 'Invalid authorization information', json[:message]
|
||||||
|
|
||||||
|
refute @domain.registrar == @user.registrar
|
||||||
|
end
|
||||||
|
|
||||||
def test_transfers_domain
|
def test_transfers_domain
|
||||||
payload = {
|
payload = {
|
||||||
"data": {
|
"data": {
|
||||||
|
|
85
test/integration/repp/v1/domains/update_test.rb
Normal file
85
test/integration/repp/v1/domains/update_test.rb
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
class ReppV1DomainsUpdateTest < ActionDispatch::IntegrationTest
|
||||||
|
def setup
|
||||||
|
@user = users(:api_bestnames)
|
||||||
|
@domain = domains(:shop)
|
||||||
|
token = Base64.encode64("#{@user.username}:#{@user.plain_text_password}")
|
||||||
|
token = "Basic #{token}"
|
||||||
|
|
||||||
|
@auth_headers = { 'Authorization' => token }
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_updates_transfer_code_for_domain
|
||||||
|
@auth_headers['Content-Type'] = 'application/json'
|
||||||
|
new_auth_code = 'aisdcbkabcsdnc'
|
||||||
|
|
||||||
|
payload = {
|
||||||
|
domain: {
|
||||||
|
auth_code: new_auth_code
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
put "/repp/v1/domains/#{@domain.name}", headers: @auth_headers, params: payload.to_json
|
||||||
|
@domain.reload
|
||||||
|
json = JSON.parse(response.body, symbolize_names: true)
|
||||||
|
assert_response :ok
|
||||||
|
assert_equal 1000, json[:code]
|
||||||
|
assert_equal 'Command completed successfully', json[:message]
|
||||||
|
|
||||||
|
assert new_auth_code, @domain.auth_info
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_domain_pending_update_on_registrant_change
|
||||||
|
Setting.request_confirmation_on_registrant_change_enabled = true
|
||||||
|
|
||||||
|
@auth_headers['Content-Type'] = 'application/json'
|
||||||
|
new_registrant = contacts(:william)
|
||||||
|
refute @domain.registrant == new_registrant
|
||||||
|
|
||||||
|
payload = {
|
||||||
|
domain: {
|
||||||
|
registrant: {
|
||||||
|
code: new_registrant.code
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
put "/repp/v1/domains/#{@domain.name}", headers: @auth_headers, params: payload.to_json
|
||||||
|
@domain.reload
|
||||||
|
json = JSON.parse(response.body, symbolize_names: true)
|
||||||
|
assert_response :ok
|
||||||
|
assert_equal 1000, json[:code]
|
||||||
|
assert_equal 'Command completed successfully', json[:message]
|
||||||
|
|
||||||
|
refute @domain.registrant.code == new_registrant.code
|
||||||
|
assert @domain.statuses.include? DomainStatus::PENDING_UPDATE
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_replaces_registrant_when_verified
|
||||||
|
Setting.request_confirmation_on_registrant_change_enabled = true
|
||||||
|
|
||||||
|
@auth_headers['Content-Type'] = 'application/json'
|
||||||
|
new_registrant = contacts(:william)
|
||||||
|
refute @domain.registrant == new_registrant
|
||||||
|
|
||||||
|
payload = {
|
||||||
|
domain: {
|
||||||
|
registrant: {
|
||||||
|
code: new_registrant.code,
|
||||||
|
verified: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
put "/repp/v1/domains/#{@domain.name}", headers: @auth_headers, params: payload.to_json
|
||||||
|
@domain.reload
|
||||||
|
json = JSON.parse(response.body, symbolize_names: true)
|
||||||
|
assert_response :ok
|
||||||
|
assert_equal 1000, json[:code]
|
||||||
|
assert_equal 'Command completed successfully', json[:message]
|
||||||
|
|
||||||
|
assert @domain.registrant.code == new_registrant.code
|
||||||
|
refute @domain.statuses.include? DomainStatus::PENDING_UPDATE
|
||||||
|
end
|
||||||
|
end
|
|
@ -101,4 +101,79 @@ class ReppV1RegistrarNameserversTest < ActionDispatch::IntegrationTest
|
||||||
assert_equal 2005, json[:code]
|
assert_equal 2005, json[:code]
|
||||||
assert_equal 'IPv6 is invalid [ipv6]', json[:message]
|
assert_equal 'IPv6 is invalid [ipv6]', json[:message]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_ipv4_isnt_array
|
||||||
|
nameserver = nameservers(:shop_ns1)
|
||||||
|
payload = {
|
||||||
|
"data": {
|
||||||
|
"id": nameserver.hostname,
|
||||||
|
"type": "nameserver",
|
||||||
|
"domains": ["shop.test", "airport.test", "library.test", "metro.test"],
|
||||||
|
"attributes": {
|
||||||
|
"hostname": nameserver.hostname,
|
||||||
|
"ipv4": "1.1.1.1",
|
||||||
|
"ipv6": ["2620:119:352::36"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
put '/repp/v1/registrar/nameservers', headers: @auth_headers, params: payload
|
||||||
|
json = JSON.parse(response.body, symbolize_names: true)
|
||||||
|
|
||||||
|
assert_response :bad_request
|
||||||
|
assert_equal 2005, json[:code]
|
||||||
|
assert json[:message].include? 'Must be an array of String'
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_ipv6_isnt_array
|
||||||
|
nameserver = nameservers(:shop_ns1)
|
||||||
|
payload = {
|
||||||
|
"data": {
|
||||||
|
"id": nameserver.hostname,
|
||||||
|
"type": "nameserver",
|
||||||
|
"domains": ["shop.test", "airport.test", "library.test", "metro.test"],
|
||||||
|
"attributes": {
|
||||||
|
"hostname": nameserver.hostname,
|
||||||
|
"ipv4": ["1.1.1.1"],
|
||||||
|
"ipv6": "2620:119:352::36"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
put '/repp/v1/registrar/nameservers', headers: @auth_headers, params: payload
|
||||||
|
json = JSON.parse(response.body, symbolize_names: true)
|
||||||
|
|
||||||
|
assert_response :bad_request
|
||||||
|
assert_equal 2005, json[:code]
|
||||||
|
assert json[:message].include? 'Must be an array of String'
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_bulk_nameservers_change_in_array_of_domains
|
||||||
|
domain_shop = domains(:shop)
|
||||||
|
domain_airport = domains(:airport)
|
||||||
|
|
||||||
|
payload = {
|
||||||
|
"data": {
|
||||||
|
"type": "nameserver",
|
||||||
|
"id": "ns1.bestnames.test",
|
||||||
|
"domains": ["shop.test", "airport.test"],
|
||||||
|
"attributes": {
|
||||||
|
"hostname": "ns4.bestnames.test",
|
||||||
|
"ipv4": ["192.168.1.1"],
|
||||||
|
"ipv6": ["2620:119:35::36"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
put '/repp/v1/registrar/nameservers', headers: @auth_headers, params: payload
|
||||||
|
json = JSON.parse(response.body, symbolize_names: true)
|
||||||
|
domain_airport.reload
|
||||||
|
domain_shop.reload
|
||||||
|
|
||||||
|
refute domain_shop.nameservers.find_by(hostname: 'ns1.bestnames.test').present?
|
||||||
|
assert domain_shop.nameservers.find_by(hostname: 'ns4.bestnames.test').present?
|
||||||
|
assert_equal({ hostname: "ns4.bestnames.test", ipv4: ["192.168.1.1"], ipv6: ["2620:119:35::36"] }, json[:data][:attributes])
|
||||||
|
assert json[:data][:affected_domains].include? 'airport.test'
|
||||||
|
assert json[:data][:affected_domains].include? 'shop.test'
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
50
test/integration/repp/v1/registrar/notifications_test.rb
Normal file
50
test/integration/repp/v1/registrar/notifications_test.rb
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
class ReppV1RegistrarNotificationsTest < ActionDispatch::IntegrationTest
|
||||||
|
def setup
|
||||||
|
@user = users(:api_bestnames)
|
||||||
|
token = Base64.encode64("#{@user.username}:#{@user.plain_text_password}")
|
||||||
|
token = "Basic #{token}"
|
||||||
|
|
||||||
|
@auth_headers = { 'Authorization' => token }
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_gets_latest_unread_poll_message
|
||||||
|
notification = @user.registrar.notifications.where(read: false).order(created_at: :desc).first
|
||||||
|
get "/repp/v1/registrar/notifications", headers: @auth_headers
|
||||||
|
json = JSON.parse(response.body, symbolize_names: true)
|
||||||
|
|
||||||
|
assert_response :ok
|
||||||
|
assert_equal 1000, json[:code]
|
||||||
|
assert_equal 'Command completed successfully', json[:message]
|
||||||
|
assert_equal notification.text, json[:data][:text]
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_can_read_specific_notification_by_id
|
||||||
|
notification = @user.registrar.notifications.order(created_at: :desc).second
|
||||||
|
|
||||||
|
get "/repp/v1/registrar/notifications/#{notification.id}", headers: @auth_headers
|
||||||
|
json = JSON.parse(response.body, symbolize_names: true)
|
||||||
|
|
||||||
|
assert_response :ok
|
||||||
|
assert_equal 1000, json[:code]
|
||||||
|
assert_equal 'Command completed successfully', json[:message]
|
||||||
|
assert_equal notification.text, json[:data][:text]
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_can_mark_notification_as_read
|
||||||
|
@auth_headers['Content-Type'] = 'application/json'
|
||||||
|
notification = @user.registrar.notifications.where(read: false).order(created_at: :desc).first
|
||||||
|
|
||||||
|
payload = { notification: { read: true} }
|
||||||
|
put "/repp/v1/registrar/notifications/#{notification.id}", headers: @auth_headers, params: payload.to_json
|
||||||
|
json = JSON.parse(response.body, symbolize_names: true)
|
||||||
|
notification.reload
|
||||||
|
|
||||||
|
assert_response :ok
|
||||||
|
assert_equal 1000, json[:code]
|
||||||
|
assert_equal 'Command completed successfully', json[:message]
|
||||||
|
assert_equal notification.id, json[:data][:notification_id]
|
||||||
|
assert_equal notification.read, json[:data][:read]
|
||||||
|
end
|
||||||
|
end
|
|
@ -77,7 +77,7 @@ class ReppV1RetainedDomainsTest < ActionDispatch::IntegrationTest
|
||||||
status: 'disputed',
|
status: 'disputed',
|
||||||
punycode_name: 'reserved.test' }]
|
punycode_name: 'reserved.test' }]
|
||||||
|
|
||||||
assert_empty response_json[:domains] - expected_objects
|
assert_equal response_json[:domains].to_set, expected_objects.to_set
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_etags_cache
|
def test_etags_cache
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
require "test_helper"
|
require "test_helper"
|
||||||
|
require 'deserializers/xml/domain_update'
|
||||||
|
|
||||||
class DomainUpdateConfirmJobTest < ActiveSupport::TestCase
|
class DomainUpdateConfirmJobTest < ActiveSupport::TestCase
|
||||||
def setup
|
def setup
|
||||||
super
|
super
|
||||||
|
@ -55,7 +57,9 @@ class DomainUpdateConfirmJobTest < ActiveSupport::TestCase
|
||||||
" <chg>\n <registrant>#{@new_registrant.code}</registrant>\n </chg>\n </update>\n </update>\n <extension>\n <update/>\n" \
|
" <chg>\n <registrant>#{@new_registrant.code}</registrant>\n </chg>\n </update>\n </update>\n <extension>\n <update/>\n" \
|
||||||
" <extdata>\n <legalDocument type=\"pdf\">#{@legal_doc_path}</legalDocument>\n </extdata>\n" \
|
" <extdata>\n <legalDocument type=\"pdf\">#{@legal_doc_path}</legalDocument>\n </extdata>\n" \
|
||||||
" </extension>\n <clTRID>20alla-1594199756</clTRID>\n </command>\n</epp>\n"
|
" </extension>\n <clTRID>20alla-1594199756</clTRID>\n </command>\n</epp>\n"
|
||||||
@domain.pending_json['frame'] = epp_xml
|
parsed_frame = Deserializers::Xml::DomainUpdate.new(Nokogiri::XML(epp_xml), @domain.registrar.id).call
|
||||||
|
|
||||||
|
@domain.pending_json['frame'] = parsed_frame
|
||||||
@domain.update(pending_json: @domain.pending_json)
|
@domain.update(pending_json: @domain.pending_json)
|
||||||
|
|
||||||
@domain.reload
|
@domain.reload
|
||||||
|
@ -71,7 +75,9 @@ class DomainUpdateConfirmJobTest < ActiveSupport::TestCase
|
||||||
" <chg>\n <registrant>#{@new_registrant.code}</registrant>\n </chg>\n </update>\n </update>\n <extension>\n <update/>\n" \
|
" <chg>\n <registrant>#{@new_registrant.code}</registrant>\n </chg>\n </update>\n </update>\n <extension>\n <update/>\n" \
|
||||||
" <extdata>\n <legalDocument type=\"pdf\">#{@legal_doc_path}</legalDocument>\n </extdata>\n" \
|
" <extdata>\n <legalDocument type=\"pdf\">#{@legal_doc_path}</legalDocument>\n </extdata>\n" \
|
||||||
" </extension>\n <clTRID>20alla-1594199756</clTRID>\n </command>\n</epp>\n"
|
" </extension>\n <clTRID>20alla-1594199756</clTRID>\n </command>\n</epp>\n"
|
||||||
@domain.pending_json['frame'] = epp_xml
|
parsed_frame = Deserializers::Xml::DomainUpdate.new(Nokogiri::XML(epp_xml), @domain.registrar.id).call
|
||||||
|
|
||||||
|
@domain.pending_json['frame'] = parsed_frame
|
||||||
@domain.update(pending_json: @domain.pending_json)
|
@domain.update(pending_json: @domain.pending_json)
|
||||||
|
|
||||||
DomainUpdateConfirmJob.perform_now(@domain.id, RegistrantVerification::REJECTED)
|
DomainUpdateConfirmJob.perform_now(@domain.id, RegistrantVerification::REJECTED)
|
||||||
|
@ -86,7 +92,9 @@ class DomainUpdateConfirmJobTest < ActiveSupport::TestCase
|
||||||
" <chg>\n <registrant>#{@new_registrant.code}</registrant>\n </chg>\n </update>\n </update>\n <extension>\n <update/>\n" \
|
" <chg>\n <registrant>#{@new_registrant.code}</registrant>\n </chg>\n </update>\n </update>\n <extension>\n <update/>\n" \
|
||||||
" <extdata>\n <legalDocument type=\"pdf\">#{@legal_doc_path}</legalDocument>\n </extdata>\n" \
|
" <extdata>\n <legalDocument type=\"pdf\">#{@legal_doc_path}</legalDocument>\n </extdata>\n" \
|
||||||
" </extension>\n <clTRID>20alla-1594199756</clTRID>\n </command>\n</epp>\n"
|
" </extension>\n <clTRID>20alla-1594199756</clTRID>\n </command>\n</epp>\n"
|
||||||
@domain.pending_json['frame'] = epp_xml
|
parsed_frame = Deserializers::Xml::DomainUpdate.new(Nokogiri::XML(epp_xml), @domain.registrar.id).call
|
||||||
|
|
||||||
|
@domain.pending_json['frame'] = parsed_frame
|
||||||
@domain.update(pending_json: @domain.pending_json)
|
@domain.update(pending_json: @domain.pending_json)
|
||||||
@domain.update(statuses: [DomainStatus::DELETE_CANDIDATE, DomainStatus::DISPUTED])
|
@domain.update(statuses: [DomainStatus::DELETE_CANDIDATE, DomainStatus::DISPUTED])
|
||||||
|
|
||||||
|
@ -104,7 +112,9 @@ class DomainUpdateConfirmJobTest < ActiveSupport::TestCase
|
||||||
" <chg>\n <registrant>#{@new_registrant.code}</registrant>\n </chg>\n </update>\n </update>\n <extension>\n <update/>\n" \
|
" <chg>\n <registrant>#{@new_registrant.code}</registrant>\n </chg>\n </update>\n </update>\n <extension>\n <update/>\n" \
|
||||||
" <extdata>\n <legalDocument type=\"pdf\">#{@legal_doc_path}</legalDocument>\n </extdata>\n" \
|
" <extdata>\n <legalDocument type=\"pdf\">#{@legal_doc_path}</legalDocument>\n </extdata>\n" \
|
||||||
" </extension>\n <clTRID>20alla-1594199756</clTRID>\n </command>\n</epp>\n"
|
" </extension>\n <clTRID>20alla-1594199756</clTRID>\n </command>\n</epp>\n"
|
||||||
@domain.pending_json['frame'] = epp_xml
|
parsed_frame = Deserializers::Xml::DomainUpdate.new(Nokogiri::XML(epp_xml), @domain.registrar.id).call
|
||||||
|
|
||||||
|
@domain.pending_json['frame'] = parsed_frame
|
||||||
@domain.update(pending_json: @domain.pending_json)
|
@domain.update(pending_json: @domain.pending_json)
|
||||||
@domain.update(statuses: [DomainStatus::DELETE_CANDIDATE, DomainStatus::DISPUTED])
|
@domain.update(statuses: [DomainStatus::DELETE_CANDIDATE, DomainStatus::DISPUTED])
|
||||||
|
|
||||||
|
@ -122,7 +132,9 @@ class DomainUpdateConfirmJobTest < ActiveSupport::TestCase
|
||||||
" <chg>\n <registrant>#{@new_registrant.code}</registrant>\n </chg>\n </update>\n </update>\n <extension>\n <update/>\n" \
|
" <chg>\n <registrant>#{@new_registrant.code}</registrant>\n </chg>\n </update>\n </update>\n <extension>\n <update/>\n" \
|
||||||
" <extdata>\n <legalDocument type=\"pdf\">#{@legal_doc_path}</legalDocument>\n </extdata>\n" \
|
" <extdata>\n <legalDocument type=\"pdf\">#{@legal_doc_path}</legalDocument>\n </extdata>\n" \
|
||||||
" </extension>\n <clTRID>20alla-1594199756</clTRID>\n </command>\n</epp>\n"
|
" </extension>\n <clTRID>20alla-1594199756</clTRID>\n </command>\n</epp>\n"
|
||||||
@domain.pending_json['frame'] = epp_xml
|
parsed_frame = Deserializers::Xml::DomainUpdate.new(Nokogiri::XML(epp_xml), @domain.registrar.id).call
|
||||||
|
|
||||||
|
@domain.pending_json['frame'] = parsed_frame
|
||||||
@domain.update(pending_json: @domain.pending_json)
|
@domain.update(pending_json: @domain.pending_json)
|
||||||
@domain.update(statuses: [DomainStatus::PENDING_UPDATE])
|
@domain.update(statuses: [DomainStatus::PENDING_UPDATE])
|
||||||
@domain.nameservers.destroy_all
|
@domain.nameservers.destroy_all
|
||||||
|
@ -142,7 +154,9 @@ class DomainUpdateConfirmJobTest < ActiveSupport::TestCase
|
||||||
" <chg>\n <registrant>#{@new_registrant.code}</registrant>\n </chg>\n </update>\n </update>\n <extension>\n <update/>\n" \
|
" <chg>\n <registrant>#{@new_registrant.code}</registrant>\n </chg>\n </update>\n </update>\n <extension>\n <update/>\n" \
|
||||||
" <extdata>\n <legalDocument type=\"pdf\">#{@legal_doc_path}</legalDocument>\n </extdata>\n" \
|
" <extdata>\n <legalDocument type=\"pdf\">#{@legal_doc_path}</legalDocument>\n </extdata>\n" \
|
||||||
" </extension>\n <clTRID>20alla-1594199756</clTRID>\n </command>\n</epp>\n"
|
" </extension>\n <clTRID>20alla-1594199756</clTRID>\n </command>\n</epp>\n"
|
||||||
@domain.pending_json['frame'] = epp_xml
|
parsed_frame = Deserializers::Xml::DomainUpdate.new(Nokogiri::XML(epp_xml), @domain.registrar.id).call
|
||||||
|
|
||||||
|
@domain.pending_json['frame'] = parsed_frame
|
||||||
@domain.update(pending_json: @domain.pending_json)
|
@domain.update(pending_json: @domain.pending_json)
|
||||||
@domain.update(statuses: [DomainStatus::OK, DomainStatus::PENDING_UPDATE])
|
@domain.update(statuses: [DomainStatus::OK, DomainStatus::PENDING_UPDATE])
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue