Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix check force delete lift bug #2418

Merged
merged 11 commits into from
Oct 12, 2022
36 changes: 2 additions & 34 deletions app/jobs/check_force_delete_job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,41 +3,9 @@ def perform(contact_ids)
contacts = Contact.find(contact_ids)

contacts.each do |contact|
email = contact.email
next unless contact.need_to_start_force_delete?

if contact.need_to_start_force_delete?
Domains::ForceDeleteEmail::Base.run(email: email)
elsif contact.need_to_lift_force_delete?
domain_list(email).each { |domain| refresh_status_notes(contact, domain) }
end
Domains::ForceDeleteEmail::Base.run(email: contact.email)
end
end

private

def refresh_status_notes(contact, domain)
force_delete_emails = domain.status_notes[DomainStatus::FORCE_DELETE]
return unless force_delete_emails

force_delete_emails.slice!(contact.email_history)
force_delete_emails.lstrip!
domain.save(validate: false)

notify_registrar(domain) unless force_delete_emails.empty?
end

def domain_list(email)
domain_contacts = Contact.where(email: email).map(&:domain_contacts).flatten
registrant_ids = Registrant.where(email: email).pluck(:id)

(domain_contacts.map(&:domain).flatten + Domain.where(registrant_id: registrant_ids)).uniq
end

def notify_registrar(domain)
domain.registrar.notifications.create!(text: I18n.t('force_delete_auto_email',
domain_name: domain.name,
outzone_date: domain.outzone_date,
purge_date: domain.purge_date,
email: domain.status_notes[DomainStatus::FORCE_DELETE]))
end
end
35 changes: 35 additions & 0 deletions app/models/validation_event.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ class ValidationEvent < ApplicationRecord
scope :smtp, -> { where('event_data @> ?', { 'check_level': 'smtp' }.to_json) }
scope :by_object, ->(object) { where(validation_eventable: object) }

after_create :check_force_delete_lift

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that is a bad idea.

The last time we put checks for force delete and lift force delete into callbacks, firstly there were performance issues, and secondly, unexpected behavior happened when lift force delete worked in a situation where it was not supposed to.

In addition, there is an opinion that using callback is not a good practice in terms of support, code testing. But that's just an opinion, everyone has their own opinion :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll add one more comment to make it a little clearer.

We have a validation_event model, we also have a verify_email rake task. When we run this task, the mail is validated and the results are written to the validation_event table. The problem is that checking mail is a very productive operation. And if, in addition to checking mail, writing the result data, you also check for check force delete lift, this will be a VERY highly productive operation. My idea is to remove after_create :check_force_delete_lift. It should not be launched every time after checking each email and record results to validation event table, because it takes a LOT of resources. It is enough that all emails are checked and the results are recorded in the validation table. We can run the Force Delete check and removal separately, we don’t need to run the force delete lift check in the valiation_event model

def self.validated_ids_by(klass)
old_records
.successful
Expand All @@ -57,4 +59,37 @@ def event_type
def object
validation_eventable
end

private

def check_force_delete_lift
return unless object.need_to_lift_force_delete?

domain_list.each { |domain| refresh_status_notes(domain) }
end

def refresh_status_notes(domain)
return unless domain.status_notes[DomainStatus::FORCE_DELETE]

domain.status_notes[DomainStatus::FORCE_DELETE].slice!(object.email_history)
domain.status_notes[DomainStatus::FORCE_DELETE].lstrip!
domain.save(validate: false)

notify_registrar(domain) unless domain.status_notes[DomainStatus::FORCE_DELETE].empty?
end

def domain_list
domain_contacts = Contact.where(email: email).map(&:domain_contacts).flatten
registrant_ids = Registrant.where(email: email).pluck(:id)

(domain_contacts.map(&:domain).flatten + Domain.where(registrant_id: registrant_ids)).uniq
end

def notify_registrar(domain)
domain.registrar.notifications.create!(text: I18n.t('force_delete_auto_email',
domain_name: domain.name,
outzone_date: domain.outzone_date,
purge_date: domain.purge_date,
email: domain.status_notes[DomainStatus::FORCE_DELETE]))
end
end
3 changes: 1 addition & 2 deletions lib/tasks/check_force_delete.rake
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ task check_force_delete: :environment do
validations = ValidationEvent.failed.where(validation_eventable_type: 'Contact').uniq(&:validation_eventable_id)

invalid_contact_ids = validations.select do |validation|
contact = validation.validation_eventable
contact.need_to_start_force_delete? || contact.need_to_lift_force_delete?
validation.validation_eventable.need_to_start_force_delete?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

where did you hide the check for need_to_lift_force_delete? how will he understand that force delete can be removed on a specific domain?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added on the validation_event after create callback. It's the way we did before I refactor it
I moved back because it seems that after updating to a valid email, the domain didn't have the FD status notes refreshed

end.pluck(:validation_eventable_id)

CheckForceDeleteJob.perform_later(invalid_contact_ids) if invalid_contact_ids.present?
Expand Down
23 changes: 23 additions & 0 deletions test/models/domain/force_delete_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -517,6 +517,29 @@ def test_lifts_force_delete_after_bounce_changes
assert_not @domain.force_delete_scheduled?
end

def test_lifts_force_delete_after_changing_to_valid_email
@domain.update(valid_to: Time.zone.parse('2012-08-05'))
assert_not @domain.force_delete_scheduled?
travel_to Time.zone.parse('2010-07-05')
@domain.registrant.update_attribute(:email, '`@internet.ee')
3.times { @domain.registrant.verify_email }
perform_check_force_delete_job(@domain.registrant.id)
@domain.reload

assert @domain.force_delete_scheduled?

@domain.registrant.update(email: '[email protected]')
@domain.registrant.verify_email
@domain.reload

assert @domain.registrant.need_to_lift_force_delete?

perform_enqueued_jobs { 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
Expand Down