mirror of
https://github.com/internetee/registry.git
synced 2025-08-06 01:35:10 +02:00
Merge branch 'master' into registry-623
# Conflicts: # db/structure.sql
This commit is contained in:
commit
ffc32b66de
72 changed files with 1004 additions and 932 deletions
34
app/models/concerns/contact/identical.rb
Normal file
34
app/models/concerns/contact/identical.rb
Normal file
|
@ -0,0 +1,34 @@
|
|||
module Concerns::Contact::Identical
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
IDENTIFIABLE_ATTRIBUTES = %w[
|
||||
name
|
||||
email
|
||||
phone
|
||||
fax
|
||||
ident
|
||||
ident_type
|
||||
ident_country_code
|
||||
org_name
|
||||
]
|
||||
private_constant :IDENTIFIABLE_ATTRIBUTES
|
||||
|
||||
def identical(registrar)
|
||||
self.class.where(identifiable_hash)
|
||||
.where(["statuses = ?::character varying[]", "{#{read_attribute(:statuses).join(',')}}"])
|
||||
.where(registrar: registrar)
|
||||
.where.not(id: id).take
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def identifiable_hash
|
||||
attributes = IDENTIFIABLE_ATTRIBUTES
|
||||
|
||||
if self.class.address_processing?
|
||||
attributes += self.class.address_attribute_names
|
||||
end
|
||||
|
||||
slice(*attributes)
|
||||
end
|
||||
end
|
|
@ -7,6 +7,8 @@ module Concerns::Contact::Transferable
|
|||
end
|
||||
|
||||
def transfer(new_registrar)
|
||||
return identical(new_registrar) if identical(new_registrar)
|
||||
|
||||
new_contact = self.dup
|
||||
new_contact.registrar = new_registrar
|
||||
new_contact.original = self
|
||||
|
|
|
@ -52,7 +52,7 @@ module Concerns::Domain::Transferable
|
|||
|
||||
def transfer_registrant(new_registrar)
|
||||
return if registrant.registrar == new_registrar
|
||||
self.registrant = registrant.transfer(new_registrar)
|
||||
self.registrant = registrant.transfer(new_registrar).becomes(Registrant)
|
||||
end
|
||||
|
||||
def transfer_domain_contacts(new_registrar)
|
||||
|
|
|
@ -3,6 +3,7 @@ class Contact < ActiveRecord::Base
|
|||
include EppErrors
|
||||
include UserEvents
|
||||
include Concerns::Contact::Transferable
|
||||
include Concerns::Contact::Identical
|
||||
|
||||
belongs_to :original, class_name: self.name
|
||||
belongs_to :registrar, required: true
|
||||
|
@ -11,9 +12,6 @@ class Contact < ActiveRecord::Base
|
|||
has_many :legal_documents, as: :documentable
|
||||
has_many :registrant_domains, class_name: 'Domain', foreign_key: 'registrant_id'
|
||||
|
||||
# TODO: remove later
|
||||
has_many :depricated_statuses, class_name: 'DepricatedContactStatus', dependent: :destroy
|
||||
|
||||
has_paper_trail class_name: "ContactVersion", meta: { children: :children_log }
|
||||
|
||||
attr_accessor :legal_document_id
|
||||
|
@ -37,7 +35,7 @@ class Contact < ActiveRecord::Base
|
|||
validates_associated :identifier
|
||||
|
||||
validate :validate_html
|
||||
validate :validate_country_code
|
||||
validate :validate_country_code, if: 'self.class.address_processing?'
|
||||
|
||||
after_initialize do
|
||||
self.status_notes = {} if status_notes.nil?
|
||||
|
@ -70,11 +68,6 @@ class Contact < ActiveRecord::Base
|
|||
|
||||
after_save :update_related_whois_records
|
||||
|
||||
# for overwrite when doing children loop
|
||||
attr_writer :domains_present
|
||||
|
||||
scope :current_registrars, ->(id) { where(registrar_id: id) }
|
||||
|
||||
ORG = 'org'
|
||||
PRIV = 'priv'
|
||||
BIRTHDAY = 'birthday'.freeze
|
||||
|
@ -206,7 +199,7 @@ class Contact < ActiveRecord::Base
|
|||
ver_scope << "(children->'#{type}')::jsonb <@ json_build_array(#{contact.id})::jsonb"
|
||||
end
|
||||
next if DomainVersion.where("created_at > ?", Time.now - Setting.orphans_contacts_in_months.to_i.months).where(ver_scope.join(" OR ")).any?
|
||||
next if contact.domains_present?
|
||||
next if contact.in_use?
|
||||
|
||||
contact.destroy
|
||||
counter.next
|
||||
|
@ -279,7 +272,7 @@ class Contact < ActiveRecord::Base
|
|||
calculated.delete(Contact::OK)
|
||||
calculated.delete(Contact::LINKED)
|
||||
calculated << Contact::OK if calculated.empty?# && valid?
|
||||
calculated << Contact::LINKED if domains_present?
|
||||
calculated << Contact::LINKED if in_use?
|
||||
|
||||
calculated.uniq
|
||||
end
|
||||
|
@ -347,7 +340,7 @@ class Contact < ActiveRecord::Base
|
|||
# no need separate method
|
||||
# should use only in transaction
|
||||
def destroy_and_clean frame
|
||||
if domains_present?
|
||||
if in_use?
|
||||
errors.add(:domains, :exist)
|
||||
return false
|
||||
end
|
||||
|
@ -405,14 +398,6 @@ class Contact < ActiveRecord::Base
|
|||
end
|
||||
end
|
||||
|
||||
# optimization under children loop,
|
||||
# otherwise bullet will not be happy
|
||||
def domains_present?
|
||||
return @domains_present if @domains_present
|
||||
domain_contacts.present? || registrant_domains.present?
|
||||
end
|
||||
|
||||
|
||||
def search_name
|
||||
"#{code} #{name}"
|
||||
end
|
||||
|
@ -551,7 +536,7 @@ class Contact < ActiveRecord::Base
|
|||
Country.new(ident_country_code)
|
||||
end
|
||||
|
||||
def used?
|
||||
def in_use?
|
||||
registrant_domains.any? || domain_contacts.any?
|
||||
end
|
||||
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
class DepricatedContactStatus < ActiveRecord::Base
|
||||
self.table_name = :contact_statuses
|
||||
self.sequence_name = :contact_statuses_id_seq
|
||||
belongs_to :contact
|
||||
end
|
|
@ -40,15 +40,11 @@ class Domain < ActiveRecord::Base
|
|||
has_many :contacts, through: :domain_contacts, source: :contact
|
||||
has_many :admin_contacts, through: :admin_domain_contacts, source: :contact
|
||||
has_many :tech_contacts, through: :tech_domain_contacts, source: :contact
|
||||
has_many :nameservers, dependent: :destroy
|
||||
has_many :nameservers, dependent: :destroy, inverse_of: :domain
|
||||
|
||||
accepts_nested_attributes_for :nameservers, allow_destroy: true,
|
||||
reject_if: proc { |attrs| attrs[:hostname].blank? }
|
||||
|
||||
has_many :domain_statuses, dependent: :destroy
|
||||
accepts_nested_attributes_for :domain_statuses, allow_destroy: true,
|
||||
reject_if: proc { |attrs| attrs[:value].blank? }
|
||||
|
||||
has_many :transfers, class_name: 'DomainTransfer', dependent: :destroy
|
||||
|
||||
has_many :dnskeys, dependent: :destroy
|
||||
|
@ -172,10 +168,6 @@ class Domain < ActiveRecord::Base
|
|||
attribute: 'contact_code_cache'
|
||||
}
|
||||
|
||||
validates :domain_statuses, uniqueness_multi: {
|
||||
attribute: 'value'
|
||||
}
|
||||
|
||||
validates :dnskeys, uniqueness_multi: {
|
||||
attribute: 'public_key'
|
||||
}
|
||||
|
@ -610,7 +602,6 @@ class Domain < ActiveRecord::Base
|
|||
log[:tech_contacts] = tech_contact_ids
|
||||
log[:nameservers] = nameserver_ids
|
||||
log[:dnskeys] = dnskey_ids
|
||||
log[:domain_statuses]= domain_status_ids
|
||||
log[:legal_documents]= [legal_document_id]
|
||||
log[:registrant] = [registrant_id]
|
||||
log
|
||||
|
|
|
@ -179,7 +179,6 @@ class Epp::Domain < Domain
|
|||
at[:nameservers_attributes] = nameservers_attrs(frame, action)
|
||||
at[:admin_domain_contacts_attributes] = admin_domain_contacts_attrs(frame, action)
|
||||
at[:tech_domain_contacts_attributes] = tech_domain_contacts_attrs(frame, action)
|
||||
# at[:domain_statuses_attributes] = domain_statuses_attrs(frame, action)
|
||||
|
||||
pw = frame.css('authInfo > pw').text
|
||||
at[:transfer_code] = pw if pw.present?
|
||||
|
|
|
@ -2,18 +2,31 @@ class Nameserver < ActiveRecord::Base
|
|||
include Versions # version/nameserver_version.rb
|
||||
include EppErrors
|
||||
|
||||
# belongs_to :registrar
|
||||
belongs_to :domain
|
||||
HOSTNAME_REGEXP = /\A(([a-zA-Z0-9]|[a-zA-ZäöüõšžÄÖÜÕŠŽ0-9][a-zA-ZäöüõšžÄÖÜÕŠŽ0-9\-]
|
||||
*[a-zA-ZäöüõšžÄÖÜÕŠŽ0-9])\.)
|
||||
*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]
|
||||
*[A-Za-z0-9])\z/x
|
||||
|
||||
# scope :owned_by_registrar, -> (registrar) { joins(:domain).where('domains.registrar_id = ?', registrar.id) }
|
||||
IPV4_REGEXP = /\A(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}
|
||||
([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\z/x
|
||||
|
||||
# rubocop: disable Metrics/LineLength
|
||||
validates :hostname, format: { with: /\A(([a-zA-Z0-9]|[a-zA-ZäöüõšžÄÖÜÕŠŽ0-9][a-zA-ZäöüõšžÄÖÜÕŠŽ0-9\-]*[a-zA-ZäöüõšžÄÖÜÕŠŽ0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])\z/ }
|
||||
# validates :ipv4, format: { with: /\A(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\z/, allow_blank: true }
|
||||
# validates :ipv6, format: { with: /(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]).){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]).){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))/, allow_blank: true }
|
||||
validate :val_ipv4
|
||||
validate :val_ipv6
|
||||
# rubocop: enable Metrics/LineLength
|
||||
IPV6_REGEXP = /(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|
|
||||
([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|
|
||||
([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|
|
||||
([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|
|
||||
([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|
|
||||
:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|
|
||||
::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]).){3,3}(25[0-5]|(2[0-4]|
|
||||
1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|
|
||||
1{0,1}[0-9]){0,1}[0-9]).){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))/x
|
||||
|
||||
belongs_to :domain, required: true
|
||||
|
||||
validates :hostname, presence: true
|
||||
validates :hostname, format: { with: HOSTNAME_REGEXP }, allow_blank: true
|
||||
validate :validate_ipv4_format
|
||||
validate :validate_ipv6_format
|
||||
validate :require_ip, if: :glue_record_required?
|
||||
|
||||
before_validation :normalize_attributes
|
||||
before_validation :check_puny_symbols
|
||||
|
@ -38,6 +51,39 @@ class Nameserver < ActiveRecord::Base
|
|||
}
|
||||
end
|
||||
|
||||
def to_s
|
||||
hostname
|
||||
end
|
||||
|
||||
def hostname=(hostname)
|
||||
self[:hostname] = SimpleIDN.to_unicode(hostname)
|
||||
self[:hostname_puny] = SimpleIDN.to_ascii(hostname)
|
||||
end
|
||||
|
||||
class << self
|
||||
def find_by_hash_params params
|
||||
params = params.with_indifferent_access
|
||||
rel = all
|
||||
rel = rel.where(hostname: params[:hostname])
|
||||
rel
|
||||
end
|
||||
|
||||
def hostnames
|
||||
pluck(:hostname)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def require_ip
|
||||
errors.add(:base, :ip_required) if ipv4.blank? && ipv6.blank?
|
||||
end
|
||||
|
||||
def glue_record_required?
|
||||
return unless hostname? && domain
|
||||
hostname.end_with?(domain.name)
|
||||
end
|
||||
|
||||
def normalize_attributes
|
||||
self.hostname = hostname.try(:strip).try(:downcase)
|
||||
self.ipv4 = Array(ipv4).reject(&:blank?).map(&:strip)
|
||||
|
@ -45,6 +91,8 @@ class Nameserver < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def check_label_length
|
||||
return unless hostname
|
||||
|
||||
hostname_puny.split('.').each do |label|
|
||||
errors.add(:hostname, :puny_to_long) if label.length > 63
|
||||
end
|
||||
|
@ -55,71 +103,15 @@ class Nameserver < ActiveRecord::Base
|
|||
errors.add(:hostname, :invalid) if hostname =~ regexp
|
||||
end
|
||||
|
||||
def to_s
|
||||
hostname
|
||||
end
|
||||
|
||||
def hostname=(hostname)
|
||||
self[:hostname] = SimpleIDN.to_unicode(hostname)
|
||||
self[:hostname_puny] = SimpleIDN.to_ascii(hostname)
|
||||
end
|
||||
|
||||
def val_ipv4
|
||||
regexp = /\A(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\z/
|
||||
def validate_ipv4_format
|
||||
ipv4.to_a.each do |ip|
|
||||
errors.add(:ipv4, :invalid) unless ip =~ regexp
|
||||
errors.add(:ipv4, :invalid) unless ip =~ IPV4_REGEXP
|
||||
end
|
||||
end
|
||||
def val_ipv6
|
||||
regexp = /(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]).){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]).){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))/
|
||||
|
||||
def validate_ipv6_format
|
||||
ipv6.to_a.each do |ip|
|
||||
errors.add(:ipv6, :invalid) unless ip =~ regexp
|
||||
end
|
||||
end
|
||||
|
||||
class << self
|
||||
def replace_hostname_ends(domains, old_end, new_end)
|
||||
domains = domains.where('EXISTS(
|
||||
select 1 from nameservers ns where ns.domain_id = domains.id AND ns.hostname LIKE ?
|
||||
)', "%#{old_end}")
|
||||
|
||||
count, success_count = 0.0, 0.0
|
||||
domains.each do |d|
|
||||
ns_attrs = { nameservers_attributes: [] }
|
||||
|
||||
d.nameservers.each do |ns|
|
||||
next unless ns.hostname.end_with?(old_end)
|
||||
|
||||
hn = ns.hostname.chomp(old_end)
|
||||
ns_attrs[:nameservers_attributes] << {
|
||||
id: ns.id,
|
||||
hostname: "#{hn}#{new_end}"
|
||||
}
|
||||
end
|
||||
|
||||
success_count += 1 if d.update(ns_attrs)
|
||||
count += 1
|
||||
end
|
||||
|
||||
return 'replaced_none' if count == 0.0
|
||||
|
||||
prc = success_count / count
|
||||
|
||||
return 'replaced_all' if prc == 1.0
|
||||
'replaced_some'
|
||||
end
|
||||
|
||||
def find_by_hash_params params
|
||||
params = params.with_indifferent_access
|
||||
rel = all
|
||||
rel = rel.where(hostname: params[:hostname])
|
||||
# rel = rel.where(hostname: params[:hostname]) if params[:ipv4]
|
||||
# ignoring ips
|
||||
rel
|
||||
end
|
||||
|
||||
def hostnames
|
||||
pluck(:hostname)
|
||||
errors.add(:ipv6, :invalid) unless ip =~ IPV6_REGEXP
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -191,6 +191,20 @@ class Registrar < ActiveRecord::Base
|
|||
white_ips.api.pluck(:ipv4, :ipv6).flatten.include?(ip)
|
||||
end
|
||||
|
||||
# Audit log is needed, therefore no raw SQL
|
||||
def replace_nameservers(hostname, new_attributes)
|
||||
transaction do
|
||||
nameservers.where(hostname: hostname).find_each do |original_nameserver|
|
||||
new_nameserver = Nameserver.new
|
||||
new_nameserver.domain = original_nameserver.domain
|
||||
new_nameserver.attributes = new_attributes
|
||||
new_nameserver.save!
|
||||
|
||||
original_nameserver.destroy!
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_defaults
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
class ContactStatusVersion < PaperTrail::Version
|
||||
include VersionSession
|
||||
self.table_name = :log_contact_statuses
|
||||
self.sequence_name = :log_contact_statuses_id_seq
|
||||
end
|
|
@ -1,5 +0,0 @@
|
|||
class CountryVersion < PaperTrail::Version
|
||||
include VersionSession
|
||||
self.table_name = :log_countries
|
||||
self.sequence_name = :log_countries_id_seq
|
||||
end
|
|
@ -1,5 +0,0 @@
|
|||
class DomainStatusVersion < PaperTrail::Version
|
||||
include VersionSession
|
||||
self.table_name = :log_domain_statuses
|
||||
self.sequence_name = :log_domain_statuses_id_seq
|
||||
end
|
Loading…
Add table
Add a link
Reference in a new issue