discourse/app/models/user_email.rb
Bianca Nenciu 3ea8937157
FEATURE: Add email normalization rules setting (#14593)
When this setting is turned on, it will check that normalized emails
are unique. Normalized emails are emails without any dots or plus
aliases.

This setting can be used to block use of aliases of the same email
address.
2021-11-24 11:30:06 +02:00

86 lines
2.4 KiB
Ruby

# frozen_string_literal: true
class UserEmail < ActiveRecord::Base
belongs_to :user
attr_accessor :skip_validate_email
attr_accessor :skip_validate_unique_email
before_validation :strip_downcase_email
before_validation :normalize_email
validates :email, presence: true
validates :email, email: true, if: :validate_email?
validates :primary, uniqueness: { scope: [:user_id] }, if: [:user_id, :primary]
validate :user_id_not_changed, if: :primary
validate :unique_email, if: :validate_unique_email?
scope :secondary, -> { where(primary: false) }
def normalize_email
self.normalized_email = if self.email.present?
username, domain = self.email.split('@', 2)
username = username.gsub('.', '').gsub(/\+.*/, '')
"#{username}@#{domain}"
end
end
private
def strip_downcase_email
if self.email
self.email = self.email.strip
self.email = self.email.downcase
end
end
def validate_email?
return false if self.skip_validate_email
email_changed?
end
def validate_unique_email?
return false if self.skip_validate_unique_email
will_save_change_to_email?
end
def unique_email
email_exists = if SiteSetting.normalize_emails?
self.class.where("lower(email) = ? OR lower(normalized_email) = ?", email, normalized_email).exists?
else
self.class.where("lower(email) = ?", email).exists?
end
self.errors.add(:email, :taken) if email_exists
end
def user_id_not_changed
if self.will_save_change_to_user_id? && self.persisted?
self.errors.add(:user_id, I18n.t(
'active_record.errors.model.user_email.attributes.user_id.reassigning_primary_email')
)
end
end
end
# == Schema Information
#
# Table name: user_emails
#
# id :integer not null, primary key
# user_id :integer not null
# email :string(513) not null
# primary :boolean default(FALSE), not null
# created_at :datetime not null
# updated_at :datetime not null
# normalized_email :string
#
# Indexes
#
# index_user_emails_on_email (lower((email)::text)) UNIQUE
# index_user_emails_on_normalized_email (lower((normalized_email)::text))
# index_user_emails_on_user_id (user_id)
# index_user_emails_on_user_id_and_primary (user_id,primary) UNIQUE WHERE "primary"
#