mirror of
https://github.com/internetee/registry.git
synced 2025-06-04 11:47:30 +02:00
Merge remote-tracking branch 'origin/master' into registrant-api-fetch-improvements
This commit is contained in:
commit
3761fe7bbd
97 changed files with 2824 additions and 821 deletions
15
CHANGELOG.md
15
CHANGELOG.md
|
@ -1,3 +1,18 @@
|
|||
27.11.2020
|
||||
* Refactored delete confirmation for interactors [#1753](https://github.com/internetee/registry/issues/1753)
|
||||
|
||||
24.11.2020
|
||||
* Added subnet support for list of allowed IPs [#983](https://github.com/internetee/registry/issues/983)
|
||||
* Added contact endpoint to Restful EPP API [#1580](https://github.com/internetee/registry/issues/1580)
|
||||
|
||||
20.11.2020
|
||||
* Registrant confirmation over Registrant API [#1742](https://github.com/internetee/registry/pull/1742)
|
||||
* Refactored forceDelete cancellation for interactors [#1743](https://github.com/internetee/registry/issues/1743)
|
||||
|
||||
19.11.2020
|
||||
* Only sponsoring registrar has access to private contact's details [#1745](https://github.com/internetee/registry/issues/1745)
|
||||
* Refactor ForceDelete [#1740](https://github.com/internetee/registry/issues/1740)
|
||||
|
||||
13.11.2020
|
||||
* Fixed per registrar epp session limit [#729](https://github.com/internetee/registry/issues/729)
|
||||
* Correct error code is returned on reaching session limit [#587](https://github.com/internetee/registry/issues/587)
|
||||
|
|
3
Gemfile
3
Gemfile
|
@ -1,6 +1,7 @@
|
|||
source 'https://rubygems.org'
|
||||
|
||||
# core
|
||||
gem 'active_interaction', '~> 3.8'
|
||||
gem 'bootsnap', '>= 1.1.0', require: false
|
||||
gem 'iso8601', '0.12.1' # for dates and times
|
||||
gem 'rails', '~> 6.0'
|
||||
|
@ -35,8 +36,6 @@ gem 'select2-rails', '3.5.9.3' # for autocomplete
|
|||
gem 'cancancan'
|
||||
gem 'devise', '~> 4.7'
|
||||
|
||||
gem 'grape'
|
||||
|
||||
# registry specfic
|
||||
gem 'data_migrate', '~> 6.1'
|
||||
gem 'isikukood' # for EE-id validation
|
||||
|
|
37
Gemfile.lock
37
Gemfile.lock
|
@ -112,6 +112,8 @@ GEM
|
|||
erubi (~> 1.4)
|
||||
rails-dom-testing (~> 2.0)
|
||||
rails-html-sanitizer (~> 1.1, >= 1.2.0)
|
||||
active_interaction (3.8.3)
|
||||
activemodel (>= 4, < 7)
|
||||
activejob (6.0.3.3)
|
||||
activesupport (= 6.0.3.3)
|
||||
globalid (>= 0.3.6)
|
||||
|
@ -196,28 +198,6 @@ GEM
|
|||
docile (1.3.2)
|
||||
domain_name (0.5.20190701)
|
||||
unf (>= 0.0.5, < 1.0.0)
|
||||
dry-configurable (0.11.6)
|
||||
concurrent-ruby (~> 1.0)
|
||||
dry-core (~> 0.4, >= 0.4.7)
|
||||
dry-equalizer (~> 0.2)
|
||||
dry-container (0.7.2)
|
||||
concurrent-ruby (~> 1.0)
|
||||
dry-configurable (~> 0.1, >= 0.1.3)
|
||||
dry-core (0.4.9)
|
||||
concurrent-ruby (~> 1.0)
|
||||
dry-equalizer (0.3.0)
|
||||
dry-inflector (0.2.0)
|
||||
dry-logic (1.0.7)
|
||||
concurrent-ruby (~> 1.0)
|
||||
dry-core (~> 0.2)
|
||||
dry-equalizer (~> 0.2)
|
||||
dry-types (1.4.0)
|
||||
concurrent-ruby (~> 1.0)
|
||||
dry-container (~> 0.3)
|
||||
dry-core (~> 0.4, >= 0.4.4)
|
||||
dry-equalizer (~> 0.3)
|
||||
dry-inflector (~> 0.1, >= 0.1.2)
|
||||
dry-logic (~> 1.0, >= 1.0.2)
|
||||
erubi (1.9.0)
|
||||
erubis (2.7.0)
|
||||
execjs (2.7.0)
|
||||
|
@ -226,13 +206,6 @@ GEM
|
|||
thor (~> 0.14)
|
||||
globalid (0.4.2)
|
||||
activesupport (>= 4.2.0)
|
||||
grape (1.4.0)
|
||||
activesupport
|
||||
builder
|
||||
dry-types (>= 1.1)
|
||||
mustermann-grape (~> 1.0.0)
|
||||
rack (>= 1.3.0)
|
||||
rack-accept
|
||||
gyoku (1.3.1)
|
||||
builder (>= 2.1.2)
|
||||
haml (5.1.2)
|
||||
|
@ -312,8 +285,6 @@ GEM
|
|||
multi_json (1.15.0)
|
||||
mustermann (1.1.1)
|
||||
ruby2_keywords (~> 0.0.1)
|
||||
mustermann-grape (1.0.1)
|
||||
mustermann (>= 1.0.0)
|
||||
netrc (0.11.0)
|
||||
nio4r (2.5.4)
|
||||
nokogiri (1.10.10)
|
||||
|
@ -357,8 +328,6 @@ GEM
|
|||
que (~> 0.8)
|
||||
sinatra
|
||||
rack (2.2.3)
|
||||
rack-accept (0.4.5)
|
||||
rack (>= 0.4)
|
||||
rack-oauth2 (1.16.0)
|
||||
activesupport
|
||||
attr_required
|
||||
|
@ -521,6 +490,7 @@ PLATFORMS
|
|||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
active_interaction (~> 3.8)
|
||||
activerecord-import
|
||||
airbrake
|
||||
bootsnap (>= 1.1.0)
|
||||
|
@ -542,7 +512,6 @@ DEPENDENCIES
|
|||
epp!
|
||||
epp-xml (= 1.1.0)!
|
||||
figaro (= 1.1.1)
|
||||
grape
|
||||
haml (~> 5.0)
|
||||
isikukood
|
||||
iso8601 (= 0.12.1)
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
module Repp
|
||||
class AccountV1 < Grape::API
|
||||
version 'v1', using: :path
|
||||
|
||||
resource :accounts do
|
||||
desc 'Return current cash account balance'
|
||||
|
||||
get 'balance' do
|
||||
@response = {
|
||||
balance: current_user.registrar.cash_account.balance,
|
||||
currency: current_user.registrar.cash_account.currency
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,65 +0,0 @@
|
|||
module Repp
|
||||
class API < Grape::API
|
||||
format :json
|
||||
prefix :repp
|
||||
|
||||
http_basic do |username, password|
|
||||
@current_user ||= ApiUser.find_by(username: username, plain_text_password: password)
|
||||
if @current_user
|
||||
true
|
||||
else
|
||||
error! I18n.t('api_user_not_found'), 401
|
||||
end
|
||||
end
|
||||
|
||||
before do
|
||||
webclient_request = ENV['webclient_ips'].split(',').map(&:strip).include?(request.ip)
|
||||
unless webclient_request
|
||||
error! I18n.t('api.authorization.ip_not_allowed', ip: request.ip), 401 unless @current_user.registrar.api_ip_white?(request.ip)
|
||||
end
|
||||
|
||||
if @current_user.cannot?(:view, :repp)
|
||||
error! I18n.t('no_permission'), 401 unless @current_user.registrar.api_ip_white?(request.ip)
|
||||
end
|
||||
|
||||
next if Rails.env.test? || Rails.env.development?
|
||||
message = 'Certificate mismatch! Cert common name should be:'
|
||||
request_name = env['HTTP_SSL_CLIENT_S_DN_CN']
|
||||
|
||||
if webclient_request
|
||||
webclient_cert_name = ENV['webclient_cert_common_name'] || 'webclient'
|
||||
error! "Webclient #{message} #{webclient_cert_name}", 401 if webclient_cert_name != request_name
|
||||
else
|
||||
unless @current_user.pki_ok?(request.env['HTTP_SSL_CLIENT_CERT'],
|
||||
request.env['HTTP_SSL_CLIENT_S_DN_CN'])
|
||||
error! "#{message} #{@current_user.username}", 401
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
helpers do
|
||||
attr_reader :current_user
|
||||
end
|
||||
|
||||
after do
|
||||
ApiLog::ReppLog.create({
|
||||
request_path: request.path,
|
||||
request_method: request.request_method,
|
||||
request_params: request.params.except('route_info').to_json,
|
||||
response: @response.to_json,
|
||||
response_code: status,
|
||||
api_user_name: current_user.try(:username),
|
||||
api_user_registrar: current_user.try(:registrar).try(:to_s),
|
||||
ip: request.ip,
|
||||
uuid: request.try(:uuid)
|
||||
})
|
||||
end
|
||||
|
||||
mount Repp::DomainV1
|
||||
mount Repp::ContactV1
|
||||
mount Repp::AccountV1
|
||||
mount Repp::DomainTransfersV1
|
||||
mount Repp::NameserversV1
|
||||
mount Repp::DomainContactsV1
|
||||
end
|
||||
end
|
|
@ -1,35 +0,0 @@
|
|||
module Repp
|
||||
class ContactV1 < Grape::API
|
||||
version 'v1', using: :path
|
||||
|
||||
resource :contacts do
|
||||
desc 'Return list of contact'
|
||||
params do
|
||||
optional :limit, type: Integer, values: (1..200).to_a, desc: 'How many contacts to show'
|
||||
optional :offset, type: Integer, desc: 'Contact number to start at'
|
||||
optional :details, type: String, values: %w(true false), desc: 'Whether to include details'
|
||||
end
|
||||
|
||||
get '/' do
|
||||
limit = params[:limit] || 200
|
||||
offset = params[:offset] || 0
|
||||
|
||||
if params[:details] == 'true'
|
||||
contacts = current_user.registrar.contacts.limit(limit).offset(offset)
|
||||
|
||||
unless Contact.address_processing?
|
||||
attributes = Contact.attribute_names - Contact.address_attribute_names
|
||||
contacts = contacts.select(attributes)
|
||||
end
|
||||
else
|
||||
contacts = current_user.registrar.contacts.limit(limit).offset(offset).pluck(:code)
|
||||
end
|
||||
|
||||
@response = {
|
||||
contacts: contacts,
|
||||
total_number_of_records: current_user.registrar.contacts.count
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,47 +0,0 @@
|
|||
module Repp
|
||||
class DomainContactsV1 < Grape::API
|
||||
version 'v1', using: :path
|
||||
|
||||
resource :domains do
|
||||
resource :contacts do
|
||||
patch '/' do
|
||||
current_contact = current_user.registrar.contacts
|
||||
.find_by(code: params[:current_contact_id])
|
||||
new_contact = current_user.registrar.contacts.find_by(code: params[:new_contact_id])
|
||||
|
||||
unless current_contact
|
||||
error!({ error: { type: 'invalid_request_error',
|
||||
param: 'current_contact_id',
|
||||
message: "No such contact: #{params[:current_contact_id]}"} },
|
||||
:bad_request)
|
||||
end
|
||||
|
||||
unless new_contact
|
||||
error!({ error: { type: 'invalid_request_error',
|
||||
param: 'new_contact_id',
|
||||
message: "No such contact: #{params[:new_contact_id]}" } },
|
||||
:bad_request)
|
||||
end
|
||||
|
||||
if new_contact.invalid?
|
||||
error!({ error: { type: 'invalid_request_error',
|
||||
param: 'new_contact_id',
|
||||
message: 'New contact must be valid' } },
|
||||
:bad_request)
|
||||
end
|
||||
|
||||
if current_contact == new_contact
|
||||
error!({ error: { type: 'invalid_request_error',
|
||||
message: 'New contact ID must be different from current' \
|
||||
' contact ID' } },
|
||||
:bad_request)
|
||||
end
|
||||
|
||||
affected_domains, skipped_domains = TechDomainContact
|
||||
.replace(current_contact, new_contact)
|
||||
@response = { affected_domains: affected_domains, skipped_domains: skipped_domains }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,48 +0,0 @@
|
|||
module Repp
|
||||
class DomainTransfersV1 < Grape::API
|
||||
version 'v1', using: :path
|
||||
|
||||
resource :domain_transfers do
|
||||
post '/' do
|
||||
params do
|
||||
requires :data, type: Hash do
|
||||
requires :domainTransfers, type: Array do
|
||||
requires :domainName, type: String, allow_blank: false
|
||||
requires :transferCode, type: String, allow_blank: false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
new_registrar = current_user.registrar
|
||||
domain_transfers = params['data']['domainTransfers']
|
||||
successful_domain_transfers = []
|
||||
errors = []
|
||||
|
||||
domain_transfers.each do |domain_transfer|
|
||||
domain_name = domain_transfer['domainName']
|
||||
transfer_code = domain_transfer['transferCode']
|
||||
domain = Domain.find_by(name: domain_name)
|
||||
|
||||
if domain
|
||||
if domain.transfer_code == transfer_code
|
||||
DomainTransfer.request(domain, new_registrar)
|
||||
successful_domain_transfers << { type: 'domain_transfer', attributes: { domain_name: domain.name } }
|
||||
else
|
||||
errors << { title: "#{domain_name} transfer code is wrong" }
|
||||
end
|
||||
else
|
||||
errors << { title: "#{domain_name} does not exist" }
|
||||
end
|
||||
end
|
||||
|
||||
if errors.none?
|
||||
status 200
|
||||
@response = { data: successful_domain_transfers }
|
||||
else
|
||||
status 400
|
||||
@response = { errors: errors }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,50 +0,0 @@
|
|||
module Repp
|
||||
class DomainV1 < Grape::API
|
||||
version 'v1', using: :path
|
||||
|
||||
resource :domains do
|
||||
desc 'Return list of domains'
|
||||
params do
|
||||
optional :limit, type: Integer, values: (1..200).to_a, desc: 'How many domains to show'
|
||||
optional :offset, type: Integer, desc: 'Domain number to start at'
|
||||
optional :details, type: String, values: %w(true false), desc: 'Whether to include details'
|
||||
end
|
||||
|
||||
get '/' do
|
||||
limit = params[:limit] || 200
|
||||
offset = params[:offset] || 0
|
||||
|
||||
if params[:details] == 'true'
|
||||
domains = current_user.registrar.domains.limit(limit).offset(offset)
|
||||
else
|
||||
domains = current_user.registrar.domains.limit(limit).offset(offset).pluck(:name)
|
||||
end
|
||||
|
||||
@response = {
|
||||
domains: domains,
|
||||
total_number_of_records: current_user.registrar.domains.count
|
||||
}
|
||||
end
|
||||
|
||||
# example: curl -u registrar1:password localhost:3000/repp/v1/domains/1/transfer_info -H "Auth-Code: authinfopw1"
|
||||
get '/:id/transfer_info', requirements: { id: /.*/ } do
|
||||
ident = params[:id]
|
||||
domain = ident.match?(/\A[0-9]+\z/) ? Domain.find_by(id: ident) : Domain.find_by_idn(ident)
|
||||
|
||||
error! I18n.t('errors.messages.epp_domain_not_found'), 404 unless domain
|
||||
error! I18n.t('errors.messages.epp_authorization_error'), 401 unless domain.transfer_code.eql? request.headers['Auth-Code']
|
||||
|
||||
contact_repp_json = proc{|contact|
|
||||
contact.as_json.slice("code", "name", "ident", "ident_type", "ident_country_code", "phone", "email", "street", "city", "zip","country_code", "statuses")
|
||||
}
|
||||
|
||||
@response = {
|
||||
domain: domain.name,
|
||||
registrant: contact_repp_json.call(domain.registrant),
|
||||
admin_contacts: domain.admin_contacts.map{|e| contact_repp_json.call(e)},
|
||||
tech_contacts: domain.tech_contacts.map{|e| contact_repp_json.call(e)}
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,49 +0,0 @@
|
|||
module Repp
|
||||
class NameserversV1 < Grape::API
|
||||
version 'v1', using: :path
|
||||
|
||||
resource 'registrar/nameservers' do
|
||||
put '/' do
|
||||
params do
|
||||
requires :data, type: Hash, allow_blank: false do
|
||||
requires :type, type: String, allow_blank: false
|
||||
requires :id, type: String, allow_blank: false
|
||||
optional :domains, type: Array
|
||||
requires :attributes, type: Hash, allow_blank: false do
|
||||
requires :hostname, type: String, allow_blank: false
|
||||
requires :ipv4, type: Array
|
||||
requires :ipv6, type: Array
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
hostname = params[:data][:id]
|
||||
|
||||
unless current_user.registrar.nameservers.exists?(hostname: hostname)
|
||||
error!({ errors: [{ title: "Hostname #{hostname} does not exist" }] }, 404)
|
||||
end
|
||||
|
||||
new_attributes = {
|
||||
hostname: params[:data][:attributes][:hostname],
|
||||
ipv4: params[:data][:attributes][:ipv4],
|
||||
ipv6: params[:data][:attributes][:ipv6],
|
||||
}
|
||||
|
||||
domains = params[:data][:domains] || []
|
||||
|
||||
begin
|
||||
affected_domains = current_user.registrar.replace_nameservers(hostname, new_attributes,
|
||||
domains: domains)
|
||||
rescue ActiveRecord::RecordInvalid => e
|
||||
error!({ errors: e.record.errors.full_messages.map { |error| { title: error } } }, 400)
|
||||
end
|
||||
|
||||
status 200
|
||||
@response = { data: { type: 'nameserver',
|
||||
id: params[:data][:attributes][:hostname],
|
||||
attributes: params[:data][:attributes] },
|
||||
affected_domains: affected_domains }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -4,26 +4,15 @@ module Admin
|
|||
def create
|
||||
authorize! :manage, domain
|
||||
|
||||
notice = t('.scheduled')
|
||||
|
||||
domain.transaction do
|
||||
domain.schedule_force_delete(type: force_delete_type)
|
||||
domain.registrar.notifications.create!(text: t('force_delete_set_on_domain',
|
||||
domain_name: domain.name,
|
||||
outzone_date: domain.outzone_date,
|
||||
purge_date: domain.purge_date))
|
||||
|
||||
notify_by_email if notify_by_email?
|
||||
result = domain.schedule_force_delete(type: force_delete_type,
|
||||
notify_by_email: notify_by_email?)
|
||||
notice = result.errors.messages[:domain].first unless result.valid?
|
||||
end
|
||||
|
||||
redirect_to edit_admin_domain_url(domain), notice: t('.scheduled')
|
||||
end
|
||||
|
||||
def notify_by_email
|
||||
if force_delete_type == :fast_track
|
||||
send_email
|
||||
domain.update(contact_notification_sent_date: Time.zone.today)
|
||||
else
|
||||
domain.update(template_name: domain.notification_template)
|
||||
end
|
||||
redirect_to edit_admin_domain_url(domain), notice: notice
|
||||
end
|
||||
|
||||
def destroy
|
||||
|
@ -42,13 +31,6 @@ module Admin
|
|||
ActiveRecord::Type::Boolean.new.cast(params[:notify_by_email])
|
||||
end
|
||||
|
||||
def send_email
|
||||
DomainDeleteMailer.forced(domain: domain,
|
||||
registrar: domain.registrar,
|
||||
registrant: domain.registrant,
|
||||
template_name: domain.notification_template).deliver_now
|
||||
end
|
||||
|
||||
def force_delete_type
|
||||
soft_delete? ? :soft : :fast_track
|
||||
end
|
||||
|
|
119
app/controllers/api/v1/registrant/confirms_controller.rb
Normal file
119
app/controllers/api/v1/registrant/confirms_controller.rb
Normal file
|
@ -0,0 +1,119 @@
|
|||
require 'serializers/registrant_api/domain'
|
||||
|
||||
module Api
|
||||
module V1
|
||||
module Registrant
|
||||
class ConfirmsController < ::Api::V1::Registrant::BaseController
|
||||
skip_before_action :authenticate, :set_paper_trail_whodunnit
|
||||
before_action :set_domain, only: %i[index update]
|
||||
before_action :verify_action, only: %i[index update]
|
||||
before_action :verify_decision, only: %i[update]
|
||||
|
||||
def index
|
||||
res = {
|
||||
domain_name: @domain.name,
|
||||
current_registrant: serialized_registrant(@domain.registrant),
|
||||
}
|
||||
|
||||
unless delete_action?
|
||||
res[:new_registrant] = serialized_registrant(@domain.pending_registrant)
|
||||
end
|
||||
|
||||
render json: res, status: :ok
|
||||
end
|
||||
|
||||
def update
|
||||
verification = RegistrantVerification.new(domain_id: @domain.id,
|
||||
verification_token: verify_params[:token])
|
||||
|
||||
unless delete_action? ? delete_action(verification) : change_action(verification)
|
||||
head :bad_request
|
||||
return
|
||||
end
|
||||
|
||||
render json: { domain_name: @domain.name,
|
||||
current_registrant: serialized_registrant(current_registrant),
|
||||
status: params[:decision] }, status: :ok
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def initiator
|
||||
"email link, #{I18n.t(:user_not_authenticated)}"
|
||||
end
|
||||
|
||||
def current_registrant
|
||||
confirmed? && !delete_action? ? @domain.pending_registrant : @domain.registrant
|
||||
end
|
||||
|
||||
def confirmed?
|
||||
verify_params[:decision] == 'confirmed'
|
||||
end
|
||||
|
||||
def change_action(verification)
|
||||
if confirmed?
|
||||
verification.domain_registrant_change_confirm!(initiator)
|
||||
else
|
||||
verification.domain_registrant_change_reject!(initiator)
|
||||
end
|
||||
end
|
||||
|
||||
def delete_action(verification)
|
||||
if confirmed?
|
||||
verification.domain_registrant_delete_confirm!(initiator)
|
||||
else
|
||||
verification.domain_registrant_delete_reject!(initiator)
|
||||
end
|
||||
end
|
||||
|
||||
def serialized_registrant(registrant)
|
||||
{
|
||||
name: registrant.try(:name),
|
||||
ident: registrant.try(:ident),
|
||||
country: registrant.try(:ident_country_code),
|
||||
}
|
||||
end
|
||||
|
||||
def verify_params
|
||||
params do |p|
|
||||
p.require(:name)
|
||||
p.require(:token)
|
||||
p.permit(:decision)
|
||||
end
|
||||
end
|
||||
|
||||
def delete_action?
|
||||
return true if params[:template] == 'delete'
|
||||
|
||||
false
|
||||
end
|
||||
|
||||
def verify_decision
|
||||
return if %w[confirmed rejected].include?(params[:decision])
|
||||
|
||||
head :not_found
|
||||
end
|
||||
|
||||
def set_domain
|
||||
@domain = Domain.find_by(name: verify_params[:name])
|
||||
@domain ||= Domain.find_by(name_puny: verify_params[:name])
|
||||
return if @domain
|
||||
|
||||
render json: { error: 'Domain not found' }, status: :not_found
|
||||
end
|
||||
|
||||
def verify_action
|
||||
action = if params[:template] == 'change'
|
||||
@domain.registrant_update_confirmable?(verify_params[:token])
|
||||
elsif params[:template] == 'delete'
|
||||
@domain.registrant_delete_confirmable?(verify_params[:token])
|
||||
end
|
||||
|
||||
return if action
|
||||
|
||||
render json: { error: 'Application expired or not found' }, status: :unauthorized
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,10 +1,9 @@
|
|||
require 'deserializers/xml/contact_update'
|
||||
|
||||
require 'deserializers/xml/contact_create'
|
||||
module Epp
|
||||
class ContactsController < BaseController
|
||||
before_action :find_contact, only: [:info, :update, :delete]
|
||||
before_action :find_password, only: [:info, :update, :delete]
|
||||
helper_method :address_processing?
|
||||
|
||||
def info
|
||||
authorize! :info, @contact, @password
|
||||
|
@ -21,25 +20,13 @@ module Epp
|
|||
|
||||
def create
|
||||
authorize! :create, Epp::Contact
|
||||
frame = params[:parsed_frame]
|
||||
@contact = Epp::Contact.new(frame, current_user.registrar)
|
||||
|
||||
@contact.add_legal_file_to_new(frame)
|
||||
@contact.generate_code
|
||||
@contact = Epp::Contact.new(params[:parsed_frame], current_user.registrar)
|
||||
collected_data = ::Deserializers::Xml::ContactCreate.new(params[:parsed_frame])
|
||||
action = Actions::ContactCreate.new(@contact, collected_data.legal_document,
|
||||
collected_data.ident)
|
||||
|
||||
if @contact.save
|
||||
if !address_processing? && address_given?
|
||||
@response_code = 1100
|
||||
@response_description = t('epp.contacts.completed_without_address')
|
||||
else
|
||||
@response_code = 1000
|
||||
@response_description = t('epp.contacts.completed')
|
||||
end
|
||||
|
||||
render_epp_response '/epp/contacts/save'
|
||||
else
|
||||
handle_errors(@contact)
|
||||
end
|
||||
action_call_response(action: action)
|
||||
end
|
||||
|
||||
def update
|
||||
|
@ -52,29 +39,18 @@ module Epp
|
|||
collected_data.ident,
|
||||
current_user)
|
||||
|
||||
if action.call
|
||||
if !address_processing? && address_given?
|
||||
@response_code = 1100
|
||||
@response_description = t('epp.contacts.completed_without_address')
|
||||
else
|
||||
@response_code = 1000
|
||||
@response_description = t('epp.contacts.completed')
|
||||
end
|
||||
|
||||
render_epp_response 'epp/contacts/save'
|
||||
else
|
||||
handle_errors(@contact)
|
||||
end
|
||||
action_call_response(action: action)
|
||||
end
|
||||
|
||||
def delete
|
||||
authorize! :delete, @contact, @password
|
||||
|
||||
if @contact.destroy_and_clean(params[:parsed_frame])
|
||||
render_epp_response '/epp/contacts/delete'
|
||||
else
|
||||
action = Actions::ContactDelete.new(@contact, params[:legal_document])
|
||||
unless action.call
|
||||
handle_errors(@contact)
|
||||
return
|
||||
end
|
||||
|
||||
render_epp_response '/epp/contacts/delete'
|
||||
end
|
||||
|
||||
def renew
|
||||
|
@ -91,6 +67,26 @@ module Epp
|
|||
|
||||
private
|
||||
|
||||
def opt_addr?
|
||||
!Contact.address_processing? && address_given?
|
||||
end
|
||||
|
||||
def action_call_response(action:)
|
||||
# rubocop:disable Style/AndOr
|
||||
(handle_errors(@contact) and return) unless action.call
|
||||
# rubocop:enable Style/AndOr
|
||||
|
||||
if opt_addr?
|
||||
@response_code = 1100
|
||||
@response_description = t('epp.contacts.completed_without_address')
|
||||
else
|
||||
@response_code = 1000
|
||||
@response_description = t('epp.contacts.completed')
|
||||
end
|
||||
|
||||
render_epp_response('epp/contacts/save')
|
||||
end
|
||||
|
||||
def find_password
|
||||
@password = params[:parsed_frame].css('authInfo pw').text
|
||||
end
|
||||
|
@ -129,8 +125,7 @@ module Epp
|
|||
'postalInfo > addr > cc',
|
||||
]
|
||||
|
||||
required_attributes.concat(address_attributes) if address_processing?
|
||||
|
||||
required_attributes.concat(address_attributes) if Contact.address_processing?
|
||||
requires(*required_attributes)
|
||||
ident = params[:parsed_frame].css('ident')
|
||||
|
||||
|
@ -206,9 +201,5 @@ module Epp
|
|||
def address_given?
|
||||
params[:parsed_frame].css('postalInfo addr').size != 0
|
||||
end
|
||||
|
||||
def address_processing?
|
||||
Contact.address_processing?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -15,12 +15,12 @@ class Registrar
|
|||
csv.each do |row|
|
||||
domain_name = row['Domain']
|
||||
transfer_code = row['Transfer code']
|
||||
domain_transfers << { 'domainName' => domain_name, 'transferCode' => transfer_code }
|
||||
domain_transfers << { 'domain_name' => domain_name, 'transfer_code' => transfer_code }
|
||||
end
|
||||
|
||||
uri = URI.parse("#{ENV['repp_url']}domain_transfers")
|
||||
uri = URI.parse("#{ENV['repp_url']}domains/transfer")
|
||||
request = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json')
|
||||
request.body = { data: { domainTransfers: domain_transfers } }.to_json
|
||||
request.body = { data: { domain_transfers: domain_transfers } }.to_json
|
||||
request.basic_auth(current_registrar_user.username,
|
||||
current_registrar_user.plain_text_password)
|
||||
|
||||
|
|
11
app/controllers/repp/v1/accounts_controller.rb
Normal file
11
app/controllers/repp/v1/accounts_controller.rb
Normal file
|
@ -0,0 +1,11 @@
|
|||
module Repp
|
||||
module V1
|
||||
class AccountsController < BaseController
|
||||
def balance
|
||||
resp = { balance: current_user.registrar.cash_account.balance,
|
||||
currency: current_user.registrar.cash_account.currency }
|
||||
render_success(data: resp)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -3,9 +3,9 @@ module Repp
|
|||
class AuctionsController < ActionController::API
|
||||
def index
|
||||
auctions = Auction.started
|
||||
@response = { count: auctions.count, auctions: auctions_to_json(auctions) }
|
||||
|
||||
render json: { count: auctions.count,
|
||||
auctions: auctions_to_json(auctions) }
|
||||
render json: @response
|
||||
end
|
||||
|
||||
private
|
||||
|
|
111
app/controllers/repp/v1/base_controller.rb
Normal file
111
app/controllers/repp/v1/base_controller.rb
Normal file
|
@ -0,0 +1,111 @@
|
|||
module Repp
|
||||
module V1
|
||||
class BaseController < ActionController::API
|
||||
rescue_from ActiveRecord::RecordNotFound, with: :not_found_error
|
||||
before_action :authenticate_user
|
||||
before_action :check_ip_restriction
|
||||
attr_reader :current_user
|
||||
|
||||
before_action :set_paper_trail_whodunnit
|
||||
|
||||
rescue_from ActionController::ParameterMissing do |exception|
|
||||
render json: { code: 2003, message: exception }, status: :bad_request
|
||||
end
|
||||
|
||||
after_action do
|
||||
ApiLog::ReppLog.create(
|
||||
request_path: request.path, request_method: request.request_method,
|
||||
request_params: request.params.except('route_info').to_json, uuid: request.try(:uuid),
|
||||
response: @response.to_json, response_code: status, ip: request.ip,
|
||||
api_user_name: current_user.try(:username),
|
||||
api_user_registrar: current_user.try(:registrar).try(:to_s)
|
||||
)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_paper_trail_whodunnit
|
||||
::PaperTrail.request.whodunnit = current_user
|
||||
end
|
||||
|
||||
def render_success(code: nil, message: nil, data: nil)
|
||||
@response = { code: code || 1000, message: message || 'Command completed successfully',
|
||||
data: data || {} }
|
||||
|
||||
render(json: @response, status: :ok)
|
||||
end
|
||||
|
||||
def epp_errors
|
||||
@epp_errors ||= []
|
||||
end
|
||||
|
||||
def handle_errors(obj = nil, update: false)
|
||||
@epp_errors ||= []
|
||||
|
||||
obj&.construct_epp_errors
|
||||
@epp_errors += obj.errors[:epp_errors] if obj
|
||||
|
||||
format_epp_errors if update
|
||||
@epp_errors.uniq!
|
||||
|
||||
render_epp_error
|
||||
end
|
||||
|
||||
def format_epp_errors
|
||||
@epp_errors.each_with_index do |error, index|
|
||||
blocked_by_delete_prohibited?(error, index)
|
||||
end
|
||||
end
|
||||
|
||||
def blocked_by_delete_prohibited?(error, index)
|
||||
if error[:code] == 2304 && error[:value][:val] == DomainStatus::SERVER_DELETE_PROHIBITED &&
|
||||
error[:value][:obj] == 'status'
|
||||
|
||||
@epp_errors[index][:value][:val] = DomainStatus::PENDING_UPDATE
|
||||
end
|
||||
end
|
||||
|
||||
def render_epp_error(status = :bad_request, data = {})
|
||||
@epp_errors ||= []
|
||||
@epp_errors << { code: 2304, msg: 'Command failed' } if data != {}
|
||||
|
||||
@response = { code: @epp_errors[0][:code].to_i, message: @epp_errors[0][:msg], data: data }
|
||||
render(json: @response, status: status)
|
||||
end
|
||||
|
||||
def basic_token
|
||||
pattern = /^Basic /
|
||||
header = request.headers['Authorization']
|
||||
header = header.gsub(pattern, '') if header&.match(pattern)
|
||||
header.strip
|
||||
end
|
||||
|
||||
def authenticate_user
|
||||
username, password = Base64.urlsafe_decode64(basic_token).split(':')
|
||||
@current_user ||= ApiUser.find_by(username: username, plain_text_password: password)
|
||||
|
||||
return if @current_user
|
||||
|
||||
raise(ArgumentError)
|
||||
rescue NoMethodError, ArgumentError
|
||||
@response = { code: 2202, message: 'Invalid authorization information' }
|
||||
render(json: @response, status: :unauthorized)
|
||||
end
|
||||
|
||||
def check_ip_restriction
|
||||
allowed = @current_user.registrar.api_ip_white?(request.ip)
|
||||
|
||||
return if allowed
|
||||
|
||||
@response = { code: 2202,
|
||||
message: I18n.t('registrar.authorization.ip_not_allowed', ip: request.ip) }
|
||||
render(json: @response, status: :unauthorized)
|
||||
end
|
||||
|
||||
def not_found_error
|
||||
@response = { code: 2303, message: 'Object does not exist' }
|
||||
render(json: @response, status: :not_found)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
137
app/controllers/repp/v1/contacts_controller.rb
Normal file
137
app/controllers/repp/v1/contacts_controller.rb
Normal file
|
@ -0,0 +1,137 @@
|
|||
require 'serializers/repp/contact'
|
||||
module Repp
|
||||
module V1
|
||||
class ContactsController < BaseController
|
||||
before_action :find_contact, only: %i[show update destroy]
|
||||
|
||||
## GET /repp/v1/contacts
|
||||
def index
|
||||
record_count = current_user.registrar.contacts.count
|
||||
contacts = showable_contacts(params[:details], params[:limit] || 200,
|
||||
params[:offset] || 0)
|
||||
@response = { contacts: contacts, total_number_of_records: record_count }
|
||||
render(json: @response, status: :ok)
|
||||
end
|
||||
|
||||
## GET /repp/v1/contacts/1
|
||||
def show
|
||||
serializer = ::Serializers::Repp::Contact.new(@contact,
|
||||
show_address: Contact.address_processing?)
|
||||
render_success(data: serializer.to_json)
|
||||
end
|
||||
|
||||
## GET /repp/v1/contacts/check/1
|
||||
def check
|
||||
contact = Epp::Contact.find_by(code: params[:id])
|
||||
data = { contact: { id: params[:id], available: contact.nil? } }
|
||||
|
||||
render_success(data: data)
|
||||
end
|
||||
|
||||
## POST /repp/v1/contacts
|
||||
def create
|
||||
@contact = Epp::Contact.new(contact_params_with_address, current_user.registrar, epp: false)
|
||||
action = Actions::ContactCreate.new(@contact, params[:legal_document],
|
||||
contact_ident_params)
|
||||
|
||||
unless action.call
|
||||
handle_errors(@contact)
|
||||
return
|
||||
end
|
||||
|
||||
render_success(create_update_success_body)
|
||||
end
|
||||
|
||||
## PUT /repp/v1/contacts/1
|
||||
def update
|
||||
action = Actions::ContactUpdate.new(@contact, contact_params_with_address(required: false),
|
||||
params[:legal_document],
|
||||
contact_ident_params(required: false), current_user)
|
||||
|
||||
unless action.call
|
||||
handle_errors(@contact)
|
||||
return
|
||||
end
|
||||
|
||||
render_success(create_update_success_body)
|
||||
end
|
||||
|
||||
def destroy
|
||||
action = Actions::ContactDelete.new(@contact, params[:legal_document])
|
||||
unless action.call
|
||||
handle_errors(@contact)
|
||||
return
|
||||
end
|
||||
|
||||
render_success
|
||||
end
|
||||
|
||||
def contact_addr_present?
|
||||
return false unless contact_addr_params.key?(:addr)
|
||||
|
||||
contact_addr_params[:addr].keys.any?
|
||||
end
|
||||
|
||||
def create_update_success_body
|
||||
{ code: opt_addr? ? 1100 : nil, data: { contact: { id: @contact.code } },
|
||||
message: opt_addr? ? I18n.t('epp.contacts.completed_without_address') : nil }
|
||||
end
|
||||
|
||||
def showable_contacts(details, limit, offset)
|
||||
contacts = current_user.registrar.contacts.limit(limit).offset(offset)
|
||||
|
||||
return contacts.pluck(:code) unless details
|
||||
|
||||
contacts = contacts.map do |contact|
|
||||
serializer = ::Serializers::Repp::Contact.new(contact,
|
||||
show_address: Contact.address_processing?)
|
||||
serializer.to_json
|
||||
end
|
||||
|
||||
contacts
|
||||
end
|
||||
|
||||
def opt_addr?
|
||||
!Contact.address_processing? && contact_addr_present?
|
||||
end
|
||||
|
||||
def find_contact
|
||||
code = params[:id]
|
||||
@contact = Epp::Contact.find_by!(code: code, registrar: current_user.registrar)
|
||||
end
|
||||
|
||||
def contact_params_with_address(required: true)
|
||||
return contact_create_params(required: required) unless contact_addr_params.key?(:addr)
|
||||
|
||||
addr = {}
|
||||
contact_addr_params[:addr].each_key { |k| addr[k] = contact_addr_params[:addr][k] }
|
||||
contact_create_params(required: required).merge(addr)
|
||||
end
|
||||
|
||||
def contact_create_params(required: true)
|
||||
params.require(:contact).require(%i[name email phone]) if required
|
||||
params.require(:contact).permit(:name, :email, :phone, :id)
|
||||
end
|
||||
|
||||
def contact_ident_params(required: true)
|
||||
if required
|
||||
params.require(:contact).require(:ident).require(%i[ident ident_type ident_country_code])
|
||||
params.require(:contact).require(:ident).permit(:ident, :ident_type, :ident_country_code)
|
||||
else
|
||||
params.permit(contact: { ident: %i[ident ident_type ident_country_code] })
|
||||
end
|
||||
|
||||
params[:contact][:ident]
|
||||
end
|
||||
|
||||
def contact_addr_params
|
||||
if Contact.address_processing?
|
||||
params.require(:contact).require(:addr).require(%i[country_code city street zip])
|
||||
params.require(:contact).require(:addr).permit(:country_code, :city, :street, :zip)
|
||||
else
|
||||
params.require(:contact).permit(addr: %i[country_code city street zip])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
42
app/controllers/repp/v1/domains/contacts_controller.rb
Normal file
42
app/controllers/repp/v1/domains/contacts_controller.rb
Normal file
|
@ -0,0 +1,42 @@
|
|||
module Repp
|
||||
module V1
|
||||
module Domains
|
||||
class ContactsController < BaseController
|
||||
before_action :set_current_contact, only: [:update]
|
||||
before_action :set_new_contact, only: [:update]
|
||||
|
||||
def set_current_contact
|
||||
@current_contact = current_user.registrar.contacts.find_by!(
|
||||
code: contact_params[:current_contact_id]
|
||||
)
|
||||
end
|
||||
|
||||
def set_new_contact
|
||||
@new_contact = current_user.registrar.contacts.find_by!(code: params[:new_contact_id])
|
||||
end
|
||||
|
||||
def update
|
||||
@epp_errors ||= []
|
||||
@epp_errors << { code: 2304, msg: 'New contact must be valid' } if @new_contact.invalid?
|
||||
|
||||
if @new_contact == @current_contact
|
||||
@epp_errors << { code: 2304, msg: 'New contact must be different from current' }
|
||||
end
|
||||
|
||||
return handle_errors if @epp_errors.any?
|
||||
|
||||
affected, skipped = TechDomainContact.replace(@current_contact, @new_contact)
|
||||
@response = { affected_domains: affected, skipped_domains: skipped }
|
||||
render_success(data: @response)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def contact_params
|
||||
params.require(%i[current_contact_id new_contact_id])
|
||||
params.permit(:current_contact_id, :new_contact_id)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
94
app/controllers/repp/v1/domains_controller.rb
Normal file
94
app/controllers/repp/v1/domains_controller.rb
Normal file
|
@ -0,0 +1,94 @@
|
|||
module Repp
|
||||
module V1
|
||||
class DomainsController < BaseController
|
||||
before_action :set_authorized_domain, only: [:transfer_info]
|
||||
|
||||
def index
|
||||
records = current_user.registrar.domains
|
||||
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 })
|
||||
end
|
||||
|
||||
def transfer_info
|
||||
contact_fields = %i[code name ident ident_type ident_country_code phone email street city
|
||||
zip country_code statuses]
|
||||
|
||||
data = {
|
||||
domain: @domain.name,
|
||||
registrant: @domain.registrant.as_json(only: contact_fields),
|
||||
admin_contacts: @domain.admin_contacts.map { |c| c.as_json(only: contact_fields) },
|
||||
tech_contacts: @domain.tech_contacts.map { |c| c.as_json(only: contact_fields) },
|
||||
}
|
||||
|
||||
render_success(data: data)
|
||||
end
|
||||
|
||||
def transfer
|
||||
@errors ||= []
|
||||
@successful = []
|
||||
|
||||
transfer_params[:domain_transfers].each do |transfer|
|
||||
initiate_transfer(transfer)
|
||||
end
|
||||
|
||||
render_success(data: { success: @successful, failed: @errors })
|
||||
end
|
||||
|
||||
def initiate_transfer(transfer)
|
||||
domain = Epp::Domain.find_or_initialize_by(name: transfer[:domain_name])
|
||||
action = Actions::DomainTransfer.new(domain, transfer[:transfer_code],
|
||||
current_user.registrar)
|
||||
|
||||
if action.call
|
||||
@successful << { type: 'domain_transfer', domain_name: domain.name }
|
||||
else
|
||||
@errors << { type: 'domain_transfer', domain_name: domain.name,
|
||||
errors: domain.errors[:epp_errors] }
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def transfer_params
|
||||
params.require(:data).require(:domain_transfers).each do |t|
|
||||
t.require(:domain_name)
|
||||
t.permit(:domain_name)
|
||||
t.require(:transfer_code)
|
||||
t.permit(:transfer_code)
|
||||
end
|
||||
params.require(:data).permit(domain_transfers: %i[domain_name transfer_code])
|
||||
end
|
||||
|
||||
def transfer_info_params
|
||||
params.require(:id)
|
||||
params.permit(:id)
|
||||
end
|
||||
|
||||
def set_authorized_domain
|
||||
@epp_errors ||= []
|
||||
h = {}
|
||||
h[transfer_info_params[:id].match?(/\A[0-9]+\z/) ? :id : :name] = transfer_info_params[:id]
|
||||
@domain = Domain.find_by!(h)
|
||||
|
||||
return if @domain.transfer_code.eql?(request.headers['Auth-Code'])
|
||||
|
||||
@epp_errors << { code: 2202, msg: I18n.t('errors.messages.epp_authorization_error') }
|
||||
handle_errors
|
||||
end
|
||||
|
||||
def limit
|
||||
index_params[:limit] || 200
|
||||
end
|
||||
|
||||
def offset
|
||||
index_params[:offset] || 0
|
||||
end
|
||||
|
||||
def index_params
|
||||
params.permit(:limit, :offset, :details)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
51
app/controllers/repp/v1/registrar/nameservers_controller.rb
Normal file
51
app/controllers/repp/v1/registrar/nameservers_controller.rb
Normal file
|
@ -0,0 +1,51 @@
|
|||
module Repp
|
||||
module V1
|
||||
module Registrar
|
||||
class NameserversController < BaseController
|
||||
before_action :verify_nameserver_existance, only: %i[update]
|
||||
|
||||
def update
|
||||
domains = params[:data][:domains] || []
|
||||
affected = current_user.registrar
|
||||
.replace_nameservers(hostname,
|
||||
hostname_params[:data][:attributes],
|
||||
domains: domains)
|
||||
|
||||
render_success(data: data_format_for_success(affected))
|
||||
rescue ActiveRecord::RecordInvalid => e
|
||||
handle_errors(e.record)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def data_format_for_success(affected_domains)
|
||||
{
|
||||
type: 'nameserver',
|
||||
id: params[:data][:attributes][:hostname],
|
||||
attributes: params[:data][:attributes],
|
||||
affected_domains: affected_domains,
|
||||
}
|
||||
end
|
||||
|
||||
def hostname_params
|
||||
params.require(:data).require(%i[type id])
|
||||
params.require(:data).require(:attributes).require([:hostname])
|
||||
|
||||
params.permit(data: [
|
||||
:type, :id,
|
||||
{ domains: [],
|
||||
attributes: [:hostname, { ipv4: [], ipv6: [] }] }
|
||||
])
|
||||
end
|
||||
|
||||
def hostname
|
||||
hostname_params[:data][:id]
|
||||
end
|
||||
|
||||
def verify_nameserver_existance
|
||||
current_user.registrar.nameservers.find_by!(hostname: hostname)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -3,8 +3,9 @@ module Repp
|
|||
class RetainedDomainsController < ActionController::API
|
||||
def index
|
||||
domains = RetainedDomains.new(query_params)
|
||||
@response = { count: domains.count, domains: domains.to_jsonable }
|
||||
|
||||
render json: { count: domains.count, domains: domains.to_jsonable }
|
||||
render json: @response
|
||||
end
|
||||
|
||||
def query_params
|
||||
|
|
|
@ -3,7 +3,7 @@ module ObjectVersionsHelper
|
|||
version.object_changes.to_h.each do |key, value|
|
||||
method_name = "#{key}=".to_sym
|
||||
if new_object.respond_to?(method_name)
|
||||
new_object.public_send(method_name, value.last)
|
||||
new_object.public_send(method_name, event_value(version, value))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -12,4 +12,10 @@ module ObjectVersionsHelper
|
|||
field_names = model.column_names
|
||||
version.object.to_h.select { |key, _value| field_names.include?(key) }
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def event_value(version, val)
|
||||
version.event == 'destroy' ? val.first : val.last
|
||||
end
|
||||
end
|
||||
|
|
7
app/interactions/cancel_force_delete_interaction/base.rb
Normal file
7
app/interactions/cancel_force_delete_interaction/base.rb
Normal file
|
@ -0,0 +1,7 @@
|
|||
module CancelForceDeleteInteraction
|
||||
class Base < ActiveInteraction::Base
|
||||
object :domain,
|
||||
class: Domain,
|
||||
description: 'Domain to cancel ForceDelete on'
|
||||
end
|
||||
end
|
|
@ -0,0 +1,10 @@
|
|||
module CancelForceDeleteInteraction
|
||||
class CancelForceDelete < Base
|
||||
def execute
|
||||
compose(RemoveForceDeleteStatuses, inputs)
|
||||
compose(RestoreStatusesBeforeForceDelete, inputs)
|
||||
compose(ClearForceDeleteData, inputs)
|
||||
compose(NotifyRegistrar, inputs)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,10 @@
|
|||
module CancelForceDeleteInteraction
|
||||
class ClearForceDeleteData < Base
|
||||
def execute
|
||||
domain.force_delete_data = nil
|
||||
domain.force_delete_date = nil
|
||||
domain.force_delete_start = nil
|
||||
domain.save(validate: false)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,8 @@
|
|||
module CancelForceDeleteInteraction
|
||||
class NotifyRegistrar < Base
|
||||
def execute
|
||||
domain.registrar.notifications.create!(text: I18n.t('force_delete_cancelled',
|
||||
domain_name: domain.name))
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,11 @@
|
|||
module CancelForceDeleteInteraction
|
||||
class RemoveForceDeleteStatuses < Base
|
||||
def execute
|
||||
domain.statuses.delete(DomainStatus::FORCE_DELETE)
|
||||
domain.statuses.delete(DomainStatus::SERVER_RENEW_PROHIBITED)
|
||||
domain.statuses.delete(DomainStatus::SERVER_TRANSFER_PROHIBITED)
|
||||
domain.statuses.delete(DomainStatus::CLIENT_HOLD)
|
||||
domain.save(validate: false)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,9 @@
|
|||
module CancelForceDeleteInteraction
|
||||
class RestoreStatusesBeforeForceDelete < Base
|
||||
def execute
|
||||
domain.statuses = domain.statuses_before_force_delete
|
||||
domain.statuses_before_force_delete = nil
|
||||
domain.save(validate: false)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,22 @@
|
|||
module DomainDeleteConfirmInteraction
|
||||
class SendRequest < ActiveInteraction::Base
|
||||
object :domain,
|
||||
class: Domain,
|
||||
description: 'Domain to send delete confirmation'
|
||||
|
||||
def execute
|
||||
log
|
||||
DomainDeleteMailer.confirmation_request(domain: domain,
|
||||
registrar: domain.registrar,
|
||||
registrant: domain.registrant).deliver_later
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def log
|
||||
message = "Send DomainDeleteMailer#confirm email for domain #{domain.name} (##{domain.id})" \
|
||||
" to #{domain.registrant.email}"
|
||||
Rails.logger.info(message)
|
||||
end
|
||||
end
|
||||
end
|
16
app/interactions/force_delete_interaction/base.rb
Normal file
16
app/interactions/force_delete_interaction/base.rb
Normal file
|
@ -0,0 +1,16 @@
|
|||
module ForceDeleteInteraction
|
||||
class Base < ActiveInteraction::Base
|
||||
object :domain,
|
||||
class: Domain,
|
||||
description: 'Domain to set ForceDelete on'
|
||||
symbol :type,
|
||||
default: :fast_track,
|
||||
description: 'Force delete type, might be :fast_track or :soft'
|
||||
boolean :notify_by_email,
|
||||
default: false,
|
||||
description: 'Do we need to send email notification'
|
||||
|
||||
validates :type, inclusion: { in: %i[fast_track soft] }
|
||||
end
|
||||
end
|
||||
|
11
app/interactions/force_delete_interaction/check_discarded.rb
Normal file
11
app/interactions/force_delete_interaction/check_discarded.rb
Normal file
|
@ -0,0 +1,11 @@
|
|||
module ForceDeleteInteraction
|
||||
class CheckDiscarded < Base
|
||||
def execute
|
||||
return true unless domain.discarded?
|
||||
|
||||
message = 'Force delete procedure cannot be scheduled while a domain is discarded'
|
||||
errors.add(:domain, message)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
21
app/interactions/force_delete_interaction/notify_by_email.rb
Normal file
21
app/interactions/force_delete_interaction/notify_by_email.rb
Normal file
|
@ -0,0 +1,21 @@
|
|||
module ForceDeleteInteraction
|
||||
class NotifyByEmail < Base
|
||||
def execute
|
||||
return unless notify_by_email
|
||||
|
||||
if type == :fast_track
|
||||
send_email
|
||||
domain.update(contact_notification_sent_date: Time.zone.today)
|
||||
else
|
||||
domain.update(template_name: domain.notification_template)
|
||||
end
|
||||
end
|
||||
|
||||
def send_email
|
||||
DomainDeleteMailer.forced(domain: domain,
|
||||
registrar: domain.registrar,
|
||||
registrant: domain.registrant,
|
||||
template_name: domain.notification_template).deliver_now
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,10 @@
|
|||
module ForceDeleteInteraction
|
||||
class NotifyRegistrar < Base
|
||||
def execute
|
||||
domain.registrar.notifications.create!(text: I18n.t('force_delete_set_on_domain',
|
||||
domain_name: domain.name,
|
||||
outzone_date: domain.outzone_date,
|
||||
purge_date: domain.purge_date))
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,17 @@
|
|||
module ForceDeleteInteraction
|
||||
class PostSetProcess < Base
|
||||
def execute
|
||||
statuses = domain.statuses
|
||||
# Stop all pending actions
|
||||
statuses.delete(DomainStatus::PENDING_UPDATE)
|
||||
statuses.delete(DomainStatus::PENDING_TRANSFER)
|
||||
statuses.delete(DomainStatus::PENDING_RENEW)
|
||||
statuses.delete(DomainStatus::PENDING_CREATE)
|
||||
|
||||
# Allow deletion
|
||||
statuses.delete(DomainStatus::CLIENT_DELETE_PROHIBITED)
|
||||
statuses.delete(DomainStatus::SERVER_DELETE_PROHIBITED)
|
||||
domain.save(validate: false)
|
||||
end
|
||||
end
|
||||
end
|
13
app/interactions/force_delete_interaction/prepare_domain.rb
Normal file
13
app/interactions/force_delete_interaction/prepare_domain.rb
Normal file
|
@ -0,0 +1,13 @@
|
|||
module ForceDeleteInteraction
|
||||
class PrepareDomain < Base
|
||||
STATUSES_TO_SET = [DomainStatus::FORCE_DELETE,
|
||||
DomainStatus::SERVER_RENEW_PROHIBITED,
|
||||
DomainStatus::SERVER_TRANSFER_PROHIBITED].freeze
|
||||
|
||||
def execute
|
||||
domain.statuses_before_force_delete = domain.statuses
|
||||
domain.statuses |= STATUSES_TO_SET
|
||||
domain.save(validate: false)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,12 @@
|
|||
module ForceDeleteInteraction
|
||||
class SetForceDelete < Base
|
||||
def execute
|
||||
compose(CheckDiscarded, inputs)
|
||||
compose(PrepareDomain, inputs)
|
||||
compose(SetStatus, inputs)
|
||||
compose(PostSetProcess, inputs)
|
||||
compose(NotifyRegistrar, inputs)
|
||||
compose(NotifyByEmail, inputs)
|
||||
end
|
||||
end
|
||||
end
|
38
app/interactions/force_delete_interaction/set_status.rb
Normal file
38
app/interactions/force_delete_interaction/set_status.rb
Normal file
|
@ -0,0 +1,38 @@
|
|||
module ForceDeleteInteraction
|
||||
class SetStatus < Base
|
||||
def execute
|
||||
domain.force_delete_type = type
|
||||
type == :fast_track ? force_delete_fast_track : force_delete_soft
|
||||
domain.save(validate: false)
|
||||
end
|
||||
|
||||
def force_delete_fast_track
|
||||
domain.force_delete_date = Time.zone.today +
|
||||
expire_warning_period_days +
|
||||
redemption_grace_period_days
|
||||
domain.force_delete_start = Time.zone.today + 1.day
|
||||
end
|
||||
|
||||
def force_delete_soft
|
||||
years = (domain.valid_to.to_date - Time.zone.today).to_i / 365
|
||||
soft_forcedelete_dates(years) if years.positive?
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def soft_forcedelete_dates(years)
|
||||
domain.force_delete_start = domain.valid_to - years.years
|
||||
domain.force_delete_date = domain.force_delete_start +
|
||||
Setting.expire_warning_period.days +
|
||||
Setting.redemption_grace_period.days
|
||||
end
|
||||
|
||||
def redemption_grace_period_days
|
||||
Setting.redemption_grace_period.days + 1.day
|
||||
end
|
||||
|
||||
def expire_warning_period_days
|
||||
Setting.expire_warning_period.days
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,22 +0,0 @@
|
|||
class DomainDeleteConfirmEmailJob < Que::Job
|
||||
def run(domain_id)
|
||||
domain = Domain.find(domain_id)
|
||||
|
||||
log(domain)
|
||||
DomainDeleteMailer.confirmation_request(domain: domain,
|
||||
registrar: domain.registrar,
|
||||
registrant: domain.registrant).deliver_now
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def log(domain)
|
||||
message = "Send DomainDeleteMailer#confirm email for domain #{domain.name} (##{domain.id})" \
|
||||
" to #{domain.registrant.email}"
|
||||
logger.info(message)
|
||||
end
|
||||
|
||||
def logger
|
||||
Rails.logger
|
||||
end
|
||||
end
|
|
@ -1,4 +1,15 @@
|
|||
class ApplicationMailer < ActionMailer::Base
|
||||
append_view_path Rails.root.join('app', 'views', 'mailers')
|
||||
layout 'mailer'
|
||||
end
|
||||
|
||||
def registrant_confirm_url(domain:, method:)
|
||||
token = domain.registrant_verification_token
|
||||
base_url = ENV['registrant_portal_verifications_base_url']
|
||||
|
||||
url = registrant_domain_delete_confirm_url(domain, token: token) if method == 'delete'
|
||||
url ||= registrant_domain_update_confirm_url(domain, token: token)
|
||||
return url if base_url.blank?
|
||||
|
||||
"#{base_url}/confirmation/#{domain.name_puny}/#{method}/#{token}"
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,7 +2,7 @@ class DomainDeleteMailer < ApplicationMailer
|
|||
def confirmation_request(domain:, registrar:, registrant:)
|
||||
@domain = DomainPresenter.new(domain: domain, view: view_context)
|
||||
@registrar = RegistrarPresenter.new(registrar: registrar, view: view_context)
|
||||
@confirmation_url = confirmation_url(domain)
|
||||
@confirmation_url = registrant_confirm_url(domain: domain, method: 'delete')
|
||||
|
||||
subject = default_i18n_subject(domain_name: domain.name)
|
||||
mail(to: registrant.email, subject: subject)
|
||||
|
@ -48,10 +48,6 @@ class DomainDeleteMailer < ApplicationMailer
|
|||
|
||||
private
|
||||
|
||||
def confirmation_url(domain)
|
||||
registrant_domain_delete_confirm_url(domain, token: domain.registrant_verification_token)
|
||||
end
|
||||
|
||||
def forced_email_from
|
||||
ENV['action_mailer_force_delete_from'] || self.class.default[:from]
|
||||
end
|
||||
|
|
|
@ -5,7 +5,7 @@ class RegistrantChangeMailer < ApplicationMailer
|
|||
@domain = DomainPresenter.new(domain: domain, view: view_context)
|
||||
@registrar = RegistrarPresenter.new(registrar: registrar, view: view_context)
|
||||
@new_registrant = RegistrantPresenter.new(registrant: new_registrant, view: view_context)
|
||||
@confirmation_url = confirmation_url(domain)
|
||||
@confirmation_url = registrant_confirm_url(domain: domain, method: 'change')
|
||||
|
||||
subject = default_i18n_subject(domain_name: domain.name)
|
||||
mail(to: current_registrant.email, subject: subject)
|
||||
|
@ -49,10 +49,6 @@ class RegistrantChangeMailer < ApplicationMailer
|
|||
|
||||
private
|
||||
|
||||
def confirmation_url(domain)
|
||||
registrant_domain_update_confirm_url(domain, token: domain.registrant_verification_token)
|
||||
end
|
||||
|
||||
def address_processing
|
||||
Contact.address_processing?
|
||||
end
|
||||
|
|
81
app/models/actions/contact_create.rb
Normal file
81
app/models/actions/contact_create.rb
Normal file
|
@ -0,0 +1,81 @@
|
|||
module Actions
|
||||
class ContactCreate
|
||||
attr_reader :contact, :legal_document, :ident
|
||||
|
||||
def initialize(contact, legal_document, ident)
|
||||
@contact = contact
|
||||
@legal_document = legal_document
|
||||
@ident = ident
|
||||
end
|
||||
|
||||
def call
|
||||
maybe_remove_address
|
||||
maybe_attach_legal_doc
|
||||
validate_ident
|
||||
commit
|
||||
end
|
||||
|
||||
def maybe_remove_address
|
||||
return if Contact.address_processing?
|
||||
|
||||
contact.city = nil
|
||||
contact.zip = nil
|
||||
contact.street = nil
|
||||
contact.state = nil
|
||||
contact.country_code = nil
|
||||
end
|
||||
|
||||
def validate_ident
|
||||
validate_ident_integrity
|
||||
validate_ident_birthday
|
||||
|
||||
identifier = ::Contact::Ident.new(code: ident[:ident], type: ident[:ident_type],
|
||||
country_code: ident[:ident_country_code])
|
||||
|
||||
identifier.validate
|
||||
contact.identifier = identifier
|
||||
end
|
||||
|
||||
def validate_ident_integrity
|
||||
return if ident.blank?
|
||||
|
||||
if ident[:ident_type].blank?
|
||||
contact.add_epp_error('2003', nil, 'ident_type',
|
||||
I18n.t('errors.messages.required_ident_attribute_missing'))
|
||||
@error = true
|
||||
elsif !%w[priv org birthday].include?(ident[:ident_type])
|
||||
contact.add_epp_error('2003', nil, 'ident_type', 'Invalid ident type')
|
||||
@error = true
|
||||
end
|
||||
end
|
||||
|
||||
def validate_ident_birthday
|
||||
return if ident.blank?
|
||||
return unless ident[:ident_type] != 'birthday' && ident[:ident_country_code].blank?
|
||||
|
||||
contact.add_epp_error('2003', nil, 'ident_country_code',
|
||||
I18n.t('errors.messages.required_ident_attribute_missing'))
|
||||
@error = true
|
||||
end
|
||||
|
||||
def maybe_attach_legal_doc
|
||||
return unless legal_document
|
||||
|
||||
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
|
||||
|
||||
def commit
|
||||
contact.id = nil # new record
|
||||
return false if @error
|
||||
|
||||
contact.generate_code
|
||||
contact.save
|
||||
end
|
||||
end
|
||||
end
|
41
app/models/actions/contact_delete.rb
Normal file
41
app/models/actions/contact_delete.rb
Normal file
|
@ -0,0 +1,41 @@
|
|||
module Actions
|
||||
class ContactDelete
|
||||
attr_reader :contact
|
||||
attr_reader :new_attributes
|
||||
attr_reader :legal_document
|
||||
attr_reader :ident
|
||||
attr_reader :user
|
||||
|
||||
def initialize(contact, legal_document = nil)
|
||||
@legal_document = legal_document
|
||||
@contact = contact
|
||||
end
|
||||
|
||||
def call
|
||||
maybe_attach_legal_doc
|
||||
|
||||
if contact.linked?
|
||||
contact.errors.add(:domains, :exist)
|
||||
return
|
||||
end
|
||||
|
||||
commit
|
||||
end
|
||||
|
||||
def maybe_attach_legal_doc
|
||||
return unless 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
|
||||
|
||||
def commit
|
||||
contact.destroy
|
||||
end
|
||||
end
|
||||
end
|
|
@ -17,7 +17,7 @@ module Actions
|
|||
def call
|
||||
maybe_remove_address
|
||||
maybe_update_statuses
|
||||
maybe_update_ident
|
||||
maybe_update_ident if ident.present?
|
||||
maybe_attach_legal_doc
|
||||
commit
|
||||
end
|
||||
|
@ -53,7 +53,11 @@ module Actions
|
|||
end
|
||||
|
||||
def maybe_update_ident
|
||||
return unless ident[:ident]
|
||||
unless ident.is_a?(Hash)
|
||||
contact.add_epp_error('2308', nil, nil, I18n.t('epp.contacts.errors.valid_ident'))
|
||||
@error = true
|
||||
return
|
||||
end
|
||||
|
||||
if contact.identifier.valid?
|
||||
submitted_ident = ::Contact::Ident.new(code: ident[:ident],
|
||||
|
|
74
app/models/actions/domain_transfer.rb
Normal file
74
app/models/actions/domain_transfer.rb
Normal file
|
@ -0,0 +1,74 @@
|
|||
module Actions
|
||||
class DomainTransfer
|
||||
attr_reader :domain
|
||||
attr_reader :transfer_code
|
||||
attr_reader :legal_document
|
||||
attr_reader :ident
|
||||
attr_reader :user
|
||||
|
||||
def initialize(domain, transfer_code, user)
|
||||
@domain = domain
|
||||
@transfer_code = transfer_code
|
||||
@user = user
|
||||
end
|
||||
|
||||
def call
|
||||
return unless domain_exists?
|
||||
return unless valid_transfer_code?
|
||||
|
||||
run_validations
|
||||
|
||||
# return domain.pending_transfer if domain.pending_transfer
|
||||
# attach_legal_document(::Deserializers::Xml::LegalDocument.new(frame).call)
|
||||
|
||||
return if domain.errors[:epp_errors].any?
|
||||
|
||||
commit
|
||||
end
|
||||
|
||||
def domain_exists?
|
||||
return true if domain.persisted?
|
||||
|
||||
domain.add_epp_error('2303', nil, nil, 'Object does not exist')
|
||||
|
||||
false
|
||||
end
|
||||
|
||||
def run_validations
|
||||
validate_registrar
|
||||
validate_eligilibty
|
||||
validate_not_discarded
|
||||
end
|
||||
|
||||
def valid_transfer_code?
|
||||
return true if transfer_code == domain.transfer_code
|
||||
|
||||
domain.add_epp_error('2202', nil, nil, 'Invalid authorization information')
|
||||
false
|
||||
end
|
||||
|
||||
def validate_registrar
|
||||
return unless user == domain.registrar
|
||||
|
||||
domain.add_epp_error('2002', nil, nil,
|
||||
I18n.t(:domain_already_belongs_to_the_querying_registrar))
|
||||
end
|
||||
|
||||
def validate_eligilibty
|
||||
return unless domain.non_transferable?
|
||||
|
||||
domain.add_epp_error('2304', nil, nil, 'Object status prohibits operation')
|
||||
end
|
||||
|
||||
def validate_not_discarded
|
||||
return unless domain.discarded?
|
||||
|
||||
domain.add_epp_error('2106', nil, nil, 'Object is not eligible for transfer')
|
||||
end
|
||||
|
||||
def commit
|
||||
bare_domain = Domain.find(domain.id)
|
||||
::DomainTransfer.request(bare_domain, user)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -52,51 +52,14 @@ module Concerns::Domain::ForceDelete # rubocop:disable Metrics/ModuleLength
|
|||
force_delete_start + Setting.expire_warning_period.days <= valid_to
|
||||
end
|
||||
|
||||
def schedule_force_delete(type: :fast_track)
|
||||
if discarded?
|
||||
raise StandardError, 'Force delete procedure cannot be scheduled while a domain is discarded'
|
||||
end
|
||||
|
||||
type == :fast_track ? force_delete_fast_track : force_delete_soft
|
||||
end
|
||||
|
||||
def add_force_delete_type(force_delete_type)
|
||||
self.force_delete_type = force_delete_type
|
||||
end
|
||||
|
||||
def force_delete_fast_track
|
||||
preserve_current_statuses_for_force_delete
|
||||
add_force_delete_statuses
|
||||
add_force_delete_type(:fast)
|
||||
self.force_delete_date = force_delete_fast_track_start_date + 1.day
|
||||
self.force_delete_start = Time.zone.today + 1.day
|
||||
stop_all_pending_actions
|
||||
allow_deletion
|
||||
save(validate: false)
|
||||
end
|
||||
|
||||
def force_delete_soft
|
||||
preserve_current_statuses_for_force_delete
|
||||
add_force_delete_statuses
|
||||
add_force_delete_type(:soft)
|
||||
calculate_soft_delete_date
|
||||
stop_all_pending_actions
|
||||
allow_deletion
|
||||
save(validate: false)
|
||||
end
|
||||
|
||||
def clear_force_delete_data
|
||||
self.force_delete_data = nil
|
||||
def schedule_force_delete(type: :fast_track, notify_by_email: false)
|
||||
ForceDeleteInteraction::SetForceDelete.run(domain: self,
|
||||
type: type,
|
||||
notify_by_email: notify_by_email)
|
||||
end
|
||||
|
||||
def cancel_force_delete
|
||||
remove_force_delete_statuses
|
||||
restore_statuses_before_force_delete
|
||||
clear_force_delete_data
|
||||
self.force_delete_date = nil
|
||||
self.force_delete_start = nil
|
||||
save(validate: false)
|
||||
registrar.notifications.create!(text: I18n.t('force_delete_cancelled', domain_name: name))
|
||||
CancelForceDeleteInteraction::CancelForceDelete.run(domain: self)
|
||||
end
|
||||
|
||||
def outzone_date
|
||||
|
@ -107,55 +70,4 @@ module Concerns::Domain::ForceDelete # rubocop:disable Metrics/ModuleLength
|
|||
(force_delete_date&.beginning_of_day || valid_to + Setting.expire_warning_period.days +
|
||||
Setting.redemption_grace_period.days)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def calculate_soft_delete_date
|
||||
years = (valid_to.to_date - Time.zone.today).to_i / 365
|
||||
soft_delete_dates(years) if years.positive?
|
||||
end
|
||||
|
||||
def soft_delete_dates(years)
|
||||
self.force_delete_start = valid_to - years.years
|
||||
self.force_delete_date = force_delete_start + Setting.expire_warning_period.days +
|
||||
Setting.redemption_grace_period.days
|
||||
end
|
||||
|
||||
def stop_all_pending_actions
|
||||
statuses.delete(DomainStatus::PENDING_UPDATE)
|
||||
statuses.delete(DomainStatus::PENDING_TRANSFER)
|
||||
statuses.delete(DomainStatus::PENDING_RENEW)
|
||||
statuses.delete(DomainStatus::PENDING_CREATE)
|
||||
end
|
||||
|
||||
def preserve_current_statuses_for_force_delete
|
||||
update(statuses_before_force_delete: statuses)
|
||||
end
|
||||
|
||||
def restore_statuses_before_force_delete
|
||||
self.statuses = statuses_before_force_delete
|
||||
self.statuses_before_force_delete = nil
|
||||
end
|
||||
|
||||
def add_force_delete_statuses
|
||||
self.statuses |= [DomainStatus::FORCE_DELETE,
|
||||
DomainStatus::SERVER_RENEW_PROHIBITED,
|
||||
DomainStatus::SERVER_TRANSFER_PROHIBITED]
|
||||
end
|
||||
|
||||
def remove_force_delete_statuses
|
||||
statuses.delete(DomainStatus::FORCE_DELETE)
|
||||
statuses.delete(DomainStatus::SERVER_RENEW_PROHIBITED)
|
||||
statuses.delete(DomainStatus::SERVER_TRANSFER_PROHIBITED)
|
||||
statuses.delete(DomainStatus::CLIENT_HOLD)
|
||||
end
|
||||
|
||||
def allow_deletion
|
||||
statuses.delete(DomainStatus::CLIENT_DELETE_PROHIBITED)
|
||||
statuses.delete(DomainStatus::SERVER_DELETE_PROHIBITED)
|
||||
end
|
||||
|
||||
def force_delete_fast_track_start_date
|
||||
Time.zone.today + Setting.expire_warning_period.days + Setting.redemption_grace_period.days
|
||||
end
|
||||
end
|
||||
|
|
|
@ -333,31 +333,6 @@ class Contact < ApplicationRecord
|
|||
Country.new(country_code)
|
||||
end
|
||||
|
||||
# TODO: refactor, it should not allow to destroy with normal destroy,
|
||||
# no need separate method
|
||||
# should use only in transaction
|
||||
def destroy_and_clean frame
|
||||
if linked?
|
||||
errors.add(:domains, :exist)
|
||||
return false
|
||||
end
|
||||
|
||||
legal_document_data = ::Deserializers::Xml::LegalDocument.new(frame).call
|
||||
|
||||
if legal_document_data
|
||||
|
||||
doc = LegalDocument.create(
|
||||
documentable_type: Contact,
|
||||
document_type: legal_document_data[:type],
|
||||
body: legal_document_data[:body]
|
||||
)
|
||||
self.legal_documents = [doc]
|
||||
self.legal_document_id = doc.id
|
||||
self.save
|
||||
end
|
||||
destroy
|
||||
end
|
||||
|
||||
def to_upcase_country_code
|
||||
self.ident_country_code = ident_country_code.upcase if ident_country_code
|
||||
self.country_code = country_code.upcase if country_code
|
||||
|
|
|
@ -418,7 +418,7 @@ class Domain < ApplicationRecord
|
|||
pending_delete_confirmation!
|
||||
save(validate: false) # should check if this did succeed
|
||||
|
||||
DomainDeleteConfirmEmailJob.enqueue(id)
|
||||
DomainDeleteConfirmInteraction::SendRequest.run(domain: self)
|
||||
end
|
||||
|
||||
def cancel_pending_delete
|
||||
|
|
|
@ -30,12 +30,13 @@ class Epp::Contact < Contact
|
|||
at
|
||||
end
|
||||
|
||||
def new(frame, registrar)
|
||||
def new(frame, registrar, epp: true)
|
||||
return super if frame.blank?
|
||||
|
||||
attrs = epp ? attrs_from(frame, new_record: true) : frame
|
||||
super(
|
||||
attrs_from(frame, new_record: true).merge(
|
||||
code: frame.css('id').text,
|
||||
attrs.merge(
|
||||
code: epp ? frame.css('id').text : frame[:id],
|
||||
registrar: registrar
|
||||
)
|
||||
)
|
||||
|
|
|
@ -137,7 +137,8 @@ class Registrar < ApplicationRecord
|
|||
|
||||
def api_ip_white?(ip)
|
||||
return true unless Setting.api_ip_whitelist_enabled
|
||||
white_ips.api.pluck(:ipv4, :ipv6).flatten.include?(ip)
|
||||
|
||||
white_ips.api.include_ip?(ip)
|
||||
end
|
||||
|
||||
# Audit log is needed, therefore no raw SQL
|
||||
|
|
|
@ -2,8 +2,8 @@ class WhiteIp < ApplicationRecord
|
|||
include Versions
|
||||
belongs_to :registrar
|
||||
|
||||
validates :ipv4, format: { with: /\A(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\z/, allow_blank: true }
|
||||
validates :ipv6, format: { with: /(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]).){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]).){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))/, allow_blank: true }
|
||||
validate :valid_ipv4?
|
||||
validate :valid_ipv6?
|
||||
|
||||
validate :validate_ipv4_and_ipv6
|
||||
def validate_ipv4_and_ipv6
|
||||
|
@ -11,6 +11,22 @@ class WhiteIp < ApplicationRecord
|
|||
errors.add(:base, I18n.t(:ipv4_or_ipv6_must_be_present))
|
||||
end
|
||||
|
||||
def valid_ipv4?
|
||||
return if ipv4.blank?
|
||||
|
||||
IPAddr.new(ipv4, Socket::AF_INET)
|
||||
rescue StandardError => _e
|
||||
errors.add(:ipv4, :invalid)
|
||||
end
|
||||
|
||||
def valid_ipv6?
|
||||
return if ipv6.blank?
|
||||
|
||||
IPAddr.new(ipv6, Socket::AF_INET6)
|
||||
rescue StandardError => _e
|
||||
errors.add(:ipv6, :invalid)
|
||||
end
|
||||
|
||||
API = 'api'
|
||||
REGISTRAR = 'registrar'
|
||||
INTERFACES = [API, REGISTRAR]
|
||||
|
@ -23,8 +39,37 @@ class WhiteIp < ApplicationRecord
|
|||
end
|
||||
|
||||
class << self
|
||||
# rubocop:disable Style/CaseEquality
|
||||
# rubocop:disable Metrics/AbcSize
|
||||
def include_ip?(ip)
|
||||
where('ipv4 = :ip OR ipv6 = :ip', ip: ip).any?
|
||||
return false if ip.blank?
|
||||
|
||||
where(id: ids_including(ip)).any?
|
||||
end
|
||||
|
||||
def ids_including(ip)
|
||||
ipv4 = ipv6 = []
|
||||
if check_ip4(ip).present?
|
||||
ipv4 = select { |white_ip| IPAddr.new(white_ip.ipv4, Socket::AF_INET) === check_ip4(ip) }
|
||||
end
|
||||
if check_ip6(ip).present?
|
||||
ipv6 = select { |white_ip| IPAddr.new(white_ip.ipv6, Socket::AF_INET6) === check_ip6(ip) }
|
||||
end
|
||||
(ipv4 + ipv6).pluck(:id).flatten.uniq
|
||||
end
|
||||
# rubocop:enable Style/CaseEquality
|
||||
# rubocop:enable Metrics/AbcSize
|
||||
|
||||
def check_ip4(ip)
|
||||
IPAddr.new(ip, Socket::AF_INET)
|
||||
rescue StandardError => _e
|
||||
nil
|
||||
end
|
||||
|
||||
def check_ip6(ip)
|
||||
IPAddr.new(ip, Socket::AF_INET6)
|
||||
rescue StandardError => _e
|
||||
nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -5,6 +5,7 @@ class RegistrantChange
|
|||
end
|
||||
|
||||
def confirm
|
||||
Dispute.close_by_domain(@domain.name) if @domain.disputed?
|
||||
notify_registrant
|
||||
end
|
||||
|
||||
|
|
|
@ -14,11 +14,15 @@ xml.epp_head do
|
|||
end
|
||||
|
||||
xml.tag!('contact:postalInfo', type: 'int') do
|
||||
xml.tag!('contact:name', @contact.name)
|
||||
if can? :view_full_info, @contact, @password
|
||||
xml.tag!('contact:name', @contact.name)
|
||||
else
|
||||
xml.tag!('contact:name', 'No access')
|
||||
end
|
||||
if can? :view_full_info, @contact, @password
|
||||
xml.tag!('contact:org', @contact.org_name) if @contact.org_name.present?
|
||||
|
||||
if address_processing?
|
||||
if Contact.address_processing?
|
||||
xml.tag!('contact:addr') do
|
||||
xml.tag!('contact:street', @contact.street)
|
||||
xml.tag!('contact:city', @contact.city)
|
||||
|
@ -31,7 +35,7 @@ xml.epp_head do
|
|||
else
|
||||
xml.tag!('contact:org', 'No access')
|
||||
|
||||
if address_processing?
|
||||
if Contact.address_processing?
|
||||
xml.tag!('contact:addr') do
|
||||
xml.tag!('contact:street', 'No access')
|
||||
xml.tag!('contact:city', 'No access')
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
<p>Lugupeetud .ee domeeni registreerija/halduskontakt</p>
|
||||
|
||||
<p>Domeeninimi <%= @domain.name %> on aegunud ja ei ole alates <%= @domain.on_hold_date %> internetis kättesaadav. Domeeniga on seotud puudulike kontakti objekte, milles tulenevalt on Eesti Interneti SA blokeerinud domeeni pikendamise ja registripidaja vahetuse, kuniks kontaktandmed korrastatakse. Andmete korrastamiseks ja registreeringu pikendamiseks pöörduge palun oma registripidaja poole.</p>
|
||||
<p>Domeeninimi <%= @domain.name %> on aegunud ja ei ole alates <%= @domain.on_hold_date %> internetis kättesaadav. Domeeniga on seotud puudulikke kontakti objekte, millest tulenevalt on Eesti Interneti SA blokeerinud domeeni pikendamise ja registripidaja vahetuse, kuniks kontaktandmed korrastatakse. Andmete korrastamiseks ja registreeringu pikendamiseks pöörduge palun oma registripidaja poole.</p>
|
||||
|
||||
<p><%= @domain.name %> pikendamata jätmisel domeen kustub ja läheb <%= @domain.delete_date %> oksjonile .ee oksjonikeskkonda. Domeenioksjonite kohta loe lähemalt <a href="https://www.internet.ee/domeenioksjonid">siit</a>.</p>
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ Domeen <%= @domain.name %> on aegunud ning suunatud kustutusmenetlusse kuna olem
|
|||
|
||||
Lugupeetud .ee domeeni registreerija/halduskontakt
|
||||
|
||||
Domeeninimi <%= @domain.name %> on aegunud ja ei ole alates <%= @domain.on_hold_date %> internetis kättesaadav. Domeeniga on seotud puudulike kontakti objekte, milles tulenevalt on Eesti Interneti SA blokeerinud domeeni pikendamise ja registripidaja vahetuse, kuniks kontaktandmed korrastatakse. Andmete korrastamiseks ja registreeringu pikendamiseks pöörduge palun oma registripidaja poole.
|
||||
Domeeninimi <%= @domain.name %> on aegunud ja ei ole alates <%= @domain.on_hold_date %> internetis kättesaadav. Domeeniga on seotud puudulikke kontakti objekte, millest tulenevalt on Eesti Interneti SA blokeerinud domeeni pikendamise ja registripidaja vahetuse, kuniks kontaktandmed korrastatakse. Andmete korrastamiseks ja registreeringu pikendamiseks pöörduge palun oma registripidaja poole.
|
||||
|
||||
<%= @domain.name %> pikendamata jätmisel domeen kustub ja läheb <%= @domain.delete_date %> oksjonile .ee oksjonikeskkonda. Domeenioksjonite kohta loe lähemalt siit https://www.internet.ee/domeenioksjonid.
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
.col-md-8
|
||||
= render 'registrar/contacts/form/general', f: f
|
||||
|
||||
- if address_processing?
|
||||
- if Contact.address_processing?
|
||||
.row
|
||||
.col-md-8
|
||||
= render 'registrar/contacts/form/address', f: f
|
||||
|
|
|
@ -13,5 +13,5 @@
|
|||
- registrant = Contact.find_by_code(x.text)
|
||||
%tr
|
||||
%td= x['type']
|
||||
%td= registrant.name
|
||||
%td= registrant.registrar == current_registrar_user.registrar ? registrant.name : 'N/A'
|
||||
%td= x.text
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
|
||||
<% registrant = Contact.find_by_code(@data.css('registrant').text) %>
|
||||
<dt><%= t('.registrant') %></dt>
|
||||
<dd><%= "#{registrant.name} (#{@data.css('registrant').text})" %></dd>
|
||||
<dd><%= registrant.registrar == current_registrar_user.registrar ? "#{registrant.name} (#{@data.css('registrant').text})" : @data.css('registrant').text %></dd>
|
||||
|
||||
<dt><%= t('.registered') %></dt>
|
||||
<dd><%= @data.css('crDate').text %></dd>
|
||||
|
|
|
@ -36,6 +36,7 @@ module DomainNameRegistry
|
|||
|
||||
# Autoload all model subdirs
|
||||
config.autoload_paths += Dir[Rails.root.join('app', 'models', '**/')]
|
||||
config.autoload_paths += Dir[Rails.root.join('app', 'interactions', '**/')]
|
||||
config.eager_load_paths << config.root.join('lib', 'validators')
|
||||
config.watchable_dirs['lib'] = %i[rb]
|
||||
|
||||
|
|
|
@ -87,6 +87,9 @@ sk_digi_doc_service_name: 'Testimine'
|
|||
registrant_api_base_url:
|
||||
registrant_api_auth_allowed_ips: '127.0.0.1, 0.0.0.0' #ips, separated with commas
|
||||
|
||||
# Base URL (inc. https://) of REST registrant portal
|
||||
# Leave blank to use internal registrant portal
|
||||
registrant_portal_verifications_base_url: ''
|
||||
#
|
||||
# MISC
|
||||
|
||||
|
|
|
@ -37,12 +37,35 @@ Rails.application.routes.draw do
|
|||
get 'error/:command', to: 'errors#error'
|
||||
end
|
||||
|
||||
mount Repp::API => '/'
|
||||
|
||||
namespace :repp do
|
||||
namespace :v1 do
|
||||
resources :contacts do
|
||||
collection do
|
||||
get 'check/:id', to: 'contacts#check'
|
||||
end
|
||||
end
|
||||
|
||||
resources :accounts do
|
||||
collection do
|
||||
get 'balance'
|
||||
end
|
||||
end
|
||||
resources :auctions, only: %i[index]
|
||||
resources :retained_domains, only: %i[index]
|
||||
namespace :registrar do
|
||||
resources :nameservers do
|
||||
collection do
|
||||
put '/', to: 'nameservers#update'
|
||||
end
|
||||
end
|
||||
end
|
||||
resources :domains do
|
||||
collection do
|
||||
get ':id/transfer_info', to: 'domains#transfer_info', constraints: { id: /.*/ }
|
||||
post 'transfer', to: 'domains#transfer'
|
||||
patch 'contacts', to: 'domains/contacts#update'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -56,6 +79,8 @@ Rails.application.routes.draw do
|
|||
namespace :v1 do
|
||||
namespace :registrant do
|
||||
post 'auth/eid', to: 'auth#eid'
|
||||
get 'confirms/:name/:template/:token', to: 'confirms#index', constraints: { name: /[^\/]+/ }
|
||||
post 'confirms/:name/:template/:token/:decision', to: 'confirms#update', constraints: { name: /[^\/]+/ }
|
||||
|
||||
resources :domains, only: %i[index show], param: :uuid do
|
||||
resource :registry_lock, only: %i[create destroy]
|
||||
|
|
|
@ -19,7 +19,11 @@ Content-Length: 37
|
|||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"balance": "324.45",
|
||||
"currency": "EUR"
|
||||
"code": 1000,
|
||||
"message": "Command completed successfully",
|
||||
"data": {
|
||||
"balance": "356.0",
|
||||
"currency": "EUR"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
|
|
@ -88,3 +88,141 @@ Content-Type: application/json
|
|||
"total_number_of_records": 2
|
||||
}
|
||||
```
|
||||
|
||||
## POST /repp/v1/contacts
|
||||
Creates new contact
|
||||
|
||||
|
||||
#### Request
|
||||
```
|
||||
POST /repp/v1/contacts HTTP/1.1
|
||||
Authorization: Basic dGVzdDp0ZXN0MTIz
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"contact": {
|
||||
"name": "John Doe",
|
||||
"email": "john@doe.com",
|
||||
"phone": "+371.1234567",
|
||||
"ident": {
|
||||
"ident": "12345678901",
|
||||
"ident_type": "priv",
|
||||
"ident_country_code": "EE"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Response
|
||||
```
|
||||
HTTP/1.1 200
|
||||
Cache-Control: max-age=0, private, must-revalidate
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"code": 1000,
|
||||
"message": "Command completed successfully",
|
||||
"data": {
|
||||
"contact": {
|
||||
"id": "ATSAA:20DCDCA1"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Failed response
|
||||
```
|
||||
HTTP/1.1 400
|
||||
Cache-Control: max-age=0, private, must-revalidate
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"code": 2005,
|
||||
"message": "Ident code does not conform to national identification number format of Estonia",
|
||||
"data": {}
|
||||
}
|
||||
```
|
||||
|
||||
## PUT /repp/v1/contacts/**contact id**
|
||||
Updates existing contact
|
||||
|
||||
|
||||
#### Request
|
||||
```
|
||||
PUT /repp/v1/contacts/ATSAA:9CD5F321 HTTP/1.1
|
||||
Authorization: Basic dGVzdDp0ZXN0MTIz
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"contact": {
|
||||
"phone": "+372.123123123"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Response
|
||||
```
|
||||
HTTP/1.1 200
|
||||
Cache-Control: max-age=0, private, must-revalidate
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"code": 1000,
|
||||
"message": "Command completed successfully",
|
||||
"data": {
|
||||
"contact": {
|
||||
"id": "ATSAA:20DCDCA1"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Failed response
|
||||
```
|
||||
HTTP/1.1 400
|
||||
Cache-Control: max-age=0, private, must-revalidate
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"code": 2005,
|
||||
"message": "Phone nr is invalid [phone]",
|
||||
"data": {}
|
||||
}
|
||||
```
|
||||
|
||||
## DELETE /repp/v1/contacts/**contact id**
|
||||
Deletes existing contact
|
||||
|
||||
|
||||
#### Request
|
||||
```
|
||||
DELETE /repp/v1/contacts/ATSAA:9CD5F321 HTTP/1.1
|
||||
Authorization: Basic dGVzdDp0ZXN0MTIz
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
#### Response
|
||||
```
|
||||
HTTP/1.1 200
|
||||
Cache-Control: max-age=0, private, must-revalidate
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"code": 1000,
|
||||
"message": "Command completed successfully",
|
||||
"data": {}
|
||||
}
|
||||
```
|
||||
|
||||
#### Failed response
|
||||
```
|
||||
HTTP/1.1 400
|
||||
Cache-Control: max-age=0, private, must-revalidate
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"code": 2305,
|
||||
"message": "Object association prohibits operation [domains]",
|
||||
"data": {}
|
||||
}
|
||||
```
|
||||
|
|
|
@ -25,44 +25,52 @@ Content-Type: application/json
|
|||
```
|
||||
HTTP/1.1 200
|
||||
Cache-Control: max-age=0, private, must-revalidate
|
||||
Content-Length: 808
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"domains": [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "domain0.ee",
|
||||
"registrar_id": 2,
|
||||
"registered_at": "2015-09-09T09:11:14.861Z",
|
||||
"status": null,
|
||||
"valid_from": "2015-09-09T09:11:14.861Z",
|
||||
"valid_to": "2016-09-09T09:11:14.861Z",
|
||||
"registrant_id": 1,
|
||||
"transfer_code": "98oiewslkfkd",
|
||||
"created_at": "2015-09-09T09:11:14.861Z",
|
||||
"updated_at": "2015-09-09T09:11:14.860Z",
|
||||
"name_dirty": "domain0.ee",
|
||||
"name_puny": "domain0.ee",
|
||||
"period": 1,
|
||||
"period_unit": "y",
|
||||
"creator_str": null,
|
||||
"updator_str": null,
|
||||
"outzone_at": "2016-09-24T09:11:14.861Z",
|
||||
"delete_date": "2016-10-24",
|
||||
"registrant_verification_asked_at": null,
|
||||
"registrant_verification_token": null,
|
||||
"pending_json": {
|
||||
},
|
||||
"force_delete_date": null,
|
||||
"statuses": [
|
||||
"ok"
|
||||
],
|
||||
"status_notes": {
|
||||
"code": 1000,
|
||||
"message": "Command completed successfully",
|
||||
"data": {
|
||||
"domains": [
|
||||
{
|
||||
"id": 7,
|
||||
"name": "private.ee",
|
||||
"registrar_id": 2,
|
||||
"valid_to": "2022-09-23T00:00:00.000+03:00",
|
||||
"registrant_id": 11,
|
||||
"created_at": "2020-09-22T14:16:47.420+03:00",
|
||||
"updated_at": "2020-10-21T13:31:43.733+03:00",
|
||||
"name_dirty": "private.ee",
|
||||
"name_puny": "private.ee",
|
||||
"period": 1,
|
||||
"period_unit": "y",
|
||||
"creator_str": "2-ApiUser: test",
|
||||
"updator_str": null,
|
||||
"outzone_at": null,
|
||||
"delete_date": null,
|
||||
"registrant_verification_asked_at": null,
|
||||
"registrant_verification_token": null,
|
||||
"pending_json": {},
|
||||
"force_delete_date": null,
|
||||
"statuses": [
|
||||
"serverRenewProhibited"
|
||||
],
|
||||
"status_notes": {
|
||||
"ok": "",
|
||||
"serverRenewProhibited": ""
|
||||
},
|
||||
"upid": null,
|
||||
"up_date": null,
|
||||
"uuid": "6b6affa7-1449-4bd8-acf5-8b4752406705",
|
||||
"locked_by_registrant_at": null,
|
||||
"force_delete_start": null,
|
||||
"force_delete_data": null,
|
||||
"auth_info": "367b1e6d1f0d9aa190971ad8f571cd4d",
|
||||
"valid_from": "2020-09-22T14:16:47.420+03:00"
|
||||
}
|
||||
}
|
||||
],
|
||||
"total_number_of_records": 2
|
||||
],
|
||||
"total_number_of_records": 10
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -83,14 +91,17 @@ Content-Type: application/json
|
|||
```
|
||||
HTTP/1.1 200
|
||||
Cache-Control: max-age=0, private, must-revalidate
|
||||
Content-Length: 54
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"domains": [
|
||||
"domain1.ee"
|
||||
],
|
||||
"total_number_of_records": 2
|
||||
"code": 1000,
|
||||
"message": "Command completed successfully",
|
||||
"data": {
|
||||
"domains": [
|
||||
"private.ee",
|
||||
],
|
||||
"total_number_of_records": 1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -117,65 +128,68 @@ Please note that domain transfer/authorisation code must be placed in header - *
|
|||
```
|
||||
HTTP/1.1 200 OK
|
||||
Cache-Control: max-age=0, private, must-revalidate
|
||||
Content-Length: 784
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"domain":"ee-test.ee",
|
||||
"registrant":{
|
||||
"code":"EE:R1",
|
||||
"name":"Registrant",
|
||||
"ident":"17612535",
|
||||
"ident_type":"org",
|
||||
"ident_country_code":"EE",
|
||||
"phone":"+372.1234567",
|
||||
"email":"registrant@cache.ee",
|
||||
"street":"Businesstreet 1",
|
||||
"city":"Tallinn",
|
||||
"zip":"10101",
|
||||
"country_code":"EE",
|
||||
"statuses":[
|
||||
"ok",
|
||||
"linked"
|
||||
]
|
||||
},
|
||||
"admin_contacts":[
|
||||
{
|
||||
"code":"EE:A1",
|
||||
"name":"Admin Contact",
|
||||
"ident":"17612535376",
|
||||
"ident_type":"priv",
|
||||
"ident_country_code":"EE",
|
||||
"phone":"+372.7654321",
|
||||
"email":"admin@cache.ee",
|
||||
"street":"Adminstreet 2",
|
||||
"city":"Tallinn",
|
||||
"zip":"12345",
|
||||
"country_code":"EE",
|
||||
"statuses":[
|
||||
"ok",
|
||||
"linked"
|
||||
"code": 1000,
|
||||
"message": "Command completed successfully",
|
||||
"data": {
|
||||
"domain":"ee-test.ee",
|
||||
"registrant":{
|
||||
"code":"EE:R1",
|
||||
"name":"Registrant",
|
||||
"ident":"17612535",
|
||||
"ident_type":"org",
|
||||
"ident_country_code":"EE",
|
||||
"phone":"+372.1234567",
|
||||
"email":"registrant@cache.ee",
|
||||
"street":"Businesstreet 1",
|
||||
"city":"Tallinn",
|
||||
"zip":"10101",
|
||||
"country_code":"EE",
|
||||
"statuses":[
|
||||
"ok",
|
||||
"linked"
|
||||
]
|
||||
},
|
||||
"admin_contacts":[
|
||||
{
|
||||
"code":"EE:A1",
|
||||
"name":"Admin Contact",
|
||||
"ident":"17612535376",
|
||||
"ident_type":"priv",
|
||||
"ident_country_code":"EE",
|
||||
"phone":"+372.7654321",
|
||||
"email":"admin@cache.ee",
|
||||
"street":"Adminstreet 2",
|
||||
"city":"Tallinn",
|
||||
"zip":"12345",
|
||||
"country_code":"EE",
|
||||
"statuses":[
|
||||
"ok",
|
||||
"linked"
|
||||
]
|
||||
}
|
||||
],
|
||||
"tech_contacts":[
|
||||
{
|
||||
"code":"EE:T1",
|
||||
"name":"Tech Contact",
|
||||
"ident":"17612536",
|
||||
"ident_type":"org",
|
||||
"ident_country_code":"EE",
|
||||
"phone":"+372.7654321",
|
||||
"email":"tech@cache.ee",
|
||||
"street":"Techstreet 1",
|
||||
"city":"Tallinn",
|
||||
"zip":"12345",
|
||||
"country_code":"EE",
|
||||
"statuses":[
|
||||
"ok",
|
||||
"linked"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"tech_contacts":[
|
||||
{
|
||||
"code":"EE:T1",
|
||||
"name":"Tech Contact",
|
||||
"ident":"17612536",
|
||||
"ident_type":"org",
|
||||
"ident_country_code":"EE",
|
||||
"phone":"+372.7654321",
|
||||
"email":"tech@cache.ee",
|
||||
"street":"Techstreet 1",
|
||||
"city":"Tallinn",
|
||||
"zip":"12345",
|
||||
"country_code":"EE",
|
||||
"statuses":[
|
||||
"ok",
|
||||
"linked"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
|
|
@ -5,15 +5,26 @@ Replaces all domain contacts of the current registrar.
|
|||
|
||||
### Example request
|
||||
```
|
||||
$ curl https://repp.internet.ee/v1/domains/contacts \
|
||||
-X PATCH \
|
||||
-u username:password \
|
||||
-d current_contact_id=foo \
|
||||
-d new_contact_id=bar
|
||||
PATCH /repp/v1/domains/contacts HTTP/1.1
|
||||
Accept: application/json
|
||||
Content-Type: application/json
|
||||
Authorization: Basic dGVzdDp0ZXN0dGVzdA==
|
||||
|
||||
{
|
||||
"current_contact_id": "ATSAA:749AA80F",
|
||||
"new_contact_id": "ATSAA:E36957D7"
|
||||
}
|
||||
```
|
||||
### Example response
|
||||
```
|
||||
{
|
||||
"affected_domains": ["example.com", "example.org"]
|
||||
"code": 1000,
|
||||
"message": "Command completed successfully",
|
||||
"data": {
|
||||
"affected_domains": [
|
||||
"private.ee",
|
||||
],
|
||||
"skipped_domains": []
|
||||
}
|
||||
}
|
||||
```
|
||||
|
|
|
@ -1,28 +1,28 @@
|
|||
# Domain transfers
|
||||
|
||||
## POST /repp/v1/domain_transfers
|
||||
## POST /repp/v1/domains/transfer
|
||||
Transfers domains.
|
||||
|
||||
#### Request
|
||||
```
|
||||
POST /repp/v1/domain_transfers
|
||||
POST /repp/v1/domains/transfer
|
||||
Accept: application/json
|
||||
Content-Type: application/json
|
||||
Authorization: Basic dGVzdDp0ZXN0dGVzdA==
|
||||
|
||||
{
|
||||
"data":{
|
||||
"domainTransfers":[
|
||||
{
|
||||
"domainName":"example.com",
|
||||
"transferCode":"63e7"
|
||||
},
|
||||
{
|
||||
"domainName":"example.org",
|
||||
"transferCode":"15f9"
|
||||
}
|
||||
]
|
||||
}
|
||||
"data": {
|
||||
"domain_transfers": [
|
||||
{
|
||||
"domain_name":"example.com",
|
||||
"transferCode":"63e7"
|
||||
},
|
||||
{
|
||||
"domain_name":"example.org",
|
||||
"transferCode":"15f9"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -31,14 +31,21 @@ Authorization: Basic dGVzdDp0ZXN0dGVzdA==
|
|||
HTTP/1.1 200
|
||||
Content-Type: application/json
|
||||
{
|
||||
"data":[
|
||||
"code": 1000,
|
||||
"message": "Command completed successfully",
|
||||
"data": {
|
||||
"success": [
|
||||
{
|
||||
"type":"domain_transfer"
|
||||
"type": "domain_transfer",
|
||||
"domain_name": "example.com"
|
||||
},
|
||||
{
|
||||
"type":"domain_transfer"
|
||||
"type": "domain_transfer",
|
||||
"domain_name": "example.org"
|
||||
}
|
||||
]
|
||||
],
|
||||
"failed": []
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -48,13 +55,32 @@ Content-Type: application/json
|
|||
HTTP/1.1 400
|
||||
Content-Type: application/json
|
||||
{
|
||||
"errors":[
|
||||
"code": 1000,
|
||||
"message": "Command completed successfully",
|
||||
"data": {
|
||||
"success": [],
|
||||
"failed": [
|
||||
{
|
||||
"title":"example.com transfer code is wrong"
|
||||
"type": "domain_transfer",
|
||||
"domain_name": "example.com",
|
||||
"errors": [
|
||||
{
|
||||
"code": "2202",
|
||||
"msg": "Invalid authorization information"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title":"example.org does not exist"
|
||||
"type": "domain_transfer",
|
||||
"domain_name": "example.org",
|
||||
"errors": [
|
||||
{
|
||||
"code": "2304",
|
||||
"msg": "Object status prohibits operation"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
|
|
@ -10,15 +10,15 @@ Accept: application/json
|
|||
Content-Type: application/json
|
||||
Authorization: Basic dGVzdDp0ZXN0dGVzdA==
|
||||
{
|
||||
"data":{
|
||||
"type": "nameserver",
|
||||
"id": "ns1.example.com",
|
||||
"attributes": {
|
||||
"hostname": "new-ns1.example.com",
|
||||
"ipv4": ["192.0.2.1", "192.0.2.2"],
|
||||
"ipv6": ["2001:db8::1", "2001:db8::2"]
|
||||
},
|
||||
"data": {
|
||||
"type": "nameserver",
|
||||
"id": "ns1.example.com",
|
||||
"attributes": {
|
||||
"hostname": "new-ns1.example.com",
|
||||
"ipv4": ["192.0.2.1", "192.0.2.2"],
|
||||
"ipv6": ["2001:db8::1", "2001:db8::2"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -27,16 +27,26 @@ Authorization: Basic dGVzdDp0ZXN0dGVzdA==
|
|||
HTTP/1.1 200
|
||||
Content-Type: application/json
|
||||
{
|
||||
"data":{
|
||||
"code": 1000,
|
||||
"message": "Command completed successfully",
|
||||
"data": {
|
||||
"type": "nameserver",
|
||||
"id": "new-ns1.example.com",
|
||||
"attributes": {
|
||||
"hostname": "new-ns1.example.com",
|
||||
"ipv4": ["192.0.2.1", "192.0.2.2"],
|
||||
"ipv6": ["2001:db8::1", "2001:db8::2"]
|
||||
}
|
||||
},
|
||||
"affected_domains": ["example.com", "example.org"]
|
||||
"ipv4": [
|
||||
"192.0.2.1",
|
||||
"192.0.2.2"
|
||||
],
|
||||
"ipv6": [
|
||||
"2001:db8::1",
|
||||
"2001:db8::2"
|
||||
]
|
||||
},
|
||||
"affected_domains": [
|
||||
"private.ee"
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -44,14 +54,10 @@ Content-Type: application/json
|
|||
```
|
||||
HTTP/1.1 400
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"errors":[
|
||||
{
|
||||
"title":"ns1.example.com does not exist"
|
||||
},
|
||||
{
|
||||
"title":"192.0.2.1 is not a valid IPv4 address"
|
||||
}
|
||||
]
|
||||
"code": 2005,
|
||||
"message": "IPv4 is invalid [ipv4]",
|
||||
"data": {}
|
||||
}
|
||||
```
|
||||
|
|
10
lib/deserializers/xml/contact_create.rb
Normal file
10
lib/deserializers/xml/contact_create.rb
Normal file
|
@ -0,0 +1,10 @@
|
|||
require 'deserializers/xml/legal_document'
|
||||
require 'deserializers/xml/ident'
|
||||
require 'deserializers/xml/contact'
|
||||
|
||||
module Deserializers
|
||||
module Xml
|
||||
class ContactCreate < ContactUpdate
|
||||
end
|
||||
end
|
||||
end
|
BIN
lib/serializers/registrant_api/.DS_Store
vendored
Normal file
BIN
lib/serializers/registrant_api/.DS_Store
vendored
Normal file
Binary file not shown.
36
lib/serializers/repp/contact.rb
Normal file
36
lib/serializers/repp/contact.rb
Normal file
|
@ -0,0 +1,36 @@
|
|||
module Serializers
|
||||
module Repp
|
||||
class Contact
|
||||
attr_reader :contact
|
||||
|
||||
def initialize(contact, show_address:)
|
||||
@contact = contact
|
||||
@show_address = show_address
|
||||
end
|
||||
|
||||
def to_json(obj = contact)
|
||||
json = { id: obj.code, name: obj.name, ident: ident,
|
||||
email: obj.email, phone: obj.phone, fax: obj.fax,
|
||||
auth_info: obj.auth_info, statuses: obj.statuses,
|
||||
disclosed_attributes: obj.disclosed_attributes }
|
||||
|
||||
json[:address] = address if @show_address
|
||||
|
||||
json
|
||||
end
|
||||
|
||||
def ident
|
||||
{
|
||||
code: contact.ident,
|
||||
type: contact.ident_type,
|
||||
country_code: contact.ident_country_code,
|
||||
}
|
||||
end
|
||||
|
||||
def address
|
||||
{ street: contact.street, zip: contact.zip, city: contact.city,
|
||||
state: contact.state, country_code: contact.country_code }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -27,8 +27,8 @@ class APIDomainContactsTest < ApplicationIntegrationTest
|
|||
headers: { 'HTTP_AUTHORIZATION' => http_auth_key }
|
||||
|
||||
assert_response :ok
|
||||
assert_equal ({ affected_domains: %w[airport.test shop.test],
|
||||
skipped_domains: [] }),
|
||||
assert_equal ({ code: 1000, message: 'Command completed successfully', data: { affected_domains: %w[airport.test shop.test],
|
||||
skipped_domains: [] }}),
|
||||
JSON.parse(response.body, symbolize_names: true)
|
||||
end
|
||||
|
||||
|
@ -42,7 +42,7 @@ class APIDomainContactsTest < ApplicationIntegrationTest
|
|||
|
||||
assert_response :ok
|
||||
assert_equal %w[airport.test shop.test], JSON.parse(response.body,
|
||||
symbolize_names: true)[:skipped_domains]
|
||||
symbolize_names: true)[:data][:skipped_domains]
|
||||
end
|
||||
|
||||
def test_keep_other_tech_contacts_intact
|
||||
|
@ -66,10 +66,8 @@ class APIDomainContactsTest < ApplicationIntegrationTest
|
|||
new_contact_id: 'william-002' },
|
||||
headers: { 'HTTP_AUTHORIZATION' => http_auth_key }
|
||||
|
||||
assert_response :bad_request
|
||||
assert_equal ({ error: { type: 'invalid_request_error',
|
||||
param: 'current_contact_id',
|
||||
message: 'No such contact: jack-001' } }),
|
||||
assert_response :not_found
|
||||
assert_equal ({ code: 2303, message: 'Object does not exist' }),
|
||||
JSON.parse(response.body, symbolize_names: true)
|
||||
end
|
||||
|
||||
|
@ -77,10 +75,8 @@ class APIDomainContactsTest < ApplicationIntegrationTest
|
|||
patch '/repp/v1/domains/contacts', params: { current_contact_id: 'non-existent',
|
||||
new_contact_id: 'john-001' },
|
||||
headers: { 'HTTP_AUTHORIZATION' => http_auth_key }
|
||||
assert_response :bad_request
|
||||
assert_equal ({ error: { type: 'invalid_request_error',
|
||||
param: 'current_contact_id',
|
||||
message: 'No such contact: non-existent' } }),
|
||||
assert_response :not_found
|
||||
assert_equal ({ code: 2303, message: 'Object does not exist' }),
|
||||
JSON.parse(response.body, symbolize_names: true)
|
||||
end
|
||||
|
||||
|
@ -88,10 +84,8 @@ class APIDomainContactsTest < ApplicationIntegrationTest
|
|||
patch '/repp/v1/domains/contacts', params: { current_contact_id: 'william-001',
|
||||
new_contact_id: 'non-existent' },
|
||||
headers: { 'HTTP_AUTHORIZATION' => http_auth_key }
|
||||
assert_response :bad_request
|
||||
assert_equal ({ error: { type: 'invalid_request_error',
|
||||
param: 'new_contact_id',
|
||||
message: 'No such contact: non-existent' } }),
|
||||
assert_response :not_found
|
||||
assert_equal ({code: 2303, message: 'Object does not exist'}),
|
||||
JSON.parse(response.body, symbolize_names: true)
|
||||
end
|
||||
|
||||
|
@ -100,9 +94,7 @@ class APIDomainContactsTest < ApplicationIntegrationTest
|
|||
new_contact_id: 'invalid' },
|
||||
headers: { 'HTTP_AUTHORIZATION' => http_auth_key }
|
||||
assert_response :bad_request
|
||||
assert_equal ({ error: { type: 'invalid_request_error',
|
||||
param: 'new_contact_id',
|
||||
message: 'New contact must be valid' } }),
|
||||
assert_equal ({ code: 2304, message: 'New contact must be valid', data: {} }),
|
||||
JSON.parse(response.body, symbolize_names: true)
|
||||
end
|
||||
|
||||
|
@ -111,8 +103,7 @@ class APIDomainContactsTest < ApplicationIntegrationTest
|
|||
new_contact_id: 'william-001' },
|
||||
headers: { 'HTTP_AUTHORIZATION' => http_auth_key }
|
||||
assert_response :bad_request
|
||||
assert_equal ({ error: { type: 'invalid_request_error',
|
||||
message: 'New contact ID must be different from current contact ID' } }),
|
||||
assert_equal ({ code: 2304, message: 'New contact must be different from current', data: {} }),
|
||||
JSON.parse(response.body, symbolize_names: true)
|
||||
end
|
||||
|
||||
|
|
|
@ -12,34 +12,21 @@ class APIDomainTransfersTest < ApplicationIntegrationTest
|
|||
Setting.transfer_wait_time = @original_transfer_wait_time
|
||||
end
|
||||
|
||||
def test_returns_domain_transfers
|
||||
post '/repp/v1/domain_transfers', params: request_params, as: :json,
|
||||
headers: { 'HTTP_AUTHORIZATION' => http_auth_key }
|
||||
assert_response 200
|
||||
assert_equal ({ data: [{
|
||||
type: 'domain_transfer',
|
||||
attributes: {
|
||||
domain_name: 'shop.test'
|
||||
},
|
||||
}] }),
|
||||
JSON.parse(response.body, symbolize_names: true)
|
||||
end
|
||||
|
||||
def test_creates_new_domain_transfer
|
||||
assert_difference -> { @domain.transfers.size } do
|
||||
post '/repp/v1/domain_transfers', params: request_params, as: :json,
|
||||
post '/repp/v1/domains/transfer', params: request_params, as: :json,
|
||||
headers: { 'HTTP_AUTHORIZATION' => http_auth_key }
|
||||
end
|
||||
end
|
||||
|
||||
def test_approves_automatically_if_auto_approval_is_enabled
|
||||
post '/repp/v1/domain_transfers', params: request_params, as: :json,
|
||||
post '/repp/v1/domains/transfer', params: request_params, as: :json,
|
||||
headers: { 'HTTP_AUTHORIZATION' => http_auth_key }
|
||||
assert @domain.transfers.last.approved?
|
||||
end
|
||||
|
||||
def test_assigns_new_registrar
|
||||
post '/repp/v1/domain_transfers', params: request_params, as: :json,
|
||||
post '/repp/v1/domains/transfer', params: request_params, as: :json,
|
||||
headers: { 'HTTP_AUTHORIZATION' => http_auth_key }
|
||||
@domain.reload
|
||||
assert_equal @new_registrar, @domain.registrar
|
||||
|
@ -48,7 +35,7 @@ class APIDomainTransfersTest < ApplicationIntegrationTest
|
|||
def test_regenerates_transfer_code
|
||||
@old_transfer_code = @domain.transfer_code
|
||||
|
||||
post '/repp/v1/domain_transfers', params: request_params, as: :json,
|
||||
post '/repp/v1/domains/transfer', params: request_params, as: :json,
|
||||
headers: { 'HTTP_AUTHORIZATION' => http_auth_key }
|
||||
@domain.reload
|
||||
refute_equal @domain.transfer_code, @old_transfer_code
|
||||
|
@ -58,51 +45,28 @@ class APIDomainTransfersTest < ApplicationIntegrationTest
|
|||
@old_registrar = @domain.registrar
|
||||
|
||||
assert_difference -> { @old_registrar.notifications.count } do
|
||||
post '/repp/v1/domain_transfers', params: request_params, as: :json,
|
||||
post '/repp/v1/domains/transfer', params: request_params, as: :json,
|
||||
headers: { 'HTTP_AUTHORIZATION' => http_auth_key }
|
||||
end
|
||||
end
|
||||
|
||||
def test_duplicates_registrant_admin_and_tech_contacts
|
||||
assert_difference -> { @new_registrar.contacts.size }, 3 do
|
||||
post '/repp/v1/domain_transfers', params: request_params, as: :json,
|
||||
post '/repp/v1/domains/transfer', params: request_params, as: :json,
|
||||
headers: { 'HTTP_AUTHORIZATION' => http_auth_key }
|
||||
end
|
||||
end
|
||||
|
||||
def test_reuses_identical_contact
|
||||
post '/repp/v1/domain_transfers', params: request_params, as: :json,
|
||||
post '/repp/v1/domains/transfer', params: request_params, as: :json,
|
||||
headers: { 'HTTP_AUTHORIZATION' => http_auth_key }
|
||||
assert_equal 1, @new_registrar.contacts.where(name: 'William').size
|
||||
end
|
||||
|
||||
def test_fails_if_domain_does_not_exist
|
||||
post '/repp/v1/domain_transfers',
|
||||
params: { data: { domainTransfers: [{ domainName: 'non-existent.test',
|
||||
transferCode: 'any' }] } },
|
||||
as: :json,
|
||||
headers: { 'HTTP_AUTHORIZATION' => http_auth_key }
|
||||
assert_response 400
|
||||
assert_equal ({ errors: [{ title: 'non-existent.test does not exist' }] }),
|
||||
JSON.parse(response.body, symbolize_names: true)
|
||||
end
|
||||
|
||||
def test_fails_if_transfer_code_is_wrong
|
||||
post '/repp/v1/domain_transfers',
|
||||
params: { data: { domainTransfers: [{ domainName: 'shop.test',
|
||||
transferCode: 'wrong' }] } },
|
||||
as: :json,
|
||||
headers: { 'HTTP_AUTHORIZATION' => http_auth_key }
|
||||
assert_response 400
|
||||
refute_equal @new_registrar, @domain.registrar
|
||||
assert_equal ({ errors: [{ title: 'shop.test transfer code is wrong' }] }),
|
||||
JSON.parse(response.body, symbolize_names: true)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def request_params
|
||||
{ data: { domainTransfers: [{ domainName: 'shop.test', transferCode: '65078d5' }] } }
|
||||
{ data: { domain_transfers: [{ domain_name: 'shop.test', transfer_code: '65078d5' }] } }
|
||||
end
|
||||
|
||||
def http_auth_key
|
||||
|
|
|
@ -60,12 +60,14 @@ class APINameserversPutTest < ApplicationIntegrationTest
|
|||
headers: { 'HTTP_AUTHORIZATION' => http_auth_key }
|
||||
|
||||
assert_response 200
|
||||
assert_equal ({ data: { type: 'nameserver',
|
||||
assert_equal ({ code: 1000,
|
||||
message: 'Command completed successfully',
|
||||
data: { type: 'nameserver',
|
||||
id: 'ns55.bestnames.test',
|
||||
attributes: { hostname: 'ns55.bestnames.test',
|
||||
ipv4: ['192.0.2.55'],
|
||||
ipv6: ['2001:db8::55'] } },
|
||||
affected_domains: ["airport.test", "shop.test"] }),
|
||||
ipv6: ['2001:db8::55'] },
|
||||
affected_domains: ["airport.test", "shop.test"] }}),
|
||||
JSON.parse(response.body, symbolize_names: true)
|
||||
end
|
||||
|
||||
|
@ -85,7 +87,7 @@ class APINameserversPutTest < ApplicationIntegrationTest
|
|||
headers: { 'HTTP_AUTHORIZATION' => http_auth_key }
|
||||
|
||||
assert_response 404
|
||||
assert_equal ({ errors: [{ title: 'Hostname non-existent.test does not exist' }] }),
|
||||
assert_equal ({code: 2303, message: 'Object does not exist' }),
|
||||
JSON.parse(response.body, symbolize_names: true)
|
||||
end
|
||||
|
||||
|
@ -96,7 +98,8 @@ class APINameserversPutTest < ApplicationIntegrationTest
|
|||
headers: { 'HTTP_AUTHORIZATION' => http_auth_key }
|
||||
|
||||
assert_response 400
|
||||
assert_equal ({ errors: [{ title: 'Hostname is missing' }] }),
|
||||
assert_equal ({ code: 2003,
|
||||
message: 'param is missing or the value is empty: hostname' }),
|
||||
JSON.parse(response.body, symbolize_names: true)
|
||||
end
|
||||
|
||||
|
|
|
@ -0,0 +1,297 @@
|
|||
require 'test_helper'
|
||||
require 'auth_token/auth_token_creator'
|
||||
|
||||
class RegistrantApiVerificationsTest < ApplicationIntegrationTest
|
||||
def setup
|
||||
super
|
||||
|
||||
@domain = domains(:hospital)
|
||||
@registrant = @domain.registrant
|
||||
@new_registrant = contacts(:jack)
|
||||
@user = users(:api_bestnames)
|
||||
|
||||
@token = 'verysecrettoken'
|
||||
|
||||
@domain.update!(statuses: [DomainStatus::PENDING_UPDATE],
|
||||
registrant_verification_asked_at: Time.zone.now - 1.day,
|
||||
registrant_verification_token: @token)
|
||||
|
||||
end
|
||||
|
||||
def test_fetches_registrant_change_request
|
||||
pending_json = { new_registrant_id: @new_registrant.id,
|
||||
new_registrant_name: @new_registrant.name,
|
||||
new_registrant_email: @new_registrant.email,
|
||||
current_user_id: @user.id }
|
||||
|
||||
@domain.update(pending_json: pending_json)
|
||||
@domain.reload
|
||||
|
||||
assert @domain.registrant_update_confirmable?(@token)
|
||||
|
||||
get "/api/v1/registrant/confirms/#{@domain.name_puny}/change/#{@token}"
|
||||
assert_equal(200, response.status)
|
||||
|
||||
res = JSON.parse(response.body, symbolize_names: true)
|
||||
expected_body = {
|
||||
domain_name: "hospital.test",
|
||||
current_registrant: {
|
||||
name: @registrant.name,
|
||||
ident: @registrant.ident,
|
||||
country: @registrant.ident_country_code
|
||||
},
|
||||
new_registrant: {
|
||||
name: @new_registrant.name,
|
||||
ident: @new_registrant.ident,
|
||||
country: @new_registrant.ident_country_code
|
||||
}
|
||||
}
|
||||
|
||||
assert_equal expected_body, res
|
||||
end
|
||||
|
||||
def test_approves_registrant_change_request
|
||||
pending_json = { new_registrant_id: @new_registrant.id,
|
||||
new_registrant_name: @new_registrant.name,
|
||||
new_registrant_email: @new_registrant.email,
|
||||
current_user_id: @user.id }
|
||||
|
||||
@domain.update!(pending_json: pending_json)
|
||||
@domain.reload
|
||||
|
||||
assert @domain.registrant_update_confirmable?(@token)
|
||||
|
||||
perform_enqueued_jobs do
|
||||
post "/api/v1/registrant/confirms/#{@domain.name_puny}/change/#{@token}/confirmed"
|
||||
assert_equal(200, response.status)
|
||||
|
||||
res = JSON.parse(response.body, symbolize_names: true)
|
||||
expected_body = {
|
||||
domain_name: @domain.name,
|
||||
current_registrant: {
|
||||
name: @new_registrant.name,
|
||||
ident: @new_registrant.ident,
|
||||
country: @new_registrant.ident_country_code
|
||||
},
|
||||
status: 'confirmed'
|
||||
}
|
||||
assert_equal expected_body, res
|
||||
end
|
||||
end
|
||||
|
||||
def test_rejects_registrant_change_request
|
||||
pending_json = { new_registrant_id: @new_registrant.id,
|
||||
new_registrant_name: @new_registrant.name,
|
||||
new_registrant_email: @new_registrant.email,
|
||||
current_user_id: @user.id }
|
||||
|
||||
@domain.update(pending_json: pending_json)
|
||||
@domain.reload
|
||||
|
||||
assert @domain.registrant_update_confirmable?(@token)
|
||||
|
||||
post "/api/v1/registrant/confirms/#{@domain.name_puny}/change/#{@token}/rejected"
|
||||
assert_equal(200, response.status)
|
||||
|
||||
res = JSON.parse(response.body, symbolize_names: true)
|
||||
expected_body = {
|
||||
domain_name: @domain.name,
|
||||
current_registrant: {
|
||||
name: @registrant.name,
|
||||
ident: @registrant.ident,
|
||||
country: @registrant.ident_country_code
|
||||
},
|
||||
status: 'rejected'
|
||||
}
|
||||
|
||||
assert_equal expected_body, res
|
||||
end
|
||||
|
||||
def test_registrant_change_requires_valid_attributes
|
||||
pending_json = { new_registrant_id: @new_registrant.id,
|
||||
new_registrant_name: @new_registrant.name,
|
||||
new_registrant_email: @new_registrant.email,
|
||||
current_user_id: @user.id }
|
||||
|
||||
@domain.update(pending_json: pending_json)
|
||||
@domain.reload
|
||||
|
||||
get "/api/v1/registrant/confirms/#{@domain.name_puny}/change/123"
|
||||
assert_equal 401, response.status
|
||||
|
||||
get "/api/v1/registrant/confirms/aohldfjg.ee/change/123"
|
||||
assert_equal 404, response.status
|
||||
|
||||
post "/api/v1/registrant/confirms/#{@domain.name_puny}/change/#{@token}/invalidaction"
|
||||
assert_equal 404, response.status
|
||||
end
|
||||
|
||||
def test_fetches_domain_delete_request
|
||||
pending_json = { new_registrant_id: @new_registrant.id,
|
||||
new_registrant_name: @new_registrant.name,
|
||||
new_registrant_email: @new_registrant.email,
|
||||
current_user_id: @user.id }
|
||||
|
||||
@domain.update(pending_json: pending_json, statuses: [DomainStatus::PENDING_DELETE_CONFIRMATION])
|
||||
@domain.reload
|
||||
|
||||
assert @domain.registrant_delete_confirmable?(@token)
|
||||
|
||||
get "/api/v1/registrant/confirms/#{@domain.name_puny}/delete/#{@token}"
|
||||
assert_equal(200, response.status)
|
||||
|
||||
res = JSON.parse(response.body, symbolize_names: true)
|
||||
expected_body = {
|
||||
domain_name: "hospital.test",
|
||||
current_registrant: {
|
||||
name: @registrant.name,
|
||||
ident: @registrant.ident,
|
||||
country: @registrant.ident_country_code
|
||||
}
|
||||
}
|
||||
|
||||
assert_equal expected_body, res
|
||||
end
|
||||
|
||||
def test_approves_domain_delete_request
|
||||
pending_json = { new_registrant_id: @new_registrant.id,
|
||||
new_registrant_name: @new_registrant.name,
|
||||
new_registrant_email: @new_registrant.email,
|
||||
current_user_id: @user.id }
|
||||
|
||||
@domain.update(pending_json: pending_json, statuses: [DomainStatus::PENDING_DELETE_CONFIRMATION])
|
||||
@domain.reload
|
||||
|
||||
assert @domain.registrant_delete_confirmable?(@token)
|
||||
|
||||
post "/api/v1/registrant/confirms/#{@domain.name_puny}/delete/#{@token}/confirmed"
|
||||
assert_equal(200, response.status)
|
||||
|
||||
res = JSON.parse(response.body, symbolize_names: true)
|
||||
expected_body = {
|
||||
domain_name: @domain.name,
|
||||
current_registrant: {
|
||||
name: @registrant.name,
|
||||
ident: @registrant.ident,
|
||||
country: @registrant.ident_country_code
|
||||
},
|
||||
status: 'confirmed'
|
||||
}
|
||||
|
||||
assert_equal expected_body, res
|
||||
end
|
||||
|
||||
def test_rejects_domain_delete_request
|
||||
pending_json = { new_registrant_id: @new_registrant.id,
|
||||
new_registrant_name: @new_registrant.name,
|
||||
new_registrant_email: @new_registrant.email,
|
||||
current_user_id: @user.id }
|
||||
|
||||
@domain.update(pending_json: pending_json, statuses: [DomainStatus::PENDING_DELETE_CONFIRMATION])
|
||||
@domain.reload
|
||||
|
||||
assert @domain.registrant_delete_confirmable?(@token)
|
||||
|
||||
post "/api/v1/registrant/confirms/#{@domain.name_puny}/delete/#{@token}/rejected"
|
||||
assert_equal(200, response.status)
|
||||
|
||||
res = JSON.parse(response.body, symbolize_names: true)
|
||||
expected_body = {
|
||||
domain_name: @domain.name,
|
||||
current_registrant: {
|
||||
name: @registrant.name,
|
||||
ident: @registrant.ident,
|
||||
country: @registrant.ident_country_code
|
||||
},
|
||||
status: 'rejected'
|
||||
}
|
||||
|
||||
assert_equal expected_body, res
|
||||
end
|
||||
|
||||
def test_domain_delete_requires_valid_attributes
|
||||
pending_json = { new_registrant_id: @new_registrant.id,
|
||||
new_registrant_name: @new_registrant.name,
|
||||
new_registrant_email: @new_registrant.email,
|
||||
current_user_id: @user.id }
|
||||
|
||||
@domain.update(pending_json: pending_json, statuses: [DomainStatus::PENDING_DELETE_CONFIRMATION])
|
||||
@domain.reload
|
||||
|
||||
get "/api/v1/registrant/confirms/#{@domain.name_puny}/delete/123"
|
||||
assert_equal 401, response.status
|
||||
|
||||
get "/api/v1/registrant/confirms/aohldfjg.ee/delete/123"
|
||||
assert_equal 404, response.status
|
||||
|
||||
post "/api/v1/registrant/confirms/#{@domain.name_puny}/delete/#{@token}/invalidaction"
|
||||
assert_equal 404, response.status
|
||||
end
|
||||
#def test_get_non_existent_domain_details_by_uuid
|
||||
# get '/api/v1/registrant/domains/random-uuid', headers: @auth_headers
|
||||
# assert_equal(404, response.status)
|
||||
|
||||
# response_json = JSON.parse(response.body, symbolize_names: true)
|
||||
# assert_equal({ errors: [base: ['Domain not found']] }, response_json)
|
||||
#end
|
||||
|
||||
#def test_root_returns_domain_list
|
||||
# get '/api/v1/registrant/domains', headers: @auth_headers
|
||||
# assert_equal(200, response.status)
|
||||
|
||||
# response_json = JSON.parse(response.body, symbolize_names: true)
|
||||
# array_of_domain_names = response_json.map { |x| x[:name] }
|
||||
# assert(array_of_domain_names.include?('hospital.test'))
|
||||
|
||||
# array_of_domain_registrars = response_json.map { |x| x[:registrar] }
|
||||
# assert(array_of_domain_registrars.include?({name: 'Good Names', website: nil}))
|
||||
#end
|
||||
|
||||
#def test_root_accepts_limit_and_offset_parameters
|
||||
# get '/api/v1/registrant/domains', params: { 'limit' => 2, 'offset' => 0 },
|
||||
# headers: @auth_headers
|
||||
# response_json = JSON.parse(response.body, symbolize_names: true)
|
||||
|
||||
# assert_equal(200, response.status)
|
||||
# assert_equal(2, response_json.count)
|
||||
|
||||
# get '/api/v1/registrant/domains', headers: @auth_headers
|
||||
# response_json = JSON.parse(response.body, symbolize_names: true)
|
||||
|
||||
# assert_equal(4, response_json.count)
|
||||
#end
|
||||
|
||||
#def test_root_does_not_accept_limit_higher_than_200
|
||||
# get '/api/v1/registrant/domains', params: { 'limit' => 400, 'offset' => 0 },
|
||||
# headers: @auth_headers
|
||||
|
||||
# assert_equal(400, response.status)
|
||||
# response_json = JSON.parse(response.body, symbolize_names: true)
|
||||
# assert_equal({ errors: [{ limit: ['parameter is out of range'] }] }, response_json)
|
||||
#end
|
||||
|
||||
#def test_root_does_not_accept_offset_lower_than_0
|
||||
# get '/api/v1/registrant/domains', params: { 'limit' => 200, 'offset' => "-10" },
|
||||
# headers: @auth_headers
|
||||
|
||||
# assert_equal(400, response.status)
|
||||
# response_json = JSON.parse(response.body, symbolize_names: true)
|
||||
# assert_equal({ errors: [{ offset: ['parameter is out of range'] }] }, response_json)
|
||||
#end
|
||||
|
||||
#def test_root_returns_401_without_authorization
|
||||
# get '/api/v1/registrant/domains'
|
||||
# assert_equal(401, response.status)
|
||||
# json_body = JSON.parse(response.body, symbolize_names: true)
|
||||
|
||||
# assert_equal({ errors: [base: ['Not authorized']] }, json_body)
|
||||
#end
|
||||
|
||||
#def test_details_returns_401_without_authorization
|
||||
# get '/api/v1/registrant/domains/5edda1a5-3548-41ee-8b65-6d60daf85a37'
|
||||
# assert_equal(401, response.status)
|
||||
# json_body = JSON.parse(response.body, symbolize_names: true)
|
||||
|
||||
# assert_equal({ errors: [base: ['Not authorized']] }, json_body)
|
||||
#end
|
||||
end
|
|
@ -44,7 +44,7 @@ class EppContactInfoBaseTest < EppTestCase
|
|||
contact: xml_schema).text
|
||||
end
|
||||
|
||||
def test_hides_password_when_current_registrar_is_not_sponsoring
|
||||
def test_hides_password_and_name_when_current_registrar_is_not_sponsoring
|
||||
non_sponsoring_registrar = registrars(:goodnames)
|
||||
@contact.update!(registrar: non_sponsoring_registrar)
|
||||
|
||||
|
@ -70,6 +70,7 @@ class EppContactInfoBaseTest < EppTestCase
|
|||
assert_epp_response :completed_successfully
|
||||
response_xml = Nokogiri::XML(response.body)
|
||||
assert_nil response_xml.at_xpath('//contact:authInfo', contact: xml_schema)
|
||||
assert_equal 'No access', response_xml.at_xpath('//contact:name', contact: xml_schema).text
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
@ -35,7 +35,6 @@ class EppDomainDeleteBaseTest < EppTestCase
|
|||
XML
|
||||
|
||||
post epp_delete_path, params: { frame: request_xml }, headers: { 'HTTP_COOKIE' => 'session=api_bestnames' }
|
||||
# binding.pry
|
||||
assert_includes Domain.find_by(name: 'invalid.test').statuses, DomainStatus::PENDING_DELETE_CONFIRMATION
|
||||
assert_epp_response :completed_successfully_action_pending
|
||||
end
|
||||
|
@ -90,7 +89,9 @@ class EppDomainDeleteBaseTest < EppTestCase
|
|||
</epp>
|
||||
XML
|
||||
|
||||
post epp_delete_path, params: { frame: request_xml }, headers: { 'HTTP_COOKIE' => 'session=api_bestnames' }
|
||||
perform_enqueued_jobs do
|
||||
post epp_delete_path, params: { frame: request_xml }, headers: { 'HTTP_COOKIE' => 'session=api_bestnames' }
|
||||
end
|
||||
@domain.reload
|
||||
|
||||
assert @domain.registrant_verification_asked?
|
||||
|
@ -121,7 +122,9 @@ class EppDomainDeleteBaseTest < EppTestCase
|
|||
</epp>
|
||||
XML
|
||||
|
||||
post epp_delete_path, params: { frame: request_xml }, headers: { 'HTTP_COOKIE' => 'session=api_bestnames' }
|
||||
perform_enqueued_jobs do
|
||||
post epp_delete_path, params: { frame: request_xml }, headers: { 'HTTP_COOKIE' => 'session=api_bestnames' }
|
||||
end
|
||||
@domain.reload
|
||||
|
||||
assert_not @domain.registrant_verification_asked?
|
||||
|
@ -152,7 +155,9 @@ class EppDomainDeleteBaseTest < EppTestCase
|
|||
</epp>
|
||||
XML
|
||||
|
||||
post epp_delete_path, params: { frame: request_xml }, headers: { 'HTTP_COOKIE' => 'session=api_bestnames' }
|
||||
perform_enqueued_jobs do
|
||||
post epp_delete_path, params: { frame: request_xml }, headers: { 'HTTP_COOKIE' => 'session=api_bestnames' }
|
||||
end
|
||||
@domain.reload
|
||||
|
||||
assert_not @domain.registrant_verification_asked?
|
||||
|
|
22
test/integration/repp/v1/accounts/balance_test.rb
Normal file
22
test/integration/repp/v1/accounts/balance_test.rb
Normal file
|
@ -0,0 +1,22 @@
|
|||
require 'test_helper'
|
||||
|
||||
class ReppV1BalanceTest < ActionDispatch::IntegrationTest
|
||||
def setup
|
||||
@registrar = users(:api_bestnames)
|
||||
token = Base64.encode64("#{@registrar.username}:#{@registrar.plain_text_password}")
|
||||
token = "Basic #{token}"
|
||||
|
||||
@auth_headers = { 'Authorization' => token }
|
||||
end
|
||||
|
||||
def test_can_query_balance
|
||||
get '/repp/v1/accounts/balance', 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 @registrar.registrar.cash_account.balance.to_s, json[:data][:balance]
|
||||
assert_equal @registrar.registrar.cash_account.currency, json[:data][:currency]
|
||||
end
|
||||
end
|
63
test/integration/repp/v1/base_test.rb
Normal file
63
test/integration/repp/v1/base_test.rb
Normal file
|
@ -0,0 +1,63 @@
|
|||
require 'test_helper'
|
||||
|
||||
class ReppV1BaseTest < ActionDispatch::IntegrationTest
|
||||
def setup
|
||||
@registrar = users(:api_bestnames)
|
||||
token = Base64.encode64("#{@registrar.username}:#{@registrar.plain_text_password}")
|
||||
token = "Basic #{token}"
|
||||
|
||||
@auth_headers = { 'Authorization' => token }
|
||||
end
|
||||
|
||||
def test_unauthorized_user_has_no_access
|
||||
get repp_v1_contacts_path
|
||||
response_json = JSON.parse(response.body, symbolize_names: true)
|
||||
|
||||
assert_response :unauthorized
|
||||
assert_equal 'Invalid authorization information', response_json[:message]
|
||||
|
||||
invalid_token = Base64.encode64("nonexistant:user")
|
||||
headers = { 'Authorization' => "Basic #{invalid_token}" }
|
||||
|
||||
get repp_v1_contacts_path, headers: headers
|
||||
response_json = JSON.parse(response.body, symbolize_names: true)
|
||||
|
||||
assert_response :unauthorized
|
||||
assert_equal 'Invalid authorization information', response_json[:message]
|
||||
end
|
||||
|
||||
def test_authenticates_valid_user
|
||||
get repp_v1_contacts_path, headers: @auth_headers
|
||||
response_json = JSON.parse(response.body, symbolize_names: true)
|
||||
|
||||
assert_response :ok
|
||||
end
|
||||
|
||||
def test_processes_invalid_base64_token_format_properly
|
||||
token = '??as8d9sf kjsdjh klsdfjjf'
|
||||
headers = { 'Authorization' => "Basic #{token}"}
|
||||
get repp_v1_contacts_path, headers: headers
|
||||
response_json = JSON.parse(response.body, symbolize_names: true)
|
||||
|
||||
assert_response :unauthorized
|
||||
assert_equal 'Invalid authorization information', response_json[:message]
|
||||
end
|
||||
|
||||
def test_takes_ip_whitelist_into_account
|
||||
Setting.api_ip_whitelist_enabled = true
|
||||
Setting.registrar_ip_whitelist_enabled = true
|
||||
|
||||
whiteip = white_ips(:one)
|
||||
whiteip.update(ipv4: '1.1.1.1')
|
||||
|
||||
get repp_v1_contacts_path, headers: @auth_headers
|
||||
response_json = JSON.parse(response.body, symbolize_names: true)
|
||||
|
||||
assert_response :unauthorized
|
||||
assert_equal 2202, response_json[:code]
|
||||
assert response_json[:message].include? 'Access denied from IP'
|
||||
|
||||
Setting.api_ip_whitelist_enabled = false
|
||||
Setting.registrar_ip_whitelist_enabled = false
|
||||
end
|
||||
end
|
30
test/integration/repp/v1/contacts/check_test.rb
Normal file
30
test/integration/repp/v1/contacts/check_test.rb
Normal file
|
@ -0,0 +1,30 @@
|
|||
require 'test_helper'
|
||||
|
||||
class ReppV1ContactsCheckTest < 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_code_based_check_returns_true_for_available_contact
|
||||
get '/repp/v1/contacts/check/nonexistant:code', headers: @auth_headers
|
||||
json = JSON.parse(response.body, symbolize_names: true)
|
||||
|
||||
assert_response :ok
|
||||
assert_equal 'nonexistant:code', json[:data][:contact][:id]
|
||||
assert_equal true, json[:data][:contact][:available]
|
||||
end
|
||||
|
||||
def test_code_based_check_returns_true_for_available_contact
|
||||
contact = contacts(:jack)
|
||||
get "/repp/v1/contacts/check/#{contact.code}", headers: @auth_headers
|
||||
json = JSON.parse(response.body, symbolize_names: true)
|
||||
|
||||
assert_response :ok
|
||||
assert_equal contact.code, json[:data][:contact][:id]
|
||||
assert_equal false, json[:data][:contact][:available]
|
||||
end
|
||||
end
|
156
test/integration/repp/v1/contacts/create_test.rb
Normal file
156
test/integration/repp/v1/contacts/create_test.rb
Normal file
|
@ -0,0 +1,156 @@
|
|||
require 'test_helper'
|
||||
|
||||
class ReppV1ContactsCreateTest < 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_creates_new_contact
|
||||
request_body = {
|
||||
"contact": {
|
||||
"name": "Donald Trump",
|
||||
"phone": "+372.51111112",
|
||||
"email": "donald@trumptower.com",
|
||||
"ident": {
|
||||
"ident_type": "priv",
|
||||
"ident_country_code": "EE",
|
||||
"ident": "39708290069"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
post '/repp/v1/contacts', headers: @auth_headers, params: request_body
|
||||
json = JSON.parse(response.body, symbolize_names: true)
|
||||
|
||||
assert_response :ok
|
||||
assert_equal 1000, json[:code]
|
||||
assert_equal 'Command completed successfully', json[:message]
|
||||
|
||||
contact = Contact.find_by(code: json[:data][:contact][:id])
|
||||
assert contact.present?
|
||||
|
||||
assert_equal(request_body[:contact][:name], contact.name)
|
||||
assert_equal(request_body[:contact][:phone], contact.phone)
|
||||
assert_equal(request_body[:contact][:email], contact.email)
|
||||
assert_equal(request_body[:contact][:ident][:ident_type], contact.ident_type)
|
||||
assert_equal(request_body[:contact][:ident][:ident_country_code], contact.ident_country_code)
|
||||
assert_equal(request_body[:contact][:ident][:ident], contact.ident)
|
||||
end
|
||||
|
||||
def test_removes_postal_info_when_contact_created
|
||||
request_body = {
|
||||
"contact": {
|
||||
"name": "Donald Trump",
|
||||
"phone": "+372.51111111",
|
||||
"email": "donald@trump.com",
|
||||
"ident": {
|
||||
"ident_type": "priv",
|
||||
"ident_country_code": "EE",
|
||||
"ident": "39708290069"
|
||||
},
|
||||
"addr": {
|
||||
"city": "Tallinn",
|
||||
"street": "Wismari 13",
|
||||
"zip": "12345",
|
||||
"country_code": "EE"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
post '/repp/v1/contacts', headers: @auth_headers, params: request_body
|
||||
json = JSON.parse(response.body, symbolize_names: true)
|
||||
|
||||
assert_response :ok
|
||||
assert_equal 1100, json[:code]
|
||||
assert_equal 'Command completed successfully; Postal address data discarded', json[:message]
|
||||
|
||||
contact = Contact.find_by(code: json[:data][:contact][:id])
|
||||
assert contact.present?
|
||||
|
||||
assert_nil contact.city
|
||||
assert_nil contact.street
|
||||
assert_nil contact.zip
|
||||
assert_nil contact.country_code
|
||||
end
|
||||
|
||||
def test_requires_contact_address_when_processing_enabled
|
||||
Setting.address_processing = true
|
||||
|
||||
request_body = {
|
||||
"contact": {
|
||||
"name": "Donald Trump",
|
||||
"phone": "+372.51111112",
|
||||
"email": "donald@trumptower.com",
|
||||
"ident": {
|
||||
"ident_type": "priv",
|
||||
"ident_country_code": "EE",
|
||||
"ident": "39708290069"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
post '/repp/v1/contacts', headers: @auth_headers, params: request_body
|
||||
json = JSON.parse(response.body, symbolize_names: true)
|
||||
|
||||
assert_response :bad_request
|
||||
assert_equal 2003, json[:code]
|
||||
assert json[:message].include? 'param is missing or the value is empty'
|
||||
|
||||
Setting.address_processing = false
|
||||
end
|
||||
|
||||
def test_validates_ident_code
|
||||
request_body = {
|
||||
"contact": {
|
||||
"name": "Donald Trump",
|
||||
"phone": "+372.51111112",
|
||||
"email": "donald@trumptower.com",
|
||||
"ident": {
|
||||
"ident_type": "priv",
|
||||
"ident_country_code": "EE",
|
||||
"ident": "123123123"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
post '/repp/v1/contacts', headers: @auth_headers, params: request_body
|
||||
json = JSON.parse(response.body, symbolize_names: true)
|
||||
|
||||
assert_response :bad_request
|
||||
assert_equal 2005, json[:code]
|
||||
assert json[:message].include? 'Ident code does not conform to national identification number format'
|
||||
end
|
||||
|
||||
def test_attaches_legaldoc_if_present
|
||||
request_body = {
|
||||
"contact": {
|
||||
"name": "Donald Trump",
|
||||
"phone": "+372.51111112",
|
||||
"email": "donald@trumptower.com",
|
||||
"ident": {
|
||||
"ident_type": "priv",
|
||||
"ident_country_code": "EE",
|
||||
"ident": "39708290069"
|
||||
},
|
||||
},
|
||||
"legal_document": {
|
||||
"type": "pdf",
|
||||
"body": "#{'test' * 2000}"
|
||||
}
|
||||
}
|
||||
|
||||
post '/repp/v1/contacts', headers: @auth_headers, params: request_body
|
||||
json = JSON.parse(response.body, symbolize_names: true)
|
||||
|
||||
assert_response :ok
|
||||
assert_equal 1000, json[:code]
|
||||
assert_equal 'Command completed successfully', json[:message]
|
||||
|
||||
contact = Contact.find_by(code: json[:data][:contact][:id])
|
||||
assert contact.legal_documents.any?
|
||||
end
|
||||
end
|
47
test/integration/repp/v1/contacts/delete_test.rb
Normal file
47
test/integration/repp/v1/contacts/delete_test.rb
Normal file
|
@ -0,0 +1,47 @@
|
|||
require 'test_helper'
|
||||
|
||||
class ReppV1ContactsDeleteTest < 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_deletes_unassociated_contact
|
||||
contact = contacts(:invalid_email)
|
||||
delete "/repp/v1/contacts/#{contact.code}", 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]
|
||||
end
|
||||
|
||||
def test_can_not_delete_associated_contact
|
||||
contact = contacts(:john)
|
||||
delete "/repp/v1/contacts/#{contact.code}", headers: @auth_headers
|
||||
json = JSON.parse(response.body, symbolize_names: true)
|
||||
|
||||
assert_response :bad_request
|
||||
assert_equal 2305, json[:code]
|
||||
assert_equal 'Object association prohibits operation [domains]', json[:message]
|
||||
end
|
||||
|
||||
def test_handles_unknown_contact
|
||||
delete "/repp/v1/contacts/definitely:unexistant", headers: @auth_headers
|
||||
json = JSON.parse(response.body, symbolize_names: true)
|
||||
|
||||
assert_response :not_found
|
||||
end
|
||||
|
||||
def test_can_not_destroy_other_registrar_contact
|
||||
contact = contacts(:jack)
|
||||
|
||||
delete "/repp/v1/contacts/#{contact.code}", headers: @auth_headers
|
||||
json = JSON.parse(response.body, symbolize_names: true)
|
||||
|
||||
assert_response :not_found
|
||||
end
|
||||
end
|
55
test/integration/repp/v1/contacts/list_test.rb
Normal file
55
test/integration/repp/v1/contacts/list_test.rb
Normal file
|
@ -0,0 +1,55 @@
|
|||
require 'test_helper'
|
||||
|
||||
class ReppV1ContactsListTest < 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_returns_registrar_contacts
|
||||
get repp_v1_contacts_path, headers: @auth_headers
|
||||
json = JSON.parse(response.body, symbolize_names: true)
|
||||
|
||||
assert_response :ok
|
||||
|
||||
assert_equal @user.registrar.contacts.count, json[:total_number_of_records]
|
||||
assert_equal @user.registrar.contacts.count, json[:contacts].length
|
||||
|
||||
assert json[:contacts][0].is_a? String
|
||||
end
|
||||
|
||||
|
||||
def test_returns_detailed_registrar_contacts
|
||||
get repp_v1_contacts_path(details: true), headers: @auth_headers
|
||||
json = JSON.parse(response.body, symbolize_names: true)
|
||||
|
||||
assert_response :ok
|
||||
|
||||
assert_equal @user.registrar.contacts.count, json[:total_number_of_records]
|
||||
assert_equal @user.registrar.contacts.count, json[:contacts].length
|
||||
|
||||
assert json[:contacts][0].is_a? Hash
|
||||
end
|
||||
|
||||
def test_respects_limit
|
||||
get repp_v1_contacts_path(details: true, limit: 2), headers: @auth_headers
|
||||
json = JSON.parse(response.body, symbolize_names: true)
|
||||
|
||||
assert_response :ok
|
||||
|
||||
assert_equal 2, json[:contacts].length
|
||||
end
|
||||
|
||||
def test_respects_offset
|
||||
offset = 1
|
||||
get repp_v1_contacts_path(details: true, offset: offset), headers: @auth_headers
|
||||
json = JSON.parse(response.body, symbolize_names: true)
|
||||
|
||||
assert_response :ok
|
||||
|
||||
assert_equal (@user.registrar.contacts.count - offset), json[:contacts].length
|
||||
end
|
||||
end
|
45
test/integration/repp/v1/contacts/show_test.rb
Normal file
45
test/integration/repp/v1/contacts/show_test.rb
Normal file
|
@ -0,0 +1,45 @@
|
|||
require 'test_helper'
|
||||
|
||||
class ReppV1ContactsShowTest < 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_returns_error_when_not_found
|
||||
get repp_v1_contact_path(id: 'definitelynotexistant'), 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_shows_existing_contact
|
||||
contact = @user.registrar.contacts.first
|
||||
|
||||
get repp_v1_contact_path(id: contact.code), 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 contact.code, json[:data][:id]
|
||||
end
|
||||
|
||||
def test_can_not_access_out_of_scope_contacts
|
||||
# Contact of registrar goodnames, we're using bestnames API credentials
|
||||
contact = contacts(:jack)
|
||||
|
||||
get repp_v1_contact_path(id: contact.code), 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
|
||||
end
|
119
test/integration/repp/v1/contacts/update_test.rb
Normal file
119
test/integration/repp/v1/contacts/update_test.rb
Normal file
|
@ -0,0 +1,119 @@
|
|||
require 'test_helper'
|
||||
|
||||
class ReppV1ContactsUpdateTest < ActionDispatch::IntegrationTest
|
||||
def setup
|
||||
@contact = contacts(:john)
|
||||
@user = users(:api_bestnames)
|
||||
token = Base64.encode64("#{@user.username}:#{@user.plain_text_password}")
|
||||
token = "Basic #{token}"
|
||||
|
||||
@auth_headers = { 'Authorization' => token }
|
||||
end
|
||||
|
||||
def test_updates_contact
|
||||
request_body = {
|
||||
"contact": {
|
||||
"email": "donaldtrump@yandex.ru"
|
||||
}
|
||||
}
|
||||
|
||||
put "/repp/v1/contacts/#{@contact.code}", headers: @auth_headers, params: request_body
|
||||
json = JSON.parse(response.body, symbolize_names: true)
|
||||
|
||||
assert_response :ok
|
||||
assert_equal 1000, json[:code]
|
||||
assert_equal 'Command completed successfully', json[:message]
|
||||
|
||||
contact = Contact.find_by(code: json[:data][:contact][:id])
|
||||
assert contact.present?
|
||||
|
||||
assert_equal(request_body[:contact][:email], contact.email)
|
||||
end
|
||||
|
||||
def test_removes_postal_info_when_updated
|
||||
request_body = {
|
||||
"contact": {
|
||||
"addr": {
|
||||
"city": "Tallinn",
|
||||
"street": "Wismari 13",
|
||||
"zip": "12345",
|
||||
"country_code": "EE"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
put "/repp/v1/contacts/#{@contact.code}", headers: @auth_headers, params: request_body
|
||||
json = JSON.parse(response.body, symbolize_names: true)
|
||||
|
||||
assert_response :ok
|
||||
assert_equal 1100, json[:code]
|
||||
assert_equal 'Command completed successfully; Postal address data discarded', json[:message]
|
||||
|
||||
contact = Contact.find_by(code: json[:data][:contact][:id])
|
||||
assert contact.present?
|
||||
|
||||
assert_nil contact.city
|
||||
assert_nil contact.street
|
||||
assert_nil contact.zip
|
||||
assert_nil contact.country_code
|
||||
end
|
||||
|
||||
def test_can_not_change_ident_code
|
||||
request_body = {
|
||||
"contact": {
|
||||
"name": "Donald Trumpster",
|
||||
"ident": {
|
||||
"ident_type": "priv",
|
||||
"ident_country_code": "US",
|
||||
"ident": "12345"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
put "/repp/v1/contacts/#{@contact.code}", headers: @auth_headers, params: request_body
|
||||
json = JSON.parse(response.body, symbolize_names: true)
|
||||
|
||||
@contact.reload
|
||||
assert_not @contact.ident == 12345
|
||||
assert_response :bad_request
|
||||
assert_equal 2308, json[:code]
|
||||
assert json[:message].include? 'Ident update is not allowed. Consider creating new contact object'
|
||||
end
|
||||
|
||||
def test_attaches_legaldoc_if_present
|
||||
request_body = {
|
||||
"contact": {
|
||||
"email": "donaldtrump@yandex.ru"
|
||||
},
|
||||
"legal_document": {
|
||||
"type": "pdf",
|
||||
"body": "#{'test' * 2000}"
|
||||
}
|
||||
}
|
||||
|
||||
put "/repp/v1/contacts/#{@contact.code}", headers: @auth_headers, params: request_body
|
||||
json = JSON.parse(response.body, symbolize_names: true)
|
||||
|
||||
assert_response :ok
|
||||
assert_equal 1000, json[:code]
|
||||
assert_equal 'Command completed successfully', json[:message]
|
||||
|
||||
@contact.reload
|
||||
assert @contact.legal_documents.any?
|
||||
end
|
||||
|
||||
def test_returns_error_if_ident_wrong_format
|
||||
request_body = {
|
||||
"contact": {
|
||||
"ident": "123"
|
||||
}
|
||||
}
|
||||
|
||||
put "/repp/v1/contacts/#{@contact.code}", headers: @auth_headers, params: request_body
|
||||
json = JSON.parse(response.body, symbolize_names: true)
|
||||
|
||||
assert_response :bad_request
|
||||
assert_equal 2308, json[:code]
|
||||
assert_equal 'Ident update is not allowed. Consider creating new contact object', json[:message]
|
||||
end
|
||||
end
|
65
test/integration/repp/v1/domains/contact_replacement_test.rb
Normal file
65
test/integration/repp/v1/domains/contact_replacement_test.rb
Normal file
|
@ -0,0 +1,65 @@
|
|||
require 'test_helper'
|
||||
|
||||
class ReppV1DomainsContactReplacementTest < 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_contact_with_new_one
|
||||
replaceable_contact = contacts(:william)
|
||||
replacing_contact = contacts(:jane)
|
||||
|
||||
payload = {
|
||||
"current_contact_id": replaceable_contact.code,
|
||||
"new_contact_id": replacing_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_equal 'Command completed successfully', json[:message]
|
||||
|
||||
assert json[:data][:affected_domains].include? 'airport.test'
|
||||
assert json[:data][:affected_domains].include? 'shop.test'
|
||||
|
||||
assert_empty json[:data][:skipped_domains]
|
||||
end
|
||||
|
||||
def test_tech_contact_id_must_differ
|
||||
replaceable_contact = contacts(:william)
|
||||
replacing_contact = contacts(:william)
|
||||
|
||||
payload = {
|
||||
"current_contact_id": replaceable_contact.code,
|
||||
"new_contact_id": replacing_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_contact_codes_must_be_valid
|
||||
payload = {
|
||||
"current_contact_id": 'dfgsdfg',
|
||||
"new_contact_id": 'vvv'
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
end
|
54
test/integration/repp/v1/domains/list_test.rb
Normal file
54
test/integration/repp/v1/domains/list_test.rb
Normal file
|
@ -0,0 +1,54 @@
|
|||
require 'test_helper'
|
||||
|
||||
class ReppV1DomainsListTest < 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_returns_registrar_domains
|
||||
get repp_v1_domains_path, headers: @auth_headers
|
||||
json = JSON.parse(response.body, symbolize_names: true)
|
||||
|
||||
assert_response :ok
|
||||
|
||||
assert_equal @user.registrar.domains.count, json[:data][:total_number_of_records]
|
||||
assert_equal @user.registrar.domains.count, json[:data][:domains].length
|
||||
|
||||
assert json[:data][:domains][0].is_a? String
|
||||
end
|
||||
|
||||
def test_returns_detailed_registrar_domains
|
||||
get repp_v1_domains_path(details: true), headers: @auth_headers
|
||||
json = JSON.parse(response.body, symbolize_names: true)
|
||||
|
||||
assert_response :ok
|
||||
|
||||
assert_equal @user.registrar.domains.count, json[:data][:total_number_of_records]
|
||||
assert_equal @user.registrar.domains.count, json[:data][:domains].length
|
||||
|
||||
assert json[:data][:domains][0].is_a? Hash
|
||||
end
|
||||
|
||||
def test_respects_limit
|
||||
get repp_v1_domains_path(details: true, limit: 2), headers: @auth_headers
|
||||
json = JSON.parse(response.body, symbolize_names: true)
|
||||
|
||||
assert_response :ok
|
||||
|
||||
assert_equal 2, json[:data][:domains].length
|
||||
end
|
||||
|
||||
def test_respects_offset
|
||||
offset = 1
|
||||
get repp_v1_domains_path(details: true, offset: offset), headers: @auth_headers
|
||||
json = JSON.parse(response.body, symbolize_names: true)
|
||||
|
||||
assert_response :ok
|
||||
|
||||
assert_equal (@user.registrar.domains.count - offset), json[:data][:domains].length
|
||||
end
|
||||
end
|
40
test/integration/repp/v1/domains/transfer_info_test.rb
Normal file
40
test/integration/repp/v1/domains/transfer_info_test.rb
Normal file
|
@ -0,0 +1,40 @@
|
|||
require 'test_helper'
|
||||
|
||||
class ReppV1DomainsTransferInfoTest < ActionDispatch::IntegrationTest
|
||||
def setup
|
||||
@user = users(:api_bestnames)
|
||||
token = Base64.encode64("#{@user.username}:#{@user.plain_text_password}")
|
||||
token = "Basic #{token}"
|
||||
@domain = domains(:shop)
|
||||
@auth_headers = { 'Authorization' => token }
|
||||
end
|
||||
|
||||
def test_can_query_domain_info
|
||||
headers = @auth_headers
|
||||
headers['Auth-Code'] = @domain.transfer_code
|
||||
|
||||
get "/repp/v1/domains/#{@domain.name}/transfer_info", headers: 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.name, json[:data][:domain]
|
||||
assert json[:data][:registrant].present?
|
||||
assert json[:data][:admin_contacts].present?
|
||||
assert json[:data][:tech_contacts].present?
|
||||
end
|
||||
|
||||
def test_respects_domain_authorization_code
|
||||
headers = @auth_headers
|
||||
headers['Auth-Code'] = 'jhfgifhdg'
|
||||
|
||||
get "/repp/v1/domains/#{@domain.name}/transfer_info", headers: headers
|
||||
json = JSON.parse(response.body, symbolize_names: true)
|
||||
|
||||
assert_response :bad_request
|
||||
assert_equal 2202, json[:code]
|
||||
assert_equal 'Authorization error', json[:message]
|
||||
assert_empty json[:data]
|
||||
end
|
||||
end
|
127
test/integration/repp/v1/domains/transfer_test.rb
Normal file
127
test/integration/repp/v1/domains/transfer_test.rb
Normal file
|
@ -0,0 +1,127 @@
|
|||
require 'test_helper'
|
||||
|
||||
class ReppV1DomainsTransferTest < ActionDispatch::IntegrationTest
|
||||
def setup
|
||||
@user = users(:api_bestnames)
|
||||
token = Base64.encode64("#{@user.username}:#{@user.plain_text_password}")
|
||||
token = "Basic #{token}"
|
||||
@domain = domains(:hospital)
|
||||
|
||||
@auth_headers = { 'Authorization' => token }
|
||||
end
|
||||
|
||||
def test_transfers_domain
|
||||
payload = {
|
||||
"data": {
|
||||
"domain_transfers": [
|
||||
{ "domain_name": @domain.name, "transfer_code": @domain.transfer_code }
|
||||
]
|
||||
}
|
||||
}
|
||||
post "/repp/v1/domains/transfer", headers: @auth_headers, params: payload
|
||||
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.name, json[:data][:success][0][:domain_name]
|
||||
|
||||
@domain.reload
|
||||
|
||||
assert @domain.registrar = @user.registrar
|
||||
end
|
||||
|
||||
def test_does_not_transfer_domain_if_not_transferable
|
||||
@domain.schedule_force_delete(type: :fast_track)
|
||||
|
||||
payload = {
|
||||
"data": {
|
||||
"domain_transfers": [
|
||||
{ "domain_name": @domain.name, "transfer_code": @domain.transfer_code }
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
post "/repp/v1/domains/transfer", headers: @auth_headers, params: payload
|
||||
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 'Object status prohibits operation', json[:data][:failed][0][:errors][0][:msg]
|
||||
|
||||
@domain.reload
|
||||
|
||||
assert_not @domain.registrar == @user.registrar
|
||||
end
|
||||
|
||||
def test_does_not_transfer_domain_with_invalid_auth_code
|
||||
payload = {
|
||||
"data": {
|
||||
"domain_transfers": [
|
||||
{ "domain_name": @domain.name, "transfer_code": "sdfgsdfg" }
|
||||
]
|
||||
}
|
||||
}
|
||||
post "/repp/v1/domains/transfer", headers: @auth_headers, params: payload
|
||||
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 "Invalid authorization information", json[:data][:failed][0][:errors][0][:msg]
|
||||
end
|
||||
|
||||
def test_does_not_transfer_domain_to_same_registrar
|
||||
@domain.update!(registrar: @user.registrar)
|
||||
|
||||
payload = {
|
||||
"data": {
|
||||
"domain_transfers": [
|
||||
{ "domain_name": @domain.name, "transfer_code": @domain.transfer_code }
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
post "/repp/v1/domains/transfer", headers: @auth_headers, params: payload
|
||||
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 already belongs to the querying registrar', json[:data][:failed][0][:errors][0][:msg]
|
||||
|
||||
@domain.reload
|
||||
|
||||
assert @domain.registrar == @user.registrar
|
||||
end
|
||||
|
||||
def test_does_not_transfer_domain_if_discarded
|
||||
@domain.update!(statuses: [DomainStatus::DELETE_CANDIDATE])
|
||||
|
||||
payload = {
|
||||
"data": {
|
||||
"domain_transfers": [
|
||||
{ "domain_name": @domain.name, "transfer_code": @domain.transfer_code }
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
post "/repp/v1/domains/transfer", headers: @auth_headers, params: payload
|
||||
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 'Object is not eligible for transfer', json[:data][:failed][0][:errors][0][:msg]
|
||||
|
||||
@domain.reload
|
||||
|
||||
assert_not @domain.registrar == @user.registrar
|
||||
end
|
||||
end
|
77
test/integration/repp/v1/registrar/nameservers_test.rb
Normal file
77
test/integration/repp/v1/registrar/nameservers_test.rb
Normal file
|
@ -0,0 +1,77 @@
|
|||
require 'test_helper'
|
||||
|
||||
class ReppV1RegistrarNameserversTest < 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_updates_nameserver_values
|
||||
nameserver = nameservers(:shop_ns1)
|
||||
payload = {
|
||||
"data": {
|
||||
"id": nameserver.hostname,
|
||||
"type": "nameserver",
|
||||
"attributes": {
|
||||
"hostname": "#{nameserver.hostname}.test",
|
||||
"ipv4": ["1.1.1.1"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
put '/repp/v1/registrar/nameservers', headers: @auth_headers, params: payload
|
||||
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({ hostname: "#{nameserver.hostname}.test", ipv4: ["1.1.1.1"] }, json[:data][:attributes])
|
||||
assert_equal({ hostname: "#{nameserver.hostname}.test", ipv4: ["1.1.1.1"] }, json[:data][:attributes])
|
||||
assert json[:data][:affected_domains].include? 'airport.test'
|
||||
assert json[:data][:affected_domains].include? 'shop.test'
|
||||
end
|
||||
|
||||
def test_nameserver_with_hostname_must_exist
|
||||
payload = {
|
||||
"data": {
|
||||
"id": 'ns.nonexistant.test',
|
||||
"type": "nameserver",
|
||||
"attributes": {
|
||||
"hostname": "ns1.dn.test",
|
||||
"ipv4": ["1.1.1.1"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
put '/repp/v1/registrar/nameservers', 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_ip_must_be_in_correct_format
|
||||
nameserver = nameservers(:shop_ns1)
|
||||
payload = {
|
||||
"data": {
|
||||
"id": nameserver.hostname,
|
||||
"type": "nameserver",
|
||||
"attributes": {
|
||||
"hostname": "#{nameserver.hostname}.test",
|
||||
"ipv6": ["1.1.1.1"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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_equal 'IPv6 is invalid [ipv6]', json[:message]
|
||||
end
|
||||
end
|
|
@ -1,18 +1,20 @@
|
|||
require 'test_helper'
|
||||
|
||||
class NewDomainForceDeleteTest < ActiveSupport::TestCase
|
||||
class ForceDeleteTest < ActionMailer::TestCase
|
||||
setup do
|
||||
@domain = domains(:shop)
|
||||
Setting.redemption_grace_period = 30
|
||||
ActionMailer::Base.deliveries.clear
|
||||
end
|
||||
|
||||
def test_schedules_force_delete_fast_track
|
||||
assert_not @domain.force_delete_scheduled?
|
||||
travel_to Time.zone.parse('2010-07-05')
|
||||
|
||||
@domain.schedule_force_delete(type: :fast_track)
|
||||
@domain.schedule_force_delete(type: :fast_track, notify_by_email: true)
|
||||
@domain.reload
|
||||
|
||||
assert_emails 1
|
||||
assert @domain.force_delete_scheduled?
|
||||
assert_equal Date.parse('2010-08-20'), @domain.force_delete_date.to_date
|
||||
assert_equal Date.parse('2010-07-06'), @domain.force_delete_start.to_date
|
||||
|
@ -111,9 +113,12 @@ class NewDomainForceDeleteTest < ActiveSupport::TestCase
|
|||
|
||||
def test_force_delete_cannot_be_scheduled_when_a_domain_is_discarded
|
||||
@domain.update!(statuses: [DomainStatus::DELETE_CANDIDATE])
|
||||
assert_raises StandardError do
|
||||
@domain.schedule_force_delete(type: :fast_track)
|
||||
end
|
||||
result = ForceDeleteInteraction::SetForceDelete.run(domain: @domain, type: :fast_track)
|
||||
|
||||
assert_not result.valid?
|
||||
assert_not @domain.force_delete_scheduled?
|
||||
message = ["Force delete procedure cannot be scheduled while a domain is discarded"]
|
||||
assert_equal message, result.errors.messages[:domain]
|
||||
end
|
||||
|
||||
def test_cancels_force_delete
|
||||
|
|
|
@ -414,7 +414,7 @@ class DomainTest < ActiveSupport::TestCase
|
|||
force_delete_date: nil)
|
||||
@domain.update(template_name: 'legal_person')
|
||||
travel_to Time.zone.parse('2010-07-05')
|
||||
@domain.schedule_force_delete(type: :fast_track)
|
||||
ForceDeleteInteraction::SetForceDelete.run!(domain: @domain, type: :fast_track)
|
||||
assert(@domain.force_delete_scheduled?)
|
||||
other_registrant = Registrant.find_by(code: 'jane-001')
|
||||
@domain.pending_json['new_registrant_id'] = other_registrant.id
|
||||
|
|
|
@ -70,6 +70,6 @@ class Whois::RecordTest < ActiveSupport::TestCase
|
|||
end
|
||||
|
||||
def registration_deadline
|
||||
Time.zone.now + 10.days
|
||||
@registration_deadline ||= Time.zone.now + 10.days
|
||||
end
|
||||
end
|
||||
|
|
|
@ -29,6 +29,16 @@ class RegistrarAreaBaseTestTest < ApplicationSystemTestCase
|
|||
assert_button 'Login'
|
||||
end
|
||||
|
||||
def test_user_can_access_when_ip_is_whitelisted_with_subnet
|
||||
white_ips(:one).update!(ipv4: '127.0.0.1/32', interfaces: [WhiteIp::REGISTRAR])
|
||||
Setting.registrar_ip_whitelist_enabled = true
|
||||
|
||||
visit new_registrar_user_session_url
|
||||
|
||||
assert_no_text 'Access denied from IP 127.0.0.1'
|
||||
assert_button 'Login'
|
||||
end
|
||||
|
||||
def test_user_can_access_when_ip_is_not_whitelisted_and_whitelist_is_disabled
|
||||
Setting.registrar_ip_whitelist_enabled = false
|
||||
WhiteIp.delete_all
|
||||
|
|
|
@ -6,9 +6,9 @@ class RegistrarAreaBulkTransferTest < ApplicationSystemTestCase
|
|||
end
|
||||
|
||||
def test_transfer_multiple_domains_in_bulk
|
||||
request_body = { data: { domainTransfers: [{ domainName: 'shop.test', transferCode: '65078d5' }] } }
|
||||
request_body = { data: { domain_transfers: [{ domain_name: 'shop.test', transfer_code: '65078d5' }] } }
|
||||
headers = { 'Content-type' => Mime[:json] }
|
||||
request_stub = stub_request(:post, /domain_transfers/).with(body: request_body,
|
||||
request_stub = stub_request(:post, /domains\/transfer/).with(body: request_body,
|
||||
headers: headers,
|
||||
basic_auth: ['test_goodnames', 'testtest'])
|
||||
.to_return(body: { data: [{
|
||||
|
@ -29,7 +29,7 @@ class RegistrarAreaBulkTransferTest < ApplicationSystemTestCase
|
|||
def test_fail_gracefully
|
||||
body = { errors: [{ title: 'epic fail' }] }.to_json
|
||||
headers = { 'Content-type' => Mime[:json] }
|
||||
stub_request(:post, /domain_transfers/).to_return(status: 400, body: body, headers: headers)
|
||||
stub_request(:post, /domains\/transfer/).to_return(status: 400, body: body, headers: headers)
|
||||
|
||||
visit registrar_domains_url
|
||||
click_link 'Bulk change'
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue