Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make admin contacts optional for private registrants #2730

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 36 additions & 8 deletions app/models/domain.rb
Original file line number Diff line number Diff line change
Expand Up @@ -164,15 +164,35 @@ def status_is_consistant
max: -> { Setting.dnskeys_max_count },
}

validates :admin_domain_contacts, object_count: {
min: -> { Setting.admin_contacts_min_count },
max: -> { Setting.admin_contacts_max_count },
}
def self.admin_contacts_validation_rules(for_org:)
{
min: -> { for_org ? Setting.admin_contacts_min_count : 0 },
max: -> { Setting.admin_contacts_max_count }
}
end

validates :tech_domain_contacts, object_count: {
min: -> { Setting.tech_contacts_min_count },
max: -> { Setting.tech_contacts_max_count },
}
def self.tech_contacts_validation_rules(for_org:)
{
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: {
attribute: 'hostname',
Expand Down Expand Up @@ -835,4 +855,12 @@ def self.swap_elements(array, indexes)
end
array
end

def require_admin_contacts?
registrant.present? && registrant.org?
end

def require_tech_contacts?
registrant.present? && registrant.org?
end
end
2 changes: 2 additions & 0 deletions app/models/epp/domain.rb
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,9 @@ def epp_code_map

def attach_default_contacts
return if registrant.blank?

registrant_obj = Contact.find_by(code: registrant.code)
return if registrant_obj.priv?

tech_contacts << registrant_obj if tech_domain_contacts.blank?
admin_contacts << registrant_obj if admin_domain_contacts.blank? && !registrant.org?
Expand Down
54 changes: 54 additions & 0 deletions test/integration/epp/domain/create/base_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,9 @@ def test_registers_new_domain_with_required_attributes
contact = contacts(:john)
registrant = contact.becomes(Registrant)

registrant.update!(ident_type: 'org')
registrant.reload

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')}">
Expand All @@ -444,6 +447,7 @@ def test_registers_new_domain_with_required_attributes
<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:contact type="admin">#{contact.code}</domain:contact>
</domain:create>
</create>
<extension>
Expand Down Expand Up @@ -937,4 +941,54 @@ def test_returns_error_response_if_throttled
ENV["shunter_default_threshold"] = '10000'
ENV["shunter_enabled"] = 'false'
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
23 changes: 23 additions & 0 deletions test/integration/repp/v1/domains/contacts_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,32 @@ def test_can_remove_tech_contacts
refute @domain.tech_contacts.find_by(code: contact.code).present?
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
Spy.on_instance_method(Actions::DomainUpdate, :validate_email).and_return(true)

@domain.registrant.update!(ident_type: 'org')
@domain.reload

contact = @domain.admin_contacts.last

payload = { contacts: [ { code: contact.code, type: 'admin' } ] }
Expand Down
58 changes: 58 additions & 0 deletions test/models/domain_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,10 @@ def test_validates_admin_contact_count
assert domain.valid?, proc { domain.errors.full_messages }

domain.admin_domain_contacts.clear

domain.registrant.update!(ident_type: 'org')
domain.reload
assert domain.registrant.org?
assert domain.invalid?

domain.admin_domain_contacts.clear
Expand All @@ -236,6 +240,10 @@ def test_validates_tech_contact_count
Setting.tech_contacts_min_count = min_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
min_count.times { domain.tech_domain_contacts.build(domain_contact_attributes) }
assert domain.valid?, proc { domain.errors.full_messages }
Expand Down Expand Up @@ -475,6 +483,56 @@ def test_not_renewable_if_pending_delete_unconfirmed
assert_not @domain.renewable?
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

def valid_domain
Expand Down