mirror of
https://github.com/internetee/registry.git
synced 2025-07-28 13:36:15 +02:00
Make admin contacts optional for private registrants
This change makes admin contacts optional for private registrants while keeping them mandatory for organizations. The changes include: - Updated Domain model validations to make admin and tech contacts optional (min=0) for private registrants - Added validation rules methods to handle different requirements based on registrant type - Modified EPP domain creation to support domains without admin contacts for private registrants - Updated attach_default_contacts to skip adding contacts for private registrants - Added comprehensive test coverage for: - Domain model validations with private/org registrants - EPP domain creation without admin contacts for private registrants - REPP API contact management for private registrants This implements the requirement to make admin contacts optional for private registrations of .ee domains while maintaining the existing validation rules for organizations.
This commit is contained in:
parent
bfe2a10889
commit
3c169bb00b
5 changed files with 173 additions and 8 deletions
|
@ -164,15 +164,35 @@ class Domain < ApplicationRecord
|
||||||
max: -> { Setting.dnskeys_max_count },
|
max: -> { Setting.dnskeys_max_count },
|
||||||
}
|
}
|
||||||
|
|
||||||
validates :admin_domain_contacts, object_count: {
|
def self.admin_contacts_validation_rules(for_org:)
|
||||||
min: -> { Setting.admin_contacts_min_count },
|
{
|
||||||
max: -> { Setting.admin_contacts_max_count },
|
min: -> { for_org ? Setting.admin_contacts_min_count : 0 },
|
||||||
}
|
max: -> { Setting.admin_contacts_max_count }
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
validates :tech_domain_contacts, object_count: {
|
def self.tech_contacts_validation_rules(for_org:)
|
||||||
min: -> { Setting.tech_contacts_min_count },
|
{
|
||||||
max: -> { Setting.tech_contacts_max_count },
|
min: -> { for_org ? Setting.tech_contacts_min_count : 0 },
|
||||||
}
|
max: -> { Setting.tech_contacts_max_count }
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
validates :admin_domain_contacts,
|
||||||
|
object_count: admin_contacts_validation_rules(for_org: true),
|
||||||
|
if: :require_admin_contacts?
|
||||||
|
|
||||||
|
validates :admin_domain_contacts,
|
||||||
|
object_count: admin_contacts_validation_rules(for_org: false),
|
||||||
|
unless: :require_admin_contacts?
|
||||||
|
|
||||||
|
validates :tech_domain_contacts,
|
||||||
|
object_count: tech_contacts_validation_rules(for_org: true),
|
||||||
|
if: :require_tech_contacts?
|
||||||
|
|
||||||
|
validates :tech_domain_contacts,
|
||||||
|
object_count: tech_contacts_validation_rules(for_org: false),
|
||||||
|
unless: :require_tech_contacts?
|
||||||
|
|
||||||
validates :nameservers, uniqueness_multi: {
|
validates :nameservers, uniqueness_multi: {
|
||||||
attribute: 'hostname',
|
attribute: 'hostname',
|
||||||
|
@ -835,4 +855,12 @@ class Domain < ApplicationRecord
|
||||||
end
|
end
|
||||||
array
|
array
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def require_admin_contacts?
|
||||||
|
registrant.present? && registrant.org?
|
||||||
|
end
|
||||||
|
|
||||||
|
def require_tech_contacts?
|
||||||
|
registrant.present? && registrant.org?
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -114,7 +114,9 @@ class Epp::Domain < Domain
|
||||||
|
|
||||||
def attach_default_contacts
|
def attach_default_contacts
|
||||||
return if registrant.blank?
|
return if registrant.blank?
|
||||||
|
|
||||||
registrant_obj = Contact.find_by(code: registrant.code)
|
registrant_obj = Contact.find_by(code: registrant.code)
|
||||||
|
return if registrant_obj.priv?
|
||||||
|
|
||||||
tech_contacts << registrant_obj if tech_domain_contacts.blank?
|
tech_contacts << registrant_obj if tech_domain_contacts.blank?
|
||||||
admin_contacts << registrant_obj if admin_domain_contacts.blank? && !registrant.org?
|
admin_contacts << registrant_obj if admin_domain_contacts.blank? && !registrant.org?
|
||||||
|
|
|
@ -436,6 +436,9 @@ class EppDomainCreateBaseTest < EppTestCase
|
||||||
contact = contacts(:john)
|
contact = contacts(:john)
|
||||||
registrant = contact.becomes(Registrant)
|
registrant = contact.becomes(Registrant)
|
||||||
|
|
||||||
|
registrant.update!(ident_type: 'org')
|
||||||
|
registrant.reload
|
||||||
|
|
||||||
request_xml = <<-XML
|
request_xml = <<-XML
|
||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
<epp xmlns="#{Xsd::Schema.filename(for_prefix: 'epp-ee', for_version: '1.0')}">
|
<epp xmlns="#{Xsd::Schema.filename(for_prefix: 'epp-ee', for_version: '1.0')}">
|
||||||
|
@ -444,6 +447,7 @@ class EppDomainCreateBaseTest < EppTestCase
|
||||||
<domain:create xmlns:domain="#{Xsd::Schema.filename(for_prefix: 'domain-ee', for_version: '1.2')}">
|
<domain:create xmlns:domain="#{Xsd::Schema.filename(for_prefix: 'domain-ee', for_version: '1.2')}">
|
||||||
<domain:name>#{name}</domain:name>
|
<domain:name>#{name}</domain:name>
|
||||||
<domain:registrant>#{registrant.code}</domain:registrant>
|
<domain:registrant>#{registrant.code}</domain:registrant>
|
||||||
|
<domain:contact type="admin">#{contact.code}</domain:contact>
|
||||||
</domain:create>
|
</domain:create>
|
||||||
</create>
|
</create>
|
||||||
<extension>
|
<extension>
|
||||||
|
@ -937,4 +941,54 @@ class EppDomainCreateBaseTest < EppTestCase
|
||||||
ENV["shunter_default_threshold"] = '10000'
|
ENV["shunter_default_threshold"] = '10000'
|
||||||
ENV["shunter_enabled"] = 'false'
|
ENV["shunter_enabled"] = 'false'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_registers_new_domain_with_private_registrant_without_admin_contacts
|
||||||
|
now = Time.zone.parse('2010-07-05')
|
||||||
|
travel_to now
|
||||||
|
name = "new.#{dns_zones(:one).origin}"
|
||||||
|
contact = contacts(:john)
|
||||||
|
registrant = contact.becomes(Registrant)
|
||||||
|
|
||||||
|
registrant.update!(ident_type: 'priv')
|
||||||
|
registrant.reload
|
||||||
|
assert_not registrant.org?
|
||||||
|
|
||||||
|
request_xml = <<-XML
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<epp xmlns="#{Xsd::Schema.filename(for_prefix: 'epp-ee', for_version: '1.0')}">
|
||||||
|
<command>
|
||||||
|
<create>
|
||||||
|
<domain:create xmlns:domain="#{Xsd::Schema.filename(for_prefix: 'domain-ee', for_version: '1.2')}">
|
||||||
|
<domain:name>#{name}</domain:name>
|
||||||
|
<domain:registrant>#{registrant.code}</domain:registrant>
|
||||||
|
</domain:create>
|
||||||
|
</create>
|
||||||
|
<extension>
|
||||||
|
<eis:extdata xmlns:eis="#{Xsd::Schema.filename(for_prefix: 'eis', for_version: '1.0')}">
|
||||||
|
<eis:legalDocument type="pdf">#{'test' * 2000}</eis:legalDocument>
|
||||||
|
</eis:extdata>
|
||||||
|
</extension>
|
||||||
|
</command>
|
||||||
|
</epp>
|
||||||
|
XML
|
||||||
|
|
||||||
|
assert_difference 'Domain.count' do
|
||||||
|
post epp_create_path, params: { frame: request_xml },
|
||||||
|
headers: { 'HTTP_COOKIE' => 'session=api_bestnames' }
|
||||||
|
end
|
||||||
|
response_xml = Nokogiri::XML(response.body)
|
||||||
|
assert_correct_against_schema response_xml
|
||||||
|
|
||||||
|
assert_epp_response :completed_successfully
|
||||||
|
|
||||||
|
domain = Domain.find_by(name: name)
|
||||||
|
assert_equal name, domain.name
|
||||||
|
assert_equal registrant, domain.registrant
|
||||||
|
assert_empty domain.admin_contacts
|
||||||
|
assert_empty domain.tech_contacts
|
||||||
|
assert_not_empty domain.transfer_code
|
||||||
|
|
||||||
|
default_registration_period = 1.year + 1.day
|
||||||
|
assert_equal now + default_registration_period, domain.expire_time
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -108,9 +108,32 @@ class ReppV1DomainsContactsTest < ActionDispatch::IntegrationTest
|
||||||
refute @domain.tech_contacts.find_by(code: contact.code).present?
|
refute @domain.tech_contacts.find_by(code: contact.code).present?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_can_remove_all_admin_contacts_for_private_registrant
|
||||||
|
Spy.on_instance_method(Actions::DomainUpdate, :validate_email).and_return(true)
|
||||||
|
|
||||||
|
@domain.registrant.update!(ident_type: 'priv')
|
||||||
|
@domain.reload
|
||||||
|
assert_not @domain.registrant.org?
|
||||||
|
|
||||||
|
contact = @domain.admin_contacts.last
|
||||||
|
|
||||||
|
payload = { contacts: [ { code: contact.code, type: 'admin' } ] }
|
||||||
|
delete "/repp/v1/domains/#{@domain.name}/contacts", headers: @auth_headers, params: payload
|
||||||
|
json = JSON.parse(response.body, symbolize_names: true)
|
||||||
|
|
||||||
|
@domain.reload
|
||||||
|
assert_response :ok
|
||||||
|
assert_equal 1000, json[:code]
|
||||||
|
|
||||||
|
assert_empty @domain.admin_contacts
|
||||||
|
end
|
||||||
|
|
||||||
def test_can_not_remove_one_and_only_contact
|
def test_can_not_remove_one_and_only_contact
|
||||||
Spy.on_instance_method(Actions::DomainUpdate, :validate_email).and_return(true)
|
Spy.on_instance_method(Actions::DomainUpdate, :validate_email).and_return(true)
|
||||||
|
|
||||||
|
@domain.registrant.update!(ident_type: 'org')
|
||||||
|
@domain.reload
|
||||||
|
|
||||||
contact = @domain.admin_contacts.last
|
contact = @domain.admin_contacts.last
|
||||||
|
|
||||||
payload = { contacts: [ { code: contact.code, type: 'admin' } ] }
|
payload = { contacts: [ { code: contact.code, type: 'admin' } ] }
|
||||||
|
|
|
@ -221,6 +221,10 @@ class DomainTest < ActiveSupport::TestCase
|
||||||
assert domain.valid?, proc { domain.errors.full_messages }
|
assert domain.valid?, proc { domain.errors.full_messages }
|
||||||
|
|
||||||
domain.admin_domain_contacts.clear
|
domain.admin_domain_contacts.clear
|
||||||
|
|
||||||
|
domain.registrant.update!(ident_type: 'org')
|
||||||
|
domain.reload
|
||||||
|
assert domain.registrant.org?
|
||||||
assert domain.invalid?
|
assert domain.invalid?
|
||||||
|
|
||||||
domain.admin_domain_contacts.clear
|
domain.admin_domain_contacts.clear
|
||||||
|
@ -236,6 +240,10 @@ class DomainTest < ActiveSupport::TestCase
|
||||||
Setting.tech_contacts_min_count = min_count
|
Setting.tech_contacts_min_count = min_count
|
||||||
Setting.tech_contacts_max_count = max_count
|
Setting.tech_contacts_max_count = max_count
|
||||||
|
|
||||||
|
domain.registrant.update!(ident_type: 'org')
|
||||||
|
domain.reload
|
||||||
|
assert domain.registrant.org?
|
||||||
|
|
||||||
domain.tech_domain_contacts.clear
|
domain.tech_domain_contacts.clear
|
||||||
min_count.times { domain.tech_domain_contacts.build(domain_contact_attributes) }
|
min_count.times { domain.tech_domain_contacts.build(domain_contact_attributes) }
|
||||||
assert domain.valid?, proc { domain.errors.full_messages }
|
assert domain.valid?, proc { domain.errors.full_messages }
|
||||||
|
@ -475,6 +483,56 @@ class DomainTest < ActiveSupport::TestCase
|
||||||
assert_not @domain.renewable?
|
assert_not @domain.renewable?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_validates_admin_contact_count_for_private_registrant
|
||||||
|
domain_contact_attributes = domain_contacts(:shop_jane).dup.attributes
|
||||||
|
domain = valid_domain
|
||||||
|
max_count = 2
|
||||||
|
Setting.admin_contacts_max_count = max_count
|
||||||
|
|
||||||
|
domain.registrant.update!(ident_type: 'priv')
|
||||||
|
domain.reload
|
||||||
|
assert_not domain.registrant.org?
|
||||||
|
|
||||||
|
# Valid without any admin contacts
|
||||||
|
domain.admin_domain_contacts.clear
|
||||||
|
assert domain.valid?, proc { domain.errors.full_messages }
|
||||||
|
|
||||||
|
# Valid with some admin contacts
|
||||||
|
domain.admin_domain_contacts.clear
|
||||||
|
max_count.pred.times { domain.admin_domain_contacts.build(domain_contact_attributes) }
|
||||||
|
assert domain.valid?, proc { domain.errors.full_messages }
|
||||||
|
|
||||||
|
# Invalid when exceeding max contacts
|
||||||
|
domain.admin_domain_contacts.clear
|
||||||
|
max_count.next.times { domain.admin_domain_contacts.build(domain_contact_attributes) }
|
||||||
|
assert domain.invalid?
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_validates_tech_contact_count_for_private_registrant
|
||||||
|
domain_contact_attributes = domain_contacts(:shop_william).dup.attributes
|
||||||
|
domain = valid_domain
|
||||||
|
max_count = 2
|
||||||
|
Setting.tech_contacts_max_count = max_count
|
||||||
|
|
||||||
|
domain.registrant.update!(ident_type: 'priv')
|
||||||
|
domain.reload
|
||||||
|
assert_not domain.registrant.org?
|
||||||
|
|
||||||
|
# Valid without any tech contacts
|
||||||
|
domain.tech_domain_contacts.clear
|
||||||
|
assert domain.valid?, proc { domain.errors.full_messages }
|
||||||
|
|
||||||
|
# Valid with some tech contacts
|
||||||
|
domain.tech_domain_contacts.clear
|
||||||
|
max_count.pred.times { domain.tech_domain_contacts.build(domain_contact_attributes) }
|
||||||
|
assert domain.valid?, proc { domain.errors.full_messages }
|
||||||
|
|
||||||
|
# Invalid when exceeding max contacts
|
||||||
|
domain.tech_domain_contacts.clear
|
||||||
|
max_count.next.times { domain.tech_domain_contacts.build(domain_contact_attributes) }
|
||||||
|
assert domain.invalid?
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def valid_domain
|
def valid_domain
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue