FIX: Conform EmailLog#bounce_error_code to RFC (#16010)

This commit makes sure that the email log's bounce_error_code
conforms to the SMTP error code RFC on save, so that
it is always in the format X.X.X or XXX without any
additional string details. Also included is a migration
to fix this issue for past records.
This commit is contained in:
Martin Brennan 2022-02-21 11:26:39 +10:00 committed by GitHub
parent 189df5ef43
commit 01ef1d08fc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 46 additions and 0 deletions

View File

@ -14,6 +14,9 @@ class EmailLog < ActiveRecord::Base
signup_after_approval
}
# cf. https://www.iana.org/assignments/smtp-enhanced-status-codes/smtp-enhanced-status-codes.xhtml
SMTP_ERROR_CODE_REGEXP = Regexp.new(/\d\.\d\.\d|\d\d\d/).freeze
belongs_to :user
belongs_to :post
belongs_to :smtp_group, class_name: 'Group'
@ -34,6 +37,13 @@ class EmailLog < ActiveRecord::Base
SQL
end
before_save do
if self.bounce_error_code.present?
match = SMTP_ERROR_CODE_REGEXP.match(self.bounce_error_code)
self.bounce_error_code = match.present? ? match[0] : nil
end
end
after_create do
# Update last_emailed_at if the user_id is present and email was sent
User.where(id: user_id).update_all("last_emailed_at = CURRENT_TIMESTAMP") if user_id.present?

View File

@ -0,0 +1,19 @@
# frozen_string_literal: true
#
class ConformBounceErrorCode < ActiveRecord::Migration[6.1]
def up
DB.exec(<<~SQL, regexp: '\d\.\d\.\d|\d\d\d')
UPDATE email_logs
SET bounce_error_code = (
SELECT array_to_string(
regexp_matches(bounce_error_code, :regexp),
''
)
) WHERE bounce_error_code IS NOT NULL;
SQL
end
def down
raise ActiveRecord::IrreversibleMigration
end
end

View File

@ -161,4 +161,21 @@ describe EmailLog do
expect(EmailLog.addressed_to_user(user).count).to eq(0)
end
end
describe "bounce_error_code fix before update" do
fab!(:email_log) { Fabricate(:email_log) }
it "makes sure the bounce_error_code is in the format X.X.X or XXX" do
email_log.update!(bounce_error_code: "5.1.1")
expect(email_log.reload.bounce_error_code).to eq("5.1.1")
email_log.update!(bounce_error_code: "5.0.0 (permanent failure)")
expect(email_log.reload.bounce_error_code).to eq("5.0.0")
email_log.update!(bounce_error_code: "422")
expect(email_log.reload.bounce_error_code).to eq("422")
email_log.update!(bounce_error_code: "5.2")
expect(email_log.reload.bounce_error_code).to eq(nil)
email_log.update!(bounce_error_code: "blah")
expect(email_log.reload.bounce_error_code).to eq(nil)
end
end
end