##// END OF EJS Templates
Sort groups on user groups setting (#4389)....
Sort groups on user groups setting (#4389). git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@3160 e93f8b46-1217-0410-a6f0-8f06a7374b81

File last commit:

r2910:c31411ec0029
r3046:72ceefd36eab
Show More
user.rb
353 lines | 11.0 KiB | text/x-ruby | RubyLexer
Jean-Philippe Lang
User groups branch merged....
r2755 # Redmine - project management software
# Copyright (C) 2006-2009 Jean-Philippe Lang
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330 #
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require "digest/sha1"
Jean-Philippe Lang
User groups branch merged....
r2755 class User < Principal
Jean-Philippe Lang
Better error message and AR errors in log for failed LDAP on-the-fly user creation (closes #932, #1042)....
r1330
Jean-Philippe Lang
User's projects alphabetically sorted in the Projects drop down menu....
r535 # Account statuses
Jean-Philippe Lang
Anonymous users can now be allowed to create, edit, comment issues, comment news and post messages in the forums....
r906 STATUS_ANONYMOUS = 0
Jean-Philippe Lang
User's projects alphabetically sorted in the Projects drop down menu....
r535 STATUS_ACTIVE = 1
STATUS_REGISTERED = 2
STATUS_LOCKED = 3
Jean-Philippe Lang
User display format is now configurable in administration settings....
r1089
USER_FORMATS = {
:firstname_lastname => '#{firstname} #{lastname}',
:firstname => '#{firstname}',
:lastname_firstname => '#{lastname} #{firstname}',
:lastname_coma_firstname => '#{lastname}, #{firstname}',
:username => '#{login}'
}
Jean-Philippe Lang
User's projects alphabetically sorted in the Projects drop down menu....
r535
Jean-Philippe Lang
User groups branch merged....
r2755 has_and_belongs_to_many :groups, :after_add => Proc.new {|user, group| group.user_added(user)},
:after_remove => Proc.new {|user, group| group.user_removed(user)}
Jean-Philippe Lang
Each category can now be associated to a user, so that new issues in that category are automatically assigned to that user....
r574 has_many :issue_categories, :foreign_key => 'assigned_to_id', :dependent => :nullify
Jean-Philippe Lang
Maps repository users to Redmine users (#1383)....
r2004 has_many :changesets, :dependent => :nullify
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330 has_one :preference, :dependent => :destroy, :class_name => 'UserPreference'
Jean-Philippe Lang
Merged 0.6 branch into trunk....
r663 has_one :rss_token, :dependent => :destroy, :class_name => 'Token', :conditions => "action='feeds'"
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330 belongs_to :auth_source
Jean-Philippe Lang
Replaces User.find_active with a named scope....
r2077 # Active non-anonymous users scope
named_scope :active, :conditions => "#{User.table_name}.status = #{STATUS_ACTIVE}"
Jean-Philippe Lang
Custom fields refactoring: most of code moved from controllers to models (using new module ActsAsCustomizable)....
r1578 acts_as_customizable
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330 attr_accessor :password, :password_confirmation
attr_accessor :last_before_login_on
# Prevents unauthorized assignments
Jean-Philippe Lang
User groups branch merged....
r2755 attr_protected :login, :admin, :password, :password_confirmation, :hashed_password, :group_ids
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330
Jean-Philippe Lang
Anonymous users can now be allowed to create, edit, comment issues, comment news and post messages in the forums....
r906 validates_presence_of :login, :firstname, :lastname, :mail, :if => Proc.new { |user| !user.is_a?(AnonymousUser) }
Jean-Philippe Lang
Prevent 'has already been taken' error messages for user login and email if these fields are left empty....
r1029 validates_uniqueness_of :login, :if => Proc.new { |user| !user.login.blank? }
Jean-Philippe Lang
Makes email adress uniqueness case-insensitive (#2473)....
r2251 validates_uniqueness_of :mail, :if => Proc.new { |user| !user.mail.blank? }, :case_sensitive => false
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330 # Login must contain lettres, numbers, underscores only
Jean-Philippe Lang
Anonymous users can now be allowed to create, edit, comment issues, comment news and post messages in the forums....
r906 validates_format_of :login, :with => /^[a-z0-9_\-@\.]*$/i
Jean-Philippe Lang
Added some attributes length validations....
r397 validates_length_of :login, :maximum => 30
Jean-Philippe Lang
Allow dot in firstnames and lastnames (closes #1426)....
r1547 validates_format_of :firstname, :lastname, :with => /^[\w\s\'\-\.]*$/i
Jean-Philippe Lang
Added some attributes length validations....
r397 validates_length_of :firstname, :lastname, :maximum => 30
Jean-Philippe Lang
Anonymous users can now be allowed to create, edit, comment issues, comment news and post messages in the forums....
r906 validates_format_of :mail, :with => /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i, :allow_nil => true
validates_length_of :mail, :maximum => 60, :allow_nil => true
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330 validates_confirmation_of :password, :allow_nil => true
Jean-Philippe Lang
More flexible mail notifications settings at user level. A user has now 3 options:...
r842 def before_create
self.mail_notification = false
true
end
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330 def before_save
# update hashed_password if password was set
self.hashed_password = User.hash_password(self.password) if self.password
end
Jean-Philippe Lang
Sort users by their display names so that user dropdown lists are sorted alphabetically (#2015)....
r2008
def reload(*args)
@name = nil
super
end
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330
Eric Davis
Normalize the identity_url when it's set....
r2392 def identity_url=(url)
Jean-Philippe Lang
Fixed: User#identity_url raises an error when invalid url is supplied (#2742)....
r2415 if url.blank?
write_attribute(:identity_url, '')
else
begin
write_attribute(:identity_url, OpenIdAuthentication.normalize_identifier(url))
rescue OpenIdAuthentication::InvalidOpenId
# Invlaid url, don't save
end
Eric Davis
Normalize the identity_url when it's set....
r2392 end
self.read_attribute(:identity_url)
end
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330 # Returns the user that matches provided login and password, or nil
def self.try_to_login(login, password)
Jean-Philippe Lang
Prevent LDAP authentication with empty password related problems....
r1217 # Make sure no one can sign in with an empty password
return nil if password.to_s.empty?
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330 user = find(:first, :conditions => ["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.hash_password(password) == user.hashed_password
end
else
# user is not yet registered, try to authenticate with available sources
attrs = AuthSource.authenticate(login, password)
if attrs
Jean-Philippe Lang
Improved on-the-fly account creation. If some attributes are missing (eg. not present in the LDAP) or are invalid, the registration form is displayed so that the user is able to fill or fix these attributes....
r1661 user = new(*attrs)
user.login = login
user.language = Setting.default_language
if user.save
user.reload
Jean-Philippe Lang
Better error message and AR errors in log for failed LDAP on-the-fly user creation (closes #932, #1042)....
r1330 logger.info("User '#{user.login}' created from the LDAP") if logger
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330 end
end
end
Jean-Philippe Lang
Improved on-the-fly account creation. If some attributes are missing (eg. not present in the LDAP) or are invalid, the registration form is displayed so that the user is able to fill or fix these attributes....
r1661 user.update_attribute(:last_login_on, Time.now) if user && !user.new_record?
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330 user
Jean-Philippe Lang
Better error message and AR errors in log for failed LDAP on-the-fly user creation (closes #932, #1042)....
r1330 rescue => text
raise text
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330 end
Jean-Philippe Lang
Fixed: When logging in via an autologin cookie the user's last_login_on should be updated (#2820)....
r2460
# Returns the user who matches the given autologin +key+ or nil
def self.try_to_autologin(key)
Jean-Philippe Lang
Do not autologin if more that one token is found (#3351)....
r2643 tokens = Token.find_all_by_action_and_value('autologin', key)
# 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
Jean-Philippe Lang
Fixed: When logging in via an autologin cookie the user's last_login_on should be updated (#2820)....
r2460 end
end
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330
# Return user's full name for display
Jean-Philippe Lang
User display format is now configurable in administration settings....
r1089 def name(formatter = nil)
Jean-Philippe Lang
Fixes #2170: user display format in application settings broken by r2010....
r2029 if formatter
eval('"' + (USER_FORMATS[formatter] || USER_FORMATS[:firstname_lastname]) + '"')
else
@name ||= eval('"' + (USER_FORMATS[Setting.user_format] || USER_FORMATS[:firstname_lastname]) + '"')
end
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330 end
def active?
self.status == STATUS_ACTIVE
end
def registered?
self.status == STATUS_REGISTERED
end
def locked?
self.status == STATUS_LOCKED
end
def check_password?(clear_password)
User.hash_password(clear_password) == self.hashed_password
end
Eric Davis
Hooked up on the fly OpenID user creation....
r2382
# Generate and set a random password. Useful for automated user creation
# Based on Token#generate_token_value
#
def random_password
chars = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a
password = ''
40.times { |i| password << chars[rand(chars.size-1)] }
self.password = password
self.password_confirmation = password
self
end
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330
def pref
self.preference ||= UserPreference.new(:user => self)
end
Jean-Philippe Lang
added rss/atom feeds at project levels for:...
r336
Jean-Philippe Lang
* Added time zone support: users can select their time zone on their account view....
r904 def time_zone
Jean-Philippe Lang
Rails 2.1.2 deprecations (#2332)....
r2132 @time_zone ||= (self.pref.time_zone.blank? ? nil : ActiveSupport::TimeZone[self.pref.time_zone])
Jean-Philippe Lang
* Added time zone support: users can select their time zone on their account view....
r904 end
Jean-Philippe Lang
Add a user preference to choose how comments/replies are displayed: in chronological or reverse chronological order (#589, #776)....
r1183 def wants_comments_in_reverse_order?
self.pref[:comments_sorting] == 'desc'
end
Jean-Philippe Lang
Merged 0.6 branch into trunk....
r663 # Return user's RSS key (a 40 chars long string), used to access feeds
def rss_key
token = self.rss_token || Token.create(:user => self, :action => 'feeds')
token.value
Jean-Philippe Lang
added rss/atom feeds at project levels for:...
r336 end
Jean-Philippe Lang
More flexible mail notifications settings at user level. A user has now 3 options:...
r842 # Return an array of project ids for which the user has explicitly turned mail notifications on
def notified_projects_ids
@notified_projects_ids ||= memberships.select {|m| m.mail_notification?}.collect(&:project_id)
end
def notified_project_ids=(ids)
Member.update_all("mail_notification = #{connection.quoted_false}", ['user_id = ?', id])
Member.update_all("mail_notification = #{connection.quoted_true}", ['user_id = ? AND project_id IN (?)', id, ids]) if ids && !ids.empty?
@notified_projects_ids = nil
notified_projects_ids
end
Jean-Philippe Lang
added rss/atom feeds at project levels for:...
r336 def self.find_by_rss_key(key)
token = Token.find_by_value(key)
token && token.user.active? ? token.user : nil
end
Jean-Philippe Lang
Added autologin feature (disabled by default)....
r511
Jean-Philippe Lang
Makes User.find_by_mail case-insensitive (password reminder #2322, repo users mapping)....
r2120 # Makes find_by_mail case-insensitive
def self.find_by_mail(mail)
find(:first, :conditions => ["LOWER(mail) = ?", mail.to_s.downcase])
end
Jean-Philippe Lang
Various changes on views. On project summary, members are now grouped by role and subprojects are listed inline....
r431
Jean-Philippe Lang
Sort users by their display names so that user dropdown lists are sorted alphabetically (#2015)....
r2008 # Sort users by their display names
Jean-Philippe Lang
Various changes on views. On project summary, members are now grouped by role and subprojects are listed inline....
r431 def <=>(user)
Jean-Philippe Lang
Sort users by their display names so that user dropdown lists are sorted alphabetically (#2015)....
r2008 self.to_s.downcase <=> user.to_s.downcase
Jean-Philippe Lang
Various changes on views. On project summary, members are now grouped by role and subprojects are listed inline....
r431 end
Jean-Philippe Lang
Merged 0.6 branch into trunk....
r663 def to_s
name
end
Jean-Philippe Lang
Fixed: Pre-filled time tracking date ignores timezone (#4160)....
r2898 # Returns the current day according to user's time zone
def today
if time_zone.nil?
Date.today
else
Time.now.in_time_zone(time_zone).to_date
end
end
Jean-Philippe Lang
Merged 0.6 branch into trunk....
r663 def logged?
true
end
Jean-Philippe Lang
Adds links to the user page on various views....
r1657 def anonymous?
!logged?
end
Jean-Philippe Lang
Allows multiple roles on the same project (#706). Prerequisite for user groups feature....
r2627 # Return user's roles for project
def roles_for_project(project)
roles = []
Jean-Philippe Lang
Merged 0.6 branch into trunk....
r663 # No role on archived projects
Jean-Philippe Lang
Allows multiple roles on the same project (#706). Prerequisite for user groups feature....
r2627 return roles unless project && project.active?
Jean-Philippe Lang
Slight optimization in User#role_for_project....
r915 if logged?
# Find project membership
membership = memberships.detect {|m| m.project_id == project.id}
if membership
Jean-Philippe Lang
Allows multiple roles on the same project (#706). Prerequisite for user groups feature....
r2627 roles = membership.roles
Jean-Philippe Lang
Slight optimization in User#role_for_project....
r915 else
@role_non_member ||= Role.non_member
Jean-Philippe Lang
Allows multiple roles on the same project (#706). Prerequisite for user groups feature....
r2627 roles << @role_non_member
Jean-Philippe Lang
Slight optimization in User#role_for_project....
r915 end
Jean-Philippe Lang
Merged 0.6 branch into trunk....
r663 else
Jean-Philippe Lang
Slight optimization in User#role_for_project....
r915 @role_anonymous ||= Role.anonymous
Jean-Philippe Lang
Allows multiple roles on the same project (#706). Prerequisite for user groups feature....
r2627 roles << @role_anonymous
Jean-Philippe Lang
Merged 0.6 branch into trunk....
r663 end
Jean-Philippe Lang
Allows multiple roles on the same project (#706). Prerequisite for user groups feature....
r2627 roles
Jean-Philippe Lang
Merged 0.6 branch into trunk....
r663 end
# Return true if the user is a member of project
def member_of?(project)
Jean-Philippe Lang
Allows multiple roles on the same project (#706). Prerequisite for user groups feature....
r2627 !roles_for_project(project).detect {|role| role.member?}.nil?
Jean-Philippe Lang
Merged 0.6 branch into trunk....
r663 end
# Return true if the user is allowed to do the specified action on project
# action can be:
# * a parameter-like Hash (eg. :controller => 'projects', :action => 'edit')
# * a permission Symbol (eg. :edit_project)
Jean-Philippe Lang
Global queries can be saved from the global issue list (follows r1311 and closes #897)....
r1297 def allowed_to?(action, project, options={})
if project
# No action allowed on archived projects
return false unless project.active?
# No action allowed on disabled modules
return false unless project.allows_to?(action)
# Admin users are authorized for anything else
return true if admin?
Jean-Philippe Lang
Allows multiple roles on the same project (#706). Prerequisite for user groups feature....
r2627 roles = roles_for_project(project)
return false unless roles
roles.detect {|role| (project.is_public? || role.member?) && role.allowed_to?(action)}
Jean-Philippe Lang
Global queries can be saved from the global issue list (follows r1311 and closes #897)....
r1297
elsif options[:global]
Jean-Philippe Lang
Ability to allow non-admin users to create projects (#1007)....
r2651 # Admin users are always authorized
return true if admin?
Jean-Philippe Lang
Global queries can be saved from the global issue list (follows r1311 and closes #897)....
r1297 # authorize if user has at least one role that has this permission
Jean-Philippe Lang
Allows multiple roles on the same project (#706). Prerequisite for user groups feature....
r2627 roles = memberships.collect {|m| m.roles}.flatten.uniq
Jean-Philippe Lang
Adds cross-project time reports support (#994)....
r1777 roles.detect {|r| r.allowed_to?(action)} || (self.logged? ? Role.non_member.allowed_to?(action) : Role.anonymous.allowed_to?(action))
Jean-Philippe Lang
Global queries can be saved from the global issue list (follows r1311 and closes #897)....
r1297 else
false
end
Jean-Philippe Lang
Merged 0.6 branch into trunk....
r663 end
def self.current=(user)
@current_user = user
end
def self.current
Jean-Philippe Lang
Anonymous users can now be allowed to create, edit, comment issues, comment news and post messages in the forums....
r906 @current_user ||= User.anonymous
Jean-Philippe Lang
Merged 0.6 branch into trunk....
r663 end
Eric Davis
Added some RDoc documentation for some models....
r2536 # Returns the anonymous user. If the anonymous user does not exist, it is created. There can be only
# one anonymous user per database.
Jean-Philippe Lang
Merged 0.6 branch into trunk....
r663 def self.anonymous
Jean-Philippe Lang
Anonymous users can now be allowed to create, edit, comment issues, comment news and post messages in the forums....
r906 anonymous_user = AnonymousUser.find(:first)
if anonymous_user.nil?
anonymous_user = AnonymousUser.create(:lastname => 'Anonymous', :firstname => '', :mail => '', :login => '', :status => 0)
raise 'Unable to create the anonymous user.' if anonymous_user.new_record?
end
Jean-Philippe Lang
Fixed: non member or anonymous permissions change is effective only after an application restart (#1280)....
r1429 anonymous_user
Jean-Philippe Lang
Merged 0.6 branch into trunk....
r663 end
Jean-Philippe Lang
Makes minimum password length configurable....
r2586 protected
def validate
# Password length validation based on setting
if !password.nil? && password.size < Setting.password_min_length.to_i
errors.add(:password, :too_short, :count => Setting.password_min_length.to_i)
end
end
private
Jean-Philippe Lang
User groups branch merged....
r2755
Jean-Philippe Lang
added svn:eol-style native property on /app files...
r330 # Return password digest
def self.hash_password(clear_password)
Digest::SHA1.hexdigest(clear_password || "")
Jean-Philippe Lang
v0.2.0...
r5 end
Jean-Philippe Lang
Initial commit...
r2 end
Jean-Philippe Lang
Merged 0.6 branch into trunk....
r663
class AnonymousUser < User
Jean-Philippe Lang
Anonymous users can now be allowed to create, edit, comment issues, comment news and post messages in the forums....
r906 def validate_on_create
# There should be only one AnonymousUser in the database
errors.add_to_base 'An anonymous user already exists.' if AnonymousUser.find(:first)
Jean-Philippe Lang
* Added time zone support: users can select their time zone on their account view....
r904 end
Jean-Philippe Lang
Custom fields refactoring: most of code moved from controllers to models (using new module ActsAsCustomizable)....
r1578 def available_custom_fields
[]
end
Jean-Philippe Lang
Anonymous users can now be allowed to create, edit, comment issues, comment news and post messages in the forums....
r906 # Overrides a few properties
def logged?; false end
def admin; false end
Jean-Philippe Lang
Fixes ApplicationHelper#link_to_user...
r2910 def name(*args); I18n.t(:label_user_anonymous) end
Jean-Philippe Lang
Anonymous users can now be allowed to create, edit, comment issues, comment news and post messages in the forums....
r906 def mail; nil end
def time_zone; nil end
def rss_key; nil end
Jean-Philippe Lang
Merged 0.6 branch into trunk....
r663 end