Improve Ident validation, extract Ident from Contact

#569
This commit is contained in:
Artur Beljajev 2017-08-18 13:24:56 +03:00
parent c5e1516d89
commit feb8d83a26
17 changed files with 809 additions and 195 deletions

View file

@ -1,6 +1,7 @@
class Admin::ContactsController < AdminController
load_and_authorize_resource
before_action :set_contact, only: [:show]
helper_method :ident_types
def index
params[:q] ||= {}
@ -78,4 +79,8 @@ class Admin::ContactsController < AdminController
params[:q][:created_at_lteq] = ca_cache
end
def ident_types
Contact::Ident.types
end
end

View file

@ -2,6 +2,7 @@ class Registrar
class ContactsController < DeppController
before_action :init_epp_contact
helper_method :address_processing?
helper_method :ident_types
def index
authorize! :view, Depp::Contact
@ -140,5 +141,9 @@ class Registrar
def address_processing?
Contact.address_processing?
end
def ident_types
Contact::Ident.types
end
end
end

View file

@ -11,6 +11,12 @@ module EppErrors
epp_errors << collect_child_errors(attr)
end
if self.class.reflect_on_aggregation(attr)
aggregation = send(attr)
epp_errors << collect_aggregation_errors(aggregation)
next
end
epp_errors << collect_parent_errors(attr, errors)
end
@ -46,6 +52,31 @@ module EppErrors
epp_errors
end
def collect_aggregation_errors(aggregation)
epp_errors = []
aggregation.errors.details.each do |attr, error_details|
error_details.each do |error_detail|
aggregation.class.epp_code_map.each do |epp_code, attr_to_error|
epp_code_found = attr_to_error.any? { |i| i == [attr, error_detail[:error]] }
if epp_code_found
message = aggregation.errors.generate_message(attr, error_detail[:error], error_detail)
message = aggregation.errors.full_message(attr, message)
if attr != :base
message = "#{aggregation.model_name.human} #{message.camelize(:lower)}"
end
epp_errors << { code: epp_code, msg: message }
end
end
end
end
epp_errors
end
def find_epp_code_and_value(msg)
epp_code_map.each do |code, values|
values.each do |x|

View file

@ -19,27 +19,22 @@ class Contact < ActiveRecord::Base
accepts_nested_attributes_for :legal_documents
validates :name, :email, :ident, :ident_type, presence: true
validates :name, :email, presence: true
validates :street, :city, :zip, :country_code, presence: true, if: 'self.class.address_processing?'
validates :phone, presence: true, e164: true, phone: true
validates :email, format: /@/
validates :email, email_format: { message: :invalid }, if: proc { |c| c.email_changed? }
validates :ident,
format: { with: /\d{4}-\d{2}-\d{2}/, message: :invalid_birthday_format },
if: proc { |c| c.ident_type == 'birthday' }
validates :ident_country_code, presence: true, if: proc { |c| %w(org priv).include? c.ident_type }, on: :create
validates :code,
uniqueness: { message: :epp_id_taken },
format: { with: /\A[\w\-\:\.\_]*\z/i, message: :invalid },
length: { maximum: 100, message: :too_long_contact_code }
validates_associated :identifier
validate :val_ident_type
validate :val_ident_valid_format?
validate :validate_html
validate :validate_country_code
validate :validate_ident_country_code
after_initialize do
self.status_notes = {} if status_notes.nil?
@ -49,8 +44,15 @@ class Contact < ActiveRecord::Base
before_validation :to_upcase_country_code
before_validation :strip_email
before_create :generate_auth_info
before_update :manage_emails
composed_of :identifier,
class_name: 'Contact::Ident',
constructor: Proc.new { |code, type, country_code| Contact::Ident.new(code: code,
type: type,
country_code: country_code) },
mapping: [%w[ident code], %w[ident_type type], %w[ident_country_code country_code]]
def manage_emails
return nil unless email_changed?
return nil unless deliver_emails == true
@ -76,12 +78,6 @@ class Contact < ActiveRecord::Base
BIRTHDAY = 'birthday'.freeze
PASSPORT = 'passport'
IDENT_TYPES = [
ORG, # Company registry code (or similar)
PRIV, # National idendtification number
BIRTHDAY # Birthday date
]
attr_accessor :deliver_emails
attr_accessor :domain_transfer # hack but solves problem faster
@ -299,28 +295,6 @@ class Contact < ActiveRecord::Base
name || '[no name]'
end
def val_ident_type
errors.add(:ident_type, :epp_ident_type_invalid, code: code) if !%w(org priv birthday).include?(ident_type)
end
def val_ident_valid_format?
case ident_country_code
when 'EE'.freeze
err_msg = "invalid_EE_identity_format#{"_update" if id}".to_sym
case ident_type
when 'priv'.freeze
errors.add(:ident, err_msg) unless Isikukood.new(ident).valid?
when 'org'.freeze
# !%w(1 7 8 9).freeze.include?(ident.first) ||
if ident.size != 8 || !(ident =~/\A[0-9]{8}\z/)
errors.add(:ident, err_msg)
end
when BIRTHDAY
errors.add(:ident, err_msg) if id.blank? # only for create action right now. Later for all of them
end
end
end
def validate_html
self.class.columns.each do |column|
next unless column.type == :string
@ -334,7 +308,6 @@ class Contact < ActiveRecord::Base
end
end
def org?
ident_type == ORG
end
@ -344,10 +317,6 @@ class Contact < ActiveRecord::Base
!org?
end
def birthday?
ident_type == BIRTHDAY
end
def generate_auth_info
return if @generate_auth_info_disabled
return if auth_info.present?
@ -424,10 +393,6 @@ class Contact < ActiveRecord::Base
errors.add(:country_code, :invalid) unless Country.new(country_code)
end
def validate_ident_country_code
errors.add(:ident, :invalid_country_code) unless Country.new(ident_country_code)
end
def related_domain_descriptions
ActiveSupport::Deprecation.warn('Use #domain_names_with_roles')

View file

@ -0,0 +1,72 @@
class Contact::Ident
include ActiveModel::Model
attr_accessor :code
attr_accessor :type
attr_accessor :country_code
validates :code, presence: true, code: true
validates :code, iso8601: { date_only: true }, if: :birthday?
validates :type, presence: true, inclusion: { in: Proc.new { types } }
validates :country_code, presence: true, iso31661_alpha2: true
validate :mismatched
def self.epp_code_map
{
'2003' => [
[:code, :blank],
[:type, :blank],
[:country_code, :blank],
],
'2005' => [
[:base, :mismatch],
[:code, :invalid_national_id],
[:code, :invalid_reg_no],
[:code, :invalid_iso8601],
[:country_code, :invalid_iso31661_alpha2],
],
}
end
def self.types
%w[org priv birthday]
end
Mismatch = Struct.new(:type, :country)
def self.mismatches
[
Mismatch.new('birthday', Country.new('EE')),
]
end
def marked_for_destruction?
false
end
def birthday?
type == 'birthday'
end
def national_id?
type == 'priv'
end
def reg_no?
type == 'org'
end
def country
Country.new(country_code)
end
private
# https://github.com/rails/rails/issues/1513
def validation_context=(value); end
def mismatched
mismatched = self.class.mismatches.include?(Mismatch.new(type, country))
errors.add(:base, :mismatch, type: type, country: country) if mismatched
end
end

View file

@ -109,7 +109,7 @@ class Epp::Contact < Contact
end
delegate :ident_attr_valid?, to: :class
def epp_code_map # rubocop:disable Metrics/MethodLength
def epp_code_map
{
'2003' => [ # Required parameter missing
[:name, :blank],
@ -124,27 +124,16 @@ class Epp::Contact < Contact
[:name, :invalid],
[:phone, :invalid],
[:email, :invalid],
[:ident, :invalid],
[:ident, :invalid_EE_identity_format],
[:ident, :invalid_EE_identity_format_update],
[:ident, :invalid_birthday_format],
[:ident, :invalid_country_code],
[:country_code, :invalid],
[:ident_type, :missing],
[:code, :invalid],
[:code, :too_long_contact_code]
],
'2302' => [ # Object exists
[:code, :epp_id_taken]
],
'2304' => [ # Object status prohibits operation
[:ident_type, :epp_ident_type_invalid, { value: { obj: 'code', val: code}, interpolation: {code: code}}]
],
'2305' => [ # Association exists
[:domains, :exist]
],
'2306' => [ # Parameter policy error
]
}
end
@ -164,36 +153,26 @@ class Epp::Contact < Contact
self.deliver_emails = true # turn on email delivery for epp
# Allow ident data update for legacy contacts
if frame.css('ident').first
self.ident_updated_at ||= Time.zone.now
ident_frame = frame.css('ident').first
if ident_frame && ident_attr_valid?(ident_frame)
org_priv = %w(org priv).freeze
if ident_frame.text == ident
if ident_type.present? && ident_country_code.present?
at.merge!(ident_type: ident_frame.attr('type'))
at.merge!(ident_country_code: ident_frame.attr('cc'))
elsif ident_country_code.blank? && org_priv.include?(ident_type) && org_priv.include?(ident_frame.attr('type'))
at.merge!(ident_country_code: ident_frame.attr('cc'), ident_type: ident_frame.attr('type'))
elsif ident_type == 'birthday' && !ident[/\A\d{4}-\d{2}-\d{2}\z/] && (Date.parse(ident) rescue false)
at.merge!(ident: ident_frame.text)
at.merge!(ident_country_code: ident_frame.attr('cc'))
elsif ident_type == 'birthday' && ident_country_code.blank?
at.merge!(ident_country_code: ident_frame.attr('cc'))
elsif ident_type.blank? && ident_country_code.blank?
at.merge!(ident_type: ident_frame.attr('type'))
at.merge!(ident_country_code: ident_frame.attr('cc'))
else
deny_ident_update
end
else
deny_ident_update
end
else
# https://github.com/internetee/registry/issues/576
if identifier.valid?
deny_ident_update
else
if ident_frame && ident_attr_valid?(ident_frame)
deny_ident_update if ident_frame.text != ident
identifier = Ident.new(code: ident,
type: ident_frame.attr('type'),
country_code: ident_frame.attr('cc'),
)
identifier.validate
self.identifier = identifier
self.ident_updated_at ||= Time.zone.now
end
end
end

View file

@ -0,0 +1,29 @@
class Contact::Ident::CodeValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
if record.country_code == 'EE'
if record.national_id?
record.errors.add(attribute,
:invalid_national_id,
country: record.country) unless valid_national_id_ee?(value)
end
if record.reg_no?
validator = ActiveModel::Validations::FormatValidator.new(with: reg_no_ee_format,
attributes: attribute,
message: :invalid_reg_no,
country: record.country)
validator.validate(record)
end
end
end
private
def reg_no_ee_format
/\A[0-9]{8}\z/
end
def valid_national_id_ee?(ident)
Isikukood.new(ident).valid?
end
end

View file

@ -19,7 +19,7 @@
.col-md-3
.form-group
= label_tag t(:ident_type)
= select_tag '[q][ident_type_eq]', options_for_select(Contact::IDENT_TYPES, params[:q][:ident_type_eq]), { include_blank: true, placeholder: t(:choose), class: 'form-control selectize' }
= select_tag '[q][ident_type_eq]', options_for_select(ident_types, params[:q][:ident_type_eq]), { include_blank: true, placeholder: t(:choose), class: 'form-control selectize' }
.row
.col-md-3
.form-group
@ -75,7 +75,7 @@
.row
.col-md-12
.table-responsive
%table.table.table-hover.table-bordered.table-condensed
%table.table.table-hover.table-bordered.table-condensed.contacts
%thead
%tr
%th{class: 'col-xs-2'}

View file

@ -21,7 +21,7 @@
.col-md-3
.form-group
= label_tag t(:ident_type)
= select_tag '[q][ident_type_eq]', options_for_select(Contact::IDENT_TYPES, params[:q][:ident_type_eq]), { include_blank: true, placeholder: t(:choose), class: 'form-control selectize' }
= select_tag '[q][ident_type_eq]', options_for_select(ident_types, params[:q][:ident_type_eq]), { include_blank: true, placeholder: t(:choose), class: 'form-control selectize' }
.row
.col-md-3
.form-group
@ -85,7 +85,7 @@
.row
.col-md-12
.table-responsive
%table.table.table-hover.table-bordered.table-condensed
%table.table.table-hover.table-bordered.table-condensed.contacts
%thead
%tr
%th{class: 'col-xs-2'}

View file

@ -20,15 +20,6 @@ en:
email:
blank: "Required parameter missing - email"
invalid: "Email is invalid"
ident:
blank: "Required parameter missing - ident"
invalid_EE_identity_format: "Ident not in valid Estonian identity format."
invalid_EE_identity_format_update: "Ident not in valid Estonian identity format. Please create new contact"
invalid_birthday_format: "Ident not in valid birthday format, should be YYYY-MM-DD"
invalid_country_code: "Ident country code is not valid, should be in ISO_3166-1 alpha 2 format"
ident_type:
ident_type_invalid: 'Ident type is invalid'
epp_ident_type_invalid: 'Object status prohibits operation: ident_type of contact %{code} is invalid'
domains:
exist: 'Object association prohibits operation'
statuses:

11
config/locales/idents.yml Normal file
View file

@ -0,0 +1,11 @@
en:
activemodel:
errors:
models:
contact/ident:
attributes:
base:
mismatch: Ident type "%{type}" is invalid for %{country}
code:
invalid_national_id: does not conform to national identification number format of %{country}
invalid_reg_no: does not conform to registration number format of %{country}

View file

@ -0,0 +1,12 @@
require 'rails_helper'
RSpec.feature 'Contact list', settings: false do
background do
sign_in_to_admin_area
end
it 'is visible' do
visit admin_contacts_path
expect(page).to have_css('.contacts')
end
end

View file

@ -0,0 +1,15 @@
require 'rails_helper'
RSpec.feature 'Contact list', settings: false do
given!(:registrar) { create(:registrar) }
given!(:contact) { create(:contact, registrar: registrar) }
background do
sign_in_to_registrar_area(user: create(:api_user_with_unlimited_balance, registrar: registrar))
end
it 'is visible' do
visit registrar_contacts_path
expect(page).to have_css('.contacts')
end
end

View file

@ -0,0 +1,217 @@
require 'active_model'
require 'lib/validators/iso31661_alpha2'
require 'lib/validators/iso8601'
RSpec.describe Contact::Ident, db: false do
let(:ident) { described_class.new }
describe 'country code' do
it_behaves_like 'iso31661_alpha2' do
let(:model) { ident }
let(:attribute) { :country_code }
end
end
describe 'code validation' do
it 'rejects absent' do
ident.code = nil
ident.validate
expect(ident.errors).to be_added(:code, :blank)
end
context 'when type is :birthday' do
let(:ident) { described_class.new(type: 'birthday') }
it_behaves_like 'iso8601' do
let(:model) { ident }
let(:attribute) { :code }
end
end
context 'when type is not :birthday' do
let(:ident) { described_class.new(type: 'priv') }
it 'accepts any' do
ident.code = '%123456789%'
ident.validate
expect(ident.errors).to_not include(:code)
end
end
context 'when country code is EE' do
context 'when type is :priv' do
let(:ident) { described_class.new(country_code: 'EE', type: 'priv') }
it 'rejects invalid' do
ident.code = 'invalid'
ident.validate
expect(ident.errors).to be_added(:code, :invalid_national_id, country: 'Estonia')
end
it 'accepts valid' do
ident.code = '47101010033'
ident.validate
expect(ident.errors).to_not be_added(:code, :invalid_national_id, country: 'Estonia')
end
end
context 'when ident type is :org' do
let(:ident) { described_class.new(country_code: 'EE', type: 'org') }
it 'rejects invalid' do
ident.code = '1' * 7
ident.validate
expect(ident.errors).to be_added(:code, :invalid_reg_no, country: 'Estonia')
end
it 'accepts valid length' do
ident.code = '1' * 8
ident.validate
expect(ident.errors).to_not be_added(:code, :invalid_reg_no, country: 'Estonia')
end
end
end
context 'when ident country code is not EE' do
let(:ident) { described_class.new(country_code: 'US') }
it 'accepts any' do
ident.code = 'test-123456789'
ident.validate
expect(ident.errors).to_not include(:code)
end
end
it 'translates :invalid_national_id error message' do
expect(ident.errors.generate_message(:code, :invalid_national_id, country: 'Germany'))
.to eq('does not conform to national identification number format of Germany')
end
it 'translates :invalid_reg_no error message' do
expect(ident.errors.generate_message(:code, :invalid_reg_no, country: 'Germany'))
.to eq('does not conform to registration number format of Germany')
end
end
describe 'type validation' do
before do
allow(described_class).to receive(:types).and_return(%w(valid))
end
it 'rejects absent' do
ident.type = nil
ident.validate
expect(ident.errors).to be_added(:type, :blank)
end
it 'rejects invalid' do
ident.type = 'invalid'
ident.validate
expect(ident.errors).to be_added(:type, :inclusion)
end
it 'accepts valid' do
ident.type = 'valid'
ident.validate
expect(ident.errors).to_not be_added(:type, :inclusion)
end
end
describe 'country code validation' do
it 'rejects absent' do
ident.country_code = nil
ident.validate
expect(ident.errors).to be_added(:country_code, :blank)
end
end
describe 'mismatch validation' do
let(:ident) { described_class.new(type: 'test', country_code: 'DE') }
before do
mismatches = [Contact::Ident::Mismatch.new('test', Country.new('DE'))]
allow(described_class).to receive(:mismatches).and_return(mismatches)
end
it 'rejects mismatched' do
ident.validate
expect(ident.errors).to be_added(:base, :mismatch, type: 'test', country: 'Germany')
end
it 'accepts matched' do
ident.validate
expect(ident.errors).to_not be_added(:base, :mismatch, type: 'another-test', country: 'Germany')
end
it 'translates :mismatch error message' do
expect(ident.errors.generate_message(:base, :mismatch, type: 'test', country: 'Germany'))
.to eq('Ident type "test" is invalid for Germany')
end
end
describe '::types' do
it 'returns types' do
types = %w[
org
priv
birthday
]
expect(described_class.types).to eq(types)
end
end
describe '::mismatches' do
it 'returns mismatches' do
mismatches = [
Contact::Ident::Mismatch.new('birthday', Country.new('EE')),
]
expect(described_class.mismatches).to eq(mismatches)
end
end
describe '#birthday?' do
context 'when type is birthday' do
subject(:ident) { described_class.new(type: 'birthday') }
it { is_expected.to be_birthday }
end
context 'when type is not birthday' do
subject(:ident) { described_class.new(type: 'priv') }
it { is_expected.to_not be_birthday }
end
end
describe '#national_id?' do
context 'when type is priv' do
subject(:ident) { described_class.new(type: 'priv') }
it { is_expected.to be_national_id }
end
context 'when type is not' do
subject(:ident) { described_class.new(type: 'org') }
it { is_expected.to_not be_national_id }
end
end
describe '#reg_no?' do
context 'when type is birthday' do
subject(:ident) { described_class.new(type: 'org') }
it { is_expected.to be_reg_no }
end
context 'when type is not birthday' do
subject(:ident) { described_class.new(type: 'priv') }
it { is_expected.to_not be_reg_no }
end
end
describe '#country' do
let(:ident) { described_class.new(country_code: 'US') }
it 'returns country' do
expect(ident.country).to eq(Country.new('US'))
end
end
end

View file

@ -28,45 +28,6 @@ RSpec.describe Contact do
@contact.updator.should == nil
end
it 'should require country code when org' do
@contact.ident_type = 'org'
@contact.valid?
@contact.errors[:ident_country_code].should == ['is missing']
end
it 'should require country code when priv' do
@contact.ident_type = 'priv'
@contact.valid?
@contact.errors[:ident_country_code].should == ['is missing']
end
it 'should validate correct country code' do
@contact.ident = 1
@contact.ident_type = 'org'
@contact.ident_country_code = 'EE'
@contact.valid?
@contact.errors[:ident_country_code].should == []
end
it 'should require valid country code' do
@contact.ident = '123'
@contact.ident_type = 'org'
@contact.ident_country_code = 'INVALID'
@contact.valid?
expect(@contact.errors).to have_key(:ident)
end
it 'should convert to alpha2 country code' do
@contact.ident = 1
@contact.ident_type = 'org'
@contact.ident_country_code = 'ee'
@contact.validate
@contact.ident_country_code.should == 'EE'
end
it 'should not have any versions' do
@contact.versions.should == []
end
@ -119,14 +80,6 @@ RSpec.describe Contact do
@contact.domains_present?.should == false
end
it 'org should be valid' do
contact = Fabricate.build(:contact, ident_type: 'org', ident: '1' * 8)
contact.validate
contact.errors.full_messages.should match_array([])
end
it 'should not overwrite code' do
old_code = @contact.code
@contact.code = 'CID:REG1:should-not-overwrite-old-code-12345'
@ -217,31 +170,6 @@ RSpec.describe Contact do
end
end
context 'as birthday' do
before :example do
@contact.ident_type = 'birthday'
end
it 'birthday should be valid' do
valid = ['2012-12-11', '1990-02-16']
valid.each do |date|
@contact.ident = date
@contact.valid?
@contact.errors.full_messages.should match_array([])
end
end
it 'birthday should be invalid' do
invalid = ['123' '12/12/2012', 'aaaa', '12/12/12', '02-11-1999']
invalid.each do |date|
@contact.ident = date
@contact.valid?
@contact.errors.full_messages.should ==
["Ident Ident not in valid birthday format, should be YYYY-MM-DD"]
end
end
end
context 'with callbacks' do
before :example do
# Ensure callbacks are not taken out from other specs
@ -445,7 +373,7 @@ RSpec.describe Contact do
end
end
describe 'country code validation' do
describe 'country code validation', db: false do
let(:contact) { described_class.new(country_code: 'test') }
it 'rejects invalid' do
@ -455,6 +383,28 @@ RSpec.describe Contact do
end
end
describe 'identifier validation', db: false do
let(:contact) { described_class.new }
it 'rejects invalid' do
ident = Contact::Ident.new
ident.validate
contact.identifier = ident
contact.validate
expect(contact.errors).to be_added(:identifier, :invalid)
end
it 'accepts valid' do
ident = Contact::Ident.new(code: 'test', type: 'priv', country_code: 'US')
ident.validate
contact.identifier = ident
contact.validate
expect(contact.errors).to_not be_added(:identifier, :invalid)
end
end
describe '#remove_address' do
let(:contact) { described_class.new(city: 'test',
street: 'test',
@ -561,4 +511,13 @@ RSpec.describe Contact do
expect(domain_names).to eq({ 'test.com' => %i[admin_domain_contact].to_set })
end
end
it 'normalizes ident country code', db: false do
contact = described_class.new
contact.ident_country_code = 'ee'
contact.validate
expect(contact.ident_country_code).to eq('EE')
end
end

View file

@ -0,0 +1,237 @@
require 'rails_helper'
RSpec.describe 'EPP contact:create' do
let(:request) { post '/epp/command/create', frame: request_xml }
before do
Setting.address_processing = false
sign_in_to_epp_area
end
context 'when all ident params are valid' do
let(:ident) { Contact.first.identifier }
let(: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>
<create>
<contact:create xmlns:contact="https://epp.tld.ee/schema/contact-ee-1.1.xsd">
<contact:postalInfo>
<contact:name>test</contact:name>
</contact:postalInfo>
<contact:voice>+1.2</contact:voice>
<contact:email>test@test.com</contact:email>
</contact:create>
</create>
<extension>
<eis:extdata xmlns:eis="https://epp.tld.ee/schema/eis-1.0.xsd">
<eis:ident type="priv" cc="US">test</eis:ident>
</eis:extdata>
</extension>
</command>
</epp>
XML
}
it 'creates a contact' do
expect { request }.to change { Contact.count }.from(0).to(1)
end
it 'saves ident type' do
request
expect(ident.type).to eq('priv')
end
it 'saves ident country code' do
request
expect(ident.country_code).to eq('US')
end
specify do
request
expect(epp_response).to have_result(:success)
end
end
context 'when code is blank' do
let(: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>
<create>
<contact:create xmlns:contact="https://epp.tld.ee/schema/contact-ee-1.1.xsd">
<contact:postalInfo>
<contact:name>test</contact:name>
</contact:postalInfo>
<contact:voice>+1.2</contact:voice>
<contact:email>test@test.com</contact:email>
</contact:create>
</create>
<extension>
<eis:extdata xmlns:eis="https://epp.tld.ee/schema/eis-1.0.xsd">
<eis:ident type="priv" cc="US"></eis:ident>
</eis:extdata>
</extension>
</command>
</epp>
XML
}
it 'does not create a contact' do
expect { request }.to_not change { Contact.count }
end
specify do
request
expect(epp_response).to have_result(:required_param_missing,
'Required parameter missing: extension > extdata > ident [ident]')
end
end
context 'when code is invalid' do
let(: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>
<create>
<contact:create xmlns:contact="https://epp.tld.ee/schema/contact-ee-1.1.xsd">
<contact:postalInfo>
<contact:name>test</contact:name>
</contact:postalInfo>
<contact:voice>+1.2</contact:voice>
<contact:email>test@test.com</contact:email>
</contact:create>
</create>
<extension>
<eis:extdata xmlns:eis="https://epp.tld.ee/schema/eis-1.0.xsd">
<eis:ident type="priv" cc="EE">invalid</eis:ident>
</eis:extdata>
</extension>
</command>
</epp>
XML
}
it 'does not create a contact' do
expect { request }.to_not change { Contact.count }
end
specify do
request
message = 'Ident code does not conform to national identification number format of Estonia'
expect(epp_response).to have_result(:param_syntax_error, message)
end
end
context 'when country code is absent' do
let(: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>
<create>
<contact:create xmlns:contact="https://epp.tld.ee/schema/contact-ee-1.1.xsd">
<contact:postalInfo>
<contact:name>test</contact:name>
</contact:postalInfo>
<contact:voice>+1.2</contact:voice>
<contact:email>test@test.com</contact:email>
</contact:create>
</create>
<extension>
<eis:extdata xmlns:eis="https://epp.tld.ee/schema/eis-1.0.xsd">
<eis:ident type="priv">test</eis:ident>
</eis:extdata>
</extension>
</command>
</epp>
XML
}
it 'does not create a contact' do
expect { request }.to_not change { Contact.count }
end
specify do
request
expect(epp_response).to have_result(:required_param_missing,
'Required ident attribute missing: cc')
end
end
context 'when country code is blank' do
let(: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>
<create>
<contact:create xmlns:contact="https://epp.tld.ee/schema/contact-ee-1.1.xsd">
<contact:postalInfo>
<contact:name>test</contact:name>
</contact:postalInfo>
<contact:voice>+1.2</contact:voice>
<contact:email>test@test.com</contact:email>
</contact:create>
</create>
<extension>
<eis:extdata xmlns:eis="https://epp.tld.ee/schema/eis-1.0.xsd">
<eis:ident type="priv" cc="">test</eis:ident>
</eis:extdata>
</extension>
</command>
</epp>
XML
}
it 'does not create a contact' do
expect { request }.to_not change { Contact.count }
end
specify do
request
expect(epp_response).to have_result(:syntax_error)
end
end
context 'when mismatches' do
let(: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>
<create>
<contact:create xmlns:contact="https://epp.tld.ee/schema/contact-ee-1.1.xsd">
<contact:postalInfo>
<contact:name>test</contact:name>
</contact:postalInfo>
<contact:voice>+1.2</contact:voice>
<contact:email>test@test.com</contact:email>
</contact:create>
</create>
<extension>
<eis:extdata xmlns:eis="https://epp.tld.ee/schema/eis-1.0.xsd">
<eis:ident type="priv" cc="DE">test</eis:ident>
</eis:extdata>
</extension>
</command>
</epp>
XML
}
before do
mismatches = [
Contact::Ident::Mismatch.new('priv', Country.new('DE')),
]
allow(Contact::Ident).to receive(:mismatches).and_return(mismatches)
end
it 'does not create a contact' do
expect { request }.to_not change { Contact.count }
end
specify do
request
expect(epp_response).to have_result(:param_syntax_error,
'Ident type "priv" is invalid for Germany')
end
end
end

View file

@ -1,6 +1,9 @@
require 'rails_helper'
# https://github.com/internetee/registry/issues/576
RSpec.describe 'EPP contact:update' do
let(:ident) { contact.identifier }
let(:request) { post '/epp/command/update', frame: request_xml }
let(:request_xml) { <<-XML
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
@ -18,7 +21,7 @@ RSpec.describe 'EPP contact:update' do
</update>
<extension>
<eis:extdata xmlns:eis="https://epp.tld.ee/schema/eis-1.0.xsd">
<eis:ident cc="GB" type="priv">test</eis:ident>
<eis:ident cc="US" type="priv">test</eis:ident>
</eis:extdata>
</extension>
</command>
@ -30,45 +33,128 @@ RSpec.describe 'EPP contact:update' do
sign_in_to_epp_area
end
context 'when submitted ident matches current one' do
let!(:contact) { create(:contact, code: 'TEST', ident: 'test', ident_type: 'org', ident_country_code: 'US') }
context 'when contact ident is valid' do
let!(:contact) { create(:contact, code: 'TEST', ident: 'test', ident_type: 'priv', ident_country_code: 'US') }
it 'updates :ident_type' do
request
contact.reload
expect(contact.ident_type).to eq('priv')
it 'does not update code' do
expect { request; contact.reload }.to_not change { ident.code }
end
it 'updates :ident_country_code' do
request
contact.reload
expect(contact.ident_country_code).to eq('GB')
it 'does not update type' do
expect { request; contact.reload }.to_not change { ident.type }
end
it 'does not update country code' do
expect { request; contact.reload }.to_not change { ident.country_code }
end
specify do
request
expect(response).to have_code_of(1000)
message = 'Data management policy violation:' \
' update of ident not allowed, please consider creating new contact object'
expect(epp_response).to have_result(:data_management_policy_violation, message)
end
end
context 'when submitted ident does not match current one' do
let!(:contact) { create(:contact, code: 'TEST', ident: 'some-ident', ident_type: 'org', ident_country_code: 'US') }
context 'when contact ident is invalid' do
let(:contact) { build(:contact, code: 'TEST', ident: 'test', ident_type: nil, ident_country_code: nil) }
it 'does not update :ident_type' do
request
contact.reload
expect(contact.ident_type).to eq('org')
before do
contact.save(validate: false)
end
it 'does not update :ident_country_code' do
request
contact.reload
expect(contact.ident_country_code).to eq('US')
context 'when submitted ident is the same as current one' do
let(:request_xml) { <<-XML
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<epp xmlns="https://epp.tld.ee/schema/epp-ee-1.0.xsd">
<command>
<update>
<contact:update xmlns:contact="https://epp.tld.ee/schema/contact-ee-1.1.xsd">
<contact:id>TEST</contact:id>
<contact:chg>
<contact:postalInfo>
<contact:name>test</contact:name>
</contact:postalInfo>
</contact:chg>
</contact:update>
</update>
<extension>
<eis:extdata xmlns:eis="https://epp.tld.ee/schema/eis-1.0.xsd">
<eis:ident cc="US" type="priv">test</eis:ident>
</eis:extdata>
</extension>
</command>
</epp>
XML
}
it 'does not update code' do
expect { request; contact.reload }.to_not change { ident.code }
end
it 'updates type' do
request
contact.reload
expect(ident.type).to eq('priv')
end
it 'updates country code' do
request
contact.reload
expect(ident.country_code).to eq('US')
end
specify do
request
expect(epp_response).to have_result(:success)
end
end
specify do
request
expect(response).to have_code_of(2308)
context 'when submitted ident is different from current one' do
let(:request_xml) { <<-XML
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<epp xmlns="https://epp.tld.ee/schema/epp-ee-1.0.xsd">
<command>
<update>
<contact:update xmlns:contact="https://epp.tld.ee/schema/contact-ee-1.1.xsd">
<contact:id>TEST</contact:id>
<contact:chg>
<contact:postalInfo>
<contact:name>test</contact:name>
</contact:postalInfo>
</contact:chg>
</contact:update>
</update>
<extension>
<eis:extdata xmlns:eis="https://epp.tld.ee/schema/eis-1.0.xsd">
<eis:ident cc="US" type="priv">another-test</eis:ident>
</eis:extdata>
</extension>
</command>
</epp>
XML
}
it 'does not update code' do
expect { request; contact.reload }.to_not change { ident.code }
end
it 'does not update type' do
expect { request; contact.reload }.to_not change { ident.type }
end
it 'does not update country code' do
expect { request; contact.reload }.to_not change { ident.country_code }
end
specify do
request
message = 'Data management policy violation:' \
' update of ident not allowed, please consider creating new contact object'
expect(epp_response).to have_result(:data_management_policy_violation, message)
end
end
end
end