diff --git a/app/controllers/epp/domains_controller.rb b/app/controllers/epp/domains_controller.rb index 12b2277ef..f39aee81b 100644 --- a/app/controllers/epp/domains_controller.rb +++ b/app/controllers/epp/domains_controller.rb @@ -87,8 +87,8 @@ class Epp::DomainsController < EppController def check authorize! :check, Epp::Domain - names = params[:parsed_frame].css('name').map(&:text) - @domains = Epp::Domain.check_availability(names) + domain_names = params[:parsed_frame].css('name').map(&:text) + @domains = Epp::Domain.check_availability(domain_names) render_epp_response '/epp/domains/check' end diff --git a/app/models/dns/domain_name.rb b/app/models/dns/domain_name.rb new file mode 100644 index 000000000..f388a975d --- /dev/null +++ b/app/models/dns/domain_name.rb @@ -0,0 +1,39 @@ +module DNS + # Namespace is needed, because a class with the same name is defined by `domain_name` gem, + # a dependency of `actionmailer`, + class DomainName + def initialize(name) + @name = name + end + + def unavailable? + registered? || blocked? || zone_with_same_origin? + end + + def unavailability_reason + if registered? + :registered + elsif blocked? + :blocked + elsif zone_with_same_origin? + :zone_with_same_origin + end + end + + private + + attr_reader :name + + def registered? + Domain.find_by_idn(name) + end + + def blocked? + BlockedDomain.where(name: name).any? + end + + def zone_with_same_origin? + DNS::Zone.where(origin: name).any? + end + end +end diff --git a/app/models/epp/domain.rb b/app/models/epp/domain.rb index 2f25f3da5..4e3d20305 100644 --- a/app/models/epp/domain.rb +++ b/app/models/epp/domain.rb @@ -788,31 +788,32 @@ class Epp::Domain < Domain } end - def check_availability(domains) - domains = [domains] if domains.is_a?(String) + def check_availability(domain_names) + domain_names = [domain_names] if domain_names.is_a?(String) - res = [] - domains.each do |x| - x.strip! - x.downcase! - unless DomainNameValidator.validate_format(x) - res << { name: x, avail: 0, reason: 'invalid format' } + result = [] + + domain_names.each do |domain_name_as_string| + domain_name_as_string.strip! + domain_name_as_string.downcase! + + unless DomainNameValidator.validate_format(domain_name_as_string) + result << { name: domain_name_as_string, avail: 0, reason: 'invalid format' } next end - if ReservedDomain.pw_for(x).present? - res << { name: x, avail: 0, reason: I18n.t('errors.messages.epp_domain_reserved') } + domain_name = DNS::DomainName.new(domain_name_as_string) + + if domain_name.unavailable? + reason = I18n.t("errors.messages.epp_domain_#{domain_name.unavailability_reason}") + result << { name: domain_name_as_string, avail: 0, reason: reason } next end - if Domain.find_by_idn x - res << { name: x, avail: 0, reason: 'in use' } - else - res << { name: x, avail: 1 } - end + result << { name: domain_name_as_string, avail: 1 } end - res + result end end diff --git a/config/locales/en.yml b/config/locales/en.yml index e9e499def..a01604919 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -196,7 +196,9 @@ en: errors: messages: blank: 'is missing' - epp_domain_reserved: 'Domain name is reserved' + epp_domain_registered: in use + epp_domain_blocked: Blocked + epp_domain_zone_with_same_origin: Zone with the same origin exists epp_obj_does_not_exist: 'Object does not exist' epp_authorization_error: 'Authorization error' epp_id_taken: 'Contact id already exists' diff --git a/test/integration/epp/domain/check/base_test.rb b/test/integration/epp/domain/check/base_test.rb index 5d98b60ff..65e746947 100644 --- a/test/integration/epp/domain/check/base_test.rb +++ b/test/integration/epp/domain/check/base_test.rb @@ -23,7 +23,7 @@ class EppDomainCheckBaseTest < ApplicationIntegrationTest assert_equal 'some.test', response_xml.at_xpath('//domain:name', 'domain' => 'https://epp.tld.ee/schema/domain-eis-1.0.xsd').text end - def test_domain_is_available_when_not_registered_blocked_nor_reserved + def test_domain_is_available_when_not_registered_or_blocked request_xml = <<-XML @@ -44,6 +44,29 @@ class EppDomainCheckBaseTest < ApplicationIntegrationTest assert_nil response_xml.at_xpath('//domain:reason', 'domain' => 'https://epp.tld.ee/schema/domain-eis-1.0.xsd') end + def test_domain_is_available_when_reserved + assert_equal 'reserved.test', reserved_domains(:one).name + + request_xml = <<-XML + + + + + + reserved.test + + + + + XML + + post '/epp/command/check', { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + + response_xml = Nokogiri::XML(response.body) + assert_equal '1', response_xml.at_xpath('//domain:name', 'domain' => 'https://epp.tld.ee/schema/domain-eis-1.0.xsd')['avail'] + assert_nil response_xml.at_xpath('//domain:reason', 'domain' => 'https://epp.tld.ee/schema/domain-eis-1.0.xsd') + end + def test_domain_is_unavailable_when_format_is_invalid request_xml = <<-XML @@ -88,8 +111,8 @@ class EppDomainCheckBaseTest < ApplicationIntegrationTest assert_equal 'in use', response_xml.at_xpath('//domain:reason', 'domain' => 'https://epp.tld.ee/schema/domain-eis-1.0.xsd').text end - def test_domain_is_unavailable_when_reserved - assert_equal 'reserved.test', reserved_domains(:one).name + def test_domain_is_unavailable_when_blocked + assert_equal 'blocked.test', blocked_domains(:one).name request_xml = <<-XML @@ -97,7 +120,7 @@ class EppDomainCheckBaseTest < ApplicationIntegrationTest - reserved.test + blocked.test @@ -108,7 +131,30 @@ class EppDomainCheckBaseTest < ApplicationIntegrationTest response_xml = Nokogiri::XML(response.body) assert_equal '0', response_xml.at_xpath('//domain:name', 'domain' => 'https://epp.tld.ee/schema/domain-eis-1.0.xsd')['avail'] - assert_equal 'Domain name is reserved', response_xml.at_xpath('//domain:reason', 'domain' => 'https://epp.tld.ee/schema/domain-eis-1.0.xsd').text + assert_equal 'Blocked', response_xml.at_xpath('//domain:reason', 'domain' => 'https://epp.tld.ee/schema/domain-eis-1.0.xsd').text + end + + def test_domain_is_unavailable_when_zone_with_the_same_origin_exists + assert_equal 'test', dns_zones(:one).origin + + request_xml = <<-XML + + + + + + test + + + + + XML + + post '/epp/command/check', { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' + + response_xml = Nokogiri::XML(response.body) + assert_equal '0', response_xml.at_xpath('//domain:name', 'domain' => 'https://epp.tld.ee/schema/domain-eis-1.0.xsd')['avail'] + assert_equal 'Zone with the same origin exists', response_xml.at_xpath('//domain:reason', 'domain' => 'https://epp.tld.ee/schema/domain-eis-1.0.xsd').text end def test_multiple_domains diff --git a/test/models/dns/domain_name_test.rb b/test/models/dns/domain_name_test.rb new file mode 100644 index 000000000..c0445cf9e --- /dev/null +++ b/test/models/dns/domain_name_test.rb @@ -0,0 +1,27 @@ +require 'test_helper' + +class DNS::DomainNameTest < ActiveSupport::TestCase + def test_unavailable_when_registered + domain_name = DNS::DomainName.new('shop.test') + assert_equal 'shop.test', domains(:shop).name + + assert domain_name.unavailable? + assert_equal :registered, domain_name.unavailability_reason + end + + def test_unavailable_when_blocked + domain_name = DNS::DomainName.new('blocked.test') + assert_equal 'blocked.test', blocked_domains(:one).name + + assert domain_name.unavailable? + assert_equal :blocked, domain_name.unavailability_reason + end + + def test_unavailable_when_zone_with_the_same_origin_exists + domain_name = DNS::DomainName.new('test') + assert_equal 'test', dns_zones(:one).origin + + assert domain_name.unavailable? + assert_equal :zone_with_same_origin, domain_name.unavailability_reason + end +end diff --git a/test/models/domain/domain_test.rb b/test/models/domain_test.rb similarity index 100% rename from test/models/domain/domain_test.rb rename to test/models/domain_test.rb