Added custom contact id support

This commit is contained in:
Priit Tark 2015-03-03 16:30:31 +02:00
parent aa5cc83344
commit 767f7bb6df
13 changed files with 195 additions and 42 deletions

View file

@ -3,11 +3,11 @@ group :red_green_refactor, halt_on_fail: true do
# be sure you have apache2 configured to
# accept EPP request on port 701, what proxy to 8989.
# port and environment is just for correct notification, all is overwritten by CLI
guard :rails, port: 8989, environment: 'test' do
# guard :rails, port: 8989, environment: 'test', CLI: 'RAILS_ENV=test unicorn -p 8989' do
watch('Gemfile.lock')
watch(%r{^(config|lib)/.*})
end
# guard :rails, port: 8989, environment: 'test' do
# # guard :rails, port: 8989, environment: 'test', CLI: 'RAILS_ENV=test unicorn -p 8989' do
# watch('Gemfile.lock')
# watch(%r{^(config|lib)/.*})
# end
guard :rspec, cmd: 'spring rspec', notification: false do
watch(%r{^spec/.+_spec\.rb$})

View file

@ -17,9 +17,7 @@ class Epp::ContactsController < EppController
def create
authorize! :create, Epp::Contact
@contact = Epp::Contact.new(params[:parsed_frame])
@contact.registrar = current_user.registrar
@contact = Epp::Contact.new(params[:parsed_frame], current_user.registrar)
if @contact.save
render_epp_response '/epp/contacts/create'

View file

@ -22,7 +22,11 @@ class Contact < ActiveRecord::Base
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(bic priv).include? c.ident_type }
validates :code, uniqueness: { message: :epp_id_taken }
validates :code,
uniqueness: { message: :epp_id_taken },
format: { with: /\A[\w\-\:]*\Z/i },
length: { maximum: 100 }
validate :ident_valid_format?
delegate :street, to: :address
@ -99,15 +103,27 @@ class Contact < ActiveRecord::Base
ident_type != IDENT_TYPE_BIC
end
# generate random id for contact
def generate_code
self.code = SecureRandom.hex(4)
self.code = SecureRandom.hex(4) if code.blank?
end
def generate_auth_info
return if @generate_auth_info_disabled
self.auth_info = SecureRandom.hex(16)
end
def disable_generate_auth_info! # needed for testing
@generate_auth_info_disabled = true
end
def auth_info=(pw)
self[:auth_info] = pw if new_record?
end
def code=(code)
self[:code] = code if new_record?
end
# Find a way to use self.domains with contact
def domains_owned
Domain.where(owner_contact_id: id)

View file

@ -45,9 +45,22 @@ class Epp::Contact < Contact
# rubocop: enable Metrics/PerceivedComplexity
# rubocop: enable Metrics/CyclomaticComplexity
def new(frame)
def new(frame, registrar)
return super if frame.blank?
super(attrs_from(frame))
custom_code =
if frame.css('id').present?
"#{registrar.code}:#{frame.css('id').text.parameterize}"
else
nil
end
super(
attrs_from(frame).merge(
code: custom_code,
registrar: registrar
)
)
end
def legal_document_attrs(legal_frame)

View file

@ -9,10 +9,18 @@ class Registrar < ActiveRecord::Base
validates :name, :reg_no, :country_code, :email, presence: true
validates :name, :reg_no, uniqueness: true
validate :set_code, if: :new_record?
after_save :touch_domains_version
validates :email, :billing_email, format: /@/, allow_blank: true
class << self
def search_by_query(query)
res = search(name_or_reg_no_cont: query).result
res.reduce([]) { |o, v| o << { id: v[:id], display_key: "#{v[:name]} (#{v[:reg_no]})" } }
end
end
def domain_transfers
at = DomainTransfer.arel_table
DomainTransfer.where(
@ -34,10 +42,23 @@ class Registrar < ActiveRecord::Base
Country.new(country_code)
end
class << self
def search_by_query(query)
res = search(name_or_reg_no_cont: query).result
res.reduce([]) { |o, v| o << { id: v[:id], display_key: "#{v[:name]} (#{v[:reg_no]})" } }
def code=(code)
self[:code] = code if new_record?
end
private
def set_code
return false if name.blank?
new_code = name.parameterize
# ensure code is always uniq automatically for a new record
seq = 1
while self.class.find_by_code(new_code)
new_code += seq.to_s
seq += 1
end
self.code = new_code
end
end

View file

@ -0,0 +1,6 @@
class AddCodeToRegistrar < ActiveRecord::Migration
def change
add_column :registrars, :code, :string
add_index :registrars, :code
end
end

View file

@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20150227113121) do
ActiveRecord::Schema.define(version: 20150303130729) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@ -611,8 +611,11 @@ ActiveRecord::Schema.define(version: 20150227113121) do
t.string "city"
t.string "street"
t.string "zip"
t.string "code"
end
add_index "registrars", ["code"], name: "index_registrars_on_code", using: :btree
create_table "reserved_domains", force: :cascade do |t|
t.string "name"
t.datetime "created_at"

View file

@ -13,6 +13,7 @@ Contact Mapping protocol short version:
----------------------- ------- -----------------
<create> 1
<contact:create> 1 Attribute: xmlns:contact="urn:ietf:params:xml:ns:contact-1.0"
<contact:id> 0-1 Contact id, optional, generated automatically if missing
<contact:postalInfo> 1 Postal information container
<contact:name> 1 Full name of the contact
<contact:org> 0-1 Name of organization
@ -42,7 +43,7 @@ Contact Mapping protocol short version:
----------------------- ------- -----------------
<update> 1
<contact:update> 1 Attribute: xmlns:contact="urn:ietf:params:xml:ns:contact-1.0"
<contact:id> 1 contact id, required
<contact:id> 1 Contact id, required
<contact:chg> 1 Change container
<contact:postalInfo> 1 Postal information container
<contact:name> 0-1 Full name of the contact

View file

@ -13,10 +13,8 @@ describe 'EPP Contact', epp: true do
login_as :registrar1
Contact.skip_callback(:create, :before, :generate_code)
Contact.skip_callback(:create, :before, :generate_auth_info)
@contact = Fabricate(:contact, registrar: @registrar1)
@legal_document = {
legalDocument: {
value: 'JVBERi0xLjQKJcOkw7zDtsOfCjIgMCBvYmoKPDwvTGVuZ3RoIDMgMCBSL0Zp==',
@ -25,11 +23,6 @@ describe 'EPP Contact', epp: true do
}
end
after :all do
Contact.set_callback(:create, :before, :generate_code)
Contact.set_callback(:create, :before, :generate_auth_info)
end
context 'with valid user' do
context 'create command' do
def create_request(overwrites = {})
@ -133,6 +126,17 @@ describe 'EPP Contact', epp: true do
# 5 seconds for what-ever weird lag reasons might happen
cr_date.text.to_time.should be_within(5).of(Time.now)
end
it 'successfully saves custom code' do
response = create_request(
{ id: { value: '12345' } }
)
response[:msg].should == 'Command completed successfully'
response[:result_code].should == '1000'
Contact.last.code.should == 'registrar1:12345'
end
end
context 'update command' do
@ -140,11 +144,9 @@ describe 'EPP Contact', epp: true do
@contact =
Fabricate(
:contact,
# created_by_id: 1,
registrar: @registrar1,
email: 'not_updated@test.test',
code: 'sh8013',
auth_info: 'password'
code: 'sh8013'
)
end
@ -226,6 +228,20 @@ describe 'EPP Contact', epp: true do
response[:results][1][:msg].should == 'Email is invalid'
response[:results][1][:result_code].should == '2005'
end
it 'should not update code with custom string' do
response = update_request(
id: { value: 'sh8013' },
chg: {
id: { value: 'notpossibletoupdate' }
}
)
response[:msg].should == 'Object does not exist'
response[:result_code].should == '2303'
@contact.reload.code.should == 'sh8013'
end
end
context 'delete command' do

View file

@ -11,8 +11,6 @@ describe 'EPP Domain', epp: true do
login_as :registrar1
Contact.skip_callback(:create, :before, :generate_code)
Fabricate(:contact, code: 'citizen_1234')
Fabricate(:contact, code: 'sh8013')
Fabricate(:contact, code: 'sh801333')
@ -254,8 +252,8 @@ describe 'EPP Domain', epp: true do
})
response = epp_plain_request(xml, :xml)
response[:result_code].should == '2005'
response[:msg].should == 'Hostname is invalid'
response[:result_code].should == '2005'
end
it 'checks hostAttr presence' do
@ -271,8 +269,8 @@ describe 'EPP Domain', epp: true do
})
response = epp_plain_request(xml, :xml)
response[:result_code].should == '2003'
response[:msg].should == 'Required parameter missing: create > create > ns > hostAttr'
response[:result_code].should == '2003'
end
it 'creates domain with nameservers with ips' do

View file

@ -1,13 +1,16 @@
Fabricator(:contact) do
code { "sh#{Faker::Number.number(8)}" }
auth_info 'password'
name { sequence(:name) { |i| "#{Faker::Name.name}#{i}" } }
phone '+372.12345678'
email Faker::Internet.email
ident '37605030299'
ident_type 'priv'
ident_country_code 'EE'
auth_info 'ccds4324pok'
address
registrar { Fabricate(:registrar, name: Faker::Company.name, reg_no: Faker::Company.duns_number) }
disclosure { Fabricate(:contact_disclosure) }
# rubocop: disable Style/SymbolProc
after_validation { |c| c.disable_generate_auth_info! }
# rubocop: enamble Style/SymbolProc
end

View file

@ -91,6 +91,12 @@ describe Contact do
it 'should not have any versions' do
@contact.versions.should == []
end
it 'should not accept long code' do
@contact.code = 'verylongcode' * 100
@contact.valid?
@contact.errors[:code].should == ['is too long (maximum is 100 characters)']
end
end
context 'with valid attributes' do
@ -130,6 +136,17 @@ describe Contact do
@contact.errors.full_messages.should match_array([])
end
it 'should not accept new custom code' do
old_code = @contact.code
@contact.code = 'CID:REG1:12345'
@contact.save.should == true
@contact.code.should == old_code
end
it 'should have static password' do
@contact.auth_info.should == 'password'
end
context 'as birthday' do
before :all do
@contact.ident_type = 'birthday'
@ -182,20 +199,56 @@ describe Contact do
end
context 'after create' do
it 'should generate a new code and password' do
it 'should not generate a new code when code is present' do
@contact = Fabricate.build(:contact, code: '123asd', auth_info: 'qwe321')
@contact.code.should == '123asd'
@contact.save.should == true
@contact.code.should == '123asd'
end
it 'should generate a new password' do
@contact = Fabricate.build(:contact, code: '123asd', auth_info: 'qwe321')
@contact.code.should == '123asd'
@contact.auth_info.should == 'qwe321'
@contact.save!
@contact.code.should_not == '123asd'
@contact.save.should == true
@contact.auth_info.should_not == 'qwe321'
end
it 'should not allow same code' do
@double_contact = Fabricate.build(:contact, code: @contact.code)
@double_contact.valid?
@double_contact.errors.full_messages.should == ["Code Contact id already exists"]
end
it 'should allow supported code format' do
@contact = Fabricate.build(:contact, code: 'CID:REG1:12345')
@contact.valid?
@contact.errors.full_messages.should == []
end
it 'should not allow unsupported characters in code' do
@contact = Fabricate.build(:contact, code: 'unsupported!ÄÖÜ~?')
@contact.valid?
@contact.errors.full_messages.should == ['Code is invalid']
end
it 'should generate code if empty code is given' do
@contact = Fabricate(:contact, code: '')
@contact.code.should_not == ''
end
it 'should not allow empty spaces as code' do
@contact = Fabricate.build(:contact, code: ' ')
@contact.valid?
@contact.errors.full_messages.should == ['Code is invalid']
end
end
context 'after update' do
before :all do
@contact.code = '123asd'
@contact.auth_info = 'qwe321'
@contact = Fabricate.build(:contact, code: '123asd', auth_info: 'qwe321')
@contact.save
@contact.code.should == '123asd'
@auth_info = @contact.auth_info
end
it 'should not generate new code' do
@ -205,7 +258,7 @@ describe Contact do
it 'should not generate new auth_info' do
@contact.update_attributes(name: 'fvrsgbqevciherot23')
@contact.auth_info.should == 'qwe321'
@contact.auth_info.should == @auth_info
end
end
end

View file

@ -28,6 +28,10 @@ describe Registrar do
@registrar.errors[:email].should == ['is invalid']
@registrar.errors[:billing_email].should == ['is invalid']
end
it 'should not have valid code' do
@registrar.code.should == nil
end
end
context 'with valid attributes' do
@ -59,5 +63,26 @@ describe Registrar do
it 'should return full address' do
@registrar.address.should == 'Street 999, Town, County, Postal'
end
it 'should have code' do
@registrar.code.should =~ /registrar/
end
it 'should not be able to change code' do
@registrar.code = 'not-updated'
@registrar.code.should =~ /registrar/
end
it 'should automatically add next code if original is taken' do
@registrar = Fabricate(:registrar, name: 'uniq')
@registrar.name = 'New name'
@registrar.code.should == 'uniq'
@registrar.save
@new_registrar = Fabricate.build(:registrar, name: 'uniq')
@new_registrar.valid?
@new_registrar.errors.full_messages.should == []
@new_registrar.code.should == 'uniq1'
end
end
end