mirror of
https://github.com/internetee/registry.git
synced 2025-05-17 09:57:23 +02:00
703 lines
21 KiB
Ruby
703 lines
21 KiB
Ruby
# rubocop: disable Metrics/ClassLength
|
|
class Domain < ActiveRecord::Base
|
|
include UserEvents
|
|
include Versions # version/domain_version.rb
|
|
include Concerns::Domain::Expirable
|
|
include Concerns::Domain::Activatable
|
|
include Concerns::Domain::ForceDelete
|
|
include Concerns::Domain::Deletable
|
|
include Concerns::Domain::Transferable
|
|
|
|
has_paper_trail class_name: "DomainVersion", meta: { children: :children_log }
|
|
|
|
attr_accessor :roles
|
|
|
|
attr_accessor :legal_document_id
|
|
|
|
alias_attribute :on_hold_time, :outzone_at
|
|
alias_attribute :outzone_time, :outzone_at
|
|
alias_attribute :auth_info, :transfer_code # Old attribute name; for PaperTrail
|
|
|
|
# TODO: whois requests ip whitelist for full info for own domains and partial info for other domains
|
|
# TODO: most inputs should be trimmed before validatation, probably some global logic?
|
|
|
|
belongs_to :registrar, required: true
|
|
belongs_to :registrant, required: true
|
|
# TODO: should we user validates_associated :registrant here?
|
|
|
|
has_many :admin_domain_contacts
|
|
accepts_nested_attributes_for :admin_domain_contacts, allow_destroy: true, reject_if: :admin_change_prohibited?
|
|
has_many :tech_domain_contacts
|
|
accepts_nested_attributes_for :tech_domain_contacts, allow_destroy: true, reject_if: :tech_change_prohibited?
|
|
|
|
def registrant_change_prohibited?
|
|
statuses.include? DomainStatus::SERVER_REGISTRANT_CHANGE_PROHIBITED
|
|
end
|
|
|
|
|
|
# NB! contacts, admin_contacts, tech_contacts are empty for a new record
|
|
has_many :domain_contacts, dependent: :destroy
|
|
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
|
|
|
|
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 :domain_transfers, dependent: :destroy
|
|
|
|
has_many :dnskeys, dependent: :destroy
|
|
|
|
has_many :keyrelays
|
|
has_one :whois_record # destroyment will be done in after_commit
|
|
|
|
accepts_nested_attributes_for :dnskeys, allow_destroy: true
|
|
|
|
has_many :legal_documents, as: :documentable
|
|
accepts_nested_attributes_for :legal_documents, reject_if: proc { |attrs| attrs[:body].blank? }
|
|
|
|
delegate :name, to: :registrant, prefix: true
|
|
delegate :code, to: :registrant, prefix: true
|
|
delegate :ident, to: :registrant, prefix: true
|
|
delegate :email, to: :registrant, prefix: true
|
|
delegate :phone, to: :registrant, prefix: true
|
|
delegate :street, to: :registrant, prefix: true
|
|
delegate :city, to: :registrant, prefix: true
|
|
delegate :zip, to: :registrant, prefix: true
|
|
delegate :state, to: :registrant, prefix: true
|
|
delegate :country, to: :registrant, prefix: true
|
|
|
|
delegate :name, to: :registrar, prefix: true
|
|
delegate :street, to: :registrar, prefix: true
|
|
|
|
after_initialize do
|
|
self.pending_json = {} if pending_json.blank?
|
|
self.statuses = [] if statuses.nil?
|
|
self.status_notes = {} if status_notes.nil?
|
|
end
|
|
|
|
before_create -> { self.reserved = in_reserved_list?; nil }
|
|
before_save :manage_automatic_statuses
|
|
before_save :touch_always_version
|
|
def touch_always_version
|
|
self.updated_at = Time.zone.now
|
|
end
|
|
|
|
before_update :manage_statuses
|
|
def manage_statuses
|
|
return unless registrant_id_changed? # rollback has not yet happened
|
|
pending_update! if registrant_verification_asked?
|
|
true
|
|
end
|
|
|
|
after_commit :update_whois_record
|
|
|
|
after_create :update_reserved_domains
|
|
def update_reserved_domains
|
|
ReservedDomain.new_password_for(name) if in_reserved_list?
|
|
end
|
|
|
|
validates :name_dirty, domain_name: true, uniqueness: true
|
|
validates :puny_label, length: { maximum: 63 }
|
|
validates :period, presence: true, numericality: { only_integer: true }
|
|
validates :transfer_code, presence: true
|
|
|
|
validate :validate_reservation
|
|
def validate_reservation
|
|
return if persisted? || !in_reserved_list?
|
|
|
|
if reserved_pw.blank?
|
|
errors.add(:base, :required_parameter_missing_reserved)
|
|
return false
|
|
end
|
|
|
|
return if ReservedDomain.pw_for(name) == reserved_pw
|
|
errors.add(:base, :invalid_auth_information_reserved)
|
|
end
|
|
|
|
validate :status_is_consistant
|
|
def status_is_consistant
|
|
has_error = (statuses.include?(DomainStatus::SERVER_HOLD) && statuses.include?(DomainStatus::SERVER_MANUAL_INZONE))
|
|
unless has_error
|
|
if (statuses & [DomainStatus::PENDING_DELETE_CONFIRMATION, DomainStatus::PENDING_DELETE, DomainStatus::FORCE_DELETE]).any?
|
|
has_error = statuses.include? DomainStatus::SERVER_DELETE_PROHIBITED
|
|
end
|
|
end
|
|
errors.add(:domains, I18n.t(:object_status_prohibits_operation)) if has_error
|
|
end
|
|
|
|
attr_accessor :is_admin
|
|
|
|
validate :check_permissions, :unless => :is_admin
|
|
def check_permissions
|
|
return unless force_delete_scheduled?
|
|
errors.add(:base, I18n.t(:object_status_prohibits_operation))
|
|
false
|
|
end
|
|
|
|
validates :nameservers, domain_nameserver: {
|
|
min: -> { Setting.ns_min_count },
|
|
max: -> { Setting.ns_max_count }
|
|
}
|
|
|
|
validates :dnskeys, object_count: {
|
|
min: -> { Setting.dnskeys_min_count },
|
|
max: -> { Setting.dnskeys_max_count }
|
|
}
|
|
|
|
validates :admin_domain_contacts, object_count: {
|
|
min: -> { Setting.admin_contacts_min_count },
|
|
max: -> { Setting.admin_contacts_max_count }
|
|
}
|
|
|
|
validates :tech_domain_contacts, object_count: {
|
|
min: -> { Setting.tech_contacts_min_count },
|
|
max: -> { Setting.tech_contacts_max_count }
|
|
}
|
|
|
|
validates :nameservers, uniqueness_multi: {
|
|
attribute: 'hostname'
|
|
}
|
|
|
|
validates :tech_domain_contacts, uniqueness_multi: {
|
|
attribute: 'contact_code_cache'
|
|
}
|
|
|
|
validates :admin_domain_contacts, uniqueness_multi: {
|
|
attribute: 'contact_code_cache'
|
|
}
|
|
|
|
validates :domain_statuses, uniqueness_multi: {
|
|
attribute: 'value'
|
|
}
|
|
|
|
validates :dnskeys, uniqueness_multi: {
|
|
attribute: 'public_key'
|
|
}
|
|
|
|
validate :validate_nameserver_ips
|
|
|
|
validate :statuses_uniqueness
|
|
def statuses_uniqueness
|
|
return if statuses.uniq == statuses
|
|
errors.add(:statuses, :taken)
|
|
end
|
|
|
|
attr_accessor :registrant_typeahead, :update_me, :deliver_emails,
|
|
:epp_pending_update, :epp_pending_delete, :reserved_pw
|
|
|
|
def subordinate_nameservers
|
|
nameservers.select { |x| x.hostname.end_with?(name) }
|
|
end
|
|
|
|
def delegated_nameservers
|
|
nameservers.select { |x| !x.hostname.end_with?(name) }
|
|
end
|
|
|
|
def admin_change_prohibited?
|
|
statuses.include? DomainStatus::SERVER_ADMIN_CHANGE_PROHIBITED
|
|
end
|
|
|
|
def tech_change_prohibited?
|
|
statuses.include? DomainStatus::SERVER_TECH_CHANGE_PROHIBITED
|
|
end
|
|
|
|
def self.clean_expired_pendings
|
|
ActiveSupport::Deprecation.instance.deprecation_warning(DomainCron, __method__)
|
|
DomainCron.send(__method__)
|
|
end
|
|
|
|
def self.start_redemption_grace_period
|
|
ActiveSupport::Deprecation.instance.deprecation_warning(DomainCron, __method__)
|
|
DomainCron.send(__method__)
|
|
end
|
|
|
|
def self.start_delete_period
|
|
ActiveSupport::Deprecation.instance.deprecation_warning(DomainCron, __method__)
|
|
DomainCron.send(__method__)
|
|
end
|
|
|
|
def self.destroy_delete_candidates
|
|
ActiveSupport::Deprecation.instance.deprecation_warning(DomainCron, __method__)
|
|
DomainCron.send(__method__)
|
|
end
|
|
|
|
class << self
|
|
def included
|
|
includes(
|
|
:registrant,
|
|
:registrar,
|
|
:nameservers,
|
|
:whois_record,
|
|
{ tech_contacts: :registrar },
|
|
{ admin_contacts: :registrar }
|
|
)
|
|
end
|
|
|
|
def nameserver_required?
|
|
Setting.nameserver_required
|
|
end
|
|
end
|
|
|
|
def name=(value)
|
|
value.strip!
|
|
value.downcase!
|
|
self[:name] = SimpleIDN.to_unicode(value)
|
|
self[:name_puny] = SimpleIDN.to_ascii(value)
|
|
self[:name_dirty] = value
|
|
end
|
|
|
|
# find by internationalized domain name
|
|
# internet domain name => ascii or puny, but db::domains.name is unicode
|
|
def self.find_by_idn(name)
|
|
domain = self.find_by_name name
|
|
if domain.blank? && name.include?('-')
|
|
unicode = SimpleIDN.to_unicode name # we have no index on domains.name_puny
|
|
domain = self.find_by_name unicode
|
|
end
|
|
domain
|
|
end
|
|
|
|
def roid
|
|
"EIS-#{id}"
|
|
end
|
|
|
|
def puny_label
|
|
name_puny.to_s.split('.').first
|
|
end
|
|
|
|
def registrant_typeahead
|
|
@registrant_typeahead || registrant.try(:name) || nil
|
|
end
|
|
|
|
def in_reserved_list?
|
|
@in_reserved_list ||= ReservedDomain.by_domain(name).any?
|
|
end
|
|
|
|
def pending_transfer
|
|
domain_transfers.find_by(status: DomainTransfer::PENDING)
|
|
end
|
|
|
|
def server_holdable?
|
|
return false if statuses.include?(DomainStatus::SERVER_HOLD)
|
|
return false if statuses.include?(DomainStatus::SERVER_MANUAL_INZONE)
|
|
true
|
|
end
|
|
|
|
def delete_candidateable?
|
|
return false if delete_at > Time.zone.now
|
|
return false if statuses.include?(DomainStatus::DELETE_CANDIDATE)
|
|
return false if statuses.include?(DomainStatus::SERVER_DELETE_PROHIBITED)
|
|
true
|
|
end
|
|
|
|
def renewable?
|
|
if Setting.days_to_renew_domain_before_expire != 0
|
|
# if you can renew domain at days_to_renew before domain expiration
|
|
if (expire_time.to_date - Date.today) + 1 > Setting.days_to_renew_domain_before_expire
|
|
return false
|
|
end
|
|
end
|
|
|
|
return false if statuses.include_any?(DomainStatus::DELETE_CANDIDATE, DomainStatus::PENDING_RENEW,
|
|
DomainStatus::PENDING_TRANSFER, DomainStatus::PENDING_DELETE,
|
|
DomainStatus::PENDING_UPDATE, DomainStatus::PENDING_DELETE_CONFIRMATION)
|
|
true
|
|
end
|
|
|
|
def poll_message!(message_key)
|
|
registrar.messages.create!(
|
|
body: "#{I18n.t(message_key)}: #{name}",
|
|
attached_obj_id: id,
|
|
attached_obj_type: self.class.to_s
|
|
)
|
|
end
|
|
|
|
def preclean_pendings
|
|
self.registrant_verification_token = nil
|
|
self.registrant_verification_asked_at = nil
|
|
end
|
|
|
|
def clean_pendings!
|
|
preclean_pendings
|
|
self.pending_json = {}
|
|
statuses.delete(DomainStatus::PENDING_DELETE_CONFIRMATION)
|
|
statuses.delete(DomainStatus::PENDING_UPDATE)
|
|
statuses.delete(DomainStatus::PENDING_DELETE)
|
|
status_notes[DomainStatus::PENDING_UPDATE] = ''
|
|
status_notes[DomainStatus::PENDING_DELETE] = ''
|
|
save
|
|
end
|
|
|
|
|
|
# state changes may be done low-level - no validation
|
|
# in this metod we still save PaperTrail log.
|
|
def clean_pendings_lowlevel
|
|
statuses.delete(DomainStatus::PENDING_DELETE_CONFIRMATION)
|
|
statuses.delete(DomainStatus::PENDING_UPDATE)
|
|
statuses.delete(DomainStatus::PENDING_DELETE)
|
|
|
|
status_notes[DomainStatus::PENDING_UPDATE] = ''
|
|
status_notes[DomainStatus::PENDING_DELETE] = ''
|
|
|
|
hash = {
|
|
registrant_verification_token: nil,
|
|
registrant_verification_asked_at: nil,
|
|
pending_json: {},
|
|
status_notes: status_notes,
|
|
statuses: statuses.presence || [DomainStatus::OK],
|
|
# need this column in order to update PaperTrail version properly
|
|
updated_at: Time.now.utc
|
|
}
|
|
|
|
# PaperTrail
|
|
self.attributes = hash
|
|
record_update
|
|
clear_version_instance!
|
|
reset_transaction_id
|
|
|
|
update_columns(hash)
|
|
end
|
|
|
|
def pending_update!
|
|
return true if pending_update?
|
|
self.epp_pending_update = true # for epp
|
|
|
|
return true unless registrant_verification_asked?
|
|
pending_json_cache = pending_json
|
|
token = registrant_verification_token
|
|
asked_at = registrant_verification_asked_at
|
|
new_registrant_id = registrant.id
|
|
new_registrant_email = registrant.email
|
|
new_registrant_name = registrant.name
|
|
|
|
RegistrantChangeConfirmEmailJob.enqueue(id, new_registrant_id)
|
|
RegistrantChangeNoticeEmailJob.enqueue(id, new_registrant_id)
|
|
|
|
reload
|
|
|
|
self.pending_json = pending_json_cache
|
|
self.registrant_verification_token = token
|
|
self.registrant_verification_asked_at = asked_at
|
|
set_pending_update
|
|
touch_always_version
|
|
pending_json['new_registrant_id'] = new_registrant_id
|
|
pending_json['new_registrant_email'] = new_registrant_email
|
|
pending_json['new_registrant_name'] = new_registrant_name
|
|
|
|
# This pending_update! method is triggered by before_update
|
|
# Note, all before_save callbacks are executed before before_update,
|
|
# thus automatic statuses has already executed by this point
|
|
# and we need to trigger automatic statuses manually (second time).
|
|
manage_automatic_statuses
|
|
end
|
|
|
|
# rubocop: disable Metrics/CyclomaticComplexity
|
|
def registrant_update_confirmable?(token)
|
|
return false if (statuses & [DomainStatus::FORCE_DELETE, DomainStatus::DELETE_CANDIDATE]).any?
|
|
return false unless pending_update?
|
|
return false unless registrant_verification_asked?
|
|
return false unless registrant_verification_token == token
|
|
true
|
|
end
|
|
|
|
def registrant_delete_confirmable?(token)
|
|
return false unless pending_delete?
|
|
return false unless registrant_verification_asked?
|
|
return false unless registrant_verification_token == token
|
|
true
|
|
end
|
|
# rubocop: enable Metrics/CyclomaticComplexity
|
|
|
|
def registrant_verification_asked?
|
|
registrant_verification_asked_at.present? && registrant_verification_token.present?
|
|
end
|
|
|
|
def registrant_verification_asked!(frame_str, current_user_id)
|
|
pending_json['frame'] = frame_str
|
|
pending_json['current_user_id'] = current_user_id
|
|
self.registrant_verification_asked_at = Time.zone.now
|
|
self.registrant_verification_token = SecureRandom.hex(42)
|
|
end
|
|
|
|
def pending_delete!
|
|
return true if pending_delete?
|
|
self.epp_pending_delete = true # for epp
|
|
|
|
# TODO: if this were to ever return true, that would be wrong. EPP would report sucess pending
|
|
return true unless registrant_verification_asked?
|
|
pending_delete_confirmation!
|
|
save(validate: false) # should check if this did succeed
|
|
|
|
DomainDeleteConfirmEmailJob.enqueue(id)
|
|
end
|
|
|
|
def cancel_pending_delete
|
|
statuses.delete DomainStatus::PENDING_DELETE_CONFIRMATION
|
|
statuses.delete DomainStatus::PENDING_DELETE
|
|
self.delete_at = nil
|
|
end
|
|
|
|
def pricelist(operation_category, period_i = nil, unit = nil)
|
|
period_i ||= period
|
|
unit ||= period_unit
|
|
|
|
zone_name = name.split('.').drop(1).join('.')
|
|
zone = DNS::Zone.find_by(origin: zone_name)
|
|
|
|
duration = "P#{period_i}#{unit.upcase}"
|
|
|
|
Billing::Price.price_for(zone, operation_category, duration)
|
|
end
|
|
|
|
### VALIDATIONS ###
|
|
|
|
def validate_nameserver_ips
|
|
nameservers.to_a.reject(&:marked_for_destruction?).each do |ns|
|
|
next unless ns.hostname.end_with?(".#{name}")
|
|
next if ns.ipv4.present? || ns.ipv6.present?
|
|
|
|
errors.add(:nameservers, :invalid) if errors[:nameservers].blank?
|
|
ns.errors.add(:ipv4, :blank)
|
|
end
|
|
end
|
|
|
|
# used for highlighting form tabs
|
|
def parent_valid?
|
|
assoc_errors = errors.keys.select { |x| x.match(/\./) }
|
|
(errors.keys - assoc_errors).empty?
|
|
end
|
|
|
|
## SHARED
|
|
|
|
def name_in_wire_format
|
|
res = ''
|
|
parts = name_puny.split('.')
|
|
parts.each do |x|
|
|
res += format('%02X', x.length) # length of label in hex
|
|
res += x.each_byte.map { |b| format('%02X', b) }.join # label
|
|
end
|
|
|
|
res += '00'
|
|
|
|
res
|
|
end
|
|
|
|
def to_s
|
|
name
|
|
end
|
|
|
|
def pending_registrant
|
|
return '' if pending_json.blank?
|
|
return '' if pending_json['new_registrant_id'].blank?
|
|
Registrant.find_by(id: pending_json['new_registrant_id'])
|
|
end
|
|
|
|
def set_graceful_expired
|
|
self.outzone_at = expire_time + self.class.expire_warning_period
|
|
self.delete_at = outzone_at + self.class.redemption_grace_period
|
|
self.statuses |= [DomainStatus::EXPIRED]
|
|
end
|
|
|
|
def pending_update?
|
|
statuses.include?(DomainStatus::PENDING_UPDATE) && !statuses.include?(DomainStatus::FORCE_DELETE)
|
|
end
|
|
|
|
# depricated not used, not valid
|
|
def update_prohibited?
|
|
pending_update_prohibited? && pending_delete_prohibited?
|
|
end
|
|
|
|
# public api
|
|
def delete_prohibited?
|
|
statuses.include?(DomainStatus::FORCE_DELETE)
|
|
end
|
|
|
|
# special handling for admin changing status
|
|
def admin_status_update(update)
|
|
# check for deleted status
|
|
statuses.each do |s|
|
|
unless update.include? s
|
|
case s
|
|
when DomainStatus::PENDING_DELETE
|
|
self.delete_at = nil
|
|
when DomainStatus::SERVER_MANUAL_INZONE # removal causes server hold to set
|
|
self.outzone_at = Time.zone.now if self.force_delete_at.present?
|
|
when DomainStatus::DomainStatus::EXPIRED # removal causes server hold to set
|
|
self.outzone_at = self.expire_time + 15.day
|
|
when DomainStatus::DomainStatus::SERVER_HOLD # removal causes server hold to set
|
|
self.outzone_at = nil
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
def pending_update_prohibited?
|
|
(statuses_was & DomainStatus::UPDATE_PROHIBIT_STATES).present?
|
|
end
|
|
|
|
def set_pending_update
|
|
if pending_update_prohibited?
|
|
logger.info "DOMAIN STATUS UPDATE ISSUE ##{id}: PENDING_UPDATE not allowed to set. [#{statuses}]"
|
|
return nil
|
|
end
|
|
statuses << DomainStatus::PENDING_UPDATE
|
|
end
|
|
|
|
def pending_delete?
|
|
(statuses & [DomainStatus::PENDING_DELETE_CONFIRMATION, DomainStatus::PENDING_DELETE]).any?
|
|
end
|
|
|
|
def pending_delete_confirmation?
|
|
statuses.include? DomainStatus::PENDING_DELETE_CONFIRMATION
|
|
end
|
|
|
|
def pending_delete_confirmation!
|
|
statuses << DomainStatus::PENDING_DELETE_CONFIRMATION unless pending_delete_prohibited?
|
|
end
|
|
|
|
def pending_delete_prohibited?
|
|
(statuses_was & DomainStatus::DELETE_PROHIBIT_STATES).present?
|
|
end
|
|
|
|
# let's use positive method names
|
|
def pending_deletable?
|
|
!pending_delete_prohibited?
|
|
end
|
|
|
|
def set_pending_delete
|
|
if pending_delete_prohibited?
|
|
logger.info "DOMAIN STATUS UPDATE ISSUE ##{id}: PENDING_DELETE not allowed to set. [#{statuses}]"
|
|
return nil
|
|
end
|
|
statuses << DomainStatus::PENDING_DELETE
|
|
end
|
|
|
|
def set_server_hold
|
|
statuses << DomainStatus::SERVER_HOLD
|
|
self.outzone_at = Time.current
|
|
end
|
|
|
|
# rubocop: disable Metrics/CyclomaticComplexity
|
|
# rubocop: disable Metrics/PerceivedComplexity
|
|
def manage_automatic_statuses
|
|
if !self.class.nameserver_required?
|
|
deactivate if nameservers.reject(&:marked_for_destruction?).empty?
|
|
activate if nameservers.reject(&:marked_for_destruction?).size >= Setting.ns_min_count
|
|
end
|
|
|
|
if statuses.empty? && valid?
|
|
statuses << DomainStatus::OK
|
|
elsif (statuses.length > 1 && active?) || !valid?
|
|
statuses.delete(DomainStatus::OK)
|
|
end
|
|
|
|
p_d = statuses.include?(DomainStatus::PENDING_DELETE)
|
|
s_h = (statuses & [DomainStatus::SERVER_MANUAL_INZONE, DomainStatus::SERVER_HOLD]).empty?
|
|
statuses << DomainStatus::SERVER_HOLD if p_d && s_h
|
|
end
|
|
# rubocop: enable Metrics/CyclomaticComplexity
|
|
# rubocop: enable Metrics/PerceivedComplexity
|
|
|
|
def children_log
|
|
log = HashWithIndifferentAccess.new
|
|
log[:admin_contacts] = admin_contact_ids
|
|
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
|
|
end
|
|
|
|
def update_whois_record
|
|
UpdateWhoisRecordJob.enqueue name, 'domain'
|
|
end
|
|
|
|
def status_notes_array=(notes)
|
|
self.status_notes = {}
|
|
notes ||= []
|
|
statuses.each_with_index do |status, i|
|
|
status_notes[status] = notes[i]
|
|
end
|
|
end
|
|
|
|
def send_mail(action)
|
|
DomainMailer.send(action, DomainMailModel.new(self).send(action)).deliver
|
|
end
|
|
|
|
def admin_contact_names
|
|
admin_contacts.names
|
|
end
|
|
|
|
def admin_contact_emails
|
|
admin_contacts.emails
|
|
end
|
|
|
|
def tech_contact_names
|
|
tech_contacts.names
|
|
end
|
|
|
|
def nameserver_hostnames
|
|
nameservers.hostnames
|
|
end
|
|
|
|
def primary_contact_emails
|
|
(admin_contact_emails << registrant_email).uniq
|
|
end
|
|
|
|
def new_registrant_email
|
|
pending_json['new_registrant_email']
|
|
end
|
|
|
|
def new_registrant_id
|
|
pending_json['new_registrant_id']
|
|
end
|
|
|
|
def as_json(_options)
|
|
hash = super
|
|
hash['auth_info'] = hash.delete('transfer_code') # API v1 requirement
|
|
hash
|
|
end
|
|
|
|
def self.to_csv
|
|
CSV.generate do |csv|
|
|
csv << column_names
|
|
all.each do |domain|
|
|
csv << domain.attributes.values_at(*column_names)
|
|
end
|
|
end
|
|
end
|
|
|
|
def self.pdf(html)
|
|
kit = PDFKit.new(html)
|
|
kit.to_pdf
|
|
end
|
|
|
|
def self.expire_warning_period
|
|
Setting.expire_warning_period.days
|
|
end
|
|
|
|
def self.redemption_grace_period
|
|
Setting.redemption_grace_period.days
|
|
end
|
|
|
|
def self.outzone_candidates
|
|
where("#{attribute_alias(:outzone_time)} < ?", Time.zone.now)
|
|
end
|
|
|
|
def self.delete_candidates
|
|
where("#{attribute_alias(:delete_time)} < ?", Time.zone.now)
|
|
end
|
|
|
|
def self.uses_zone?(zone)
|
|
exists?(["name ILIKE ?", "%.#{zone.origin}"])
|
|
end
|
|
end
|
|
# rubocop: enable Metrics/ClassLength
|