diff --git a/app/interactions/domains/expire_period/base.rb b/app/interactions/domains/expire_period/base.rb new file mode 100644 index 000000000..eab8171bf --- /dev/null +++ b/app/interactions/domains/expire_period/base.rb @@ -0,0 +1,10 @@ +module Domains + module ExpirePeriod + class Base < ActiveInteraction::Base + def to_stdout(message) + time = Time.zone.now.utc + STDOUT << "#{time} - #{message}\n" unless Rails.env.test? + end + end + end +end diff --git a/app/interactions/domains/expire_period/process_expired.rb b/app/interactions/domains/expire_period/process_expired.rb new file mode 100644 index 000000000..595de1228 --- /dev/null +++ b/app/interactions/domains/expire_period/process_expired.rb @@ -0,0 +1,28 @@ +module Domains + module ExpirePeriod + class ProcessExpired < Base + object :domain, + class: Domain, + description: 'Domain to set expiration' + + def execute + set_graceful_expired + to_stdout("start_expire_period: ##{domain.id} (#{domain.name}) #{domain.changes}") + + saved = domain.save(validate: false) + + DomainExpireEmailJob.enqueue(domain.id, run_at: send_time) if saved + end + + def set_graceful_expired + domain.outzone_at = domain.expire_time + Domain.expire_warning_period + domain.delete_date = domain.outzone_at + Domain.redemption_grace_period + domain.statuses |= [DomainStatus::EXPIRED] + end + + def send_time + domain.valid_to + Setting.expiration_reminder_mail.to_i.days + end + end + end +end diff --git a/app/interactions/domains/expire_period/start.rb b/app/interactions/domains/expire_period/start.rb new file mode 100644 index 000000000..1ed2342f1 --- /dev/null +++ b/app/interactions/domains/expire_period/start.rb @@ -0,0 +1,19 @@ +module Domains + module ExpirePeriod + class Start < Base + def execute + ::PaperTrail.request.whodunnit = "cron - #{self.class.name}" + count = 0 + + Domain.expired.each do |domain| + next unless domain.expirable? + + count += 1 + Domains::ExpirePeriod::ProcessExpired.run(domain: domain) + end + + to_stdout("Successfully expired #{count}") + end + end + end +end diff --git a/app/interactions/domains/expired_pendings/base.rb b/app/interactions/domains/expired_pendings/base.rb new file mode 100644 index 000000000..7faa32050 --- /dev/null +++ b/app/interactions/domains/expired_pendings/base.rb @@ -0,0 +1,10 @@ +module Domains + module ExpiredPendings + class Base < ActiveInteraction::Base + def to_stdout(message) + time = Time.zone.now.utc + STDOUT << "#{time} - #{message}\n" unless Rails.env.test? + end + end + end +end diff --git a/app/interactions/domains/expired_pendings/clean_all.rb b/app/interactions/domains/expired_pendings/clean_all.rb new file mode 100644 index 000000000..1dbab266c --- /dev/null +++ b/app/interactions/domains/expired_pendings/clean_all.rb @@ -0,0 +1,35 @@ +module Domains + module ExpiredPendings + class CleanAll < Base + def execute + to_stdout('Clean expired domain pendings') + + ::PaperTrail.request.whodunnit = "cron - #{self.class.name}" + + count = 0 + expired_pending_domains.each do |domain| + log_error(domain) && next unless need_to_be_cleared?(domain) + count += 1 + Domains::ExpiredPendings::ProcessClean.run(domain: domain) + end + to_stdout("Successfully cancelled #{count} domain pendings") + end + + private + + def need_to_be_cleared?(domain) + domain.pending_update? || domain.pending_delete? || domain.pending_delete_confirmation? + end + + def log_error(domain) + to_stdout("ISSUE: DOMAIN #{domain.id}: #{domain.name} IS IN EXPIRED PENDING LIST, "\ + 'but no pendingDelete/pendingUpdate state present!') + end + + def expired_pending_domains + expire_at = Setting.expire_pending_confirmation.hours.ago + Domain.where('registrant_verification_asked_at <= ?', expire_at) + end + end + end +end diff --git a/app/interactions/domains/expired_pendings/process_clean.rb b/app/interactions/domains/expired_pendings/process_clean.rb new file mode 100644 index 000000000..c6277c3c5 --- /dev/null +++ b/app/interactions/domains/expired_pendings/process_clean.rb @@ -0,0 +1,60 @@ +module Domains + module ExpiredPendings + class ProcessClean < Base + object :domain, + class: Domain + + def execute + check_notify + clean_pendings + + to_stdout("DomainCron.clean_expired_pendings: ##{domain.id} (#{domain.name})") + UpdateWhoisRecordJob.enqueue domain.name, 'domain' + end + + private + + def notify_pending_update + RegistrantChangeMailer.expired(domain: domain, + registrar: domain.registrar, + registrant: domain.registrant).deliver_later + end + + def notify_pending_delete + DomainDeleteMailer.expired(domain).deliver_later + end + + def clean_pendings + clean_verification_data + domain.pending_json = {} + clean_statuses + domain.save + end + + def statuses_to_clean + [DomainStatus::PENDING_DELETE_CONFIRMATION, + DomainStatus::PENDING_UPDATE, + DomainStatus::PENDING_DELETE] + end + + def clean_statuses + domain.statuses = domain.statuses - statuses_to_clean + domain.status_notes[DomainStatus::PENDING_UPDATE] = '' + domain.status_notes[DomainStatus::PENDING_DELETE] = '' + end + + def clean_verification_data + domain.registrant_verification_token = nil + domain.registrant_verification_asked_at = nil + end + + def check_notify + notify_pending_update if domain.pending_update? + + return unless domain.pending_delete? || domain.pending_delete_confirmation? + + notify_pending_delete + end + end + end +end diff --git a/app/interactions/domains/redemption_grace_period/base.rb b/app/interactions/domains/redemption_grace_period/base.rb new file mode 100644 index 000000000..5d1ede289 --- /dev/null +++ b/app/interactions/domains/redemption_grace_period/base.rb @@ -0,0 +1,10 @@ +module Domains + module RedemptionGracePeriod + class Base < ActiveInteraction::Base + def to_stdout(message) + time = Time.zone.now.utc + STDOUT << "#{time} - #{message}\n" unless Rails.env.test? + end + end + end +end diff --git a/app/interactions/domains/redemption_grace_period/process_grace_period.rb b/app/interactions/domains/redemption_grace_period/process_grace_period.rb new file mode 100644 index 000000000..0f120a996 --- /dev/null +++ b/app/interactions/domains/redemption_grace_period/process_grace_period.rb @@ -0,0 +1,20 @@ +module Domains + module RedemptionGracePeriod + class ProcessGracePeriod < Base + object :domain, + class: Domain + + def execute + domain.statuses << DomainStatus::SERVER_HOLD + to_stdout(process_msg) + domain.save(validate: false) + end + + private + + def process_msg + "start_redemption_grace_period: #{domain.id} (#{domain.name}) #{domain.changes}" + end + end + end +end diff --git a/app/interactions/domains/redemption_grace_period/start.rb b/app/interactions/domains/redemption_grace_period/start.rb new file mode 100644 index 000000000..ef7f42e58 --- /dev/null +++ b/app/interactions/domains/redemption_grace_period/start.rb @@ -0,0 +1,20 @@ +module Domains + module RedemptionGracePeriod + class Start < Base + def execute + to_stdout('Setting server_hold to domains') + + ::PaperTrail.request.whodunnit = "cron - #{self.class.name}" + count = 0 + + Domain.outzone_candidates.each do |domain| + next unless domain.server_holdable? + + count += 1 + Domains::RedemptionGracePeriod::ProcessGracePeriod.run(domain: domain) + end + to_stdout("Successfully set server_hold to #{count} of domains") + end + end + end +end diff --git a/app/models/domain.rb b/app/models/domain.rb index d2f555977..cdbbeb4af 100644 --- a/app/models/domain.rb +++ b/app/models/domain.rb @@ -485,12 +485,6 @@ class Domain < ApplicationRecord 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_date = outzone_at + self.class.redemption_grace_period - self.statuses |= [DomainStatus::EXPIRED] - end - def pending_update? statuses.include?(DomainStatus::PENDING_UPDATE) end diff --git a/app/models/domain_cron.rb b/app/models/domain_cron.rb index d09141d52..e936c29e6 100644 --- a/app/models/domain_cron.rb +++ b/app/models/domain_cron.rb @@ -1,81 +1,14 @@ class DomainCron def self.clean_expired_pendings - STDOUT << "#{Time.zone.now.utc} - Clean expired domain pendings\n" unless Rails.env.test? - - ::PaperTrail.request.whodunnit = "cron - #{__method__}" - expire_at = Setting.expire_pending_confirmation.hours.ago - count = 0 - expired_pending_domains = Domain.where('registrant_verification_asked_at <= ?', expire_at) - expired_pending_domains.each do |domain| - unless domain.pending_update? || domain.pending_delete? || domain.pending_delete_confirmation? - msg = "#{Time.zone.now.utc} - ISSUE: DOMAIN #{domain.id}: #{domain.name} IS IN EXPIRED PENDING LIST, " \ - "but no pendingDelete/pendingUpdate state present!\n" - STDOUT << msg unless Rails.env.test? - next - end - count += 1 - if domain.pending_update? - RegistrantChangeExpiredEmailJob.enqueue(domain.id) - end - if domain.pending_delete? || domain.pending_delete_confirmation? - DomainDeleteMailer.expired(domain).deliver_now - end - - domain.preclean_pendings - domain.clean_pendings! - - unless Rails.env.test? - STDOUT << "#{Time.zone.now.utc} DomainCron.clean_expired_pendings: ##{domain.id} (#{domain.name})\n" - end - UpdateWhoisRecordJob.enqueue domain.name, 'domain' - end - STDOUT << "#{Time.zone.now.utc} - Successfully cancelled #{count} domain pendings\n" unless Rails.env.test? - count + Domains::ExpiredPendings::CleanAll.run! end def self.start_expire_period - ::PaperTrail.request.whodunnit = "cron - #{__method__}" - domains = Domain.expired - marked = 0 - real = 0 - - domains.each do |domain| - next unless domain.expirable? - real += 1 - domain.set_graceful_expired - STDOUT << "#{Time.zone.now.utc} DomainCron.start_expire_period: ##{domain.id} (#{domain.name}) #{domain.changes}\n" unless Rails.env.test? - - send_time = domain.valid_to + Setting.expiration_reminder_mail.to_i.days - saved = domain.save(validate: false) - - if saved - DomainExpireEmailJob.enqueue(domain.id, run_at: send_time) - marked += 1 - end - end - - STDOUT << "#{Time.zone.now.utc} - Successfully expired #{marked} of #{real} domains\n" unless Rails.env.test? + Domains::ExpirePeriod::Start.run! end def self.start_redemption_grace_period - STDOUT << "#{Time.zone.now.utc} - Setting server_hold to domains\n" unless Rails.env.test? - - ::PaperTrail.request.whodunnit = "cron - #{__method__}" - - domains = Domain.outzone_candidates - marked = 0 - real = 0 - - domains.each do |domain| - next unless domain.server_holdable? - real += 1 - domain.statuses << DomainStatus::SERVER_HOLD - STDOUT << "#{Time.zone.now.utc} DomainCron.start_redemption_grace_period: ##{domain.id} (#{domain.name}) #{domain.changes}\n" unless Rails.env.test? - domain.save(validate: false) and marked += 1 - end - - STDOUT << "#{Time.zone.now.utc} - Successfully set server_hold to #{marked} of #{real} domains\n" unless Rails.env.test? - marked + Domains::RedemptionGracePeriod::Start.run! end def self.start_client_hold diff --git a/test/interactions/expire_period/start_test.rb b/test/interactions/expire_period/start_test.rb new file mode 100644 index 000000000..168b255bb --- /dev/null +++ b/test/interactions/expire_period/start_test.rb @@ -0,0 +1,28 @@ +require 'test_helper' + +class StartTest < ActiveSupport::TestCase + include ActionMailer::TestHelper + + setup do + @domain = domains(:shop) + @domain.update(expire_time: Time.zone.now - 1.day) + ActionMailer::Base.deliveries.clear + end + + def test_sets_expired + job_count = lambda do + QueJob.where("args->>0 = '#{@domain.id}'", job_class: DomainExpireEmailJob.name).count + end + + assert_difference job_count, 1 do + perform_enqueued_jobs do + DomainCron.start_expire_period + end + end + + @domain.reload + assert @domain.statuses.include?(DomainStatus::EXPIRED) + assert_equal @domain.outzone_at, @domain.expire_time + Domain.expire_warning_period + assert_equal @domain.delete_date, (@domain.outzone_at + Domain.redemption_grace_period).to_date + end +end diff --git a/test/interactions/redemption_grace_period/start_test.rb b/test/interactions/redemption_grace_period/start_test.rb new file mode 100644 index 000000000..8958030f0 --- /dev/null +++ b/test/interactions/redemption_grace_period/start_test.rb @@ -0,0 +1,25 @@ +require 'test_helper' + +class StartTest < ActiveSupport::TestCase + + setup do + @domain = domains(:shop) + @domain.update(outzone_time: Time.zone.now - 1.day) + end + + def test_sets_server_hold + DomainCron.start_redemption_grace_period + + @domain.reload + assert @domain.statuses.include?(DomainStatus::SERVER_HOLD) + end + + def test_doesnt_sets_server_hold_if_not_outzone + @domain.update(outzone_time: nil) + @domain.reload + DomainCron.start_redemption_grace_period + + @domain.reload + assert_not @domain.statuses.include?(DomainStatus::SERVER_HOLD) + end +end diff --git a/test/models/domain_cron_test.rb b/test/models/domain_cron_test.rb index 0224b1a61..c417df04f 100644 --- a/test/models/domain_cron_test.rb +++ b/test/models/domain_cron_test.rb @@ -19,7 +19,9 @@ class DomainCronTest < ActiveSupport::TestCase registrant_verification_token: 'test', statuses: [DomainStatus::PENDING_DELETE_CONFIRMATION]) - DomainCron.clean_expired_pendings + perform_enqueued_jobs do + DomainCron.clean_expired_pendings + end assert_emails 1 end @@ -84,7 +86,9 @@ class DomainCronTest < ActiveSupport::TestCase assert @domain.pending_update? @domain.reload - DomainCron.clean_expired_pendings + perform_enqueued_jobs do + DomainCron.clean_expired_pendings + end @domain.reload assert_not @domain.pending_update?