From 6383dede4b51c52ea84095ec3e60ea34e0370c3f Mon Sep 17 00:00:00 2001 From: Alex Sherman Date: Tue, 6 Apr 2021 09:20:43 +0500 Subject: [PATCH 1/3] Add prototype of FD lifting interaction --- .../domains/force_delete_lift/base.rb | 31 +++++++++++++++++++ app/models/email_address_verification.rb | 8 +++-- 2 files changed, 36 insertions(+), 3 deletions(-) create mode 100644 app/interactions/domains/force_delete_lift/base.rb diff --git a/app/interactions/domains/force_delete_lift/base.rb b/app/interactions/domains/force_delete_lift/base.rb new file mode 100644 index 000000000..37826dfe1 --- /dev/null +++ b/app/interactions/domains/force_delete_lift/base.rb @@ -0,0 +1,31 @@ +module Domains + module ForceDeleteLift + class Base < ActiveInteraction::Base + string :email, + description: 'Email to check if ForceDelete needs to be lifted' + + def execute + domain_contacts = Contact.where(email: email).map(&:domain_contacts).flatten + registrant_ids = Registrant.where(email: email).pluck(:id) + + domains = domain_contacts.map(&:domain).flatten + + Domain.where(registrant_id: registrant_ids) + + domains.each { |domain| lift_force_delete(domain) if force_delete_condition(domain) } + end + + private + + def lift_force_delete(domain) + domain.cancel_force_delete + end + + def force_delete_condition(domain) + domain.force_delete_scheduled? && + domain.template_name == 'invalid_email' && + domain.contacts.all? { |contact| contact.email_verification.verified? } && + domain.registrant.email_verification.verified? + end + end + end +end diff --git a/app/models/email_address_verification.rb b/app/models/email_address_verification.rb index c54cd4224..abb1ef423 100644 --- a/app/models/email_address_verification.rb +++ b/app/models/email_address_verification.rb @@ -42,9 +42,11 @@ class EmailAddressVerification < ApplicationRecord end def check_force_delete - return unless failed? - - Domains::ForceDeleteEmail::Base.run(email: email) + if failed? + Domains::ForceDeleteEmail::Base.run(email: email) + else + Domains::ForceDeleteLift::Base.run(email: email) + end end def verify From 39d392696a319b6908ab2617151f4d52da61c432 Mon Sep 17 00:00:00 2001 From: Alex Sherman Date: Tue, 6 Apr 2021 10:15:54 +0500 Subject: [PATCH 2/3] Add a job to check if domain needs to be fd-lifted --- .../domains/force_delete_lift/base.rb | 18 +++++++------ app/jobs/check_force_delete_lift.rb | 12 +++++++++ app/models/concerns/email_verifable.rb | 8 +++--- app/models/email_address_verification.rb | 8 +++--- test/models/domain/force_delete_test.rb | 27 +++++++++++++++++++ 5 files changed, 55 insertions(+), 18 deletions(-) create mode 100644 app/jobs/check_force_delete_lift.rb diff --git a/app/interactions/domains/force_delete_lift/base.rb b/app/interactions/domains/force_delete_lift/base.rb index 37826dfe1..2aaa8930c 100644 --- a/app/interactions/domains/force_delete_lift/base.rb +++ b/app/interactions/domains/force_delete_lift/base.rb @@ -1,17 +1,14 @@ module Domains module ForceDeleteLift class Base < ActiveInteraction::Base - string :email, - description: 'Email to check if ForceDelete needs to be lifted' + object :domain, + class: Domain, + description: 'Domain to check if ForceDelete needs to be listed' def execute - domain_contacts = Contact.where(email: email).map(&:domain_contacts).flatten - registrant_ids = Registrant.where(email: email).pluck(:id) + prepare_email_verifications(domain) - domains = domain_contacts.map(&:domain).flatten + - Domain.where(registrant_id: registrant_ids) - - domains.each { |domain| lift_force_delete(domain) if force_delete_condition(domain) } + lift_force_delete(domain) if force_delete_condition(domain) end private @@ -26,6 +23,11 @@ module Domains domain.contacts.all? { |contact| contact.email_verification.verified? } && domain.registrant.email_verification.verified? end + + def prepare_email_verifications(domain) + domain.registrant.email_verification.verify + domain.contacts.each { |contact| contact.email_verification.verify } + end end end end diff --git a/app/jobs/check_force_delete_lift.rb b/app/jobs/check_force_delete_lift.rb new file mode 100644 index 000000000..43c2666b4 --- /dev/null +++ b/app/jobs/check_force_delete_lift.rb @@ -0,0 +1,12 @@ +class CheckForceDeleteLift < ApplicationJob + queue_as :default + + def perform + domains = Domain.where("force_delete_data->'template_name' = ?", 'invalid_email') + .where("force_delete_data->'force_delete_type' = ?", 'soft') + + domains.each do |domain| + Domains::ForceDeleteLift::Base.run(domain: domain) + end + end +end diff --git a/app/models/concerns/email_verifable.rb b/app/models/concerns/email_verifable.rb index 457555b44..1da52dcf3 100644 --- a/app/models/concerns/email_verifable.rb +++ b/app/models/concerns/email_verifable.rb @@ -2,16 +2,14 @@ module EmailVerifable extend ActiveSupport::Concern def email_verification - @email_verification ||= EmailAddressVerification.find_or_create_by(email: unicode_email, - domain: domain(email)) + EmailAddressVerification.find_or_create_by(email: unicode_email, domain: domain(email)) end def billing_email_verification return unless attribute_names.include?('billing_email') - @billing_email_verification ||= EmailAddressVerification - .find_or_create_by(email: unicode_billing_email, - domain: domain(billing_email)) + EmailAddressVerification.find_or_create_by(email: unicode_billing_email, + domain: domain(billing_email)) end def email_verification_failed? diff --git a/app/models/email_address_verification.rb b/app/models/email_address_verification.rb index abb1ef423..c54cd4224 100644 --- a/app/models/email_address_verification.rb +++ b/app/models/email_address_verification.rb @@ -42,11 +42,9 @@ class EmailAddressVerification < ApplicationRecord end def check_force_delete - if failed? - Domains::ForceDeleteEmail::Base.run(email: email) - else - Domains::ForceDeleteLift::Base.run(email: email) - end + return unless failed? + + Domains::ForceDeleteEmail::Base.run(email: email) end def verify diff --git a/test/models/domain/force_delete_test.rb b/test/models/domain/force_delete_test.rb index 837ad3adc..ca9f3b24f 100644 --- a/test/models/domain/force_delete_test.rb +++ b/test/models/domain/force_delete_test.rb @@ -384,6 +384,33 @@ class ForceDeleteTest < ActionMailer::TestCase assert notification.text.include? asserted_text end + def test_lifts_force_delete_if_contact_fixed + @domain.update(valid_to: Time.zone.parse('2012-08-05')) + assert_not @domain.force_delete_scheduled? + travel_to Time.zone.parse('2010-07-05') + email = 'some@strangesentence@internet.ee' + + Truemail.configure.default_validation_type = :regex + + contact = @domain.admin_contacts.first + contact.update_attribute(:email, email) + contact.email_verification.verify + + assert contact.email_verification_failed? + + @domain.reload + + assert @domain.force_delete_scheduled? + contact.update_attribute(:email, 'aaa@bbb.com') + contact.email_verification.verify + + assert_not contact.email_verification_failed? + CheckForceDeleteLift.perform_now + + @domain.reload + assert_not @domain.force_delete_scheduled? + end + def prepare_bounced_email_address(email) @bounced_mail = BouncedMailAddress.new @bounced_mail.email = email From 95a2b705b4042630420854aed6d51bb538b22e8a Mon Sep 17 00:00:00 2001 From: Alex Sherman Date: Tue, 6 Apr 2021 12:36:32 +0500 Subject: [PATCH 3/3] Add checking if any of domain emails still got bounce related --- .../domains/force_delete_lift/base.rb | 18 +++++++++++-- app/models/domain.rb | 4 +++ test/models/domain/force_delete_test.rb | 26 +++++++++++++++++++ 3 files changed, 46 insertions(+), 2 deletions(-) diff --git a/app/interactions/domains/force_delete_lift/base.rb b/app/interactions/domains/force_delete_lift/base.rb index 2aaa8930c..cb333a9dc 100644 --- a/app/interactions/domains/force_delete_lift/base.rb +++ b/app/interactions/domains/force_delete_lift/base.rb @@ -19,8 +19,17 @@ module Domains def force_delete_condition(domain) domain.force_delete_scheduled? && - domain.template_name == 'invalid_email' && - domain.contacts.all? { |contact| contact.email_verification.verified? } && + template_of_invalid_email?(domain) && + contact_emails_valid?(domain) && + bounces_absent?(domain) + end + + def template_of_invalid_email?(domain) + domain.template_name == 'invalid_email' + end + + def contact_emails_valid?(domain) + domain.contacts.all? { |contact| contact.email_verification.verified? } && domain.registrant.email_verification.verified? end @@ -28,6 +37,11 @@ module Domains domain.registrant.email_verification.verify domain.contacts.each { |contact| contact.email_verification.verify } end + + def bounces_absent?(domain) + emails = domain.all_related_emails + BouncedMailAddress.where(email: emails).empty? + end end end end diff --git a/app/models/domain.rb b/app/models/domain.rb index 3deaf594b..91b91584f 100644 --- a/app/models/domain.rb +++ b/app/models/domain.rb @@ -668,6 +668,10 @@ class Domain < ApplicationRecord end end + def all_related_emails + (admin_contacts.emails + tech_contacts.emails + [registrant.email]).uniq + end + def force_delete_contact_emails (primary_contact_emails + tech_contacts.pluck(:email) + ["info@#{name}", "#{prepared_domain_name}@#{name}"]).uniq diff --git a/test/models/domain/force_delete_test.rb b/test/models/domain/force_delete_test.rb index ca9f3b24f..de28962ec 100644 --- a/test/models/domain/force_delete_test.rb +++ b/test/models/domain/force_delete_test.rb @@ -410,6 +410,32 @@ class ForceDeleteTest < ActionMailer::TestCase @domain.reload assert_not @domain.force_delete_scheduled? end + def test_lifts_force_delete_after_bounce_changes + @domain.update(valid_to: Time.zone.parse('2012-08-05')) + assert_not @domain.force_delete_scheduled? + travel_to Time.zone.parse('2010-07-05') + email = @domain.registrant.email + asserted_text = "Invalid email: #{email}" + + prepare_bounced_email_address(email) + + @domain.reload + + assert @domain.force_delete_scheduled? + assert_equal 'invalid_email', @domain.template_name + assert_equal Date.parse('2010-09-19'), @domain.force_delete_date.to_date + assert_equal Date.parse('2010-08-05'), @domain.force_delete_start.to_date + notification = @domain.registrar.notifications.last + assert notification.text.include? asserted_text + + @domain.registrant.update(email: 'aaa@bbb.com') + @domain.registrant.email_verification.verify + assert_not @domain.registrant.email_verification_failed? + CheckForceDeleteLift.perform_now + + @domain.reload + assert_not @domain.force_delete_scheduled? + end def prepare_bounced_email_address(email) @bounced_mail = BouncedMailAddress.new