##// END OF EJS Templates
Code cleanup: renamed variables in User#allowed_to? with explicit names...
Jean-Baptiste Barth -
r4120:c43ef6e7696e
parent child
Show More
@@ -1,483 +1,483
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2009 Jean-Philippe Lang
2 # Copyright (C) 2006-2009 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 < Principal
20 class User < Principal
21
21
22 # Account statuses
22 # Account statuses
23 STATUS_ANONYMOUS = 0
23 STATUS_ANONYMOUS = 0
24 STATUS_ACTIVE = 1
24 STATUS_ACTIVE = 1
25 STATUS_REGISTERED = 2
25 STATUS_REGISTERED = 2
26 STATUS_LOCKED = 3
26 STATUS_LOCKED = 3
27
27
28 USER_FORMATS = {
28 USER_FORMATS = {
29 :firstname_lastname => '#{firstname} #{lastname}',
29 :firstname_lastname => '#{firstname} #{lastname}',
30 :firstname => '#{firstname}',
30 :firstname => '#{firstname}',
31 :lastname_firstname => '#{lastname} #{firstname}',
31 :lastname_firstname => '#{lastname} #{firstname}',
32 :lastname_coma_firstname => '#{lastname}, #{firstname}',
32 :lastname_coma_firstname => '#{lastname}, #{firstname}',
33 :username => '#{login}'
33 :username => '#{login}'
34 }
34 }
35
35
36 MAIL_NOTIFICATION_OPTIONS = [
36 MAIL_NOTIFICATION_OPTIONS = [
37 [:all, :label_user_mail_option_all],
37 [:all, :label_user_mail_option_all],
38 [:selected, :label_user_mail_option_selected],
38 [:selected, :label_user_mail_option_selected],
39 [:none, :label_user_mail_option_none],
39 [:none, :label_user_mail_option_none],
40 [:only_my_events, :label_user_mail_option_only_my_events],
40 [:only_my_events, :label_user_mail_option_only_my_events],
41 [:only_assigned, :label_user_mail_option_only_assigned],
41 [:only_assigned, :label_user_mail_option_only_assigned],
42 [:only_owner, :label_user_mail_option_only_owner]
42 [:only_owner, :label_user_mail_option_only_owner]
43 ]
43 ]
44
44
45 has_and_belongs_to_many :groups, :after_add => Proc.new {|user, group| group.user_added(user)},
45 has_and_belongs_to_many :groups, :after_add => Proc.new {|user, group| group.user_added(user)},
46 :after_remove => Proc.new {|user, group| group.user_removed(user)}
46 :after_remove => Proc.new {|user, group| group.user_removed(user)}
47 has_many :issue_categories, :foreign_key => 'assigned_to_id', :dependent => :nullify
47 has_many :issue_categories, :foreign_key => 'assigned_to_id', :dependent => :nullify
48 has_many :changesets, :dependent => :nullify
48 has_many :changesets, :dependent => :nullify
49 has_one :preference, :dependent => :destroy, :class_name => 'UserPreference'
49 has_one :preference, :dependent => :destroy, :class_name => 'UserPreference'
50 has_one :rss_token, :dependent => :destroy, :class_name => 'Token', :conditions => "action='feeds'"
50 has_one :rss_token, :dependent => :destroy, :class_name => 'Token', :conditions => "action='feeds'"
51 has_one :api_token, :dependent => :destroy, :class_name => 'Token', :conditions => "action='api'"
51 has_one :api_token, :dependent => :destroy, :class_name => 'Token', :conditions => "action='api'"
52 belongs_to :auth_source
52 belongs_to :auth_source
53
53
54 # Active non-anonymous users scope
54 # Active non-anonymous users scope
55 named_scope :active, :conditions => "#{User.table_name}.status = #{STATUS_ACTIVE}"
55 named_scope :active, :conditions => "#{User.table_name}.status = #{STATUS_ACTIVE}"
56
56
57 acts_as_customizable
57 acts_as_customizable
58
58
59 attr_accessor :password, :password_confirmation
59 attr_accessor :password, :password_confirmation
60 attr_accessor :last_before_login_on
60 attr_accessor :last_before_login_on
61 # Prevents unauthorized assignments
61 # Prevents unauthorized assignments
62 attr_protected :login, :admin, :password, :password_confirmation, :hashed_password, :group_ids
62 attr_protected :login, :admin, :password, :password_confirmation, :hashed_password, :group_ids
63
63
64 validates_presence_of :login, :firstname, :lastname, :mail, :if => Proc.new { |user| !user.is_a?(AnonymousUser) }
64 validates_presence_of :login, :firstname, :lastname, :mail, :if => Proc.new { |user| !user.is_a?(AnonymousUser) }
65 validates_uniqueness_of :login, :if => Proc.new { |user| !user.login.blank? }, :case_sensitive => false
65 validates_uniqueness_of :login, :if => Proc.new { |user| !user.login.blank? }, :case_sensitive => false
66 validates_uniqueness_of :mail, :if => Proc.new { |user| !user.mail.blank? }, :case_sensitive => false
66 validates_uniqueness_of :mail, :if => Proc.new { |user| !user.mail.blank? }, :case_sensitive => false
67 # Login must contain lettres, numbers, underscores only
67 # Login must contain lettres, numbers, underscores only
68 validates_format_of :login, :with => /^[a-z0-9_\-@\.]*$/i
68 validates_format_of :login, :with => /^[a-z0-9_\-@\.]*$/i
69 validates_length_of :login, :maximum => 30
69 validates_length_of :login, :maximum => 30
70 validates_format_of :firstname, :lastname, :with => /^[\w\s\'\-\.]*$/i
70 validates_format_of :firstname, :lastname, :with => /^[\w\s\'\-\.]*$/i
71 validates_length_of :firstname, :lastname, :maximum => 30
71 validates_length_of :firstname, :lastname, :maximum => 30
72 validates_format_of :mail, :with => /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i, :allow_nil => true
72 validates_format_of :mail, :with => /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i, :allow_nil => true
73 validates_length_of :mail, :maximum => 60, :allow_nil => true
73 validates_length_of :mail, :maximum => 60, :allow_nil => true
74 validates_confirmation_of :password, :allow_nil => true
74 validates_confirmation_of :password, :allow_nil => true
75
75
76 def before_create
76 def before_create
77 self.mail_notification = Setting.default_notification_option if self.mail_notification.blank?
77 self.mail_notification = Setting.default_notification_option if self.mail_notification.blank?
78 true
78 true
79 end
79 end
80
80
81 def before_save
81 def before_save
82 # update hashed_password if password was set
82 # update hashed_password if password was set
83 self.hashed_password = User.hash_password(self.password) if self.password && self.auth_source_id.blank?
83 self.hashed_password = User.hash_password(self.password) if self.password && self.auth_source_id.blank?
84 end
84 end
85
85
86 def reload(*args)
86 def reload(*args)
87 @name = nil
87 @name = nil
88 super
88 super
89 end
89 end
90
90
91 def mail=(arg)
91 def mail=(arg)
92 write_attribute(:mail, arg.to_s.strip)
92 write_attribute(:mail, arg.to_s.strip)
93 end
93 end
94
94
95 def identity_url=(url)
95 def identity_url=(url)
96 if url.blank?
96 if url.blank?
97 write_attribute(:identity_url, '')
97 write_attribute(:identity_url, '')
98 else
98 else
99 begin
99 begin
100 write_attribute(:identity_url, OpenIdAuthentication.normalize_identifier(url))
100 write_attribute(:identity_url, OpenIdAuthentication.normalize_identifier(url))
101 rescue OpenIdAuthentication::InvalidOpenId
101 rescue OpenIdAuthentication::InvalidOpenId
102 # Invlaid url, don't save
102 # Invlaid url, don't save
103 end
103 end
104 end
104 end
105 self.read_attribute(:identity_url)
105 self.read_attribute(:identity_url)
106 end
106 end
107
107
108 # Returns the user that matches provided login and password, or nil
108 # Returns the user that matches provided login and password, or nil
109 def self.try_to_login(login, password)
109 def self.try_to_login(login, password)
110 # Make sure no one can sign in with an empty password
110 # Make sure no one can sign in with an empty password
111 return nil if password.to_s.empty?
111 return nil if password.to_s.empty?
112 user = find_by_login(login)
112 user = find_by_login(login)
113 if user
113 if user
114 # user is already in local database
114 # user is already in local database
115 return nil if !user.active?
115 return nil if !user.active?
116 if user.auth_source
116 if user.auth_source
117 # user has an external authentication method
117 # user has an external authentication method
118 return nil unless user.auth_source.authenticate(login, password)
118 return nil unless user.auth_source.authenticate(login, password)
119 else
119 else
120 # authentication with local password
120 # authentication with local password
121 return nil unless User.hash_password(password) == user.hashed_password
121 return nil unless User.hash_password(password) == user.hashed_password
122 end
122 end
123 else
123 else
124 # user is not yet registered, try to authenticate with available sources
124 # user is not yet registered, try to authenticate with available sources
125 attrs = AuthSource.authenticate(login, password)
125 attrs = AuthSource.authenticate(login, password)
126 if attrs
126 if attrs
127 user = new(attrs)
127 user = new(attrs)
128 user.login = login
128 user.login = login
129 user.language = Setting.default_language
129 user.language = Setting.default_language
130 if user.save
130 if user.save
131 user.reload
131 user.reload
132 logger.info("User '#{user.login}' created from external auth source: #{user.auth_source.type} - #{user.auth_source.name}") if logger && user.auth_source
132 logger.info("User '#{user.login}' created from external auth source: #{user.auth_source.type} - #{user.auth_source.name}") if logger && user.auth_source
133 end
133 end
134 end
134 end
135 end
135 end
136 user.update_attribute(:last_login_on, Time.now) if user && !user.new_record?
136 user.update_attribute(:last_login_on, Time.now) if user && !user.new_record?
137 user
137 user
138 rescue => text
138 rescue => text
139 raise text
139 raise text
140 end
140 end
141
141
142 # Returns the user who matches the given autologin +key+ or nil
142 # Returns the user who matches the given autologin +key+ or nil
143 def self.try_to_autologin(key)
143 def self.try_to_autologin(key)
144 tokens = Token.find_all_by_action_and_value('autologin', key)
144 tokens = Token.find_all_by_action_and_value('autologin', key)
145 # Make sure there's only 1 token that matches the key
145 # Make sure there's only 1 token that matches the key
146 if tokens.size == 1
146 if tokens.size == 1
147 token = tokens.first
147 token = tokens.first
148 if (token.created_on > Setting.autologin.to_i.day.ago) && token.user && token.user.active?
148 if (token.created_on > Setting.autologin.to_i.day.ago) && token.user && token.user.active?
149 token.user.update_attribute(:last_login_on, Time.now)
149 token.user.update_attribute(:last_login_on, Time.now)
150 token.user
150 token.user
151 end
151 end
152 end
152 end
153 end
153 end
154
154
155 # Return user's full name for display
155 # Return user's full name for display
156 def name(formatter = nil)
156 def name(formatter = nil)
157 if formatter
157 if formatter
158 eval('"' + (USER_FORMATS[formatter] || USER_FORMATS[:firstname_lastname]) + '"')
158 eval('"' + (USER_FORMATS[formatter] || USER_FORMATS[:firstname_lastname]) + '"')
159 else
159 else
160 @name ||= eval('"' + (USER_FORMATS[Setting.user_format] || USER_FORMATS[:firstname_lastname]) + '"')
160 @name ||= eval('"' + (USER_FORMATS[Setting.user_format] || USER_FORMATS[:firstname_lastname]) + '"')
161 end
161 end
162 end
162 end
163
163
164 def active?
164 def active?
165 self.status == STATUS_ACTIVE
165 self.status == STATUS_ACTIVE
166 end
166 end
167
167
168 def registered?
168 def registered?
169 self.status == STATUS_REGISTERED
169 self.status == STATUS_REGISTERED
170 end
170 end
171
171
172 def locked?
172 def locked?
173 self.status == STATUS_LOCKED
173 self.status == STATUS_LOCKED
174 end
174 end
175
175
176 def activate
176 def activate
177 self.status = STATUS_ACTIVE
177 self.status = STATUS_ACTIVE
178 end
178 end
179
179
180 def register
180 def register
181 self.status = STATUS_REGISTERED
181 self.status = STATUS_REGISTERED
182 end
182 end
183
183
184 def lock
184 def lock
185 self.status = STATUS_LOCKED
185 self.status = STATUS_LOCKED
186 end
186 end
187
187
188 def activate!
188 def activate!
189 update_attribute(:status, STATUS_ACTIVE)
189 update_attribute(:status, STATUS_ACTIVE)
190 end
190 end
191
191
192 def register!
192 def register!
193 update_attribute(:status, STATUS_REGISTERED)
193 update_attribute(:status, STATUS_REGISTERED)
194 end
194 end
195
195
196 def lock!
196 def lock!
197 update_attribute(:status, STATUS_LOCKED)
197 update_attribute(:status, STATUS_LOCKED)
198 end
198 end
199
199
200 def check_password?(clear_password)
200 def check_password?(clear_password)
201 if auth_source_id.present?
201 if auth_source_id.present?
202 auth_source.authenticate(self.login, clear_password)
202 auth_source.authenticate(self.login, clear_password)
203 else
203 else
204 User.hash_password(clear_password) == self.hashed_password
204 User.hash_password(clear_password) == self.hashed_password
205 end
205 end
206 end
206 end
207
207
208 # Does the backend storage allow this user to change their password?
208 # Does the backend storage allow this user to change their password?
209 def change_password_allowed?
209 def change_password_allowed?
210 return true if auth_source_id.blank?
210 return true if auth_source_id.blank?
211 return auth_source.allow_password_changes?
211 return auth_source.allow_password_changes?
212 end
212 end
213
213
214 # Generate and set a random password. Useful for automated user creation
214 # Generate and set a random password. Useful for automated user creation
215 # Based on Token#generate_token_value
215 # Based on Token#generate_token_value
216 #
216 #
217 def random_password
217 def random_password
218 chars = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a
218 chars = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a
219 password = ''
219 password = ''
220 40.times { |i| password << chars[rand(chars.size-1)] }
220 40.times { |i| password << chars[rand(chars.size-1)] }
221 self.password = password
221 self.password = password
222 self.password_confirmation = password
222 self.password_confirmation = password
223 self
223 self
224 end
224 end
225
225
226 def pref
226 def pref
227 self.preference ||= UserPreference.new(:user => self)
227 self.preference ||= UserPreference.new(:user => self)
228 end
228 end
229
229
230 def time_zone
230 def time_zone
231 @time_zone ||= (self.pref.time_zone.blank? ? nil : ActiveSupport::TimeZone[self.pref.time_zone])
231 @time_zone ||= (self.pref.time_zone.blank? ? nil : ActiveSupport::TimeZone[self.pref.time_zone])
232 end
232 end
233
233
234 def wants_comments_in_reverse_order?
234 def wants_comments_in_reverse_order?
235 self.pref[:comments_sorting] == 'desc'
235 self.pref[:comments_sorting] == 'desc'
236 end
236 end
237
237
238 # Return user's RSS key (a 40 chars long string), used to access feeds
238 # Return user's RSS key (a 40 chars long string), used to access feeds
239 def rss_key
239 def rss_key
240 token = self.rss_token || Token.create(:user => self, :action => 'feeds')
240 token = self.rss_token || Token.create(:user => self, :action => 'feeds')
241 token.value
241 token.value
242 end
242 end
243
243
244 # Return user's API key (a 40 chars long string), used to access the API
244 # Return user's API key (a 40 chars long string), used to access the API
245 def api_key
245 def api_key
246 token = self.api_token || self.create_api_token(:action => 'api')
246 token = self.api_token || self.create_api_token(:action => 'api')
247 token.value
247 token.value
248 end
248 end
249
249
250 # Return an array of project ids for which the user has explicitly turned mail notifications on
250 # Return an array of project ids for which the user has explicitly turned mail notifications on
251 def notified_projects_ids
251 def notified_projects_ids
252 @notified_projects_ids ||= memberships.select {|m| m.mail_notification?}.collect(&:project_id)
252 @notified_projects_ids ||= memberships.select {|m| m.mail_notification?}.collect(&:project_id)
253 end
253 end
254
254
255 def notified_project_ids=(ids)
255 def notified_project_ids=(ids)
256 Member.update_all("mail_notification = #{connection.quoted_false}", ['user_id = ?', id])
256 Member.update_all("mail_notification = #{connection.quoted_false}", ['user_id = ?', id])
257 Member.update_all("mail_notification = #{connection.quoted_true}", ['user_id = ? AND project_id IN (?)', id, ids]) if ids && !ids.empty?
257 Member.update_all("mail_notification = #{connection.quoted_true}", ['user_id = ? AND project_id IN (?)', id, ids]) if ids && !ids.empty?
258 @notified_projects_ids = nil
258 @notified_projects_ids = nil
259 notified_projects_ids
259 notified_projects_ids
260 end
260 end
261
261
262 # Only users that belong to more than 1 project can select projects for which they are notified
262 # Only users that belong to more than 1 project can select projects for which they are notified
263 def valid_notification_options
263 def valid_notification_options
264 # Note that @user.membership.size would fail since AR ignores
264 # Note that @user.membership.size would fail since AR ignores
265 # :include association option when doing a count
265 # :include association option when doing a count
266 if memberships.length < 1
266 if memberships.length < 1
267 MAIL_NOTIFICATION_OPTIONS.delete_if {|option| option.first == :selected}
267 MAIL_NOTIFICATION_OPTIONS.delete_if {|option| option.first == :selected}
268 else
268 else
269 MAIL_NOTIFICATION_OPTIONS
269 MAIL_NOTIFICATION_OPTIONS
270 end
270 end
271 end
271 end
272
272
273 # Find a user account by matching the exact login and then a case-insensitive
273 # Find a user account by matching the exact login and then a case-insensitive
274 # version. Exact matches will be given priority.
274 # version. Exact matches will be given priority.
275 def self.find_by_login(login)
275 def self.find_by_login(login)
276 # force string comparison to be case sensitive on MySQL
276 # force string comparison to be case sensitive on MySQL
277 type_cast = (ActiveRecord::Base.connection.adapter_name == 'MySQL') ? 'BINARY' : ''
277 type_cast = (ActiveRecord::Base.connection.adapter_name == 'MySQL') ? 'BINARY' : ''
278
278
279 # First look for an exact match
279 # First look for an exact match
280 user = first(:conditions => ["#{type_cast} login = ?", login])
280 user = first(:conditions => ["#{type_cast} login = ?", login])
281 # Fail over to case-insensitive if none was found
281 # Fail over to case-insensitive if none was found
282 user ||= first(:conditions => ["#{type_cast} LOWER(login) = ?", login.to_s.downcase])
282 user ||= first(:conditions => ["#{type_cast} LOWER(login) = ?", login.to_s.downcase])
283 end
283 end
284
284
285 def self.find_by_rss_key(key)
285 def self.find_by_rss_key(key)
286 token = Token.find_by_value(key)
286 token = Token.find_by_value(key)
287 token && token.user.active? ? token.user : nil
287 token && token.user.active? ? token.user : nil
288 end
288 end
289
289
290 def self.find_by_api_key(key)
290 def self.find_by_api_key(key)
291 token = Token.find_by_action_and_value('api', key)
291 token = Token.find_by_action_and_value('api', key)
292 token && token.user.active? ? token.user : nil
292 token && token.user.active? ? token.user : nil
293 end
293 end
294
294
295 # Makes find_by_mail case-insensitive
295 # Makes find_by_mail case-insensitive
296 def self.find_by_mail(mail)
296 def self.find_by_mail(mail)
297 find(:first, :conditions => ["LOWER(mail) = ?", mail.to_s.downcase])
297 find(:first, :conditions => ["LOWER(mail) = ?", mail.to_s.downcase])
298 end
298 end
299
299
300 def to_s
300 def to_s
301 name
301 name
302 end
302 end
303
303
304 # Returns the current day according to user's time zone
304 # Returns the current day according to user's time zone
305 def today
305 def today
306 if time_zone.nil?
306 if time_zone.nil?
307 Date.today
307 Date.today
308 else
308 else
309 Time.now.in_time_zone(time_zone).to_date
309 Time.now.in_time_zone(time_zone).to_date
310 end
310 end
311 end
311 end
312
312
313 def logged?
313 def logged?
314 true
314 true
315 end
315 end
316
316
317 def anonymous?
317 def anonymous?
318 !logged?
318 !logged?
319 end
319 end
320
320
321 # Return user's roles for project
321 # Return user's roles for project
322 def roles_for_project(project)
322 def roles_for_project(project)
323 roles = []
323 roles = []
324 # No role on archived projects
324 # No role on archived projects
325 return roles unless project && project.active?
325 return roles unless project && project.active?
326 if logged?
326 if logged?
327 # Find project membership
327 # Find project membership
328 membership = memberships.detect {|m| m.project_id == project.id}
328 membership = memberships.detect {|m| m.project_id == project.id}
329 if membership
329 if membership
330 roles = membership.roles
330 roles = membership.roles
331 else
331 else
332 @role_non_member ||= Role.non_member
332 @role_non_member ||= Role.non_member
333 roles << @role_non_member
333 roles << @role_non_member
334 end
334 end
335 else
335 else
336 @role_anonymous ||= Role.anonymous
336 @role_anonymous ||= Role.anonymous
337 roles << @role_anonymous
337 roles << @role_anonymous
338 end
338 end
339 roles
339 roles
340 end
340 end
341
341
342 # Return true if the user is a member of project
342 # Return true if the user is a member of project
343 def member_of?(project)
343 def member_of?(project)
344 !roles_for_project(project).detect {|role| role.member?}.nil?
344 !roles_for_project(project).detect {|role| role.member?}.nil?
345 end
345 end
346
346
347 # Return true if the user is allowed to do the specified action on a specific context
347 # Return true if the user is allowed to do the specified action on a specific context
348 # Action can be:
348 # Action can be:
349 # * a parameter-like Hash (eg. :controller => 'projects', :action => 'edit')
349 # * a parameter-like Hash (eg. :controller => 'projects', :action => 'edit')
350 # * a permission Symbol (eg. :edit_project)
350 # * a permission Symbol (eg. :edit_project)
351 # Context can be:
351 # Context can be:
352 # * a project : returns true if user is allowed to do the specified action on this project
352 # * a project : returns true if user is allowed to do the specified action on this project
353 # * a group of projects : returns true if user is allowed on every project
353 # * a group of projects : returns true if user is allowed on every project
354 # * nil with options[:global] set : check if user has at least one role allowed for this action,
354 # * nil with options[:global] set : check if user has at least one role allowed for this action,
355 # or falls back to Non Member / Anonymous permissions depending if the user is logged
355 # or falls back to Non Member / Anonymous permissions depending if the user is logged
356 def allowed_to?(action, project, options={})
356 def allowed_to?(action, context, options={})
357 if project && project.is_a?(Project)
357 if context && context.is_a?(Project)
358 # No action allowed on archived projects
358 # No action allowed on archived projects
359 return false unless project.active?
359 return false unless context.active?
360 # No action allowed on disabled modules
360 # No action allowed on disabled modules
361 return false unless project.allows_to?(action)
361 return false unless context.allows_to?(action)
362 # Admin users are authorized for anything else
362 # Admin users are authorized for anything else
363 return true if admin?
363 return true if admin?
364
364
365 roles = roles_for_project(project)
365 roles = roles_for_project(context)
366 return false unless roles
366 return false unless roles
367 roles.detect {|role| (project.is_public? || role.member?) && role.allowed_to?(action)}
367 roles.detect {|role| (context.is_public? || role.member?) && role.allowed_to?(action)}
368
368
369 elsif project && project.is_a?(Array)
369 elsif context && context.is_a?(Array)
370 # Authorize if user is authorized on every element of the array
370 # Authorize if user is authorized on every element of the array
371 project.map do |p|
371 context.map do |project|
372 allowed_to?(action,p,options)
372 allowed_to?(action,project,options)
373 end.inject do |memo,p|
373 end.inject do |memo,allowed|
374 memo && p
374 memo && allowed
375 end
375 end
376 elsif options[:global]
376 elsif options[:global]
377 # Admin users are always authorized
377 # Admin users are always authorized
378 return true if admin?
378 return true if admin?
379
379
380 # authorize if user has at least one role that has this permission
380 # authorize if user has at least one role that has this permission
381 roles = memberships.collect {|m| m.roles}.flatten.uniq
381 roles = memberships.collect {|m| m.roles}.flatten.uniq
382 roles.detect {|r| r.allowed_to?(action)} || (self.logged? ? Role.non_member.allowed_to?(action) : Role.anonymous.allowed_to?(action))
382 roles.detect {|r| r.allowed_to?(action)} || (self.logged? ? Role.non_member.allowed_to?(action) : Role.anonymous.allowed_to?(action))
383 else
383 else
384 false
384 false
385 end
385 end
386 end
386 end
387
387
388 # Is the user allowed to do the specified action on any project?
388 # Is the user allowed to do the specified action on any project?
389 # See allowed_to? for the actions and valid options.
389 # See allowed_to? for the actions and valid options.
390 def allowed_to_globally?(action, options)
390 def allowed_to_globally?(action, options)
391 allowed_to?(action, nil, options.reverse_merge(:global => true))
391 allowed_to?(action, nil, options.reverse_merge(:global => true))
392 end
392 end
393
393
394 # Utility method to help check if a user should be notified about an
394 # Utility method to help check if a user should be notified about an
395 # event.
395 # event.
396 #
396 #
397 # TODO: only supports Issue events currently
397 # TODO: only supports Issue events currently
398 def notify_about?(object)
398 def notify_about?(object)
399 case mail_notification.to_sym
399 case mail_notification.to_sym
400 when :all
400 when :all
401 true
401 true
402 when :selected
402 when :selected
403 # Handled by the Project
403 # Handled by the Project
404 when :none
404 when :none
405 false
405 false
406 when :only_my_events
406 when :only_my_events
407 if object.is_a?(Issue) && (object.author == self || object.assigned_to == self)
407 if object.is_a?(Issue) && (object.author == self || object.assigned_to == self)
408 true
408 true
409 else
409 else
410 false
410 false
411 end
411 end
412 when :only_assigned
412 when :only_assigned
413 if object.is_a?(Issue) && object.assigned_to == self
413 if object.is_a?(Issue) && object.assigned_to == self
414 true
414 true
415 else
415 else
416 false
416 false
417 end
417 end
418 when :only_owner
418 when :only_owner
419 if object.is_a?(Issue) && object.author == self
419 if object.is_a?(Issue) && object.author == self
420 true
420 true
421 else
421 else
422 false
422 false
423 end
423 end
424 else
424 else
425 false
425 false
426 end
426 end
427 end
427 end
428
428
429 def self.current=(user)
429 def self.current=(user)
430 @current_user = user
430 @current_user = user
431 end
431 end
432
432
433 def self.current
433 def self.current
434 @current_user ||= User.anonymous
434 @current_user ||= User.anonymous
435 end
435 end
436
436
437 # Returns the anonymous user. If the anonymous user does not exist, it is created. There can be only
437 # Returns the anonymous user. If the anonymous user does not exist, it is created. There can be only
438 # one anonymous user per database.
438 # one anonymous user per database.
439 def self.anonymous
439 def self.anonymous
440 anonymous_user = AnonymousUser.find(:first)
440 anonymous_user = AnonymousUser.find(:first)
441 if anonymous_user.nil?
441 if anonymous_user.nil?
442 anonymous_user = AnonymousUser.create(:lastname => 'Anonymous', :firstname => '', :mail => '', :login => '', :status => 0)
442 anonymous_user = AnonymousUser.create(:lastname => 'Anonymous', :firstname => '', :mail => '', :login => '', :status => 0)
443 raise 'Unable to create the anonymous user.' if anonymous_user.new_record?
443 raise 'Unable to create the anonymous user.' if anonymous_user.new_record?
444 end
444 end
445 anonymous_user
445 anonymous_user
446 end
446 end
447
447
448 protected
448 protected
449
449
450 def validate
450 def validate
451 # Password length validation based on setting
451 # Password length validation based on setting
452 if !password.nil? && password.size < Setting.password_min_length.to_i
452 if !password.nil? && password.size < Setting.password_min_length.to_i
453 errors.add(:password, :too_short, :count => Setting.password_min_length.to_i)
453 errors.add(:password, :too_short, :count => Setting.password_min_length.to_i)
454 end
454 end
455 end
455 end
456
456
457 private
457 private
458
458
459 # Return password digest
459 # Return password digest
460 def self.hash_password(clear_password)
460 def self.hash_password(clear_password)
461 Digest::SHA1.hexdigest(clear_password || "")
461 Digest::SHA1.hexdigest(clear_password || "")
462 end
462 end
463 end
463 end
464
464
465 class AnonymousUser < User
465 class AnonymousUser < User
466
466
467 def validate_on_create
467 def validate_on_create
468 # There should be only one AnonymousUser in the database
468 # There should be only one AnonymousUser in the database
469 errors.add_to_base 'An anonymous user already exists.' if AnonymousUser.find(:first)
469 errors.add_to_base 'An anonymous user already exists.' if AnonymousUser.find(:first)
470 end
470 end
471
471
472 def available_custom_fields
472 def available_custom_fields
473 []
473 []
474 end
474 end
475
475
476 # Overrides a few properties
476 # Overrides a few properties
477 def logged?; false end
477 def logged?; false end
478 def admin; false end
478 def admin; false end
479 def name(*args); I18n.t(:label_user_anonymous) end
479 def name(*args); I18n.t(:label_user_anonymous) end
480 def mail; nil end
480 def mail; nil end
481 def time_zone; nil end
481 def time_zone; nil end
482 def rss_key; nil end
482 def rss_key; nil end
483 end
483 end
General Comments 0
You need to be logged in to leave comments. Login now