mirror of
https://github.com/internetee/registry.git
synced 2025-07-31 15:06:23 +02:00
Refactored and corrected code for domain force delete
This commit is contained in:
parent
316f00cadc
commit
d3bca1434c
10 changed files with 223 additions and 259 deletions
|
@ -16,19 +16,28 @@ module Actions
|
|||
end
|
||||
|
||||
def resolve_a_and_aaaa_records(dns_servers:, email_domain:, value:)
|
||||
Resolv::DNS.open({ nameserver: dns_servers }) do |dns|
|
||||
dns.timeouts = ENV['a_and_aaaa_validation_timeout'].to_i || 1
|
||||
ress = nil
|
||||
Resolv::DNS.open(nameserver: dns_servers, ndots: 1, search: []) do |dns|
|
||||
dns.timeouts = (ENV['a_and_aaaa_validation_timeout'] || 1).to_i
|
||||
|
||||
case value
|
||||
when 'A'
|
||||
ress = dns.getresources email_domain, Resolv::DNS::Resource::IN::A
|
||||
resolve_a_records(dns: dns, domain: email_domain)
|
||||
when 'AAAA'
|
||||
ress = dns.getresources email_domain, Resolv::DNS::Resource::IN::AAAA
|
||||
resolve_aaaa_records(dns: dns, domain: email_domain)
|
||||
else
|
||||
[]
|
||||
end
|
||||
|
||||
ress.map(&:address)
|
||||
end
|
||||
end
|
||||
|
||||
def resolve_a_records(dns:, domain:)
|
||||
resources = dns.getresources(domain, Resolv::DNS::Resource::IN::A)
|
||||
resources.map(&:address)
|
||||
end
|
||||
|
||||
def resolve_aaaa_records(dns:, domain:)
|
||||
resources = dns.getresources(domain, Resolv::DNS::Resource::IN::AAAA)
|
||||
resources.map(&:address)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,6 +2,8 @@ module Actions
|
|||
class EmailCheck
|
||||
attr_reader :email, :validation_eventable, :check_level
|
||||
|
||||
SAVE_RESULTS_BATCH_SIZE = 500
|
||||
|
||||
def initialize(email:, validation_eventable:, check_level: nil)
|
||||
@email = email
|
||||
@validation_eventable = validation_eventable
|
||||
|
@ -11,7 +13,7 @@ module Actions
|
|||
def call
|
||||
result = check_email(email)
|
||||
save_result(result)
|
||||
result.success ? log_success : log_failure(result)
|
||||
handle_logging(result)
|
||||
result.success
|
||||
end
|
||||
|
||||
|
@ -22,55 +24,63 @@ module Actions
|
|||
end
|
||||
|
||||
def calculate_check_level
|
||||
Rails.env.test? && check_level == 'smtp' ? :mx : check_level.to_sym
|
||||
check_level_sym = check_level.to_sym
|
||||
return :mx if Rails.env.test? && check_level_sym == :smtp
|
||||
|
||||
check_level_sym
|
||||
end
|
||||
|
||||
def filtering_old_failed_records(result, contact)
|
||||
def filter_old_failed_records(result, contact)
|
||||
ValidationEvent::INVALID_EVENTS_COUNT_BY_LEVEL.each do |level, limit|
|
||||
handle_failed_records(contact: contact, check_level: level, limit: limit, success: result.success)
|
||||
end
|
||||
end
|
||||
|
||||
def handle_failed_records(contact:, check_level:, limit:, success:)
|
||||
if @check_level.to_sym == check_level && !success && contact.validation_events.count > limit
|
||||
contact.validation_events.order!(created_at: :asc)
|
||||
while contact.validation_events.count > limit
|
||||
contact.validation_events.first.destroy
|
||||
end
|
||||
end
|
||||
return unless @check_level.to_sym == check_level.to_sym && !success
|
||||
|
||||
excess_events_count = contact.validation_events.count - limit
|
||||
return unless excess_events_count.positive?
|
||||
|
||||
contact.validation_events.order(created_at: :asc).limit(excess_events_count).destroy_all
|
||||
end
|
||||
|
||||
def filtering_old_records(contact:, success:)
|
||||
return unless success
|
||||
|
||||
contact.validation_events.destroy_all
|
||||
def filter_old_records(contact:, success:)
|
||||
contact.validation_events.destroy_all if success
|
||||
end
|
||||
|
||||
def save_result(result)
|
||||
contacts = Contact.where(email: email)
|
||||
|
||||
if !result.success && @check_level == 'mx'
|
||||
result_validation = Actions::AAndAaaaEmailValidation.call(email: @email, value: 'A')
|
||||
output_a_and_aaaa_validation_results(email: @email, result: result_validation, type: 'A')
|
||||
|
||||
result_validation = Actions::AAndAaaaEmailValidation.call(email: @email, value: 'AAAA') if result_validation.empty?
|
||||
output_a_and_aaaa_validation_results(email: @email, result: result_validation, type: 'AAAA')
|
||||
result.success = result_validation.present?
|
||||
end
|
||||
handle_mx_validation(result) if !result.success && @check_level == 'mx'
|
||||
|
||||
result.configuration = nil
|
||||
|
||||
contacts.find_in_batches(batch_size: 500) do |contact_batches|
|
||||
contacts.find_in_batches(batch_size: SAVE_RESULTS_BATCH_SIZE) do |contact_batches|
|
||||
contact_batches.each do |contact|
|
||||
# methods should be in this order!
|
||||
filtering_old_records(contact: contact, success: result.success)
|
||||
contact.validation_events.create(validation_event_attrs(result))
|
||||
filtering_old_failed_records(result, contact)
|
||||
handle_saving_result(contact, result)
|
||||
end
|
||||
end
|
||||
rescue ActiveRecord::RecordNotSaved
|
||||
logger.info "Cannot save validation result for #{log_object_id}"
|
||||
true
|
||||
logger.info "Cannot save validation result for #{log_object_id}" and return true
|
||||
end
|
||||
|
||||
def handle_mx_validation(result)
|
||||
result_validation = Actions::AAndAaaaEmailValidation.call(email: email, value: 'A')
|
||||
output_a_and_aaaa_validation_results(email: email, result: result_validation, type: 'A')
|
||||
|
||||
if result_validation.empty?
|
||||
result_validation = Actions::AAndAaaaEmailValidation.call(email: email, value: 'AAAA')
|
||||
output_a_and_aaaa_validation_results(email: email, result: result_validation, type: 'AAAA')
|
||||
end
|
||||
|
||||
result.success = result_validation.present?
|
||||
end
|
||||
|
||||
def handle_saving_result(contact, result)
|
||||
filter_old_records(contact: contact, success: result.success)
|
||||
contact.validation_events.create!(validation_event_attrs(result))
|
||||
filter_old_failed_records(result, contact)
|
||||
end
|
||||
|
||||
def output_a_and_aaaa_validation_results(email:, result:, type:)
|
||||
|
@ -79,27 +89,6 @@ module Actions
|
|||
logger.info "Validated #{type} record for #{email}. Validation result - #{result}"
|
||||
end
|
||||
|
||||
def check_for_records_value(domain:, value:)
|
||||
result = nil
|
||||
dns_servers = ENV['dnssec_resolver_ips'].to_s.split(',').map(&:strip)
|
||||
|
||||
Resolv::DNS.open({ nameserver: dns_servers }) do |dns|
|
||||
timeouts = ENV['a_and_aaaa_validation_timeout'] || '1'
|
||||
dns.timeouts = timeouts.to_i
|
||||
ress = nil
|
||||
|
||||
case value
|
||||
when 'A'
|
||||
ress = dns.getresources domain, Resolv::DNS::Resource::IN::A
|
||||
when 'AAAA'
|
||||
ress = dns.getresources domain, Resolv::DNS::Resource::IN::AAAA
|
||||
end
|
||||
result = ress.map(&:address)
|
||||
end
|
||||
|
||||
result
|
||||
end
|
||||
|
||||
def validation_event_attrs(result)
|
||||
{
|
||||
event_data: event_data(result),
|
||||
|
@ -116,13 +105,13 @@ module Actions
|
|||
result.to_h.merge(check_level: check_level)
|
||||
end
|
||||
|
||||
def log_failure(result)
|
||||
logger.info "Failed to validate email #{email} for the #{log_object_id}."
|
||||
logger.info "Validation level #{check_level}, the result was #{result}"
|
||||
end
|
||||
|
||||
def log_success
|
||||
logger.info "Successfully validated email #{email} for the #{log_object_id}."
|
||||
def handle_logging(result)
|
||||
if result.success
|
||||
logger.info "Successfully validated email #{email} for #{log_object_id}."
|
||||
else
|
||||
logger.info "Failed to validate email #{email} for #{log_object_id}."
|
||||
logger.info "Validation level #{check_level}, the result was #{result}"
|
||||
end
|
||||
end
|
||||
|
||||
def log_object_id
|
||||
|
|
|
@ -16,25 +16,26 @@ module Domains
|
|||
end
|
||||
|
||||
def force_delete_condition(domain)
|
||||
domain.force_delete_scheduled? &&
|
||||
force_delete_scheduled?(domain) &&
|
||||
template_of_invalid_email?(domain) &&
|
||||
contact_emails_valid?(domain) &&
|
||||
bounces_absent?(domain)
|
||||
end
|
||||
|
||||
def force_delete_scheduled?(domain)
|
||||
domain.force_delete_scheduled?
|
||||
end
|
||||
|
||||
def template_of_invalid_email?(domain)
|
||||
domain.template_name == 'invalid_email'
|
||||
end
|
||||
|
||||
def contact_emails_valid?(domain)
|
||||
flag = nil
|
||||
|
||||
domain.contacts.each do |c|
|
||||
flag = c.need_to_lift_force_delete?
|
||||
return flag unless flag
|
||||
return false unless c.need_to_lift_force_delete?
|
||||
end
|
||||
|
||||
flag && domain.registrant.need_to_lift_force_delete?
|
||||
domain.registrant.need_to_lift_force_delete?
|
||||
end
|
||||
|
||||
def bounces_absent?(domain)
|
||||
|
|
|
@ -2,20 +2,31 @@ class CheckForceDeleteLift < ApplicationJob
|
|||
queue_as :default
|
||||
|
||||
def perform
|
||||
domains = Domain.where("(status_notes->'serverForceDelete') is not null")
|
||||
.select { |d| d.registrant.need_to_lift_force_delete? }
|
||||
domains = find_domains_to_lift_force_delete
|
||||
|
||||
handle_refresh_status(domains) if domains.present?
|
||||
domains = (domains + Domain.where("force_delete_data->'template_name' = ?", 'invalid_email')
|
||||
.where("force_delete_data->'force_delete_type' = ?", 'soft')).uniq
|
||||
|
||||
domains.each do |domain|
|
||||
domains_to_process = find_domains_to_process(domains)
|
||||
|
||||
domains_to_process.each do |domain|
|
||||
Domains::ForceDeleteLift::Base.run(domain: domain)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def find_domains_to_lift_force_delete
|
||||
Domain.where("'#{DomainStatus::FORCE_DELETE}' = ANY (statuses)")
|
||||
.select { |d| d.registrant.need_to_lift_force_delete? }
|
||||
end
|
||||
|
||||
def find_domains_to_process(domains)
|
||||
force_delete_template_domains = Domain.where("force_delete_data->'template_name' = ?", 'invalid_email')
|
||||
.where("force_delete_data->'force_delete_type' = ?", 'soft')
|
||||
|
||||
(domains + force_delete_template_domains).uniq
|
||||
end
|
||||
|
||||
def handle_refresh_status(domains)
|
||||
domains.each do |domain|
|
||||
registrant = domain.registrant
|
||||
|
|
|
@ -4,18 +4,16 @@ class VerifyEmailsJob < ApplicationJob
|
|||
def perform(email:, check_level: 'mx')
|
||||
contact = Contact.find_by(email: email)
|
||||
|
||||
return Rails.logger.info "No found #{email} contact" if contact.nil?
|
||||
return logger.info "Contact #{email} not found!" if contact.nil?
|
||||
|
||||
return unless filter_check_level(contact)
|
||||
return unless need_to_verify?(contact)
|
||||
|
||||
validate_check_level(check_level)
|
||||
action = Actions::EmailCheck.new(email: contact.email,
|
||||
validation_eventable: contact,
|
||||
check_level: check_level)
|
||||
action.call
|
||||
|
||||
logger.info "Trying to verify contact email #{email} with check_level #{check_level}"
|
||||
contact.verify_email(check_level: check_level)
|
||||
rescue StandardError => e
|
||||
logger.error e.message
|
||||
raise e
|
||||
handle_error(e)
|
||||
end
|
||||
|
||||
private
|
||||
|
@ -26,6 +24,16 @@ class VerifyEmailsJob < ApplicationJob
|
|||
raise StandardError, "Check level #{check_level} is invalid"
|
||||
end
|
||||
|
||||
def need_to_verify?(contact)
|
||||
return true unless contact.validation_events.any?
|
||||
|
||||
last_validation = contact.validation_events.last
|
||||
|
||||
return true if last_validation.successful? && last_validation.created_at < validation_expiry_date
|
||||
|
||||
last_validation.failed? && last_validation.event_data['check_level'] == 'regex' ? false : true
|
||||
end
|
||||
|
||||
def logger
|
||||
@logger ||= Rails.logger
|
||||
end
|
||||
|
@ -34,12 +42,12 @@ class VerifyEmailsJob < ApplicationJob
|
|||
ValidationEvent::VALID_CHECK_LEVELS
|
||||
end
|
||||
|
||||
def filter_check_level(contact)
|
||||
return true unless contact.validation_events.exists?
|
||||
def validation_expiry_date
|
||||
Time.zone.now - ValidationEvent::VALIDATION_PERIOD
|
||||
end
|
||||
|
||||
data = contact.validation_events.order(created_at: :asc).last
|
||||
return true if data.successful? && data.created_at < (Time.zone.now - ValidationEvent::VALIDATION_PERIOD)
|
||||
|
||||
!(data.failed? && data.event_data['check_level'] == 'regex')
|
||||
def handle_error(error)
|
||||
logger.error error.message
|
||||
raise error
|
||||
end
|
||||
end
|
||||
|
|
|
@ -16,21 +16,19 @@ module EmailVerifable
|
|||
end
|
||||
|
||||
def need_to_start_force_delete?
|
||||
flag = false
|
||||
ValidationEvent::INVALID_EVENTS_COUNT_BY_LEVEL.each do |level, count|
|
||||
flag = true if validation_events.count >= count && validate_email_data(level: level, count: count)
|
||||
ValidationEvent::INVALID_EVENTS_COUNT_BY_LEVEL.any? do |level, count|
|
||||
validation_events.count >= count && validate_email_data(level: level, count: count)
|
||||
end
|
||||
|
||||
flag
|
||||
end
|
||||
|
||||
def need_to_lift_force_delete?
|
||||
validation_events.failed.empty? ||
|
||||
ValidationEvent::REDEEM_EVENTS_COUNT_BY_LEVEL.any? do |level, count|
|
||||
validation_events.order(created_at: :desc).limit(count).all? do |event|
|
||||
event.check_level == level.to_s && event.successful?
|
||||
end
|
||||
end
|
||||
return true if validation_events.failed.empty?
|
||||
|
||||
ValidationEvent::REDEEM_EVENTS_COUNT_BY_LEVEL.any? do |level, count|
|
||||
validation_events.order(created_at: :desc)
|
||||
.limit(count)
|
||||
.all? { |event| event.check_level == level.to_s && event.successful? }
|
||||
end
|
||||
end
|
||||
|
||||
def correct_email_format
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue