mirror of
https://github.com/internetee/registry.git
synced 2025-06-03 19:27:29 +02:00
parent
90ed23f64d
commit
b6ecae6a35
41 changed files with 1239 additions and 61 deletions
|
@ -8,6 +8,8 @@ module Api
|
|||
before_action :authenticate
|
||||
before_action :set_paper_trail_whodunnit
|
||||
|
||||
rescue_from ActiveRecord::RecordNotFound, with: :show_not_found_error
|
||||
rescue_from ActiveRecord::RecordInvalid, with: :show_invalid_record_error
|
||||
rescue_from(ActionController::ParameterMissing) do |parameter_missing_exception|
|
||||
error = {}
|
||||
error[parameter_missing_exception.param] = ['parameter is required']
|
||||
|
@ -49,6 +51,14 @@ module Api
|
|||
def set_paper_trail_whodunnit
|
||||
::PaperTrail.whodunnit = current_registrant_user.id_role_username
|
||||
end
|
||||
|
||||
def show_not_found_error
|
||||
render json: { errors: [{ base: ['Not found'] }] }, status: :not_found
|
||||
end
|
||||
|
||||
def show_invalid_record_error(exception)
|
||||
render json: { errors: exception.record.errors }, status: :bad_request
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -32,6 +32,63 @@ module Api
|
|||
end
|
||||
end
|
||||
|
||||
def update
|
||||
contact = @contacts_pool.find_by!(uuid: params[:uuid])
|
||||
contact.name = params[:name] if params[:name].present?
|
||||
contact.email = params[:email] if params[:email].present?
|
||||
contact.phone = params[:phone] if params[:phone].present?
|
||||
|
||||
if Setting.address_processing && params[:address]
|
||||
address = Contact::Address.new(params[:address][:street],
|
||||
params[:address][:zip],
|
||||
params[:address][:city],
|
||||
params[:address][:state],
|
||||
params[:address][:country_code])
|
||||
contact.address = address
|
||||
end
|
||||
|
||||
if !Setting.address_processing && params[:address]
|
||||
error_msg = 'Address processing is disabled and therefore cannot be updated'
|
||||
render json: { errors: [{ address: [error_msg] }] }, status: :bad_request and return
|
||||
end
|
||||
|
||||
if ENV['fax_enabled'] == 'true'
|
||||
contact.fax = params[:fax] if params[:fax].present?
|
||||
end
|
||||
|
||||
if ENV['fax_enabled'] != 'true' && params[:fax]
|
||||
error_msg = 'Fax processing is disabled and therefore cannot be updated'
|
||||
render json: { errors: [{ address: [error_msg] }] }, status: :bad_request and return
|
||||
end
|
||||
|
||||
contact.transaction do
|
||||
contact.save!
|
||||
action = current_registrant_user.actions.create!(contact: contact, operation: :update)
|
||||
contact.registrar.notify(action)
|
||||
end
|
||||
|
||||
render json: { id: contact.uuid,
|
||||
name: contact.name,
|
||||
code: contact.code,
|
||||
ident: {
|
||||
code: contact.ident,
|
||||
type: contact.ident_type,
|
||||
country_code: contact.ident_country_code,
|
||||
},
|
||||
email: contact.email,
|
||||
phone: contact.phone,
|
||||
fax: contact.fax,
|
||||
address: {
|
||||
street: contact.street,
|
||||
zip: contact.zip,
|
||||
city: contact.city,
|
||||
state: contact.state,
|
||||
country_code: contact.country_code,
|
||||
},
|
||||
auth_info: contact.auth_info,
|
||||
statuses: contact.statuses }
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_contacts_pool
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
class Registrant::ContactsController < RegistrantController
|
||||
helper_method :domain_ids
|
||||
helper_method :domain
|
||||
helper_method :fax_enabled?
|
||||
skip_authorization_check only: %i[edit update]
|
||||
|
||||
def show
|
||||
@contact = Contact.where(id: contacts).find_by(id: params[:id])
|
||||
|
@ -8,6 +10,25 @@ class Registrant::ContactsController < RegistrantController
|
|||
authorize! :read, @contact
|
||||
end
|
||||
|
||||
def edit
|
||||
@contact = Contact.where(id: contacts).find(params[:id])
|
||||
end
|
||||
|
||||
def update
|
||||
@contact = Contact.where(id: contacts).find(params[:id])
|
||||
@contact.attributes = contact_params
|
||||
response = update_contact_via_api(@contact.uuid)
|
||||
updated = response.is_a?(Net::HTTPSuccess)
|
||||
|
||||
if updated
|
||||
redirect_to registrant_domain_contact_url(domain, @contact), notice: t('.updated')
|
||||
else
|
||||
parsed_response = JSON.parse(response.body, symbolize_names: true)
|
||||
@errors = parsed_response[:errors]
|
||||
render :edit
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def contacts
|
||||
|
@ -41,4 +62,68 @@ class Registrant::ContactsController < RegistrantController
|
|||
current_registrant_user.domains
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def contact_params
|
||||
permitted = %i[
|
||||
name
|
||||
email
|
||||
phone
|
||||
]
|
||||
|
||||
permitted << :fax if fax_enabled?
|
||||
permitted += %i[street zip city state country_code] if Contact.address_processing?
|
||||
params.require(:contact).permit(*permitted)
|
||||
end
|
||||
|
||||
def access_token
|
||||
uri = URI.parse("#{ENV['registrant_api_base_url']}/api/v1/registrant/auth/eid")
|
||||
request = Net::HTTP::Post.new(uri)
|
||||
request.form_data = access_token_request_params
|
||||
|
||||
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: (uri.scheme == 'https')) do |http|
|
||||
http.request(request)
|
||||
end
|
||||
|
||||
json_doc = JSON.parse(response.body, symbolize_names: true)
|
||||
json_doc[:access_token]
|
||||
end
|
||||
|
||||
def access_token_request_params
|
||||
{ ident: current_registrant_user.ident,
|
||||
first_name: current_registrant_user.first_name,
|
||||
last_name: current_registrant_user.last_name }
|
||||
end
|
||||
|
||||
def fax_enabled?
|
||||
ENV['fax_enabled'] == 'true'
|
||||
end
|
||||
|
||||
def contact_update_api_params
|
||||
params = contact_params
|
||||
params = normalize_address_attributes_for_api(params) if Contact.address_processing?
|
||||
params
|
||||
end
|
||||
|
||||
def normalize_address_attributes_for_api(params)
|
||||
normalized = params
|
||||
|
||||
Contact.address_attribute_names.each do |attr|
|
||||
attr = attr.to_sym
|
||||
normalized["address[#{attr}]"] = params[attr]
|
||||
normalized.delete(attr)
|
||||
end
|
||||
|
||||
normalized
|
||||
end
|
||||
|
||||
def update_contact_via_api(uuid)
|
||||
uri = URI.parse("#{ENV['registrant_api_base_url']}/api/v1/registrant/contacts/#{uuid}")
|
||||
request = Net::HTTP::Patch.new(uri)
|
||||
request['Authorization'] = "Bearer #{access_token}"
|
||||
request.form_data = contact_update_api_params
|
||||
|
||||
Net::HTTP.start(uri.hostname, uri.port, use_ssl: (uri.scheme == 'https')) do |http|
|
||||
http.request(request)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
17
app/models/action.rb
Normal file
17
app/models/action.rb
Normal file
|
@ -0,0 +1,17 @@
|
|||
class Action < ActiveRecord::Base
|
||||
belongs_to :user
|
||||
belongs_to :contact
|
||||
|
||||
validates :operation, inclusion: { in: proc { |action| action.class.valid_operations } }
|
||||
|
||||
class << self
|
||||
def valid_operations
|
||||
%w[update]
|
||||
end
|
||||
end
|
||||
|
||||
def notification_key
|
||||
raise 'Action object is missing' unless contact
|
||||
"contact_#{operation}".to_sym
|
||||
end
|
||||
end
|
|
@ -526,4 +526,20 @@ class Contact < ActiveRecord::Base
|
|||
|
||||
domain_names
|
||||
end
|
||||
|
||||
def address=(address)
|
||||
self.street = address.street
|
||||
self.zip = address.zip
|
||||
self.city = address.city
|
||||
self.state = address.state
|
||||
self.country_code = address.country_code
|
||||
end
|
||||
|
||||
def address
|
||||
Address.new(street, zip, city, state, country_code)
|
||||
end
|
||||
|
||||
def managed_by?(registrant_user)
|
||||
ident == registrant_user.ident
|
||||
end
|
||||
end
|
||||
|
|
25
app/models/contact/address.rb
Normal file
25
app/models/contact/address.rb
Normal file
|
@ -0,0 +1,25 @@
|
|||
class Contact
|
||||
class Address
|
||||
attr_reader :street
|
||||
attr_reader :zip
|
||||
attr_reader :city
|
||||
attr_reader :state
|
||||
attr_reader :country_code
|
||||
|
||||
def initialize(street, zip, city, state, country_code)
|
||||
@street = street
|
||||
@zip = zip
|
||||
@city = city
|
||||
@state = state
|
||||
@country_code = country_code
|
||||
end
|
||||
|
||||
def ==(other)
|
||||
(street == other.street) &&
|
||||
(zip == other.zip) &&
|
||||
(city == other.city) &&
|
||||
(state == other.state) &&
|
||||
(country_code == other.country_code)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,6 +1,8 @@
|
|||
class Notification < ActiveRecord::Base
|
||||
include Versions # version/notification_version.rb
|
||||
|
||||
belongs_to :registrar
|
||||
belongs_to :action
|
||||
|
||||
scope :unread, -> { where(read: false) }
|
||||
|
||||
|
@ -20,7 +22,7 @@ class Notification < ActiveRecord::Base
|
|||
|
||||
# Needed for EPP log
|
||||
def name
|
||||
"-"
|
||||
''
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
@ -56,6 +56,14 @@ class RegistrantUser < User
|
|||
username
|
||||
end
|
||||
|
||||
def first_name
|
||||
username.split.first
|
||||
end
|
||||
|
||||
def last_name
|
||||
username.split.second
|
||||
end
|
||||
|
||||
class << self
|
||||
def find_or_create_by_idc_data(idc_data, issuer_organization)
|
||||
return false if idc_data.blank?
|
||||
|
|
|
@ -157,6 +157,11 @@ class Registrar < ActiveRecord::Base
|
|||
end
|
||||
end
|
||||
|
||||
def notify(action)
|
||||
text = I18n.t("notifications.texts.#{action.notification_key}", contact: action.contact.code)
|
||||
notifications.create!(text: text)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_defaults
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
class User < ActiveRecord::Base
|
||||
include Versions # version/user_version.rb
|
||||
|
||||
has_many :actions, dependent: :restrict_with_exception
|
||||
|
||||
attr_accessor :phone
|
||||
|
||||
def id_role_username
|
||||
|
|
9
app/views/epp/poll/_action.xml.builder
Normal file
9
app/views/epp/poll/_action.xml.builder
Normal file
|
@ -0,0 +1,9 @@
|
|||
builder.extension do
|
||||
builder.tag!('changePoll:changeData',
|
||||
'xmlns:changePoll' => 'https://epp.tld.ee/schema/changePoll-1.0.xsd') do
|
||||
builder.tag!('changePoll:operation', action.operation)
|
||||
builder.tag!('changePoll:date', action.created_at.utc.xmlschema)
|
||||
builder.tag!('changePoll:svTRID', action.id)
|
||||
builder.tag!('changePoll:who', action.user)
|
||||
end
|
||||
end
|
72
app/views/epp/poll/_contact.xml.builder
Normal file
72
app/views/epp/poll/_contact.xml.builder
Normal file
|
@ -0,0 +1,72 @@
|
|||
builder.resData do
|
||||
builder.tag!('contact:infData', 'xmlns:contact' => 'https://epp.tld.ee/schema/contact-ee-1.1.xsd') do
|
||||
builder.tag!('contact:id', contact.code)
|
||||
builder.tag!('contact:roid', contact.roid)
|
||||
|
||||
contact.statuses.each do |status|
|
||||
builder.tag!('contact:status', s: status)
|
||||
end
|
||||
|
||||
builder.tag!('contact:postalInfo', type: 'int') do
|
||||
builder.tag!('contact:name', contact.name)
|
||||
if can? :view_full_info, contact, @password
|
||||
builder.tag!('contact:org', contact.org_name) if contact.org_name.present?
|
||||
|
||||
if address_processing
|
||||
builder.tag!('contact:addr') do
|
||||
builder.tag!('contact:street', contact.street)
|
||||
builder.tag!('contact:city', contact.city)
|
||||
builder.tag!('contact:sp', contact.state)
|
||||
builder.tag!('contact:pc', contact.zip)
|
||||
builder.tag!('contact:cc', contact.country_code)
|
||||
end
|
||||
end
|
||||
|
||||
else
|
||||
builder.tag!('contact:org', 'No access')
|
||||
|
||||
if address_processing
|
||||
builder.tag!('contact:addr') do
|
||||
builder.tag!('contact:street', 'No access')
|
||||
builder.tag!('contact:city', 'No access')
|
||||
builder.tag!('contact:sp', 'No access')
|
||||
builder.tag!('contact:pc', 'No access')
|
||||
builder.tag!('contact:cc', 'No access')
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
if can? :view_full_info, contact, @password
|
||||
builder.tag!('contact:voice', contact.phone)
|
||||
builder.tag!('contact:fax', contact.fax) if contact.fax.present?
|
||||
builder.tag!('contact:email', contact.email)
|
||||
else
|
||||
builder.tag!('contact:voice', 'No access')
|
||||
builder.tag!('contact:fax', 'No access')
|
||||
builder.tag!('contact:email', 'No access')
|
||||
end
|
||||
|
||||
builder.tag!('contact:clID', contact.registrar.try(:code))
|
||||
|
||||
builder.tag!('contact:crID', contact.cr_id)
|
||||
builder.tag!('contact:crDate', contact.created_at.try(:iso8601))
|
||||
|
||||
if contact.updated_at > contact.created_at
|
||||
upID = contact.updator.try(:registrar)
|
||||
upID = upID.code if upID.present? # Did updator return a kind of User that has a registrar?
|
||||
builder.tag!('contact:upID', upID) if upID.present? # optional upID
|
||||
builder.tag!('contact:upDate', contact.updated_at.try(:iso8601))
|
||||
end
|
||||
if can? :view_password, contact, @password
|
||||
builder.tag!('contact:authInfo') do
|
||||
builder.tag!('contact:pw', contact.auth_info)
|
||||
end
|
||||
else
|
||||
builder.tag!('contact:authInfo') do
|
||||
builder.tag!('contact:pw', 'No access')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -14,6 +14,21 @@ xml.epp_head do
|
|||
xml << render('epp/domains/partials/transfer', builder: xml, dt: @object)
|
||||
end if @object
|
||||
end
|
||||
|
||||
if @notification.action&.contact
|
||||
# render(partial: 'epp/poll/contact',
|
||||
# locals: {
|
||||
# builder: xml,
|
||||
# contact: @notification.action.contact,
|
||||
# address_processing: Setting.address_processing
|
||||
# })
|
||||
render(partial: 'epp/poll/action',
|
||||
locals: {
|
||||
builder: xml,
|
||||
action: @notification.action
|
||||
})
|
||||
end
|
||||
|
||||
render('epp/shared/trID', builder: xml)
|
||||
end
|
||||
end
|
||||
|
|
7
app/views/registrant/contacts/_api_errors.html.erb
Normal file
7
app/views/registrant/contacts/_api_errors.html.erb
Normal file
|
@ -0,0 +1,7 @@
|
|||
<div class="alert alert-danger">
|
||||
<ul>
|
||||
<% errors.each_value do |errors| %>
|
||||
<li><%= errors.join('<br>') %></li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</div>
|
64
app/views/registrant/contacts/_form.html.erb
Normal file
64
app/views/registrant/contacts/_form.html.erb
Normal file
|
@ -0,0 +1,64 @@
|
|||
<%= form_for [:registrant, domain, @contact], html: { class: 'form-horizontal' } do |f| %>
|
||||
<% if @errors.present? %>
|
||||
<%= render 'api_errors', errors: @errors %>
|
||||
<% end %>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="col-md-2 control-label">
|
||||
<%= f.label :name %>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<%= f.text_field :name, required: true, autofocus: true, class: 'form-control' %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="col-md-2 control-label">
|
||||
<%= f.label :email %>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<%= f.email_field :email, required: true, class: 'form-control' %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="col-md-2 control-label">
|
||||
<%= f.label :phone %>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<%= f.text_field :phone, required: true, class: 'form-control' %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<% if Contact.address_processing? %>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading"><%= t '.address' %></div>
|
||||
<div class="panel-body">
|
||||
<%= render 'registrant/contacts/form/address', f: f %>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<% if fax_enabled? %>
|
||||
<div class="form-group">
|
||||
<div class="col-md-2 control-label">
|
||||
<%= f.label :fax %>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<%= f.text_field :fax, class: 'form-control' %>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<hr/>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6 text-right">
|
||||
<%= button_tag t('.submit_btn'), class: 'btn btn-success' %>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
12
app/views/registrant/contacts/edit.html.erb
Normal file
12
app/views/registrant/contacts/edit.html.erb
Normal file
|
@ -0,0 +1,12 @@
|
|||
<ol class="breadcrumb">
|
||||
<li><%= link_to t('registrant.domains.index.header'), registrant_domains_path %></li>
|
||||
<li><%= link_to domain, registrant_domain_path(domain) %></li>
|
||||
<li><%= t 'registrant.contacts.contact_index' %></li>
|
||||
<li><%= link_to @contact, registrant_domain_contact_path(domain, @contact) %></li>
|
||||
</ol>
|
||||
|
||||
<div class="page-header">
|
||||
<h1><%= t '.header' %></h1>
|
||||
</div>
|
||||
|
||||
<%= render 'form' %>
|
51
app/views/registrant/contacts/form/_address.html.erb
Normal file
51
app/views/registrant/contacts/form/_address.html.erb
Normal file
|
@ -0,0 +1,51 @@
|
|||
<div class="form-group">
|
||||
<div class="col-md-2 control-label">
|
||||
<%= f.label :street %>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<%= f.text_field :street, required: true, class: 'form-control' %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="col-md-2 control-label">
|
||||
<%= f.label :zip %>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<%= f.text_field :zip, required: true, class: 'form-control' %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="col-md-2 control-label">
|
||||
<%= f.label :city %>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<%= f.text_field :city, required: true, class: 'form-control' %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="col-md-2 control-label">
|
||||
<%= f.label :state %>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<%= f.text_field :state, class: 'form-control' %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="col-md-2 control-label">
|
||||
<%= f.label :country_code, 'Country' %>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<%= f.select :country_code, SortedCountry.all_options(f.object.country_code), {},
|
||||
required: true,
|
||||
class: 'form-control' %>
|
||||
</div>
|
||||
</div>
|
|
@ -5,7 +5,18 @@
|
|||
</ol>
|
||||
|
||||
<div class="page-header">
|
||||
<h1><%= @contact.name %></h1>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<h1><%= @contact %></h1>
|
||||
</div>
|
||||
|
||||
<% if @contact.managed_by?(current_registrant_user) %>
|
||||
<div class="col-md-6 text-right">
|
||||
<%= link_to t('.edit_btn'), edit_registrant_domain_contact_path(domain, @contact),
|
||||
class: 'btn btn-primary' %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
|
|
|
@ -97,6 +97,7 @@ sk_digi_doc_service_endpoint: 'https://tsp.demo.sk.ee'
|
|||
sk_digi_doc_service_name: 'Testimine'
|
||||
|
||||
# Registrant API
|
||||
registrant_api_base_url:
|
||||
registrant_api_auth_allowed_ips: '127.0.0.1, 0.0.0.0' #ips, separated with commas
|
||||
|
||||
#
|
||||
|
|
|
@ -5,3 +5,4 @@ en:
|
|||
Transfer of domain %{domain_name} has been approved.
|
||||
It was associated with registrant %{old_registrant_code}
|
||||
and contacts %{old_contacts_codes}.
|
||||
contact_update: Contact %{contact} has been updated by registrant
|
||||
|
|
|
@ -4,6 +4,7 @@ en:
|
|||
contact_index: Contacts
|
||||
|
||||
show:
|
||||
edit_btn: Edit
|
||||
general:
|
||||
header: General
|
||||
|
||||
|
@ -17,4 +18,15 @@ en:
|
|||
|
||||
domains:
|
||||
header: Domains
|
||||
all: All roles
|
||||
all: All roles
|
||||
|
||||
edit:
|
||||
header: Edit contact
|
||||
|
||||
update:
|
||||
updated: Contact has been successfully updated
|
||||
|
||||
form:
|
||||
address: Address
|
||||
submit_btn: Update contact
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ Rails.application.routes.draw do
|
|||
resources :domains, only: %i[index show], param: :uuid do
|
||||
resource :registry_lock, only: %i[create destroy]
|
||||
end
|
||||
resources :contacts, only: %i[index show], param: :uuid
|
||||
resources :contacts, only: %i[index show update], param: :uuid
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -137,7 +137,7 @@ Rails.application.routes.draw do
|
|||
|
||||
resources :registrars, only: :show
|
||||
resources :domains, only: %i[index show] do
|
||||
resources :contacts, only: %i[show]
|
||||
resources :contacts, only: %i[show edit update]
|
||||
|
||||
collection do
|
||||
get :download_list
|
||||
|
|
9
db/migrate/20180824215326_create_actions.rb
Normal file
9
db/migrate/20180824215326_create_actions.rb
Normal file
|
@ -0,0 +1,9 @@
|
|||
class CreateActions < ActiveRecord::Migration
|
||||
def change
|
||||
create_table :actions do |t|
|
||||
t.belongs_to :user, foreign_key: true
|
||||
t.string :operation
|
||||
t.datetime :created_at
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,5 @@
|
|||
class ChangeActionsOperationToNotNull < ActiveRecord::Migration
|
||||
def change
|
||||
change_column_null :actions, :operation, false
|
||||
end
|
||||
end
|
5
db/migrate/20180825232819_add_contact_id_to_actions.rb
Normal file
5
db/migrate/20180825232819_add_contact_id_to_actions.rb
Normal file
|
@ -0,0 +1,5 @@
|
|||
class AddContactIdToActions < ActiveRecord::Migration
|
||||
def change
|
||||
add_reference :actions, :contact, foreign_key: true
|
||||
end
|
||||
end
|
|
@ -0,0 +1,5 @@
|
|||
class AddActionIdToNotifications < ActiveRecord::Migration
|
||||
def change
|
||||
add_reference :notifications, :action, foreign_key: true
|
||||
end
|
||||
end
|
|
@ -370,6 +370,38 @@ CREATE SEQUENCE public.accounts_id_seq
|
|||
ALTER SEQUENCE public.accounts_id_seq OWNED BY public.accounts.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: actions; Type: TABLE; Schema: public; Owner: -; Tablespace:
|
||||
--
|
||||
|
||||
CREATE TABLE public.actions (
|
||||
id integer NOT NULL,
|
||||
user_id integer,
|
||||
operation character varying NOT NULL,
|
||||
created_at timestamp without time zone,
|
||||
contact_id integer
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: actions_id_seq; Type: SEQUENCE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE SEQUENCE public.actions_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
|
||||
--
|
||||
-- Name: actions_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER SEQUENCE public.actions_id_seq OWNED BY public.actions.id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: bank_statements; Type: TABLE; Schema: public; Owner: -; Tablespace:
|
||||
--
|
||||
|
@ -2006,7 +2038,8 @@ CREATE TABLE public.notifications (
|
|||
created_at timestamp without time zone,
|
||||
updated_at timestamp without time zone,
|
||||
creator_str character varying,
|
||||
updator_str character varying
|
||||
updator_str character varying,
|
||||
action_id integer
|
||||
);
|
||||
|
||||
|
||||
|
@ -2486,6 +2519,13 @@ ALTER TABLE ONLY public.account_activities ALTER COLUMN id SET DEFAULT nextval('
|
|||
ALTER TABLE ONLY public.accounts ALTER COLUMN id SET DEFAULT nextval('public.accounts_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.actions ALTER COLUMN id SET DEFAULT nextval('public.actions_id_seq'::regclass);
|
||||
|
||||
|
||||
--
|
||||
-- Name: id; Type: DEFAULT; Schema: public; Owner: -
|
||||
--
|
||||
|
@ -2873,6 +2913,14 @@ ALTER TABLE ONLY public.accounts
|
|||
ADD CONSTRAINT accounts_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: actions_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace:
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.actions
|
||||
ADD CONSTRAINT actions_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: bank_statements_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace:
|
||||
--
|
||||
|
@ -4057,6 +4105,30 @@ ALTER TABLE ONLY public.domain_transfers
|
|||
ADD CONSTRAINT fk_rails_87b8e40c63 FOREIGN KEY (domain_id) REFERENCES public.domains(id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: fk_rails_8c6b5c12eb; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.actions
|
||||
ADD CONSTRAINT fk_rails_8c6b5c12eb FOREIGN KEY (user_id) REFERENCES public.users(id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: fk_rails_8f9734b530; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.notifications
|
||||
ADD CONSTRAINT fk_rails_8f9734b530 FOREIGN KEY (action_id) REFERENCES public.actions(id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: fk_rails_a5ae3c203d; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.actions
|
||||
ADD CONSTRAINT fk_rails_a5ae3c203d FOREIGN KEY (contact_id) REFERENCES public.contacts(id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: fk_rails_adff2dc8e3; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
@ -4777,5 +4849,15 @@ INSERT INTO schema_migrations (version) VALUES ('20180824092855');
|
|||
|
||||
INSERT INTO schema_migrations (version) VALUES ('20180824102834');
|
||||
|
||||
INSERT INTO schema_migrations (version) VALUES ('20180824215326');
|
||||
|
||||
INSERT INTO schema_migrations (version) VALUES ('20180825153657');
|
||||
|
||||
INSERT INTO schema_migrations (version) VALUES ('20180825193437');
|
||||
|
||||
INSERT INTO schema_migrations (version) VALUES ('20180825232819');
|
||||
|
||||
INSERT INTO schema_migrations (version) VALUES ('20180826162821');
|
||||
|
||||
INSERT INTO schema_migrations (version) VALUES ('20181002090319');
|
||||
|
||||
|
|
|
@ -113,16 +113,17 @@ Update contact details for a contact.
|
|||
|
||||
#### Parameters
|
||||
|
||||
| Field name | Required | Type | Allowed values | Description |
|
||||
| ---- | --- | --- | --- | --- |
|
||||
| email | false | String | | New email address |
|
||||
| phone | false | String | | New phone number |
|
||||
| fax | false | String | | New fax number |
|
||||
| city | false | String | | New city name |
|
||||
| street | false | String | | New street name |
|
||||
| zip | false | String | | New zip code |
|
||||
| country_code | false | String | | New country code in 2 letter format ('EE', 'LV') |
|
||||
| state | false | String | | New state name |
|
||||
| Field name | Required | Type | Allowed values | Description |
|
||||
| ---- | --- | --- | --- | --- |
|
||||
| name | false | String | | New name |
|
||||
| email | false | String | | New email |
|
||||
| phone | false | String | | New phone number |
|
||||
| fax | false | String | | New fax number |
|
||||
| address[street] | false | String | | New street name |
|
||||
| address[zip] | false | String | | New zip |
|
||||
| address[city] | false | String | | New city name |
|
||||
| address[state] | false | String | | New state name |
|
||||
| address[country_code] | false | String | | New country code in 2 letter format (ISO 3166-1 alpha-2) |
|
||||
|
||||
|
||||
#### Request
|
||||
|
@ -133,14 +134,17 @@ Accept: application/json
|
|||
Content-type: application/json
|
||||
|
||||
{
|
||||
"name": "John Doe",
|
||||
"email": "foo@bar.baz",
|
||||
"phone": "+372.12345671",
|
||||
"fax": "+372.12345672",
|
||||
"city": "New City",
|
||||
"street": "Main Street 123",
|
||||
"zip": "22222",
|
||||
"country_code": "LV",
|
||||
"state": "New state"
|
||||
"address": {
|
||||
"street": "Main Street 123",
|
||||
"zip": "22222",
|
||||
"city": "New City",
|
||||
"state": "New state",
|
||||
"country_code": "LV"
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
@ -151,33 +155,28 @@ HTTP/1.1 200
|
|||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"uuid": "84c62f3d-e56f-40fa-9ca4-dc0137778949",
|
||||
"domain_names": ["example.com"],
|
||||
"code": "REGISTRAR2:SH022086480",
|
||||
"phone": "+372.12345671",
|
||||
"email": "foo@bar.baz",
|
||||
"fax": "+372.12345672",
|
||||
"created_at": "2015-09-09T09:11:14.130Z",
|
||||
"updated_at": "2018-09-09T09:11:14.130Z",
|
||||
"ident": "37605030299",
|
||||
"ident_type": "priv",
|
||||
"auth_info": "password",
|
||||
"id": "84c62f3d-e56f-40fa-9ca4-dc0137778949",
|
||||
"name": "Karson Kessler0",
|
||||
"org_name": null,
|
||||
"registrar_id": 2,
|
||||
"creator_str": null,
|
||||
"updator_str": null,
|
||||
"ident_country_code": "EE",
|
||||
"city": "New City",
|
||||
"street": "Main Street 123",
|
||||
"zip": "22222",
|
||||
"country_code": "LV",
|
||||
"state": "New state"
|
||||
"legacy_id": null,
|
||||
"code": "REGISTRAR2:SH022086480",
|
||||
"ident": {
|
||||
"code": "37605030299",
|
||||
"type": "priv",
|
||||
"country_code": "EE"
|
||||
},
|
||||
"email": "foo@bar.baz",
|
||||
"phone": "+372.12345671",
|
||||
"fax": "+372.12345672",
|
||||
"address": {
|
||||
"street": "Main Street 123",
|
||||
"zip": "22222",
|
||||
"city": "New City",
|
||||
"state": "New state",
|
||||
"country_code": "LV"
|
||||
},
|
||||
"auth_info": "password",
|
||||
"statuses": [
|
||||
"ok"
|
||||
],
|
||||
"status_notes": {}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -187,8 +186,8 @@ HTTP/1.1 400
|
|||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"errors": [
|
||||
{ "phone": "Phone nr is invalid" }
|
||||
]
|
||||
"errors": {
|
||||
"phone": ["Phone nr is invalid"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
|
123
lib/schemas/changePoll-1.0.xsd
Normal file
123
lib/schemas/changePoll-1.0.xsd
Normal file
|
@ -0,0 +1,123 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<schema targetNamespace="urn:ietf:params:xml:ns:changePoll-1.0"
|
||||
xmlns:eppcom="urn:ietf:params:xml:ns:eppcom-1.0"
|
||||
xmlns:epp="urn:ietf:params:xml:ns:epp-1.0"
|
||||
xmlns:changePoll="urn:ietf:params:xml:ns:changePoll-1.0"
|
||||
xmlns="http://www.w3.org/2001/XMLSchema"
|
||||
elementFormDefault="qualified">
|
||||
|
||||
<!--
|
||||
Import common element types.
|
||||
-->
|
||||
<import namespace="urn:ietf:params:xml:ns:eppcom-1.0"/>
|
||||
<import namespace="urn:ietf:params:xml:ns:epp-1.0"/>
|
||||
|
||||
|
||||
<annotation>
|
||||
<documentation>
|
||||
Extensible Provisioning Protocol v1.0
|
||||
Change Poll Mapping Schema.
|
||||
</documentation>
|
||||
</annotation>
|
||||
|
||||
<!--
|
||||
Change element.
|
||||
-->
|
||||
<element name="changeData" type="changePoll:changeDataType"/>
|
||||
|
||||
<!--
|
||||
Attributes associated with the change.
|
||||
-->
|
||||
<complexType name="changeDataType">
|
||||
<sequence>
|
||||
<element name="operation" type="changePoll:operationType"/>
|
||||
<element name="date" type="dateTime"/>
|
||||
<element name="svTRID" type="epp:trIDStringType"/>
|
||||
<element name="who" type="changePoll:whoType"/>
|
||||
<element name="caseId" type="changePoll:caseIdType"
|
||||
minOccurs="0"/>
|
||||
<element name="reason" type="eppcom:reasonType"
|
||||
minOccurs="0"/>
|
||||
</sequence>
|
||||
<attribute name="state" type="changePoll:stateType"
|
||||
default="after"/>
|
||||
</complexType>
|
||||
|
||||
<!--
|
||||
Enumerated list of operations, with extensibility via "custom".
|
||||
-->
|
||||
<simpleType name="operationEnum">
|
||||
<restriction base="token">
|
||||
<enumeration value="create"/>
|
||||
<enumeration value="delete"/>
|
||||
<enumeration value="renew"/>
|
||||
<enumeration value="transfer"/>
|
||||
<enumeration value="update"/>
|
||||
<enumeration value="restore"/>
|
||||
<enumeration value="autoRenew"/>
|
||||
<enumeration value="autoDelete"/>
|
||||
<enumeration value="autoPurge"/>
|
||||
<enumeration value="custom"/>
|
||||
</restriction>
|
||||
</simpleType>
|
||||
|
||||
<!--
|
||||
Enumerated of state of the object in the poll message.
|
||||
-->
|
||||
<simpleType name="stateType">
|
||||
<restriction base="token">
|
||||
<enumeration value="before"/>
|
||||
<enumeration value="after"/>
|
||||
</restriction>
|
||||
</simpleType>
|
||||
|
||||
<!--
|
||||
Transform operation type
|
||||
-->
|
||||
<complexType name="operationType">
|
||||
<simpleContent>
|
||||
<extension base="changePoll:operationEnum">
|
||||
<attribute name="op" type="token"/>
|
||||
</extension>
|
||||
</simpleContent>
|
||||
</complexType>
|
||||
|
||||
<!--
|
||||
Case identifier type
|
||||
-->
|
||||
<complexType name="caseIdType">
|
||||
<simpleContent>
|
||||
<extension base="token">
|
||||
<attribute name="type" type="changePoll:caseTypeEnum"
|
||||
use="required"/>
|
||||
<attribute name="name" type="token"
|
||||
use="optional"/>
|
||||
</extension>
|
||||
</simpleContent>
|
||||
</complexType>
|
||||
|
||||
<!--
|
||||
Enumerated list of case identifier types
|
||||
-->
|
||||
<simpleType name="caseTypeEnum">
|
||||
<restriction base="token">
|
||||
<enumeration value="udrp"/>
|
||||
<enumeration value="urs"/>
|
||||
<enumeration value="custom"/>
|
||||
</restriction>
|
||||
</simpleType>
|
||||
|
||||
<!--
|
||||
Who type
|
||||
-->
|
||||
<simpleType name="whoType">
|
||||
<restriction base="normalizedString">
|
||||
<minLength value="1"/>
|
||||
<maxLength value="255"/>
|
||||
</restriction>
|
||||
</simpleType>
|
||||
|
||||
<!--
|
||||
End of schema.
|
||||
-->
|
||||
</schema>
|
5
test/fixtures/actions.yml
vendored
Normal file
5
test/fixtures/actions.yml
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
contact_update:
|
||||
operation: update
|
||||
contact: john
|
||||
created_at: <%= Time.zone.parse('2010-07-05').to_s(:db) %>
|
||||
user: registrant
|
4
test/fixtures/contacts.yml
vendored
4
test/fixtures/contacts.yml
vendored
|
@ -9,8 +9,8 @@ john:
|
|||
code: john-001
|
||||
auth_info: cacb5b
|
||||
uuid: eb2f2766-b44c-4e14-9f16-32ab1a7cb957
|
||||
created_at: <%= Time.zone.parse('2010-07-05').to_s(:db) %>
|
||||
updated_at: <%= Time.zone.parse('2010-07-06').to_s(:db) %>
|
||||
created_at: <%= Time.zone.parse('2010-07-05') %>
|
||||
updated_at: <%= Time.zone.parse('2010-07-06') %>
|
||||
|
||||
william: &william
|
||||
name: William
|
||||
|
|
4
test/fixtures/notifications.yml
vendored
4
test/fixtures/notifications.yml
vendored
|
@ -4,8 +4,8 @@ greeting:
|
|||
registrar: bestnames
|
||||
created_at: <%= Time.zone.parse('2010-07-04') %>
|
||||
|
||||
domain_deleted:
|
||||
text: Your domain has been deleted
|
||||
complete:
|
||||
text: Your domain has been updated
|
||||
read: false
|
||||
registrar: bestnames
|
||||
created_at: <%= Time.zone.parse('2010-07-05') %>
|
||||
|
|
179
test/integration/api/v1/registrant/contacts/update_test.rb
Normal file
179
test/integration/api/v1/registrant/contacts/update_test.rb
Normal file
|
@ -0,0 +1,179 @@
|
|||
require 'test_helper'
|
||||
require 'auth_token/auth_token_creator'
|
||||
|
||||
class RegistrantApiV1ContactUpdateTest < ActionDispatch::IntegrationTest
|
||||
setup do
|
||||
@contact = contacts(:john)
|
||||
|
||||
@original_address_processing_setting = Setting.address_processing
|
||||
@original_business_registry_cache_setting = Setting.days_to_keep_business_registry_cache
|
||||
@original_fax_enabled_setting = ENV['fax_enabled']
|
||||
|
||||
Setting.days_to_keep_business_registry_cache = 1
|
||||
travel_to Time.zone.parse('2010-07-05')
|
||||
end
|
||||
|
||||
teardown do
|
||||
Setting.address_processing = @original_address_processing_setting
|
||||
Setting.days_to_keep_business_registry_cache = @original_business_registry_cache_setting
|
||||
ENV['fax_enabled'] = @original_fax_enabled_setting
|
||||
end
|
||||
|
||||
def test_update_contact
|
||||
patch api_v1_registrant_contact_path(@contact.uuid), { name: 'new name',
|
||||
email: 'new-email@coldmail.test',
|
||||
phone: '+666.6' },
|
||||
'HTTP_AUTHORIZATION' => auth_token
|
||||
assert_response :ok
|
||||
@contact.reload
|
||||
assert_equal 'new name', @contact.name
|
||||
assert_equal 'new-email@coldmail.test', @contact.email
|
||||
assert_equal '+666.6', @contact.phone
|
||||
end
|
||||
|
||||
def test_notify_registrar
|
||||
assert_difference -> { @contact.registrar.notifications.count } do
|
||||
patch api_v1_registrant_contact_path(@contact.uuid), { name: 'new name' },
|
||||
'HTTP_AUTHORIZATION' => auth_token
|
||||
end
|
||||
notification = @contact.registrar.notifications.last
|
||||
assert_equal 'Contact john-001 has been updated by registrant', notification.text
|
||||
end
|
||||
|
||||
def test_update_fax_when_enabled
|
||||
ENV['fax_enabled'] = 'true'
|
||||
@contact = contacts(:william)
|
||||
|
||||
patch api_v1_registrant_contact_path(@contact.uuid), { 'fax' => '+777.7' },
|
||||
'HTTP_AUTHORIZATION' => auth_token
|
||||
|
||||
assert_response :ok
|
||||
@contact.reload
|
||||
assert_equal '+777.7', @contact.fax
|
||||
end
|
||||
|
||||
def test_fax_cannot_be_updated_when_disabled
|
||||
ENV['fax_enabled'] = 'false'
|
||||
|
||||
patch api_v1_registrant_contact_path(@contact.uuid), { 'fax' => '+823.7' },
|
||||
'HTTP_AUTHORIZATION' => auth_token
|
||||
|
||||
assert_response :bad_request
|
||||
@contact.reload
|
||||
assert_not_equal '+823.7', @contact.fax
|
||||
|
||||
error_msg = 'Fax processing is disabled and therefore cannot be updated'
|
||||
assert_equal ({ errors: [{ address: [error_msg] }] }), JSON.parse(response.body,
|
||||
symbolize_names: true)
|
||||
end
|
||||
|
||||
def test_update_address_when_enabled
|
||||
Setting.address_processing = true
|
||||
|
||||
patch api_v1_registrant_contact_path(@contact.uuid), { 'address[city]' => 'new city',
|
||||
'address[street]' => 'new street',
|
||||
'address[zip]' => '92837',
|
||||
'address[country_code]' => 'RU',
|
||||
'address[state]' => 'new state' },
|
||||
'HTTP_AUTHORIZATION' => auth_token
|
||||
|
||||
assert_response :ok
|
||||
@contact.reload
|
||||
assert_equal Contact::Address.new('new street', '92837', 'new city', 'new state', 'RU'),
|
||||
@contact.address
|
||||
end
|
||||
|
||||
def test_address_is_optional_when_enabled
|
||||
@contact = contacts(:william)
|
||||
Setting.address_processing = true
|
||||
|
||||
patch api_v1_registrant_contact_path(@contact.uuid), { 'name' => 'any' },
|
||||
'HTTP_AUTHORIZATION' => auth_token
|
||||
|
||||
assert_response :ok
|
||||
end
|
||||
|
||||
def test_address_cannot_be_updated_when_disabled
|
||||
@contact = contacts(:william)
|
||||
@original_address = @contact.address
|
||||
Setting.address_processing = false
|
||||
|
||||
patch api_v1_registrant_contact_path(@contact.uuid), { 'address[city]' => 'new city' },
|
||||
'HTTP_AUTHORIZATION' => auth_token
|
||||
|
||||
@contact.reload
|
||||
assert_response :bad_request
|
||||
assert_equal @original_address, @contact.address
|
||||
|
||||
error_msg = 'Address processing is disabled and therefore cannot be updated'
|
||||
assert_equal ({ errors: [{ address: [error_msg] }] }), JSON.parse(response.body,
|
||||
symbolize_names: true)
|
||||
end
|
||||
|
||||
def test_return_contact_details
|
||||
patch api_v1_registrant_contact_path(@contact.uuid), { name: 'new name' },
|
||||
'HTTP_AUTHORIZATION' => auth_token
|
||||
assert_equal ({ id: @contact.uuid,
|
||||
name: 'new name',
|
||||
code: @contact.code,
|
||||
fax: @contact.fax,
|
||||
ident: {
|
||||
code: @contact.ident,
|
||||
type: @contact.ident_type,
|
||||
country_code: @contact.ident_country_code,
|
||||
},
|
||||
email: @contact.email,
|
||||
phone: @contact.phone,
|
||||
address: {
|
||||
street: @contact.street,
|
||||
zip: @contact.zip,
|
||||
city: @contact.city,
|
||||
state: @contact.state,
|
||||
country_code: @contact.country_code,
|
||||
},
|
||||
auth_info: @contact.auth_info,
|
||||
statuses: @contact.statuses }), JSON.parse(response.body, symbolize_names: true)
|
||||
end
|
||||
|
||||
def test_errors
|
||||
patch api_v1_registrant_contact_path(@contact.uuid), { phone: 'invalid' },
|
||||
'HTTP_AUTHORIZATION' => auth_token
|
||||
|
||||
assert_response :bad_request
|
||||
assert_equal ({ errors: { phone: ['Phone nr is invalid'] } }), JSON.parse(response.body,
|
||||
symbolize_names: true)
|
||||
end
|
||||
|
||||
def test_contact_of_another_user_cannot_be_updated
|
||||
@contact = contacts(:jack)
|
||||
|
||||
patch api_v1_registrant_contact_path(@contact.uuid), { name: 'any' },
|
||||
'HTTP_AUTHORIZATION' => auth_token
|
||||
|
||||
assert_response :not_found
|
||||
@contact.reload
|
||||
assert_not_equal 'any', @contact.name
|
||||
end
|
||||
|
||||
def test_non_existent_contact
|
||||
patch api_v1_registrant_contact_path('non-existent'), nil, 'HTTP_AUTHORIZATION' => auth_token
|
||||
assert_response :not_found
|
||||
assert_equal ({ errors: [{ base: ['Not found'] }] }),
|
||||
JSON.parse(response.body, symbolize_names: true)
|
||||
end
|
||||
|
||||
def test_anonymous_user
|
||||
patch api_v1_registrant_contact_path(@contact.uuid)
|
||||
assert_response :unauthorized
|
||||
assert_equal ({ errors: [{ base: ['Not authorized'] }] }),
|
||||
JSON.parse(response.body, symbolize_names: true)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def auth_token
|
||||
token_creator = AuthTokenCreator.create_with_defaults(users(:registrant))
|
||||
hash = token_creator.token_in_hash
|
||||
"Bearer #{hash[:access_token]}"
|
||||
end
|
||||
end
|
|
@ -1,9 +1,33 @@
|
|||
require 'test_helper'
|
||||
|
||||
class EppPollTest < ApplicationIntegrationTest
|
||||
setup do
|
||||
@notification = notifications(:complete)
|
||||
end
|
||||
|
||||
# Deliberately does not conform to RFC5730, which requires the first notification to be returned
|
||||
def test_return_latest_notification_when_queue_is_not_empty
|
||||
notification = notifications(:domain_deleted)
|
||||
request_xml = <<-XML
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<epp xmlns="https://epp.tld.ee/schema/epp-ee-1.0.xsd">
|
||||
<command>
|
||||
<poll op="req"/>
|
||||
</command>
|
||||
</epp>
|
||||
XML
|
||||
post '/epp/command/poll', { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames'
|
||||
|
||||
xml_doc = Nokogiri::XML(response.body)
|
||||
assert_equal 1301.to_s, xml_doc.at_css('result')[:code]
|
||||
assert_equal 1, xml_doc.css('result').size
|
||||
assert_equal 2.to_s, xml_doc.at_css('msgQ')[:count]
|
||||
assert_equal @notification.id.to_s, xml_doc.at_css('msgQ')[:id]
|
||||
assert_equal Time.zone.parse('2010-07-05').utc.xmlschema, xml_doc.at_css('msgQ qDate').text
|
||||
assert_equal 'Your domain has been updated', xml_doc.at_css('msgQ msg').text
|
||||
end
|
||||
|
||||
def test_return_action_data_when_present
|
||||
@notification.update!(action: actions(:contact_update))
|
||||
|
||||
request_xml = <<-XML
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
|
@ -14,14 +38,16 @@ class EppPollTest < ApplicationIntegrationTest
|
|||
</epp>
|
||||
XML
|
||||
post '/epp/command/poll', { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames'
|
||||
response_xml = Nokogiri::XML(response.body)
|
||||
|
||||
assert_equal 1301.to_s, response_xml.at_css('result')[:code]
|
||||
assert_equal 1, response_xml.css('result').size
|
||||
assert_equal 2.to_s, response_xml.at_css('msgQ')[:count]
|
||||
assert_equal notification.id.to_s, response_xml.at_css('msgQ')[:id]
|
||||
assert_equal Time.zone.parse('2010-07-05').utc.xmlschema, response_xml.at_css('msgQ qDate').text
|
||||
assert_equal 'Your domain has been deleted', response_xml.at_css('msgQ msg').text
|
||||
xml_doc = Nokogiri::XML(response.body)
|
||||
namespace = 'https://epp.tld.ee/schema/changePoll-1.0.xsd'
|
||||
assert_equal 'update', xml_doc.xpath('//changePoll:operation', 'changePoll' => namespace).text
|
||||
assert_equal Time.zone.parse('2010-07-05').utc.xmlschema,
|
||||
xml_doc.xpath('//changePoll:date', 'changePoll' => namespace).text
|
||||
assert_equal @notification.action.id.to_s, xml_doc.xpath('//changePoll:svTRID',
|
||||
'changePoll' => namespace).text
|
||||
assert_equal 'Registrant User', xml_doc.xpath('//changePoll:who',
|
||||
'changePoll' => namespace).text
|
||||
end
|
||||
|
||||
def test_no_notifications
|
||||
|
|
20
test/models/action_test.rb
Normal file
20
test/models/action_test.rb
Normal file
|
@ -0,0 +1,20 @@
|
|||
require 'test_helper'
|
||||
|
||||
class ActionTest < ActiveSupport::TestCase
|
||||
setup do
|
||||
@action = actions(:contact_update)
|
||||
end
|
||||
|
||||
def test_fixture_is_valid
|
||||
assert @action.valid?
|
||||
end
|
||||
|
||||
def test_invalid_with_unsupported_operation
|
||||
@action.operation = 'invalid'
|
||||
assert @action.invalid?
|
||||
end
|
||||
|
||||
def test_notification_key_for_contact
|
||||
assert_equal :contact_update, @action.notification_key
|
||||
end
|
||||
end
|
16
test/models/contact/address_test.rb
Normal file
16
test/models/contact/address_test.rb
Normal file
|
@ -0,0 +1,16 @@
|
|||
require 'test_helper'
|
||||
|
||||
class ContactAddressTest < ActiveSupport::TestCase
|
||||
setup do
|
||||
@address = Contact::Address.new('Main Street', '1234', 'NY City', 'NY State', 'US')
|
||||
end
|
||||
|
||||
def test_equal_when_all_parts_are_the_same
|
||||
assert_equal @address, Contact::Address.new('Main Street', '1234', 'NY City', 'NY State', 'US')
|
||||
end
|
||||
|
||||
def test_not_equal_when_some_part_is_different
|
||||
assert_not_equal @address, Contact::Address.new('Main Street', '1234', 'NY City', 'NY State',
|
||||
'DE')
|
||||
end
|
||||
end
|
|
@ -26,4 +26,16 @@ class ContactTest < ActiveSupport::TestCase
|
|||
def test_not_in_use_if_acts_as_neither_registrant_nor_domain_contact
|
||||
refute contacts(:not_in_use).in_use?
|
||||
end
|
||||
|
||||
def test_managed_when_identity_codes_match
|
||||
contact = Contact.new(ident: '1234')
|
||||
user = RegistrantUser.new(registrant_ident: 'US-1234')
|
||||
assert contact.managed_by?(user)
|
||||
end
|
||||
|
||||
def test_unmanaged_when_identity_codes_do_not_match
|
||||
contact = Contact.new(ident: '1234')
|
||||
user = RegistrantUser.new(registrant_ident: 'US-12345')
|
||||
assert_not contact.managed_by?(user)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -21,4 +21,13 @@ class ContactPostalAddressTest < ActiveSupport::TestCase
|
|||
@contact.country_code = 'invalid'
|
||||
assert @contact.valid?
|
||||
end
|
||||
|
||||
def test_state_is_optional_when_address_is_enabled
|
||||
Setting.address_processing = true
|
||||
contact = contacts(:william)
|
||||
assert contact.valid?
|
||||
|
||||
contact.state = ''
|
||||
assert contact.valid?
|
||||
end
|
||||
end
|
||||
|
|
|
@ -34,4 +34,18 @@ class ContactTest < ActiveSupport::TestCase
|
|||
@contact.phone = '+123.4'
|
||||
assert @contact.valid?
|
||||
end
|
||||
|
||||
def test_address
|
||||
address = Contact::Address.new('new street', '83746', 'new city', 'new state', 'EE')
|
||||
@contact.address = address
|
||||
@contact.save!
|
||||
@contact.reload
|
||||
|
||||
assert_equal 'new street', @contact.street
|
||||
assert_equal '83746', @contact.zip
|
||||
assert_equal 'new city', @contact.city
|
||||
assert_equal 'new state', @contact.state
|
||||
assert_equal 'EE', @contact.country_code
|
||||
assert_equal address, @contact.address
|
||||
end
|
||||
end
|
|
@ -35,4 +35,14 @@ class RegistrantUserTest < ActiveSupport::TestCase
|
|||
assert_equal('1234', @user.ident)
|
||||
assert_equal('US', @user.country_code)
|
||||
end
|
||||
|
||||
def test_first_name_from_username
|
||||
user = RegistrantUser.new(username: 'John Doe')
|
||||
assert_equal 'John', user.first_name
|
||||
end
|
||||
|
||||
def test_last_name_from_username
|
||||
user = RegistrantUser.new(username: 'John Doe')
|
||||
assert_equal 'Doe', user.last_name
|
||||
end
|
||||
end
|
||||
|
|
177
test/system/registrant_area/contacts/update_test.rb
Normal file
177
test/system/registrant_area/contacts/update_test.rb
Normal file
|
@ -0,0 +1,177 @@
|
|||
require 'test_helper'
|
||||
|
||||
class RegistrantAreaContactUpdateTest < ApplicationIntegrationTest
|
||||
setup do
|
||||
@domain = domains(:shop)
|
||||
@contact = contacts(:john)
|
||||
sign_in users(:registrant)
|
||||
|
||||
@original_address_processing_setting = Setting.address_processing
|
||||
@original_business_registry_cache_setting = Setting.days_to_keep_business_registry_cache
|
||||
@original_fax_enabled_setting = ENV['fax_enabled']
|
||||
@original_registrant_api_base_url_setting = ENV['registrant_api_base_url']
|
||||
|
||||
ENV['registrant_api_base_url'] = 'https://api.test'
|
||||
Setting.days_to_keep_business_registry_cache = 1
|
||||
travel_to Time.zone.parse('2010-07-05')
|
||||
end
|
||||
|
||||
teardown do
|
||||
Setting.address_processing = @original_address_processing_setting
|
||||
Setting.days_to_keep_business_registry_cache = @original_business_registry_cache_setting
|
||||
ENV['fax_enabled'] = @original_fax_enabled_setting
|
||||
ENV['registrant_api_base_url'] = @original_registrant_api_base_url_setting
|
||||
end
|
||||
|
||||
def test_form_is_pre_populated_with_contact_data
|
||||
visit edit_registrant_domain_contact_url(@domain, @contact)
|
||||
|
||||
assert_field 'Name', with: 'John'
|
||||
assert_field 'Email', with: 'john@inbox.test'
|
||||
assert_field 'Phone', with: '+555.555'
|
||||
end
|
||||
|
||||
def test_update_contact
|
||||
stub_auth_request
|
||||
|
||||
request_body = { name: 'new name', email: 'new@inbox.test', phone: '+666.6' }
|
||||
headers = { 'Authorization' => 'Bearer test-access-token' }
|
||||
url = "https://api.test/api/v1/registrant/contacts/#{@contact.uuid}"
|
||||
update_request_stub = stub_request(:patch, url).with(body: request_body, headers: headers)
|
||||
.to_return(body: '{}', status: 200)
|
||||
|
||||
visit registrant_domain_contact_url(@domain, @contact)
|
||||
click_link_or_button 'Edit'
|
||||
|
||||
fill_in 'Name', with: 'new name'
|
||||
fill_in 'Email', with: 'new@inbox.test'
|
||||
fill_in 'Phone', with: '+666.6'
|
||||
|
||||
click_link_or_button 'Update contact'
|
||||
|
||||
assert_requested update_request_stub
|
||||
assert_current_path registrant_domain_contact_path(@domain, @contact)
|
||||
assert_text 'Contact has been successfully updated'
|
||||
end
|
||||
|
||||
def test_form_is_pre_populated_with_fax_when_enabled
|
||||
ENV['fax_enabled'] = 'true'
|
||||
@contact.update!(fax: '+111.1')
|
||||
|
||||
visit edit_registrant_domain_contact_url(@domain, @contact)
|
||||
assert_field 'Fax', with: '+111.1'
|
||||
end
|
||||
|
||||
def test_update_fax_when_enabled
|
||||
ENV['fax_enabled'] = 'true'
|
||||
stub_auth_request
|
||||
|
||||
request_body = { email: 'john@inbox.test', name: 'John', phone: '+555.555', fax: '+222.2' }
|
||||
headers = { 'Authorization' => 'Bearer test-access-token' }
|
||||
url = "https://api.test/api/v1/registrant/contacts/#{@contact.uuid}"
|
||||
update_request_stub = stub_request(:patch, url).with(body: request_body, headers: headers)
|
||||
.to_return(body: '{}', status: 200)
|
||||
|
||||
visit edit_registrant_domain_contact_url(@domain, @contact)
|
||||
|
||||
fill_in 'Fax', with: '+222.2'
|
||||
click_link_or_button 'Update contact'
|
||||
|
||||
assert_requested update_request_stub
|
||||
assert_current_path registrant_domain_contact_path(@domain, @contact)
|
||||
assert_text 'Contact has been successfully updated'
|
||||
end
|
||||
|
||||
def test_hide_fax_field_when_disabled
|
||||
visit edit_registrant_domain_contact_url(@domain, @contact)
|
||||
assert_no_field 'Fax'
|
||||
end
|
||||
|
||||
def test_form_is_pre_populated_with_address_when_enabled
|
||||
Setting.address_processing = true
|
||||
@contact = contacts(:william)
|
||||
|
||||
visit edit_registrant_domain_contact_url(@domain, @contact)
|
||||
|
||||
assert_field 'Street', with: 'Main Street'
|
||||
assert_field 'Zip', with: '12345'
|
||||
assert_field 'City', with: 'New York'
|
||||
assert_field 'State', with: 'New York State'
|
||||
assert_select 'Country', selected: 'United States'
|
||||
end
|
||||
|
||||
def test_update_address_when_enabled
|
||||
Setting.address_processing = true
|
||||
stub_auth_request
|
||||
|
||||
request_body = { email: 'john@inbox.test',
|
||||
name: 'John',
|
||||
phone: '+555.555',
|
||||
address: {
|
||||
street: 'new street',
|
||||
zip: '93742',
|
||||
city: 'new city',
|
||||
state: 'new state',
|
||||
country_code: 'AT'
|
||||
} }
|
||||
headers = { 'Authorization' => 'Bearer test-access-token' }
|
||||
url = "https://api.test/api/v1/registrant/contacts/#{@contact.uuid}"
|
||||
update_request_stub = stub_request(:patch, url).with(body: request_body, headers: headers)
|
||||
.to_return(body: '{}', status: 200)
|
||||
|
||||
visit edit_registrant_domain_contact_url(@domain, @contact)
|
||||
|
||||
fill_in 'Street', with: 'new street'
|
||||
fill_in 'City', with: 'new city'
|
||||
fill_in 'State', with: 'new state'
|
||||
fill_in 'Zip', with: '93742'
|
||||
select 'Austria', from: 'Country'
|
||||
click_link_or_button 'Update contact'
|
||||
|
||||
assert_requested update_request_stub
|
||||
assert_current_path registrant_domain_contact_path(@domain, @contact)
|
||||
assert_text 'Contact has been successfully updated'
|
||||
end
|
||||
|
||||
def test_hide_address_field_when_disabled
|
||||
visit edit_registrant_domain_contact_url(@domain, @contact)
|
||||
assert_no_field 'Address'
|
||||
assert_no_field 'Street'
|
||||
end
|
||||
|
||||
def test_unmanaged_contact_cannot_be_updated
|
||||
@contact.update!(ident: '12345')
|
||||
visit registrant_domain_contact_url(@domain, @contact)
|
||||
assert_no_button 'Edit'
|
||||
assert_no_link 'Edit'
|
||||
end
|
||||
|
||||
def test_fail_gracefully
|
||||
stub_auth_request
|
||||
|
||||
response_body = { errors: { name: ['Name is invalid'] } }.to_json
|
||||
headers = { 'Authorization' => 'Bearer test-access-token' }
|
||||
stub_request(:patch, "https://api.test/api/v1/registrant/contacts/#{@contact.uuid}")
|
||||
.with(headers: headers)
|
||||
.to_return(body: response_body, status: 400)
|
||||
|
||||
visit edit_registrant_domain_contact_url(@domain, @contact)
|
||||
fill_in 'Name', with: 'invalid name'
|
||||
click_link_or_button 'Update contact'
|
||||
|
||||
assert_current_path registrant_domain_contact_path(@domain, @contact)
|
||||
assert_text 'Name is invalid'
|
||||
assert_field 'Name', with: 'invalid name'
|
||||
assert_no_text 'Contact has been successfully updated'
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def stub_auth_request
|
||||
body = { ident: '1234', first_name: 'Registrant', last_name: 'User' }
|
||||
stub_request(:post, 'https://api.test/api/v1/registrant/auth/eid').with(body: body)
|
||||
.to_return(body: { access_token: 'test-access-token' }.to_json,
|
||||
headers: { 'Content-type' => 'application/json' },
|
||||
status: 200)
|
||||
end
|
||||
end
|
Loading…
Add table
Add a link
Reference in a new issue