Skip to content

Commit

Permalink
added name checker and availability control for domain names
Browse files Browse the repository at this point in the history
  • Loading branch information
OlegPhenomenon committed Jul 17, 2024
1 parent a971fdb commit d286fbd
Show file tree
Hide file tree
Showing 6 changed files with 102 additions and 9 deletions.
19 changes: 16 additions & 3 deletions app/controllers/api/v1/business_registry/check_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,30 @@ module V1
module BusinessRegistry
class CheckController < ::Api::V1::BaseController
before_action :set_cors_header
before_action :validate_organization_name
# before_action :authenticate

def show
name = params[:name]
render json: { message: "OK - #{name}" }, status: :ok
name = params[:organization_name]
all_variants = ::BusinessRegistry::DomainNameGeneratorService.generate(name)
available_variants = ::BusinessRegistry::DomainAvailabilityChecker.filter_available(all_variants)
render json: { variants: available_variants }, status: :ok
end

private

def set_cors_header
response.headers['Access-Control-Allow-Origin'] = request.headers['Origin']
allowed_origins = ENV['ALLOWED_ORIGINS'].split(',')
if allowed_origins.include?(request.headers['Origin'])
response.headers['Access-Control-Allow-Origin'] = request.headers['Origin']
end
end

def validate_organization_name
name = params[:organization_name]
if name.blank? || name.length > 100 || !name.match?(/\A[\p{L}\p{N}\s\-]+\z/)
render json: { error: 'Invalid organization name' }, status: :bad_request
end
end
end
end
Expand Down
8 changes: 8 additions & 0 deletions app/services/business_registry/domain_availability_checker.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module BusinessRegistry
class DomainAvailabilityChecker
def self.filter_available(domains)
reserved_domains = ReservedDomain.where(name: domains).pluck(:name)
domains - reserved_domains
end
end
end
35 changes: 35 additions & 0 deletions app/services/business_registry/domain_name_generator_service.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
module BusinessRegistry
class DomainNameGeneratorService
LEGAL_FORMS = %w[AS OU FIE ].freeze

def self.generate(name)
base_name = remove_legal_forms(sanitize_input(name))
variants = generate_variants(base_name)
variants + generate_additional_variants(variants)
end

private

def self.sanitize_input(name)
name.gsub(/[^[:alnum:]\s\-]/, '').strip
end

def self.remove_legal_forms(name)
words = name.split
words.reject { |word| LEGAL_FORMS.include?(word.upcase) }.join(' ').strip
end

def self.generate_variants(name)
[
name.downcase.gsub(/\s+/, ''),
name.downcase.gsub(/\s+/, '-'),
name.downcase.gsub(/\s+/, '_')
]
end

def self.generate_additional_variants(variants)
current_year = Time.current.year
variants.map { |v| "#{v}#{current_year}" }
end
end
end
2 changes: 1 addition & 1 deletion config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@
namespace :api do
namespace :v1 do
namespace :business_registry do
get 'check/:name', to: 'check#show', as: 'check', constraints: { name: /[^\/]+/ }
get 'check', to: 'check#show', as: 'check'
post 'reserve', to: 'reserve#create', as: 'reserve'
get 'registration_code/:name', to: 'registration_code#show', as: 'registration_code', constraints: { name: /[^\/]+/ }
delete 'release/:name', to: 'release#destroy', as: 'release', constraints: { name: /[^\/]+/ }
Expand Down
4 changes: 4 additions & 0 deletions test/fixtures/reserved_domains.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
one:
name: reserved.test
password: reserved-001

two:
name: company-name.test
password: company-002
43 changes: 38 additions & 5 deletions test/integration/api/business_registry/check_test.rb
Original file line number Diff line number Diff line change
@@ -1,17 +1,50 @@
require 'test_helper'

class CheckTest < ApplicationIntegrationTest
fixtures :reserved_domains

def setup
super
ENV['ALLOWED_ORIGINS'] = 'http://example.com,http://test.com'
end

def test_return_list_of_available_organization_domain_names
get '/api/v1/business_registry/check?organization_name=Company Name AS', headers: { 'Origin' => 'http://example.com' }
json = JSON.parse(response.body, symbolize_names: true)

assert_response :success
assert_equal 'http://example.com', response.headers['Access-Control-Allow-Origin']
refute_includes json[:variants], 'company-name.test'
assert_includes json[:variants], 'companyname'
assert_includes json[:variants], 'company-name'
assert_includes json[:variants], 'company_name'
assert_includes json[:variants], "companyname#{Time.current.year}"
refute_includes json[:variants].join, 'as'
end

def test_single_word_company_name
get '/api/v1/business_registry/check?organization_name=Reserved', headers: { 'Origin' => 'http://test.com' }
json = JSON.parse(response.body, symbolize_names: true)

# @contact = contacts(:john)
assert_response :success
assert_equal 'http://test.com', response.headers['Access-Control-Allow-Origin']
assert_includes json[:variants], 'reserved'
refute_includes json[:variants], 'reserved.test'
assert_includes json[:variants], "reserved#{Time.current.year}"
end

def test_return_code_that_all_ok
get '/api/v1/business_registry/check/common.ee'
def test_invalid_organization_name
get '/api/v1/business_registry/check?organization_name=Invalid!@#Name', headers: { 'Origin' => 'http://example.com' }
json = JSON.parse(response.body, symbolize_names: true)

puts(json)
# assert_equal json[:errors], 'Contact not found'
assert_response :bad_request
assert_equal 'Invalid organization name', json[:error]
end

def test_cors_with_disallowed_origin
get '/api/v1/business_registry/check?organization_name=Test', headers: { 'Origin' => 'http://malicious.com' }

assert_response :success
assert_nil response.headers['Access-Control-Allow-Origin']
end
end

0 comments on commit d286fbd

Please sign in to comment.