diff options
author | Jean-Philippe Lang <jp_lang@yahoo.fr> | 2015-01-17 14:14:12 +0000 |
---|---|---|
committer | Jean-Philippe Lang <jp_lang@yahoo.fr> | 2015-01-17 14:14:12 +0000 |
commit | e3618bdbecd9b5d86eb6d2c8c256ba3fcdf05189 (patch) | |
tree | 3b54c10eecece6cc2674491a76a4e5e932d82d1e /app/models/user.rb | |
parent | 7f29c2fd88f271ac59f1c10b90942fec57b35ae2 (diff) | |
download | redmine-e3618bdbecd9b5d86eb6d2c8c256ba3fcdf05189.tar.gz redmine-e3618bdbecd9b5d86eb6d2c8c256ba3fcdf05189.zip |
Add support for multiple email addresses per user (#4244).
git-svn-id: http://svn.redmine.org/redmine/trunk@13886 e93f8b46-1217-0410-a6f0-8f06a7374b81
Diffstat (limited to 'app/models/user.rb')
-rw-r--r-- | app/models/user.rb | 54 |
1 files changed, 41 insertions, 13 deletions
diff --git a/app/models/user.rb b/app/models/user.rb index b680fe52d..2175d0682 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -81,6 +81,8 @@ class User < Principal has_one :preference, :dependent => :destroy, :class_name => 'UserPreference' has_one :rss_token, lambda {where "action='feeds'"}, :class_name => 'Token' has_one :api_token, lambda {where "action='api'"}, :class_name => 'Token' + has_one :email_address, lambda {where :is_default => true}, :autosave => true + has_many :email_addresses, :dependent => :delete_all belongs_to :auth_source scope :logged, lambda { where("#{User.table_name}.status <> #{STATUS_ANONYMOUS}") } @@ -96,15 +98,12 @@ class User < Principal LOGIN_LENGTH_LIMIT = 60 MAIL_LENGTH_LIMIT = 60 - validates_presence_of :login, :firstname, :lastname, :mail, :if => Proc.new { |user| !user.is_a?(AnonymousUser) } + validates_presence_of :login, :firstname, :lastname, :if => Proc.new { |user| !user.is_a?(AnonymousUser) } validates_uniqueness_of :login, :if => Proc.new { |user| user.login_changed? && user.login.present? }, :case_sensitive => false - validates_uniqueness_of :mail, :if => Proc.new { |user| user.mail_changed? && user.mail.present? }, :case_sensitive => false # Login must contain letters, numbers, underscores only validates_format_of :login, :with => /\A[a-z0-9_\-@\.]*\z/i validates_length_of :login, :maximum => LOGIN_LENGTH_LIMIT validates_length_of :firstname, :lastname, :maximum => 30 - validates_format_of :mail, :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i, :allow_blank => true - validates_length_of :mail, :maximum => MAIL_LENGTH_LIMIT, :allow_nil => true validates_inclusion_of :mail_notification, :in => MAIL_NOTIFICATION_OPTIONS.collect(&:first), :allow_blank => true validate :validate_password_length validate do @@ -113,6 +112,7 @@ class User < Principal end end + before_validation :instantiate_email_address before_create :set_mail_notification before_save :generate_password_if_needed, :update_hashed_password before_destroy :remove_references_before_destroy @@ -127,6 +127,14 @@ class User < Principal where("#{User.table_name}.id NOT IN (SELECT gu.user_id FROM #{table_name_prefix}groups_users#{table_name_suffix} gu WHERE gu.group_id = ?)", group_id) } scope :sorted, lambda { order(*User.fields_for_order_statement)} + scope :having_mail, lambda {|arg| + addresses = Array.wrap(arg).map {|a| a.to_s.downcase} + if addresses.any? + joins(:email_addresses).where("LOWER(address) IN (?)", addresses).uniq + else + none + end + } def set_mail_notification self.mail_notification = Setting.default_notification_option if self.mail_notification.blank? @@ -152,8 +160,21 @@ class User < Principal base_reload(*args) end + def mail + email_address.try(:address) + end + def mail=(arg) - write_attribute(:mail, arg.to_s.strip) + email = email_address || build_email_address + email.address = arg + end + + def mail_changed? + email_address.try(:address_changed?) + end + + def mails + email_addresses.pluck(:address) end def self.find_or_initialize_by_identity_url(url) @@ -421,7 +442,7 @@ class User < Principal # Makes find_by_mail case-insensitive def self.find_by_mail(mail) - where("LOWER(mail) = ?", mail.to_s.downcase).first + having_mail(mail).first end # Returns true if the default admin account can no longer be used @@ -669,7 +690,7 @@ class User < Principal def self.anonymous anonymous_user = AnonymousUser.first if anonymous_user.nil? - anonymous_user = AnonymousUser.create(:lastname => 'Anonymous', :firstname => '', :mail => '', :login => '', :status => 0) + anonymous_user = AnonymousUser.create(:lastname => 'Anonymous', :firstname => '', :login => '', :status => 0) raise 'Unable to create the anonymous user.' if anonymous_user.new_record? end anonymous_user @@ -699,6 +720,10 @@ class User < Principal end end + def instantiate_email_address + email_address || build_email_address + end + private def generate_password_if_needed @@ -708,16 +733,13 @@ class User < Principal end end - # Delete all outstanding password reset tokens on password or email change. + # Delete all outstanding password reset tokens on password change. # Delete the autologin tokens on password change to prohibit session leakage. # This helps to keep the account secure in case the associated email account # was compromised. def destroy_tokens - tokens = [] - tokens |= ['recovery', 'autologin'] if hashed_password_changed? - tokens |= ['recovery'] if mail_changed? - - if tokens.any? + if hashed_password_changed? + tokens = ['recovery', 'autologin'] Token.where(:user_id => id, :action => tokens).delete_all end end @@ -779,6 +801,7 @@ class AnonymousUser < User def logged?; false end def admin; false end def name(*args); I18n.t(:label_user_anonymous) end + def mail=(*args); nil end def mail; nil end def time_zone; nil end def rss_key; nil end @@ -804,4 +827,9 @@ class AnonymousUser < User def destroy false end + + protected + + def instantiate_email_address + end end |