##// END OF EJS Templates
Better error message and AR errors in log for failed LDAP on-the-fly user creation (closes #932, #1042)....
Jean-Philippe Lang -
r1330:a340d8c957bb
parent child
Show More
@@ -1,175 +1,177
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 class AccountController < ApplicationController
18 class AccountController < ApplicationController
19 layout 'base'
19 layout 'base'
20 helper :custom_fields
20 helper :custom_fields
21 include CustomFieldsHelper
21 include CustomFieldsHelper
22
22
23 # prevents login action to be filtered by check_if_login_required application scope filter
23 # prevents login action to be filtered by check_if_login_required application scope filter
24 skip_before_filter :check_if_login_required, :only => [:login, :lost_password, :register, :activate]
24 skip_before_filter :check_if_login_required, :only => [:login, :lost_password, :register, :activate]
25
25
26 # Show user's account
26 # Show user's account
27 def show
27 def show
28 @user = User.find_active(params[:id])
28 @user = User.find_active(params[:id])
29 @custom_values = @user.custom_values.find(:all, :include => :custom_field)
29 @custom_values = @user.custom_values.find(:all, :include => :custom_field)
30
30
31 # show only public projects and private projects that the logged in user is also a member of
31 # show only public projects and private projects that the logged in user is also a member of
32 @memberships = @user.memberships.select do |membership|
32 @memberships = @user.memberships.select do |membership|
33 membership.project.is_public? || (User.current.member_of?(membership.project))
33 membership.project.is_public? || (User.current.member_of?(membership.project))
34 end
34 end
35 rescue ActiveRecord::RecordNotFound
35 rescue ActiveRecord::RecordNotFound
36 render_404
36 render_404
37 end
37 end
38
38
39 # Login request and validation
39 # Login request and validation
40 def login
40 def login
41 if request.get?
41 if request.get?
42 # Logout user
42 # Logout user
43 self.logged_user = nil
43 self.logged_user = nil
44 else
44 else
45 # Authenticate user
45 # Authenticate user
46 user = User.try_to_login(params[:username], params[:password])
46 user = User.try_to_login(params[:username], params[:password])
47 if user
47 if user
48 self.logged_user = user
48 self.logged_user = user
49 # generate a key and set cookie if autologin
49 # generate a key and set cookie if autologin
50 if params[:autologin] && Setting.autologin?
50 if params[:autologin] && Setting.autologin?
51 token = Token.create(:user => user, :action => 'autologin')
51 token = Token.create(:user => user, :action => 'autologin')
52 cookies[:autologin] = { :value => token.value, :expires => 1.year.from_now }
52 cookies[:autologin] = { :value => token.value, :expires => 1.year.from_now }
53 end
53 end
54 redirect_back_or_default :controller => 'my', :action => 'page'
54 redirect_back_or_default :controller => 'my', :action => 'page'
55 else
55 else
56 flash.now[:error] = l(:notice_account_invalid_creditentials)
56 flash.now[:error] = l(:notice_account_invalid_creditentials)
57 end
57 end
58 end
58 end
59 rescue User::OnTheFlyCreationFailure
60 flash.now[:error] = 'Redmine could not retrieve the required information from the LDAP to create your account. Please, contact your Redmine administrator.'
59 end
61 end
60
62
61 # Log out current user and redirect to welcome page
63 # Log out current user and redirect to welcome page
62 def logout
64 def logout
63 cookies.delete :autologin
65 cookies.delete :autologin
64 Token.delete_all(["user_id = ? AND action = ?", User.current.id, 'autologin']) if User.current.logged?
66 Token.delete_all(["user_id = ? AND action = ?", User.current.id, 'autologin']) if User.current.logged?
65 self.logged_user = nil
67 self.logged_user = nil
66 redirect_to home_url
68 redirect_to home_url
67 end
69 end
68
70
69 # Enable user to choose a new password
71 # Enable user to choose a new password
70 def lost_password
72 def lost_password
71 redirect_to(home_url) && return unless Setting.lost_password?
73 redirect_to(home_url) && return unless Setting.lost_password?
72 if params[:token]
74 if params[:token]
73 @token = Token.find_by_action_and_value("recovery", params[:token])
75 @token = Token.find_by_action_and_value("recovery", params[:token])
74 redirect_to(home_url) && return unless @token and !@token.expired?
76 redirect_to(home_url) && return unless @token and !@token.expired?
75 @user = @token.user
77 @user = @token.user
76 if request.post?
78 if request.post?
77 @user.password, @user.password_confirmation = params[:new_password], params[:new_password_confirmation]
79 @user.password, @user.password_confirmation = params[:new_password], params[:new_password_confirmation]
78 if @user.save
80 if @user.save
79 @token.destroy
81 @token.destroy
80 flash[:notice] = l(:notice_account_password_updated)
82 flash[:notice] = l(:notice_account_password_updated)
81 redirect_to :action => 'login'
83 redirect_to :action => 'login'
82 return
84 return
83 end
85 end
84 end
86 end
85 render :template => "account/password_recovery"
87 render :template => "account/password_recovery"
86 return
88 return
87 else
89 else
88 if request.post?
90 if request.post?
89 user = User.find_by_mail(params[:mail])
91 user = User.find_by_mail(params[:mail])
90 # user not found in db
92 # user not found in db
91 flash.now[:error] = l(:notice_account_unknown_email) and return unless user
93 flash.now[:error] = l(:notice_account_unknown_email) and return unless user
92 # user uses an external authentification
94 # user uses an external authentification
93 flash.now[:error] = l(:notice_can_t_change_password) and return if user.auth_source_id
95 flash.now[:error] = l(:notice_can_t_change_password) and return if user.auth_source_id
94 # create a new token for password recovery
96 # create a new token for password recovery
95 token = Token.new(:user => user, :action => "recovery")
97 token = Token.new(:user => user, :action => "recovery")
96 if token.save
98 if token.save
97 Mailer.deliver_lost_password(token)
99 Mailer.deliver_lost_password(token)
98 flash[:notice] = l(:notice_account_lost_email_sent)
100 flash[:notice] = l(:notice_account_lost_email_sent)
99 redirect_to :action => 'login'
101 redirect_to :action => 'login'
100 return
102 return
101 end
103 end
102 end
104 end
103 end
105 end
104 end
106 end
105
107
106 # User self-registration
108 # User self-registration
107 def register
109 def register
108 redirect_to(home_url) && return unless Setting.self_registration?
110 redirect_to(home_url) && return unless Setting.self_registration?
109 if request.get?
111 if request.get?
110 @user = User.new(:language => Setting.default_language)
112 @user = User.new(:language => Setting.default_language)
111 @custom_values = UserCustomField.find(:all).collect { |x| CustomValue.new(:custom_field => x, :customized => @user) }
113 @custom_values = UserCustomField.find(:all).collect { |x| CustomValue.new(:custom_field => x, :customized => @user) }
112 else
114 else
113 @user = User.new(params[:user])
115 @user = User.new(params[:user])
114 @user.admin = false
116 @user.admin = false
115 @user.login = params[:user][:login]
117 @user.login = params[:user][:login]
116 @user.status = User::STATUS_REGISTERED
118 @user.status = User::STATUS_REGISTERED
117 @user.password, @user.password_confirmation = params[:password], params[:password_confirmation]
119 @user.password, @user.password_confirmation = params[:password], params[:password_confirmation]
118 @custom_values = UserCustomField.find(:all).collect { |x| CustomValue.new(:custom_field => x,
120 @custom_values = UserCustomField.find(:all).collect { |x| CustomValue.new(:custom_field => x,
119 :customized => @user,
121 :customized => @user,
120 :value => (params["custom_fields"] ? params["custom_fields"][x.id.to_s] : nil)) }
122 :value => (params["custom_fields"] ? params["custom_fields"][x.id.to_s] : nil)) }
121 @user.custom_values = @custom_values
123 @user.custom_values = @custom_values
122 case Setting.self_registration
124 case Setting.self_registration
123 when '1'
125 when '1'
124 # Email activation
126 # Email activation
125 token = Token.new(:user => @user, :action => "register")
127 token = Token.new(:user => @user, :action => "register")
126 if @user.save and token.save
128 if @user.save and token.save
127 Mailer.deliver_register(token)
129 Mailer.deliver_register(token)
128 flash[:notice] = l(:notice_account_register_done)
130 flash[:notice] = l(:notice_account_register_done)
129 redirect_to :action => 'login'
131 redirect_to :action => 'login'
130 end
132 end
131 when '3'
133 when '3'
132 # Automatic activation
134 # Automatic activation
133 @user.status = User::STATUS_ACTIVE
135 @user.status = User::STATUS_ACTIVE
134 if @user.save
136 if @user.save
135 flash[:notice] = l(:notice_account_activated)
137 flash[:notice] = l(:notice_account_activated)
136 redirect_to :action => 'login'
138 redirect_to :action => 'login'
137 end
139 end
138 else
140 else
139 # Manual activation by the administrator
141 # Manual activation by the administrator
140 if @user.save
142 if @user.save
141 # Sends an email to the administrators
143 # Sends an email to the administrators
142 Mailer.deliver_account_activation_request(@user)
144 Mailer.deliver_account_activation_request(@user)
143 flash[:notice] = l(:notice_account_pending)
145 flash[:notice] = l(:notice_account_pending)
144 redirect_to :action => 'login'
146 redirect_to :action => 'login'
145 end
147 end
146 end
148 end
147 end
149 end
148 end
150 end
149
151
150 # Token based account activation
152 # Token based account activation
151 def activate
153 def activate
152 redirect_to(home_url) && return unless Setting.self_registration? && params[:token]
154 redirect_to(home_url) && return unless Setting.self_registration? && params[:token]
153 token = Token.find_by_action_and_value('register', params[:token])
155 token = Token.find_by_action_and_value('register', params[:token])
154 redirect_to(home_url) && return unless token and !token.expired?
156 redirect_to(home_url) && return unless token and !token.expired?
155 user = token.user
157 user = token.user
156 redirect_to(home_url) && return unless user.status == User::STATUS_REGISTERED
158 redirect_to(home_url) && return unless user.status == User::STATUS_REGISTERED
157 user.status = User::STATUS_ACTIVE
159 user.status = User::STATUS_ACTIVE
158 if user.save
160 if user.save
159 token.destroy
161 token.destroy
160 flash[:notice] = l(:notice_account_activated)
162 flash[:notice] = l(:notice_account_activated)
161 end
163 end
162 redirect_to :action => 'login'
164 redirect_to :action => 'login'
163 end
165 end
164
166
165 private
167 private
166 def logged_user=(user)
168 def logged_user=(user)
167 if user && user.is_a?(User)
169 if user && user.is_a?(User)
168 User.current = user
170 User.current = user
169 session[:user_id] = user.id
171 session[:user_id] = user.id
170 else
172 else
171 User.current = User.anonymous
173 User.current = User.anonymous
172 session[:user_id] = nil
174 session[:user_id] = nil
173 end
175 end
174 end
176 end
175 end
177 end
@@ -1,286 +1,291
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require "digest/sha1"
18 require "digest/sha1"
19
19
20 class User < ActiveRecord::Base
20 class User < ActiveRecord::Base
21
22 class OnTheFlyCreationFailure < Exception; end
23
21 # Account statuses
24 # Account statuses
22 STATUS_ANONYMOUS = 0
25 STATUS_ANONYMOUS = 0
23 STATUS_ACTIVE = 1
26 STATUS_ACTIVE = 1
24 STATUS_REGISTERED = 2
27 STATUS_REGISTERED = 2
25 STATUS_LOCKED = 3
28 STATUS_LOCKED = 3
26
29
27 USER_FORMATS = {
30 USER_FORMATS = {
28 :firstname_lastname => '#{firstname} #{lastname}',
31 :firstname_lastname => '#{firstname} #{lastname}',
29 :firstname => '#{firstname}',
32 :firstname => '#{firstname}',
30 :lastname_firstname => '#{lastname} #{firstname}',
33 :lastname_firstname => '#{lastname} #{firstname}',
31 :lastname_coma_firstname => '#{lastname}, #{firstname}',
34 :lastname_coma_firstname => '#{lastname}, #{firstname}',
32 :username => '#{login}'
35 :username => '#{login}'
33 }
36 }
34
37
35 has_many :memberships, :class_name => 'Member', :include => [ :project, :role ], :conditions => "#{Project.table_name}.status=#{Project::STATUS_ACTIVE}", :order => "#{Project.table_name}.name", :dependent => :delete_all
38 has_many :memberships, :class_name => 'Member', :include => [ :project, :role ], :conditions => "#{Project.table_name}.status=#{Project::STATUS_ACTIVE}", :order => "#{Project.table_name}.name", :dependent => :delete_all
36 has_many :projects, :through => :memberships
39 has_many :projects, :through => :memberships
37 has_many :custom_values, :dependent => :delete_all, :as => :customized
40 has_many :custom_values, :dependent => :delete_all, :as => :customized
38 has_many :issue_categories, :foreign_key => 'assigned_to_id', :dependent => :nullify
41 has_many :issue_categories, :foreign_key => 'assigned_to_id', :dependent => :nullify
39 has_one :preference, :dependent => :destroy, :class_name => 'UserPreference'
42 has_one :preference, :dependent => :destroy, :class_name => 'UserPreference'
40 has_one :rss_token, :dependent => :destroy, :class_name => 'Token', :conditions => "action='feeds'"
43 has_one :rss_token, :dependent => :destroy, :class_name => 'Token', :conditions => "action='feeds'"
41 belongs_to :auth_source
44 belongs_to :auth_source
42
45
43 attr_accessor :password, :password_confirmation
46 attr_accessor :password, :password_confirmation
44 attr_accessor :last_before_login_on
47 attr_accessor :last_before_login_on
45 # Prevents unauthorized assignments
48 # Prevents unauthorized assignments
46 attr_protected :login, :admin, :password, :password_confirmation, :hashed_password
49 attr_protected :login, :admin, :password, :password_confirmation, :hashed_password
47
50
48 validates_presence_of :login, :firstname, :lastname, :mail, :if => Proc.new { |user| !user.is_a?(AnonymousUser) }
51 validates_presence_of :login, :firstname, :lastname, :mail, :if => Proc.new { |user| !user.is_a?(AnonymousUser) }
49 validates_uniqueness_of :login, :if => Proc.new { |user| !user.login.blank? }
52 validates_uniqueness_of :login, :if => Proc.new { |user| !user.login.blank? }
50 validates_uniqueness_of :mail, :if => Proc.new { |user| !user.mail.blank? }
53 validates_uniqueness_of :mail, :if => Proc.new { |user| !user.mail.blank? }
51 # Login must contain lettres, numbers, underscores only
54 # Login must contain lettres, numbers, underscores only
52 validates_format_of :login, :with => /^[a-z0-9_\-@\.]*$/i
55 validates_format_of :login, :with => /^[a-z0-9_\-@\.]*$/i
53 validates_length_of :login, :maximum => 30
56 validates_length_of :login, :maximum => 30
54 validates_format_of :firstname, :lastname, :with => /^[\w\s\'\-]*$/i
57 validates_format_of :firstname, :lastname, :with => /^[\w\s\'\-]*$/i
55 validates_length_of :firstname, :lastname, :maximum => 30
58 validates_length_of :firstname, :lastname, :maximum => 30
56 validates_format_of :mail, :with => /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i, :allow_nil => true
59 validates_format_of :mail, :with => /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i, :allow_nil => true
57 validates_length_of :mail, :maximum => 60, :allow_nil => true
60 validates_length_of :mail, :maximum => 60, :allow_nil => true
58 validates_length_of :password, :minimum => 4, :allow_nil => true
61 validates_length_of :password, :minimum => 4, :allow_nil => true
59 validates_confirmation_of :password, :allow_nil => true
62 validates_confirmation_of :password, :allow_nil => true
60 validates_associated :custom_values, :on => :update
63 validates_associated :custom_values, :on => :update
61
64
62 def before_create
65 def before_create
63 self.mail_notification = false
66 self.mail_notification = false
64 true
67 true
65 end
68 end
66
69
67 def before_save
70 def before_save
68 # update hashed_password if password was set
71 # update hashed_password if password was set
69 self.hashed_password = User.hash_password(self.password) if self.password
72 self.hashed_password = User.hash_password(self.password) if self.password
70 end
73 end
71
74
72 def self.active
75 def self.active
73 with_scope :find => { :conditions => [ "status = ?", STATUS_ACTIVE ] } do
76 with_scope :find => { :conditions => [ "status = ?", STATUS_ACTIVE ] } do
74 yield
77 yield
75 end
78 end
76 end
79 end
77
80
78 def self.find_active(*args)
81 def self.find_active(*args)
79 active do
82 active do
80 find(*args)
83 find(*args)
81 end
84 end
82 end
85 end
83
86
84 # Returns the user that matches provided login and password, or nil
87 # Returns the user that matches provided login and password, or nil
85 def self.try_to_login(login, password)
88 def self.try_to_login(login, password)
86 # Make sure no one can sign in with an empty password
89 # Make sure no one can sign in with an empty password
87 return nil if password.to_s.empty?
90 return nil if password.to_s.empty?
88 user = find(:first, :conditions => ["login=?", login])
91 user = find(:first, :conditions => ["login=?", login])
89 if user
92 if user
90 # user is already in local database
93 # user is already in local database
91 return nil if !user.active?
94 return nil if !user.active?
92 if user.auth_source
95 if user.auth_source
93 # user has an external authentication method
96 # user has an external authentication method
94 return nil unless user.auth_source.authenticate(login, password)
97 return nil unless user.auth_source.authenticate(login, password)
95 else
98 else
96 # authentication with local password
99 # authentication with local password
97 return nil unless User.hash_password(password) == user.hashed_password
100 return nil unless User.hash_password(password) == user.hashed_password
98 end
101 end
99 else
102 else
100 # user is not yet registered, try to authenticate with available sources
103 # user is not yet registered, try to authenticate with available sources
101 attrs = AuthSource.authenticate(login, password)
104 attrs = AuthSource.authenticate(login, password)
102 if attrs
105 if attrs
103 onthefly = new(*attrs)
106 onthefly = new(*attrs)
104 onthefly.login = login
107 onthefly.login = login
105 onthefly.language = Setting.default_language
108 onthefly.language = Setting.default_language
106 if onthefly.save
109 if onthefly.save
107 user = find(:first, :conditions => ["login=?", login])
110 user = find(:first, :conditions => ["login=?", login])
108 logger.info("User '#{user.login}' created on the fly.") if logger
111 logger.info("User '#{user.login}' created from the LDAP") if logger
112 else
113 logger.error("User '#{onthefly.login}' found in LDAP but could not be created (#{onthefly.errors.full_messages.join(', ')})") if logger
114 raise OnTheFlyCreationFailure.new
109 end
115 end
110 end
116 end
111 end
117 end
112 user.update_attribute(:last_login_on, Time.now) if user
118 user.update_attribute(:last_login_on, Time.now) if user
113 user
119 user
114
115 rescue => text
120 rescue => text
116 raise text
121 raise text
117 end
122 end
118
123
119 # Return user's full name for display
124 # Return user's full name for display
120 def name(formatter = nil)
125 def name(formatter = nil)
121 f = USER_FORMATS[formatter || Setting.user_format] || USER_FORMATS[:firstname_lastname]
126 f = USER_FORMATS[formatter || Setting.user_format] || USER_FORMATS[:firstname_lastname]
122 eval '"' + f + '"'
127 eval '"' + f + '"'
123 end
128 end
124
129
125 def active?
130 def active?
126 self.status == STATUS_ACTIVE
131 self.status == STATUS_ACTIVE
127 end
132 end
128
133
129 def registered?
134 def registered?
130 self.status == STATUS_REGISTERED
135 self.status == STATUS_REGISTERED
131 end
136 end
132
137
133 def locked?
138 def locked?
134 self.status == STATUS_LOCKED
139 self.status == STATUS_LOCKED
135 end
140 end
136
141
137 def check_password?(clear_password)
142 def check_password?(clear_password)
138 User.hash_password(clear_password) == self.hashed_password
143 User.hash_password(clear_password) == self.hashed_password
139 end
144 end
140
145
141 def pref
146 def pref
142 self.preference ||= UserPreference.new(:user => self)
147 self.preference ||= UserPreference.new(:user => self)
143 end
148 end
144
149
145 def time_zone
150 def time_zone
146 self.pref.time_zone.nil? ? nil : TimeZone[self.pref.time_zone]
151 self.pref.time_zone.nil? ? nil : TimeZone[self.pref.time_zone]
147 end
152 end
148
153
149 def wants_comments_in_reverse_order?
154 def wants_comments_in_reverse_order?
150 self.pref[:comments_sorting] == 'desc'
155 self.pref[:comments_sorting] == 'desc'
151 end
156 end
152
157
153 # Return user's RSS key (a 40 chars long string), used to access feeds
158 # Return user's RSS key (a 40 chars long string), used to access feeds
154 def rss_key
159 def rss_key
155 token = self.rss_token || Token.create(:user => self, :action => 'feeds')
160 token = self.rss_token || Token.create(:user => self, :action => 'feeds')
156 token.value
161 token.value
157 end
162 end
158
163
159 # Return an array of project ids for which the user has explicitly turned mail notifications on
164 # Return an array of project ids for which the user has explicitly turned mail notifications on
160 def notified_projects_ids
165 def notified_projects_ids
161 @notified_projects_ids ||= memberships.select {|m| m.mail_notification?}.collect(&:project_id)
166 @notified_projects_ids ||= memberships.select {|m| m.mail_notification?}.collect(&:project_id)
162 end
167 end
163
168
164 def notified_project_ids=(ids)
169 def notified_project_ids=(ids)
165 Member.update_all("mail_notification = #{connection.quoted_false}", ['user_id = ?', id])
170 Member.update_all("mail_notification = #{connection.quoted_false}", ['user_id = ?', id])
166 Member.update_all("mail_notification = #{connection.quoted_true}", ['user_id = ? AND project_id IN (?)', id, ids]) if ids && !ids.empty?
171 Member.update_all("mail_notification = #{connection.quoted_true}", ['user_id = ? AND project_id IN (?)', id, ids]) if ids && !ids.empty?
167 @notified_projects_ids = nil
172 @notified_projects_ids = nil
168 notified_projects_ids
173 notified_projects_ids
169 end
174 end
170
175
171 def self.find_by_rss_key(key)
176 def self.find_by_rss_key(key)
172 token = Token.find_by_value(key)
177 token = Token.find_by_value(key)
173 token && token.user.active? ? token.user : nil
178 token && token.user.active? ? token.user : nil
174 end
179 end
175
180
176 def self.find_by_autologin_key(key)
181 def self.find_by_autologin_key(key)
177 token = Token.find_by_action_and_value('autologin', key)
182 token = Token.find_by_action_and_value('autologin', key)
178 token && (token.created_on > Setting.autologin.to_i.day.ago) && token.user.active? ? token.user : nil
183 token && (token.created_on > Setting.autologin.to_i.day.ago) && token.user.active? ? token.user : nil
179 end
184 end
180
185
181 def <=>(user)
186 def <=>(user)
182 if user.nil?
187 if user.nil?
183 -1
188 -1
184 elsif lastname.to_s.downcase == user.lastname.to_s.downcase
189 elsif lastname.to_s.downcase == user.lastname.to_s.downcase
185 firstname.to_s.downcase <=> user.firstname.to_s.downcase
190 firstname.to_s.downcase <=> user.firstname.to_s.downcase
186 else
191 else
187 lastname.to_s.downcase <=> user.lastname.to_s.downcase
192 lastname.to_s.downcase <=> user.lastname.to_s.downcase
188 end
193 end
189 end
194 end
190
195
191 def to_s
196 def to_s
192 name
197 name
193 end
198 end
194
199
195 def logged?
200 def logged?
196 true
201 true
197 end
202 end
198
203
199 # Return user's role for project
204 # Return user's role for project
200 def role_for_project(project)
205 def role_for_project(project)
201 # No role on archived projects
206 # No role on archived projects
202 return nil unless project && project.active?
207 return nil unless project && project.active?
203 if logged?
208 if logged?
204 # Find project membership
209 # Find project membership
205 membership = memberships.detect {|m| m.project_id == project.id}
210 membership = memberships.detect {|m| m.project_id == project.id}
206 if membership
211 if membership
207 membership.role
212 membership.role
208 else
213 else
209 @role_non_member ||= Role.non_member
214 @role_non_member ||= Role.non_member
210 end
215 end
211 else
216 else
212 @role_anonymous ||= Role.anonymous
217 @role_anonymous ||= Role.anonymous
213 end
218 end
214 end
219 end
215
220
216 # Return true if the user is a member of project
221 # Return true if the user is a member of project
217 def member_of?(project)
222 def member_of?(project)
218 role_for_project(project).member?
223 role_for_project(project).member?
219 end
224 end
220
225
221 # Return true if the user is allowed to do the specified action on project
226 # Return true if the user is allowed to do the specified action on project
222 # action can be:
227 # action can be:
223 # * a parameter-like Hash (eg. :controller => 'projects', :action => 'edit')
228 # * a parameter-like Hash (eg. :controller => 'projects', :action => 'edit')
224 # * a permission Symbol (eg. :edit_project)
229 # * a permission Symbol (eg. :edit_project)
225 def allowed_to?(action, project, options={})
230 def allowed_to?(action, project, options={})
226 if project
231 if project
227 # No action allowed on archived projects
232 # No action allowed on archived projects
228 return false unless project.active?
233 return false unless project.active?
229 # No action allowed on disabled modules
234 # No action allowed on disabled modules
230 return false unless project.allows_to?(action)
235 return false unless project.allows_to?(action)
231 # Admin users are authorized for anything else
236 # Admin users are authorized for anything else
232 return true if admin?
237 return true if admin?
233
238
234 role = role_for_project(project)
239 role = role_for_project(project)
235 return false unless role
240 return false unless role
236 role.allowed_to?(action) && (project.is_public? || role.member?)
241 role.allowed_to?(action) && (project.is_public? || role.member?)
237
242
238 elsif options[:global]
243 elsif options[:global]
239 # authorize if user has at least one role that has this permission
244 # authorize if user has at least one role that has this permission
240 roles = memberships.collect {|m| m.role}.uniq
245 roles = memberships.collect {|m| m.role}.uniq
241 roles.detect {|r| r.allowed_to?(action)}
246 roles.detect {|r| r.allowed_to?(action)}
242 else
247 else
243 false
248 false
244 end
249 end
245 end
250 end
246
251
247 def self.current=(user)
252 def self.current=(user)
248 @current_user = user
253 @current_user = user
249 end
254 end
250
255
251 def self.current
256 def self.current
252 @current_user ||= User.anonymous
257 @current_user ||= User.anonymous
253 end
258 end
254
259
255 def self.anonymous
260 def self.anonymous
256 return @anonymous_user if @anonymous_user
261 return @anonymous_user if @anonymous_user
257 anonymous_user = AnonymousUser.find(:first)
262 anonymous_user = AnonymousUser.find(:first)
258 if anonymous_user.nil?
263 if anonymous_user.nil?
259 anonymous_user = AnonymousUser.create(:lastname => 'Anonymous', :firstname => '', :mail => '', :login => '', :status => 0)
264 anonymous_user = AnonymousUser.create(:lastname => 'Anonymous', :firstname => '', :mail => '', :login => '', :status => 0)
260 raise 'Unable to create the anonymous user.' if anonymous_user.new_record?
265 raise 'Unable to create the anonymous user.' if anonymous_user.new_record?
261 end
266 end
262 @anonymous_user = anonymous_user
267 @anonymous_user = anonymous_user
263 end
268 end
264
269
265 private
270 private
266 # Return password digest
271 # Return password digest
267 def self.hash_password(clear_password)
272 def self.hash_password(clear_password)
268 Digest::SHA1.hexdigest(clear_password || "")
273 Digest::SHA1.hexdigest(clear_password || "")
269 end
274 end
270 end
275 end
271
276
272 class AnonymousUser < User
277 class AnonymousUser < User
273
278
274 def validate_on_create
279 def validate_on_create
275 # There should be only one AnonymousUser in the database
280 # There should be only one AnonymousUser in the database
276 errors.add_to_base 'An anonymous user already exists.' if AnonymousUser.find(:first)
281 errors.add_to_base 'An anonymous user already exists.' if AnonymousUser.find(:first)
277 end
282 end
278
283
279 # Overrides a few properties
284 # Overrides a few properties
280 def logged?; false end
285 def logged?; false end
281 def admin; false end
286 def admin; false end
282 def name; 'Anonymous' end
287 def name; 'Anonymous' end
283 def mail; nil end
288 def mail; nil end
284 def time_zone; nil end
289 def time_zone; nil end
285 def rss_key; nil end
290 def rss_key; nil end
286 end
291 end
General Comments 0
You need to be logged in to leave comments. Login now