Mercurial > hg > soundsoftware-site
diff app/models/user.rb @ 1295:622f24f53b42 redmine-2.3
Update to Redmine SVN revision 11972 on 2.3-stable branch
author | Chris Cannam |
---|---|
date | Fri, 14 Jun 2013 09:02:21 +0100 |
parents | 433d4f72a19b |
children | 4f746d8966dd |
line wrap: on
line diff
--- a/app/models/user.rb Fri Jun 14 09:01:12 2013 +0100 +++ b/app/models/user.rb Fri Jun 14 09:02:21 2013 +0100 @@ -1,5 +1,5 @@ # Redmine - project management software -# Copyright (C) 2006-2012 Jean-Philippe Lang +# Copyright (C) 2006-2013 Jean-Philippe Lang # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -20,12 +20,6 @@ class User < Principal include Redmine::SafeAttributes - # Account statuses - STATUS_ANONYMOUS = 0 - STATUS_ACTIVE = 1 - STATUS_REGISTERED = 2 - STATUS_LOCKED = 3 - # Different ways of displaying/sorting users USER_FORMATS = { :firstname_lastname => { @@ -82,8 +76,8 @@ has_one :api_token, :class_name => 'Token', :conditions => "action='api'" belongs_to :auth_source - scope :logged, :conditions => "#{User.table_name}.status <> #{STATUS_ANONYMOUS}" - scope :status, lambda {|arg| arg.blank? ? {} : {:conditions => {:status => arg.to_i}} } + scope :logged, lambda { where("#{User.table_name}.status <> #{STATUS_ANONYMOUS}") } + scope :status, lambda {|arg| where(arg.blank? ? nil : {:status => arg.to_i}) } acts_as_customizable @@ -98,11 +92,11 @@ validates_presence_of :login, :firstname, :lastname, :mail, :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 lettres, numbers, underscores only - validates_format_of :login, :with => /^[a-z0-9_\-@\.]*$/i + # 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 => /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i, :allow_blank => true + 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_confirmation_of :password, :allow_nil => true validates_inclusion_of :mail_notification, :in => MAIL_NOTIFICATION_OPTIONS.collect(&:first), :allow_blank => true @@ -120,6 +114,7 @@ group_id = group.is_a?(Group) ? group.id : group.to_i 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)} def set_mail_notification self.mail_notification = Setting.default_notification_option if self.mail_notification.blank? @@ -133,10 +128,12 @@ end end + alias :base_reload :reload def reload(*args) @name = nil @projects_by_role = nil - super + @membership_by_project_id = nil + base_reload(*args) end def mail=(arg) @@ -150,7 +147,7 @@ begin write_attribute(:identity_url, OpenIdAuthentication.normalize_identifier(url)) rescue OpenIdAuthentication::InvalidOpenId - # Invlaid url, don't save + # Invalid url, don't save end end self.read_attribute(:identity_url) @@ -161,19 +158,13 @@ login = login.to_s password = password.to_s - # Make sure no one can sign in with an empty password - return nil if password.empty? + # Make sure no one can sign in with an empty login or password + return nil if login.empty? || password.empty? user = find_by_login(login) if user # user is already in local database - return nil if !user.active? - if user.auth_source - # user has an external authentication method - return nil unless user.auth_source.authenticate(login, password) - else - # authentication with local password - return nil unless user.check_password?(password) - end + return nil unless user.active? + return nil unless user.check_password?(password) else # user is not yet registered, try to authenticate with available sources attrs = AuthSource.authenticate(login, password) @@ -187,7 +178,7 @@ end end end - user.update_attribute(:last_login_on, Time.now) if user && !user.new_record? + user.update_column(:last_login_on, Time.now) if user && !user.new_record? user rescue => text raise text @@ -195,14 +186,10 @@ # Returns the user who matches the given autologin +key+ or nil def self.try_to_autologin(key) - tokens = Token.find_all_by_action_and_value('autologin', key.to_s) - # Make sure there's only 1 token that matches the key - if tokens.size == 1 - token = tokens.first - if (token.created_on > Setting.autologin.to_i.day.ago) && token.user && token.user.active? - token.user.update_attribute(:last_login_on, Time.now) - token.user - end + user = Token.find_active_user('autologin', key, Setting.autologin.to_i) + if user + user.update_column(:last_login_on, Time.now) + user end end @@ -359,23 +346,24 @@ # Find a user account by matching the exact login and then a case-insensitive # version. Exact matches will be given priority. def self.find_by_login(login) - # First look for an exact match - user = where(:login => login).all.detect {|u| u.login == login} - unless user - # Fail over to case-insensitive if none was found - user = where("LOWER(login) = ?", login.to_s.downcase).first + if login.present? + login = login.to_s + # First look for an exact match + user = where(:login => login).all.detect {|u| u.login == login} + unless user + # Fail over to case-insensitive if none was found + user = where("LOWER(login) = ?", login.downcase).first + end + user end - user end def self.find_by_rss_key(key) - token = Token.find_by_action_and_value('feeds', key.to_s) - token && token.user.active? ? token.user : nil + Token.find_active_user('feeds', key) end def self.find_by_api_key(key) - token = Token.find_by_action_and_value('api', key.to_s) - token && token.user.active? ? token.user : nil + Token.find_active_user('api', key) end # Makes find_by_mail case-insensitive @@ -429,6 +417,17 @@ !logged? end + # Returns user's membership for the given project + # or nil if the user is not a member of project + def membership(project) + project_id = project.is_a?(Project) ? project.id : project + + @membership_by_project_id ||= Hash.new {|h, project_id| + h[project_id] = memberships.where(:project_id => project_id).first + } + @membership_by_project_id[project_id] + end + # Return user's roles for project def roles_for_project(project) roles = [] @@ -436,7 +435,7 @@ return roles if project.nil? || project.archived? if logged? # Find project membership - membership = memberships.detect {|m| m.project_id == project.id} + membership = membership(project) if membership roles = membership.roles else @@ -452,7 +451,7 @@ # Return true if the user is a member of project def member_of?(project) - !roles_for_project(project).detect {|role| role.member?}.nil? + projects.to_a.include?(project) end # Returns a hash of user's projects grouped by roles @@ -565,47 +564,35 @@ # # TODO: only supports Issue events currently def notify_about?(object) - case mail_notification - when 'all' + if mail_notification == 'all' true - when 'selected' - # user receives notifications for created/assigned issues on unselected projects - if object.is_a?(Issue) && (object.author == self || is_or_belongs_to?(object.assigned_to) || is_or_belongs_to?(object.assigned_to_was)) + elsif mail_notification.blank? || mail_notification == 'none' + false + else + case object + when Issue + case mail_notification + when 'selected', 'only_my_events' + # user receives notifications for created/assigned issues on unselected projects + object.author == self || is_or_belongs_to?(object.assigned_to) || is_or_belongs_to?(object.assigned_to_was) + when 'only_assigned' + is_or_belongs_to?(object.assigned_to) || is_or_belongs_to?(object.assigned_to_was) + when 'only_owner' + object.author == self + end + when News + # always send to project members except when mail_notification is set to 'none' true - else - false end - when 'none' - false - when 'only_my_events' - if object.is_a?(Issue) && (object.author == self || is_or_belongs_to?(object.assigned_to) || is_or_belongs_to?(object.assigned_to_was)) - true - else - false - end - when 'only_assigned' - if object.is_a?(Issue) && (is_or_belongs_to?(object.assigned_to) || is_or_belongs_to?(object.assigned_to_was)) - true - else - false - end - when 'only_owner' - if object.is_a?(Issue) && object.author == self - true - else - false - end - else - false end end def self.current=(user) - @current_user = user + Thread.current[:current_user] = user end def self.current - @current_user ||= User.anonymous + Thread.current[:current_user] ||= User.anonymous end # Returns the anonymous user. If the anonymous user does not exist, it is created. There can be only @@ -686,7 +673,7 @@ def validate_anonymous_uniqueness # There should be only one AnonymousUser in the database - errors.add :base, 'An anonymous user already exists.' if AnonymousUser.find(:first) + errors.add :base, 'An anonymous user already exists.' if AnonymousUser.exists? end def available_custom_fields @@ -705,6 +692,10 @@ UserPreference.new(:user => self) end + def member_of?(project) + false + end + # Anonymous user can not be destroyed def destroy false