2
0

Replace EmailHelper module with normalizes via model concern (#35702)

This commit is contained in:
Matt Jankowski
2025-08-07 09:47:47 -04:00
committed by GitHub
parent 496a5f423e
commit a485f97d21
4 changed files with 47 additions and 25 deletions

View File

@@ -1,18 +0,0 @@
# frozen_string_literal: true
module EmailHelper
def self.included(base)
base.extend(self)
end
def email_to_canonical_email(str)
username, domain = str.downcase.split('@', 2)
username, = username.delete('.').split('+', 2)
"#{username}@#{domain}"
end
def email_to_canonical_email_hash(str)
Digest::SHA2.new(256).hexdigest(email_to_canonical_email(str))
end
end

View File

@@ -12,24 +12,29 @@
#
class CanonicalEmailBlock < ApplicationRecord
include EmailHelper
include CanonicalEmail
include Paginable
belongs_to :reference_account, class_name: 'Account', optional: true
validates :canonical_email_hash, presence: true, uniqueness: true
scope :matching_email, ->(email) { where(canonical_email_hash: email_to_canonical_email_hash(email)) }
scope :matching_email, ->(email) { where(canonical_email_hash: digest(normalize_value_for(:email, email))) }
def self.block?(email)
matching_email(email).exists?
end
def self.digest(value)
Digest::SHA256.hexdigest(value)
end
def to_log_human_identifier
canonical_email_hash
end
def email=(email)
self.canonical_email_hash = email_to_canonical_email_hash(email)
end
def self.block?(email)
matching_email(email).exists?
super
self.canonical_email_hash = self.class.digest(self.email)
end
end

View File

@@ -0,0 +1,27 @@
# frozen_string_literal: true
module CanonicalEmail
extend ActiveSupport::Concern
included do
normalizes :email, with: ->(value) { canonicalize_email(value) }
end
class_methods do
def canonicalize_email(email)
email
.downcase
.split('@', 2)
.then { |local, domain| [canonical_username(local), domain] }
.join('@')
end
def canonical_username(username)
username
.to_s
.delete('.')
.split('+', 2)
.first
end
end
end

View File

@@ -7,6 +7,14 @@ RSpec.describe CanonicalEmailBlock do
it { is_expected.to belong_to(:reference_account).class_name('Account').optional }
end
describe 'Normalizations' do
describe 'email' do
it { is_expected.to normalize(:email).from('TEST@HOST.EXAMPLE').to('test@host.example') }
it { is_expected.to normalize(:email).from('test+more@host.example').to('test@host.example') }
it { is_expected.to normalize(:email).from('test.user@host.example').to('testuser@host.example') }
end
end
describe 'Scopes' do
describe '.matching_email' do
subject { described_class.matching_email(email) }