##// END OF EJS Templates
Adds firstname initials+lastname user format....
Jean-Philippe Lang -
r12415:6e6c6fac5caf
parent child
Show More
@@ -1,745 +1,750
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2013 Jean-Philippe Lang
2 # Copyright (C) 2006-2013 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 include Redmine::SafeAttributes
21 include Redmine::SafeAttributes
22
22
23 # Different ways of displaying/sorting users
23 # Different ways of displaying/sorting users
24 USER_FORMATS = {
24 USER_FORMATS = {
25 :firstname_lastname => {
25 :firstname_lastname => {
26 :string => '#{firstname} #{lastname}',
26 :string => '#{firstname} #{lastname}',
27 :order => %w(firstname lastname id),
27 :order => %w(firstname lastname id),
28 :setting_order => 1
28 :setting_order => 1
29 },
29 },
30 :firstname_lastinitial => {
30 :firstname_lastinitial => {
31 :string => '#{firstname} #{lastname.to_s.chars.first}.',
31 :string => '#{firstname} #{lastname.to_s.chars.first}.',
32 :order => %w(firstname lastname id),
32 :order => %w(firstname lastname id),
33 :setting_order => 2
33 :setting_order => 2
34 },
34 },
35 :firstinitial_lastname => {
36 :string => '#{firstname.to_s.gsub(/(([[:alpha:]])[[:alpha:]]*\.?)/, \'\2.\')} #{lastname}',
37 :order => %w(firstname lastname id),
38 :setting_order => 2
39 },
35 :firstname => {
40 :firstname => {
36 :string => '#{firstname}',
41 :string => '#{firstname}',
37 :order => %w(firstname id),
42 :order => %w(firstname id),
38 :setting_order => 3
43 :setting_order => 3
39 },
44 },
40 :lastname_firstname => {
45 :lastname_firstname => {
41 :string => '#{lastname} #{firstname}',
46 :string => '#{lastname} #{firstname}',
42 :order => %w(lastname firstname id),
47 :order => %w(lastname firstname id),
43 :setting_order => 4
48 :setting_order => 4
44 },
49 },
45 :lastname_coma_firstname => {
50 :lastname_coma_firstname => {
46 :string => '#{lastname}, #{firstname}',
51 :string => '#{lastname}, #{firstname}',
47 :order => %w(lastname firstname id),
52 :order => %w(lastname firstname id),
48 :setting_order => 5
53 :setting_order => 5
49 },
54 },
50 :lastname => {
55 :lastname => {
51 :string => '#{lastname}',
56 :string => '#{lastname}',
52 :order => %w(lastname id),
57 :order => %w(lastname id),
53 :setting_order => 6
58 :setting_order => 6
54 },
59 },
55 :username => {
60 :username => {
56 :string => '#{login}',
61 :string => '#{login}',
57 :order => %w(login id),
62 :order => %w(login id),
58 :setting_order => 7
63 :setting_order => 7
59 },
64 },
60 }
65 }
61
66
62 MAIL_NOTIFICATION_OPTIONS = [
67 MAIL_NOTIFICATION_OPTIONS = [
63 ['all', :label_user_mail_option_all],
68 ['all', :label_user_mail_option_all],
64 ['selected', :label_user_mail_option_selected],
69 ['selected', :label_user_mail_option_selected],
65 ['only_my_events', :label_user_mail_option_only_my_events],
70 ['only_my_events', :label_user_mail_option_only_my_events],
66 ['only_assigned', :label_user_mail_option_only_assigned],
71 ['only_assigned', :label_user_mail_option_only_assigned],
67 ['only_owner', :label_user_mail_option_only_owner],
72 ['only_owner', :label_user_mail_option_only_owner],
68 ['none', :label_user_mail_option_none]
73 ['none', :label_user_mail_option_none]
69 ]
74 ]
70
75
71 has_and_belongs_to_many :groups,
76 has_and_belongs_to_many :groups,
72 :join_table => "#{table_name_prefix}groups_users#{table_name_suffix}",
77 :join_table => "#{table_name_prefix}groups_users#{table_name_suffix}",
73 :after_add => Proc.new {|user, group| group.user_added(user)},
78 :after_add => Proc.new {|user, group| group.user_added(user)},
74 :after_remove => Proc.new {|user, group| group.user_removed(user)}
79 :after_remove => Proc.new {|user, group| group.user_removed(user)}
75 has_many :changesets, :dependent => :nullify
80 has_many :changesets, :dependent => :nullify
76 has_one :preference, :dependent => :destroy, :class_name => 'UserPreference'
81 has_one :preference, :dependent => :destroy, :class_name => 'UserPreference'
77 has_one :rss_token, :class_name => 'Token', :conditions => "action='feeds'"
82 has_one :rss_token, :class_name => 'Token', :conditions => "action='feeds'"
78 has_one :api_token, :class_name => 'Token', :conditions => "action='api'"
83 has_one :api_token, :class_name => 'Token', :conditions => "action='api'"
79 belongs_to :auth_source
84 belongs_to :auth_source
80
85
81 scope :logged, lambda { where("#{User.table_name}.status <> #{STATUS_ANONYMOUS}") }
86 scope :logged, lambda { where("#{User.table_name}.status <> #{STATUS_ANONYMOUS}") }
82 scope :status, lambda {|arg| where(arg.blank? ? nil : {:status => arg.to_i}) }
87 scope :status, lambda {|arg| where(arg.blank? ? nil : {:status => arg.to_i}) }
83
88
84 acts_as_customizable
89 acts_as_customizable
85
90
86 attr_accessor :password, :password_confirmation, :generate_password
91 attr_accessor :password, :password_confirmation, :generate_password
87 attr_accessor :last_before_login_on
92 attr_accessor :last_before_login_on
88 # Prevents unauthorized assignments
93 # Prevents unauthorized assignments
89 attr_protected :login, :admin, :password, :password_confirmation, :hashed_password
94 attr_protected :login, :admin, :password, :password_confirmation, :hashed_password
90
95
91 LOGIN_LENGTH_LIMIT = 60
96 LOGIN_LENGTH_LIMIT = 60
92 MAIL_LENGTH_LIMIT = 60
97 MAIL_LENGTH_LIMIT = 60
93
98
94 validates_presence_of :login, :firstname, :lastname, :mail, :if => Proc.new { |user| !user.is_a?(AnonymousUser) }
99 validates_presence_of :login, :firstname, :lastname, :mail, :if => Proc.new { |user| !user.is_a?(AnonymousUser) }
95 validates_uniqueness_of :login, :if => Proc.new { |user| user.login_changed? && user.login.present? }, :case_sensitive => false
100 validates_uniqueness_of :login, :if => Proc.new { |user| user.login_changed? && user.login.present? }, :case_sensitive => false
96 validates_uniqueness_of :mail, :if => Proc.new { |user| user.mail_changed? && user.mail.present? }, :case_sensitive => false
101 validates_uniqueness_of :mail, :if => Proc.new { |user| user.mail_changed? && user.mail.present? }, :case_sensitive => false
97 # Login must contain letters, numbers, underscores only
102 # Login must contain letters, numbers, underscores only
98 validates_format_of :login, :with => /\A[a-z0-9_\-@\.]*\z/i
103 validates_format_of :login, :with => /\A[a-z0-9_\-@\.]*\z/i
99 validates_length_of :login, :maximum => LOGIN_LENGTH_LIMIT
104 validates_length_of :login, :maximum => LOGIN_LENGTH_LIMIT
100 validates_length_of :firstname, :lastname, :maximum => 30
105 validates_length_of :firstname, :lastname, :maximum => 30
101 validates_format_of :mail, :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i, :allow_blank => true
106 validates_format_of :mail, :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i, :allow_blank => true
102 validates_length_of :mail, :maximum => MAIL_LENGTH_LIMIT, :allow_nil => true
107 validates_length_of :mail, :maximum => MAIL_LENGTH_LIMIT, :allow_nil => true
103 validates_confirmation_of :password, :allow_nil => true
108 validates_confirmation_of :password, :allow_nil => true
104 validates_inclusion_of :mail_notification, :in => MAIL_NOTIFICATION_OPTIONS.collect(&:first), :allow_blank => true
109 validates_inclusion_of :mail_notification, :in => MAIL_NOTIFICATION_OPTIONS.collect(&:first), :allow_blank => true
105 validate :validate_password_length
110 validate :validate_password_length
106
111
107 before_create :set_mail_notification
112 before_create :set_mail_notification
108 before_save :generate_password_if_needed, :update_hashed_password
113 before_save :generate_password_if_needed, :update_hashed_password
109 before_destroy :remove_references_before_destroy
114 before_destroy :remove_references_before_destroy
110 after_save :update_notified_project_ids
115 after_save :update_notified_project_ids
111
116
112 scope :in_group, lambda {|group|
117 scope :in_group, lambda {|group|
113 group_id = group.is_a?(Group) ? group.id : group.to_i
118 group_id = group.is_a?(Group) ? group.id : group.to_i
114 where("#{User.table_name}.id IN (SELECT gu.user_id FROM #{table_name_prefix}groups_users#{table_name_suffix} gu WHERE gu.group_id = ?)", group_id)
119 where("#{User.table_name}.id IN (SELECT gu.user_id FROM #{table_name_prefix}groups_users#{table_name_suffix} gu WHERE gu.group_id = ?)", group_id)
115 }
120 }
116 scope :not_in_group, lambda {|group|
121 scope :not_in_group, lambda {|group|
117 group_id = group.is_a?(Group) ? group.id : group.to_i
122 group_id = group.is_a?(Group) ? group.id : group.to_i
118 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)
123 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)
119 }
124 }
120 scope :sorted, lambda { order(*User.fields_for_order_statement)}
125 scope :sorted, lambda { order(*User.fields_for_order_statement)}
121
126
122 def set_mail_notification
127 def set_mail_notification
123 self.mail_notification = Setting.default_notification_option if self.mail_notification.blank?
128 self.mail_notification = Setting.default_notification_option if self.mail_notification.blank?
124 true
129 true
125 end
130 end
126
131
127 def update_hashed_password
132 def update_hashed_password
128 # update hashed_password if password was set
133 # update hashed_password if password was set
129 if self.password && self.auth_source_id.blank?
134 if self.password && self.auth_source_id.blank?
130 salt_password(password)
135 salt_password(password)
131 end
136 end
132 end
137 end
133
138
134 alias :base_reload :reload
139 alias :base_reload :reload
135 def reload(*args)
140 def reload(*args)
136 @name = nil
141 @name = nil
137 @projects_by_role = nil
142 @projects_by_role = nil
138 @membership_by_project_id = nil
143 @membership_by_project_id = nil
139 @notified_projects_ids = nil
144 @notified_projects_ids = nil
140 @notified_projects_ids_changed = false
145 @notified_projects_ids_changed = false
141 @builtin_role = nil
146 @builtin_role = nil
142 base_reload(*args)
147 base_reload(*args)
143 end
148 end
144
149
145 def mail=(arg)
150 def mail=(arg)
146 write_attribute(:mail, arg.to_s.strip)
151 write_attribute(:mail, arg.to_s.strip)
147 end
152 end
148
153
149 def identity_url=(url)
154 def identity_url=(url)
150 if url.blank?
155 if url.blank?
151 write_attribute(:identity_url, '')
156 write_attribute(:identity_url, '')
152 else
157 else
153 begin
158 begin
154 write_attribute(:identity_url, OpenIdAuthentication.normalize_identifier(url))
159 write_attribute(:identity_url, OpenIdAuthentication.normalize_identifier(url))
155 rescue OpenIdAuthentication::InvalidOpenId
160 rescue OpenIdAuthentication::InvalidOpenId
156 # Invalid url, don't save
161 # Invalid url, don't save
157 end
162 end
158 end
163 end
159 self.read_attribute(:identity_url)
164 self.read_attribute(:identity_url)
160 end
165 end
161
166
162 # Returns the user that matches provided login and password, or nil
167 # Returns the user that matches provided login and password, or nil
163 def self.try_to_login(login, password, active_only=true)
168 def self.try_to_login(login, password, active_only=true)
164 login = login.to_s
169 login = login.to_s
165 password = password.to_s
170 password = password.to_s
166
171
167 # Make sure no one can sign in with an empty login or password
172 # Make sure no one can sign in with an empty login or password
168 return nil if login.empty? || password.empty?
173 return nil if login.empty? || password.empty?
169 user = find_by_login(login)
174 user = find_by_login(login)
170 if user
175 if user
171 # user is already in local database
176 # user is already in local database
172 return nil unless user.check_password?(password)
177 return nil unless user.check_password?(password)
173 return nil if !user.active? && active_only
178 return nil if !user.active? && active_only
174 else
179 else
175 # user is not yet registered, try to authenticate with available sources
180 # user is not yet registered, try to authenticate with available sources
176 attrs = AuthSource.authenticate(login, password)
181 attrs = AuthSource.authenticate(login, password)
177 if attrs
182 if attrs
178 user = new(attrs)
183 user = new(attrs)
179 user.login = login
184 user.login = login
180 user.language = Setting.default_language
185 user.language = Setting.default_language
181 if user.save
186 if user.save
182 user.reload
187 user.reload
183 logger.info("User '#{user.login}' created from external auth source: #{user.auth_source.type} - #{user.auth_source.name}") if logger && user.auth_source
188 logger.info("User '#{user.login}' created from external auth source: #{user.auth_source.type} - #{user.auth_source.name}") if logger && user.auth_source
184 end
189 end
185 end
190 end
186 end
191 end
187 user.update_column(:last_login_on, Time.now) if user && !user.new_record? && user.active?
192 user.update_column(:last_login_on, Time.now) if user && !user.new_record? && user.active?
188 user
193 user
189 rescue => text
194 rescue => text
190 raise text
195 raise text
191 end
196 end
192
197
193 # Returns the user who matches the given autologin +key+ or nil
198 # Returns the user who matches the given autologin +key+ or nil
194 def self.try_to_autologin(key)
199 def self.try_to_autologin(key)
195 user = Token.find_active_user('autologin', key, Setting.autologin.to_i)
200 user = Token.find_active_user('autologin', key, Setting.autologin.to_i)
196 if user
201 if user
197 user.update_column(:last_login_on, Time.now)
202 user.update_column(:last_login_on, Time.now)
198 user
203 user
199 end
204 end
200 end
205 end
201
206
202 def self.name_formatter(formatter = nil)
207 def self.name_formatter(formatter = nil)
203 USER_FORMATS[formatter || Setting.user_format] || USER_FORMATS[:firstname_lastname]
208 USER_FORMATS[formatter || Setting.user_format] || USER_FORMATS[:firstname_lastname]
204 end
209 end
205
210
206 # Returns an array of fields names than can be used to make an order statement for users
211 # Returns an array of fields names than can be used to make an order statement for users
207 # according to how user names are displayed
212 # according to how user names are displayed
208 # Examples:
213 # Examples:
209 #
214 #
210 # User.fields_for_order_statement => ['users.login', 'users.id']
215 # User.fields_for_order_statement => ['users.login', 'users.id']
211 # User.fields_for_order_statement('authors') => ['authors.login', 'authors.id']
216 # User.fields_for_order_statement('authors') => ['authors.login', 'authors.id']
212 def self.fields_for_order_statement(table=nil)
217 def self.fields_for_order_statement(table=nil)
213 table ||= table_name
218 table ||= table_name
214 name_formatter[:order].map {|field| "#{table}.#{field}"}
219 name_formatter[:order].map {|field| "#{table}.#{field}"}
215 end
220 end
216
221
217 # Return user's full name for display
222 # Return user's full name for display
218 def name(formatter = nil)
223 def name(formatter = nil)
219 f = self.class.name_formatter(formatter)
224 f = self.class.name_formatter(formatter)
220 if formatter
225 if formatter
221 eval('"' + f[:string] + '"')
226 eval('"' + f[:string] + '"')
222 else
227 else
223 @name ||= eval('"' + f[:string] + '"')
228 @name ||= eval('"' + f[:string] + '"')
224 end
229 end
225 end
230 end
226
231
227 def active?
232 def active?
228 self.status == STATUS_ACTIVE
233 self.status == STATUS_ACTIVE
229 end
234 end
230
235
231 def registered?
236 def registered?
232 self.status == STATUS_REGISTERED
237 self.status == STATUS_REGISTERED
233 end
238 end
234
239
235 def locked?
240 def locked?
236 self.status == STATUS_LOCKED
241 self.status == STATUS_LOCKED
237 end
242 end
238
243
239 def activate
244 def activate
240 self.status = STATUS_ACTIVE
245 self.status = STATUS_ACTIVE
241 end
246 end
242
247
243 def register
248 def register
244 self.status = STATUS_REGISTERED
249 self.status = STATUS_REGISTERED
245 end
250 end
246
251
247 def lock
252 def lock
248 self.status = STATUS_LOCKED
253 self.status = STATUS_LOCKED
249 end
254 end
250
255
251 def activate!
256 def activate!
252 update_attribute(:status, STATUS_ACTIVE)
257 update_attribute(:status, STATUS_ACTIVE)
253 end
258 end
254
259
255 def register!
260 def register!
256 update_attribute(:status, STATUS_REGISTERED)
261 update_attribute(:status, STATUS_REGISTERED)
257 end
262 end
258
263
259 def lock!
264 def lock!
260 update_attribute(:status, STATUS_LOCKED)
265 update_attribute(:status, STATUS_LOCKED)
261 end
266 end
262
267
263 # Returns true if +clear_password+ is the correct user's password, otherwise false
268 # Returns true if +clear_password+ is the correct user's password, otherwise false
264 def check_password?(clear_password)
269 def check_password?(clear_password)
265 if auth_source_id.present?
270 if auth_source_id.present?
266 auth_source.authenticate(self.login, clear_password)
271 auth_source.authenticate(self.login, clear_password)
267 else
272 else
268 User.hash_password("#{salt}#{User.hash_password clear_password}") == hashed_password
273 User.hash_password("#{salt}#{User.hash_password clear_password}") == hashed_password
269 end
274 end
270 end
275 end
271
276
272 # Generates a random salt and computes hashed_password for +clear_password+
277 # Generates a random salt and computes hashed_password for +clear_password+
273 # The hashed password is stored in the following form: SHA1(salt + SHA1(password))
278 # The hashed password is stored in the following form: SHA1(salt + SHA1(password))
274 def salt_password(clear_password)
279 def salt_password(clear_password)
275 self.salt = User.generate_salt
280 self.salt = User.generate_salt
276 self.hashed_password = User.hash_password("#{salt}#{User.hash_password clear_password}")
281 self.hashed_password = User.hash_password("#{salt}#{User.hash_password clear_password}")
277 end
282 end
278
283
279 # Does the backend storage allow this user to change their password?
284 # Does the backend storage allow this user to change their password?
280 def change_password_allowed?
285 def change_password_allowed?
281 return true if auth_source.nil?
286 return true if auth_source.nil?
282 return auth_source.allow_password_changes?
287 return auth_source.allow_password_changes?
283 end
288 end
284
289
285 def must_change_password?
290 def must_change_password?
286 must_change_passwd? && change_password_allowed?
291 must_change_passwd? && change_password_allowed?
287 end
292 end
288
293
289 def generate_password?
294 def generate_password?
290 generate_password == '1' || generate_password == true
295 generate_password == '1' || generate_password == true
291 end
296 end
292
297
293 # Generate and set a random password on given length
298 # Generate and set a random password on given length
294 def random_password(length=40)
299 def random_password(length=40)
295 chars = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a
300 chars = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a
296 chars -= %w(0 O 1 l)
301 chars -= %w(0 O 1 l)
297 password = ''
302 password = ''
298 length.times {|i| password << chars[SecureRandom.random_number(chars.size)] }
303 length.times {|i| password << chars[SecureRandom.random_number(chars.size)] }
299 self.password = password
304 self.password = password
300 self.password_confirmation = password
305 self.password_confirmation = password
301 self
306 self
302 end
307 end
303
308
304 def pref
309 def pref
305 self.preference ||= UserPreference.new(:user => self)
310 self.preference ||= UserPreference.new(:user => self)
306 end
311 end
307
312
308 def time_zone
313 def time_zone
309 @time_zone ||= (self.pref.time_zone.blank? ? nil : ActiveSupport::TimeZone[self.pref.time_zone])
314 @time_zone ||= (self.pref.time_zone.blank? ? nil : ActiveSupport::TimeZone[self.pref.time_zone])
310 end
315 end
311
316
312 def wants_comments_in_reverse_order?
317 def wants_comments_in_reverse_order?
313 self.pref[:comments_sorting] == 'desc'
318 self.pref[:comments_sorting] == 'desc'
314 end
319 end
315
320
316 # Return user's RSS key (a 40 chars long string), used to access feeds
321 # Return user's RSS key (a 40 chars long string), used to access feeds
317 def rss_key
322 def rss_key
318 if rss_token.nil?
323 if rss_token.nil?
319 create_rss_token(:action => 'feeds')
324 create_rss_token(:action => 'feeds')
320 end
325 end
321 rss_token.value
326 rss_token.value
322 end
327 end
323
328
324 # Return user's API key (a 40 chars long string), used to access the API
329 # Return user's API key (a 40 chars long string), used to access the API
325 def api_key
330 def api_key
326 if api_token.nil?
331 if api_token.nil?
327 create_api_token(:action => 'api')
332 create_api_token(:action => 'api')
328 end
333 end
329 api_token.value
334 api_token.value
330 end
335 end
331
336
332 # Return an array of project ids for which the user has explicitly turned mail notifications on
337 # Return an array of project ids for which the user has explicitly turned mail notifications on
333 def notified_projects_ids
338 def notified_projects_ids
334 @notified_projects_ids ||= memberships.select {|m| m.mail_notification?}.collect(&:project_id)
339 @notified_projects_ids ||= memberships.select {|m| m.mail_notification?}.collect(&:project_id)
335 end
340 end
336
341
337 def notified_project_ids=(ids)
342 def notified_project_ids=(ids)
338 @notified_projects_ids_changed = true
343 @notified_projects_ids_changed = true
339 @notified_projects_ids = ids
344 @notified_projects_ids = ids
340 end
345 end
341
346
342 # Updates per project notifications (after_save callback)
347 # Updates per project notifications (after_save callback)
343 def update_notified_project_ids
348 def update_notified_project_ids
344 if @notified_projects_ids_changed
349 if @notified_projects_ids_changed
345 ids = (mail_notification == 'selected' ? Array.wrap(notified_projects_ids).reject(&:blank?) : [])
350 ids = (mail_notification == 'selected' ? Array.wrap(notified_projects_ids).reject(&:blank?) : [])
346 members.update_all(:mail_notification => false)
351 members.update_all(:mail_notification => false)
347 members.where(:project_id => ids).update_all(:mail_notification => true) if ids.any?
352 members.where(:project_id => ids).update_all(:mail_notification => true) if ids.any?
348 end
353 end
349 end
354 end
350 private :update_notified_project_ids
355 private :update_notified_project_ids
351
356
352 def valid_notification_options
357 def valid_notification_options
353 self.class.valid_notification_options(self)
358 self.class.valid_notification_options(self)
354 end
359 end
355
360
356 # Only users that belong to more than 1 project can select projects for which they are notified
361 # Only users that belong to more than 1 project can select projects for which they are notified
357 def self.valid_notification_options(user=nil)
362 def self.valid_notification_options(user=nil)
358 # Note that @user.membership.size would fail since AR ignores
363 # Note that @user.membership.size would fail since AR ignores
359 # :include association option when doing a count
364 # :include association option when doing a count
360 if user.nil? || user.memberships.length < 1
365 if user.nil? || user.memberships.length < 1
361 MAIL_NOTIFICATION_OPTIONS.reject {|option| option.first == 'selected'}
366 MAIL_NOTIFICATION_OPTIONS.reject {|option| option.first == 'selected'}
362 else
367 else
363 MAIL_NOTIFICATION_OPTIONS
368 MAIL_NOTIFICATION_OPTIONS
364 end
369 end
365 end
370 end
366
371
367 # Find a user account by matching the exact login and then a case-insensitive
372 # Find a user account by matching the exact login and then a case-insensitive
368 # version. Exact matches will be given priority.
373 # version. Exact matches will be given priority.
369 def self.find_by_login(login)
374 def self.find_by_login(login)
370 if login.present?
375 if login.present?
371 login = login.to_s
376 login = login.to_s
372 # First look for an exact match
377 # First look for an exact match
373 user = where(:login => login).all.detect {|u| u.login == login}
378 user = where(:login => login).all.detect {|u| u.login == login}
374 unless user
379 unless user
375 # Fail over to case-insensitive if none was found
380 # Fail over to case-insensitive if none was found
376 user = where("LOWER(login) = ?", login.downcase).first
381 user = where("LOWER(login) = ?", login.downcase).first
377 end
382 end
378 user
383 user
379 end
384 end
380 end
385 end
381
386
382 def self.find_by_rss_key(key)
387 def self.find_by_rss_key(key)
383 Token.find_active_user('feeds', key)
388 Token.find_active_user('feeds', key)
384 end
389 end
385
390
386 def self.find_by_api_key(key)
391 def self.find_by_api_key(key)
387 Token.find_active_user('api', key)
392 Token.find_active_user('api', key)
388 end
393 end
389
394
390 # Makes find_by_mail case-insensitive
395 # Makes find_by_mail case-insensitive
391 def self.find_by_mail(mail)
396 def self.find_by_mail(mail)
392 where("LOWER(mail) = ?", mail.to_s.downcase).first
397 where("LOWER(mail) = ?", mail.to_s.downcase).first
393 end
398 end
394
399
395 # Returns true if the default admin account can no longer be used
400 # Returns true if the default admin account can no longer be used
396 def self.default_admin_account_changed?
401 def self.default_admin_account_changed?
397 !User.active.find_by_login("admin").try(:check_password?, "admin")
402 !User.active.find_by_login("admin").try(:check_password?, "admin")
398 end
403 end
399
404
400 def to_s
405 def to_s
401 name
406 name
402 end
407 end
403
408
404 CSS_CLASS_BY_STATUS = {
409 CSS_CLASS_BY_STATUS = {
405 STATUS_ANONYMOUS => 'anon',
410 STATUS_ANONYMOUS => 'anon',
406 STATUS_ACTIVE => 'active',
411 STATUS_ACTIVE => 'active',
407 STATUS_REGISTERED => 'registered',
412 STATUS_REGISTERED => 'registered',
408 STATUS_LOCKED => 'locked'
413 STATUS_LOCKED => 'locked'
409 }
414 }
410
415
411 def css_classes
416 def css_classes
412 "user #{CSS_CLASS_BY_STATUS[status]}"
417 "user #{CSS_CLASS_BY_STATUS[status]}"
413 end
418 end
414
419
415 # Returns the current day according to user's time zone
420 # Returns the current day according to user's time zone
416 def today
421 def today
417 if time_zone.nil?
422 if time_zone.nil?
418 Date.today
423 Date.today
419 else
424 else
420 Time.now.in_time_zone(time_zone).to_date
425 Time.now.in_time_zone(time_zone).to_date
421 end
426 end
422 end
427 end
423
428
424 # Returns the day of +time+ according to user's time zone
429 # Returns the day of +time+ according to user's time zone
425 def time_to_date(time)
430 def time_to_date(time)
426 if time_zone.nil?
431 if time_zone.nil?
427 time.to_date
432 time.to_date
428 else
433 else
429 time.in_time_zone(time_zone).to_date
434 time.in_time_zone(time_zone).to_date
430 end
435 end
431 end
436 end
432
437
433 def logged?
438 def logged?
434 true
439 true
435 end
440 end
436
441
437 def anonymous?
442 def anonymous?
438 !logged?
443 !logged?
439 end
444 end
440
445
441 # Returns user's membership for the given project
446 # Returns user's membership for the given project
442 # or nil if the user is not a member of project
447 # or nil if the user is not a member of project
443 def membership(project)
448 def membership(project)
444 project_id = project.is_a?(Project) ? project.id : project
449 project_id = project.is_a?(Project) ? project.id : project
445
450
446 @membership_by_project_id ||= Hash.new {|h, project_id|
451 @membership_by_project_id ||= Hash.new {|h, project_id|
447 h[project_id] = memberships.where(:project_id => project_id).first
452 h[project_id] = memberships.where(:project_id => project_id).first
448 }
453 }
449 @membership_by_project_id[project_id]
454 @membership_by_project_id[project_id]
450 end
455 end
451
456
452 # Returns the user's bult-in role
457 # Returns the user's bult-in role
453 def builtin_role
458 def builtin_role
454 @builtin_role ||= Role.non_member
459 @builtin_role ||= Role.non_member
455 end
460 end
456
461
457 # Return user's roles for project
462 # Return user's roles for project
458 def roles_for_project(project)
463 def roles_for_project(project)
459 roles = []
464 roles = []
460 # No role on archived projects
465 # No role on archived projects
461 return roles if project.nil? || project.archived?
466 return roles if project.nil? || project.archived?
462 if membership = membership(project)
467 if membership = membership(project)
463 roles = membership.roles
468 roles = membership.roles
464 else
469 else
465 roles << builtin_role
470 roles << builtin_role
466 end
471 end
467 roles
472 roles
468 end
473 end
469
474
470 # Return true if the user is a member of project
475 # Return true if the user is a member of project
471 def member_of?(project)
476 def member_of?(project)
472 projects.to_a.include?(project)
477 projects.to_a.include?(project)
473 end
478 end
474
479
475 # Returns a hash of user's projects grouped by roles
480 # Returns a hash of user's projects grouped by roles
476 def projects_by_role
481 def projects_by_role
477 return @projects_by_role if @projects_by_role
482 return @projects_by_role if @projects_by_role
478
483
479 @projects_by_role = Hash.new([])
484 @projects_by_role = Hash.new([])
480 memberships.each do |membership|
485 memberships.each do |membership|
481 if membership.project
486 if membership.project
482 membership.roles.each do |role|
487 membership.roles.each do |role|
483 @projects_by_role[role] = [] unless @projects_by_role.key?(role)
488 @projects_by_role[role] = [] unless @projects_by_role.key?(role)
484 @projects_by_role[role] << membership.project
489 @projects_by_role[role] << membership.project
485 end
490 end
486 end
491 end
487 end
492 end
488 @projects_by_role.each do |role, projects|
493 @projects_by_role.each do |role, projects|
489 projects.uniq!
494 projects.uniq!
490 end
495 end
491
496
492 @projects_by_role
497 @projects_by_role
493 end
498 end
494
499
495 # Returns true if user is arg or belongs to arg
500 # Returns true if user is arg or belongs to arg
496 def is_or_belongs_to?(arg)
501 def is_or_belongs_to?(arg)
497 if arg.is_a?(User)
502 if arg.is_a?(User)
498 self == arg
503 self == arg
499 elsif arg.is_a?(Group)
504 elsif arg.is_a?(Group)
500 arg.users.include?(self)
505 arg.users.include?(self)
501 else
506 else
502 false
507 false
503 end
508 end
504 end
509 end
505
510
506 # Return true if the user is allowed to do the specified action on a specific context
511 # Return true if the user is allowed to do the specified action on a specific context
507 # Action can be:
512 # Action can be:
508 # * a parameter-like Hash (eg. :controller => 'projects', :action => 'edit')
513 # * a parameter-like Hash (eg. :controller => 'projects', :action => 'edit')
509 # * a permission Symbol (eg. :edit_project)
514 # * a permission Symbol (eg. :edit_project)
510 # Context can be:
515 # Context can be:
511 # * a project : returns true if user is allowed to do the specified action on this project
516 # * a project : returns true if user is allowed to do the specified action on this project
512 # * an array of projects : returns true if user is allowed on every project
517 # * an array of projects : returns true if user is allowed on every project
513 # * nil with options[:global] set : check if user has at least one role allowed for this action,
518 # * nil with options[:global] set : check if user has at least one role allowed for this action,
514 # or falls back to Non Member / Anonymous permissions depending if the user is logged
519 # or falls back to Non Member / Anonymous permissions depending if the user is logged
515 def allowed_to?(action, context, options={}, &block)
520 def allowed_to?(action, context, options={}, &block)
516 if context && context.is_a?(Project)
521 if context && context.is_a?(Project)
517 return false unless context.allows_to?(action)
522 return false unless context.allows_to?(action)
518 # Admin users are authorized for anything else
523 # Admin users are authorized for anything else
519 return true if admin?
524 return true if admin?
520
525
521 roles = roles_for_project(context)
526 roles = roles_for_project(context)
522 return false unless roles
527 return false unless roles
523 roles.any? {|role|
528 roles.any? {|role|
524 (context.is_public? || role.member?) &&
529 (context.is_public? || role.member?) &&
525 role.allowed_to?(action) &&
530 role.allowed_to?(action) &&
526 (block_given? ? yield(role, self) : true)
531 (block_given? ? yield(role, self) : true)
527 }
532 }
528 elsif context && context.is_a?(Array)
533 elsif context && context.is_a?(Array)
529 if context.empty?
534 if context.empty?
530 false
535 false
531 else
536 else
532 # Authorize if user is authorized on every element of the array
537 # Authorize if user is authorized on every element of the array
533 context.map {|project| allowed_to?(action, project, options, &block)}.reduce(:&)
538 context.map {|project| allowed_to?(action, project, options, &block)}.reduce(:&)
534 end
539 end
535 elsif options[:global]
540 elsif options[:global]
536 # Admin users are always authorized
541 # Admin users are always authorized
537 return true if admin?
542 return true if admin?
538
543
539 # authorize if user has at least one role that has this permission
544 # authorize if user has at least one role that has this permission
540 roles = memberships.collect {|m| m.roles}.flatten.uniq
545 roles = memberships.collect {|m| m.roles}.flatten.uniq
541 roles << (self.logged? ? Role.non_member : Role.anonymous)
546 roles << (self.logged? ? Role.non_member : Role.anonymous)
542 roles.any? {|role|
547 roles.any? {|role|
543 role.allowed_to?(action) &&
548 role.allowed_to?(action) &&
544 (block_given? ? yield(role, self) : true)
549 (block_given? ? yield(role, self) : true)
545 }
550 }
546 else
551 else
547 false
552 false
548 end
553 end
549 end
554 end
550
555
551 # Is the user allowed to do the specified action on any project?
556 # Is the user allowed to do the specified action on any project?
552 # See allowed_to? for the actions and valid options.
557 # See allowed_to? for the actions and valid options.
553 def allowed_to_globally?(action, options, &block)
558 def allowed_to_globally?(action, options, &block)
554 allowed_to?(action, nil, options.reverse_merge(:global => true), &block)
559 allowed_to?(action, nil, options.reverse_merge(:global => true), &block)
555 end
560 end
556
561
557 # Returns true if the user is allowed to delete the user's own account
562 # Returns true if the user is allowed to delete the user's own account
558 def own_account_deletable?
563 def own_account_deletable?
559 Setting.unsubscribe? &&
564 Setting.unsubscribe? &&
560 (!admin? || User.active.where("admin = ? AND id <> ?", true, id).exists?)
565 (!admin? || User.active.where("admin = ? AND id <> ?", true, id).exists?)
561 end
566 end
562
567
563 safe_attributes 'login',
568 safe_attributes 'login',
564 'firstname',
569 'firstname',
565 'lastname',
570 'lastname',
566 'mail',
571 'mail',
567 'mail_notification',
572 'mail_notification',
568 'notified_project_ids',
573 'notified_project_ids',
569 'language',
574 'language',
570 'custom_field_values',
575 'custom_field_values',
571 'custom_fields',
576 'custom_fields',
572 'identity_url'
577 'identity_url'
573
578
574 safe_attributes 'status',
579 safe_attributes 'status',
575 'auth_source_id',
580 'auth_source_id',
576 'generate_password',
581 'generate_password',
577 'must_change_passwd',
582 'must_change_passwd',
578 :if => lambda {|user, current_user| current_user.admin?}
583 :if => lambda {|user, current_user| current_user.admin?}
579
584
580 safe_attributes 'group_ids',
585 safe_attributes 'group_ids',
581 :if => lambda {|user, current_user| current_user.admin? && !user.new_record?}
586 :if => lambda {|user, current_user| current_user.admin? && !user.new_record?}
582
587
583 # Utility method to help check if a user should be notified about an
588 # Utility method to help check if a user should be notified about an
584 # event.
589 # event.
585 #
590 #
586 # TODO: only supports Issue events currently
591 # TODO: only supports Issue events currently
587 def notify_about?(object)
592 def notify_about?(object)
588 if mail_notification == 'all'
593 if mail_notification == 'all'
589 true
594 true
590 elsif mail_notification.blank? || mail_notification == 'none'
595 elsif mail_notification.blank? || mail_notification == 'none'
591 false
596 false
592 else
597 else
593 case object
598 case object
594 when Issue
599 when Issue
595 case mail_notification
600 case mail_notification
596 when 'selected', 'only_my_events'
601 when 'selected', 'only_my_events'
597 # user receives notifications for created/assigned issues on unselected projects
602 # user receives notifications for created/assigned issues on unselected projects
598 object.author == self || is_or_belongs_to?(object.assigned_to) || is_or_belongs_to?(object.assigned_to_was)
603 object.author == self || is_or_belongs_to?(object.assigned_to) || is_or_belongs_to?(object.assigned_to_was)
599 when 'only_assigned'
604 when 'only_assigned'
600 is_or_belongs_to?(object.assigned_to) || is_or_belongs_to?(object.assigned_to_was)
605 is_or_belongs_to?(object.assigned_to) || is_or_belongs_to?(object.assigned_to_was)
601 when 'only_owner'
606 when 'only_owner'
602 object.author == self
607 object.author == self
603 end
608 end
604 when News
609 when News
605 # always send to project members except when mail_notification is set to 'none'
610 # always send to project members except when mail_notification is set to 'none'
606 true
611 true
607 end
612 end
608 end
613 end
609 end
614 end
610
615
611 def self.current=(user)
616 def self.current=(user)
612 Thread.current[:current_user] = user
617 Thread.current[:current_user] = user
613 end
618 end
614
619
615 def self.current
620 def self.current
616 Thread.current[:current_user] ||= User.anonymous
621 Thread.current[:current_user] ||= User.anonymous
617 end
622 end
618
623
619 # Returns the anonymous user. If the anonymous user does not exist, it is created. There can be only
624 # Returns the anonymous user. If the anonymous user does not exist, it is created. There can be only
620 # one anonymous user per database.
625 # one anonymous user per database.
621 def self.anonymous
626 def self.anonymous
622 anonymous_user = AnonymousUser.first
627 anonymous_user = AnonymousUser.first
623 if anonymous_user.nil?
628 if anonymous_user.nil?
624 anonymous_user = AnonymousUser.create(:lastname => 'Anonymous', :firstname => '', :mail => '', :login => '', :status => 0)
629 anonymous_user = AnonymousUser.create(:lastname => 'Anonymous', :firstname => '', :mail => '', :login => '', :status => 0)
625 raise 'Unable to create the anonymous user.' if anonymous_user.new_record?
630 raise 'Unable to create the anonymous user.' if anonymous_user.new_record?
626 end
631 end
627 anonymous_user
632 anonymous_user
628 end
633 end
629
634
630 # Salts all existing unsalted passwords
635 # Salts all existing unsalted passwords
631 # It changes password storage scheme from SHA1(password) to SHA1(salt + SHA1(password))
636 # It changes password storage scheme from SHA1(password) to SHA1(salt + SHA1(password))
632 # This method is used in the SaltPasswords migration and is to be kept as is
637 # This method is used in the SaltPasswords migration and is to be kept as is
633 def self.salt_unsalted_passwords!
638 def self.salt_unsalted_passwords!
634 transaction do
639 transaction do
635 User.where("salt IS NULL OR salt = ''").find_each do |user|
640 User.where("salt IS NULL OR salt = ''").find_each do |user|
636 next if user.hashed_password.blank?
641 next if user.hashed_password.blank?
637 salt = User.generate_salt
642 salt = User.generate_salt
638 hashed_password = User.hash_password("#{salt}#{user.hashed_password}")
643 hashed_password = User.hash_password("#{salt}#{user.hashed_password}")
639 User.where(:id => user.id).update_all(:salt => salt, :hashed_password => hashed_password)
644 User.where(:id => user.id).update_all(:salt => salt, :hashed_password => hashed_password)
640 end
645 end
641 end
646 end
642 end
647 end
643
648
644 protected
649 protected
645
650
646 def validate_password_length
651 def validate_password_length
647 return if password.blank? && generate_password?
652 return if password.blank? && generate_password?
648 # Password length validation based on setting
653 # Password length validation based on setting
649 if !password.nil? && password.size < Setting.password_min_length.to_i
654 if !password.nil? && password.size < Setting.password_min_length.to_i
650 errors.add(:password, :too_short, :count => Setting.password_min_length.to_i)
655 errors.add(:password, :too_short, :count => Setting.password_min_length.to_i)
651 end
656 end
652 end
657 end
653
658
654 private
659 private
655
660
656 def generate_password_if_needed
661 def generate_password_if_needed
657 if generate_password? && auth_source.nil?
662 if generate_password? && auth_source.nil?
658 length = [Setting.password_min_length.to_i + 2, 10].max
663 length = [Setting.password_min_length.to_i + 2, 10].max
659 random_password(length)
664 random_password(length)
660 end
665 end
661 end
666 end
662
667
663 # Removes references that are not handled by associations
668 # Removes references that are not handled by associations
664 # Things that are not deleted are reassociated with the anonymous user
669 # Things that are not deleted are reassociated with the anonymous user
665 def remove_references_before_destroy
670 def remove_references_before_destroy
666 return if self.id.nil?
671 return if self.id.nil?
667
672
668 substitute = User.anonymous
673 substitute = User.anonymous
669 Attachment.where(['author_id = ?', id]).update_all(['author_id = ?', substitute.id])
674 Attachment.where(['author_id = ?', id]).update_all(['author_id = ?', substitute.id])
670 Comment.where(['author_id = ?', id]).update_all(['author_id = ?', substitute.id])
675 Comment.where(['author_id = ?', id]).update_all(['author_id = ?', substitute.id])
671 Issue.where(['author_id = ?', id]).update_all(['author_id = ?', substitute.id])
676 Issue.where(['author_id = ?', id]).update_all(['author_id = ?', substitute.id])
672 Issue.where(['assigned_to_id = ?', id]).update_all('assigned_to_id = NULL')
677 Issue.where(['assigned_to_id = ?', id]).update_all('assigned_to_id = NULL')
673 Journal.where(['user_id = ?', id]).update_all(['user_id = ?', substitute.id])
678 Journal.where(['user_id = ?', id]).update_all(['user_id = ?', substitute.id])
674 JournalDetail.
679 JournalDetail.
675 where(["property = 'attr' AND prop_key = 'assigned_to_id' AND old_value = ?", id.to_s]).
680 where(["property = 'attr' AND prop_key = 'assigned_to_id' AND old_value = ?", id.to_s]).
676 update_all(['old_value = ?', substitute.id.to_s])
681 update_all(['old_value = ?', substitute.id.to_s])
677 JournalDetail.
682 JournalDetail.
678 where(["property = 'attr' AND prop_key = 'assigned_to_id' AND value = ?", id.to_s]).
683 where(["property = 'attr' AND prop_key = 'assigned_to_id' AND value = ?", id.to_s]).
679 update_all(['value = ?', substitute.id.to_s])
684 update_all(['value = ?', substitute.id.to_s])
680 Message.where(['author_id = ?', id]).update_all(['author_id = ?', substitute.id])
685 Message.where(['author_id = ?', id]).update_all(['author_id = ?', substitute.id])
681 News.where(['author_id = ?', id]).update_all(['author_id = ?', substitute.id])
686 News.where(['author_id = ?', id]).update_all(['author_id = ?', substitute.id])
682 # Remove private queries and keep public ones
687 # Remove private queries and keep public ones
683 ::Query.delete_all ['user_id = ? AND visibility = ?', id, ::Query::VISIBILITY_PRIVATE]
688 ::Query.delete_all ['user_id = ? AND visibility = ?', id, ::Query::VISIBILITY_PRIVATE]
684 ::Query.where(['user_id = ?', id]).update_all(['user_id = ?', substitute.id])
689 ::Query.where(['user_id = ?', id]).update_all(['user_id = ?', substitute.id])
685 TimeEntry.where(['user_id = ?', id]).update_all(['user_id = ?', substitute.id])
690 TimeEntry.where(['user_id = ?', id]).update_all(['user_id = ?', substitute.id])
686 Token.delete_all ['user_id = ?', id]
691 Token.delete_all ['user_id = ?', id]
687 Watcher.delete_all ['user_id = ?', id]
692 Watcher.delete_all ['user_id = ?', id]
688 WikiContent.where(['author_id = ?', id]).update_all(['author_id = ?', substitute.id])
693 WikiContent.where(['author_id = ?', id]).update_all(['author_id = ?', substitute.id])
689 WikiContent::Version.where(['author_id = ?', id]).update_all(['author_id = ?', substitute.id])
694 WikiContent::Version.where(['author_id = ?', id]).update_all(['author_id = ?', substitute.id])
690 end
695 end
691
696
692 # Return password digest
697 # Return password digest
693 def self.hash_password(clear_password)
698 def self.hash_password(clear_password)
694 Digest::SHA1.hexdigest(clear_password || "")
699 Digest::SHA1.hexdigest(clear_password || "")
695 end
700 end
696
701
697 # Returns a 128bits random salt as a hex string (32 chars long)
702 # Returns a 128bits random salt as a hex string (32 chars long)
698 def self.generate_salt
703 def self.generate_salt
699 Redmine::Utils.random_hex(16)
704 Redmine::Utils.random_hex(16)
700 end
705 end
701
706
702 end
707 end
703
708
704 class AnonymousUser < User
709 class AnonymousUser < User
705 validate :validate_anonymous_uniqueness, :on => :create
710 validate :validate_anonymous_uniqueness, :on => :create
706
711
707 def validate_anonymous_uniqueness
712 def validate_anonymous_uniqueness
708 # There should be only one AnonymousUser in the database
713 # There should be only one AnonymousUser in the database
709 errors.add :base, 'An anonymous user already exists.' if AnonymousUser.exists?
714 errors.add :base, 'An anonymous user already exists.' if AnonymousUser.exists?
710 end
715 end
711
716
712 def available_custom_fields
717 def available_custom_fields
713 []
718 []
714 end
719 end
715
720
716 # Overrides a few properties
721 # Overrides a few properties
717 def logged?; false end
722 def logged?; false end
718 def admin; false end
723 def admin; false end
719 def name(*args); I18n.t(:label_user_anonymous) end
724 def name(*args); I18n.t(:label_user_anonymous) end
720 def mail; nil end
725 def mail; nil end
721 def time_zone; nil end
726 def time_zone; nil end
722 def rss_key; nil end
727 def rss_key; nil end
723
728
724 def pref
729 def pref
725 UserPreference.new(:user => self)
730 UserPreference.new(:user => self)
726 end
731 end
727
732
728 # Returns the user's bult-in role
733 # Returns the user's bult-in role
729 def builtin_role
734 def builtin_role
730 @builtin_role ||= Role.anonymous
735 @builtin_role ||= Role.anonymous
731 end
736 end
732
737
733 def membership(*args)
738 def membership(*args)
734 nil
739 nil
735 end
740 end
736
741
737 def member_of?(*args)
742 def member_of?(*args)
738 false
743 false
739 end
744 end
740
745
741 # Anonymous user can not be destroyed
746 # Anonymous user can not be destroyed
742 def destroy
747 def destroy
743 false
748 false
744 end
749 end
745 end
750 end
@@ -1,1149 +1,1154
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2013 Jean-Philippe Lang
2 # Copyright (C) 2006-2013 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 File.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
19
19
20 class UserTest < ActiveSupport::TestCase
20 class UserTest < ActiveSupport::TestCase
21 fixtures :users, :members, :projects, :roles, :member_roles, :auth_sources,
21 fixtures :users, :members, :projects, :roles, :member_roles, :auth_sources,
22 :trackers, :issue_statuses,
22 :trackers, :issue_statuses,
23 :projects_trackers,
23 :projects_trackers,
24 :watchers,
24 :watchers,
25 :issue_categories, :enumerations, :issues,
25 :issue_categories, :enumerations, :issues,
26 :journals, :journal_details,
26 :journals, :journal_details,
27 :groups_users,
27 :groups_users,
28 :enabled_modules
28 :enabled_modules
29
29
30 def setup
30 def setup
31 @admin = User.find(1)
31 @admin = User.find(1)
32 @jsmith = User.find(2)
32 @jsmith = User.find(2)
33 @dlopper = User.find(3)
33 @dlopper = User.find(3)
34 end
34 end
35
35
36 def test_sorted_scope_should_sort_user_by_display_name
36 def test_sorted_scope_should_sort_user_by_display_name
37 assert_equal User.all.map(&:name).map(&:downcase).sort,
37 assert_equal User.all.map(&:name).map(&:downcase).sort,
38 User.sorted.all.map(&:name).map(&:downcase)
38 User.sorted.all.map(&:name).map(&:downcase)
39 end
39 end
40
40
41 def test_generate
41 def test_generate
42 User.generate!(:firstname => 'Testing connection')
42 User.generate!(:firstname => 'Testing connection')
43 User.generate!(:firstname => 'Testing connection')
43 User.generate!(:firstname => 'Testing connection')
44 assert_equal 2, User.where(:firstname => 'Testing connection').count
44 assert_equal 2, User.where(:firstname => 'Testing connection').count
45 end
45 end
46
46
47 def test_truth
47 def test_truth
48 assert_kind_of User, @jsmith
48 assert_kind_of User, @jsmith
49 end
49 end
50
50
51 def test_mail_should_be_stripped
51 def test_mail_should_be_stripped
52 u = User.new
52 u = User.new
53 u.mail = " foo@bar.com "
53 u.mail = " foo@bar.com "
54 assert_equal "foo@bar.com", u.mail
54 assert_equal "foo@bar.com", u.mail
55 end
55 end
56
56
57 def test_mail_validation
57 def test_mail_validation
58 u = User.new
58 u = User.new
59 u.mail = ''
59 u.mail = ''
60 assert !u.valid?
60 assert !u.valid?
61 assert_include I18n.translate('activerecord.errors.messages.blank'), u.errors[:mail]
61 assert_include I18n.translate('activerecord.errors.messages.blank'), u.errors[:mail]
62 end
62 end
63
63
64 def test_login_length_validation
64 def test_login_length_validation
65 user = User.new(:firstname => "new", :lastname => "user", :mail => "newuser@somenet.foo")
65 user = User.new(:firstname => "new", :lastname => "user", :mail => "newuser@somenet.foo")
66 user.login = "x" * (User::LOGIN_LENGTH_LIMIT+1)
66 user.login = "x" * (User::LOGIN_LENGTH_LIMIT+1)
67 assert !user.valid?
67 assert !user.valid?
68
68
69 user.login = "x" * (User::LOGIN_LENGTH_LIMIT)
69 user.login = "x" * (User::LOGIN_LENGTH_LIMIT)
70 assert user.valid?
70 assert user.valid?
71 assert user.save
71 assert user.save
72 end
72 end
73
73
74 def test_generate_password_should_respect_minimum_password_length
74 def test_generate_password_should_respect_minimum_password_length
75 with_settings :password_min_length => 15 do
75 with_settings :password_min_length => 15 do
76 user = User.generate!(:generate_password => true)
76 user = User.generate!(:generate_password => true)
77 assert user.password.length >= 15
77 assert user.password.length >= 15
78 end
78 end
79 end
79 end
80
80
81 def test_generate_password_should_not_generate_password_with_less_than_10_characters
81 def test_generate_password_should_not_generate_password_with_less_than_10_characters
82 with_settings :password_min_length => 4 do
82 with_settings :password_min_length => 4 do
83 user = User.generate!(:generate_password => true)
83 user = User.generate!(:generate_password => true)
84 assert user.password.length >= 10
84 assert user.password.length >= 10
85 end
85 end
86 end
86 end
87
87
88 def test_generate_password_on_create_should_set_password
88 def test_generate_password_on_create_should_set_password
89 user = User.new(:firstname => "new", :lastname => "user", :mail => "newuser@somenet.foo")
89 user = User.new(:firstname => "new", :lastname => "user", :mail => "newuser@somenet.foo")
90 user.login = "newuser"
90 user.login = "newuser"
91 user.generate_password = true
91 user.generate_password = true
92 assert user.save
92 assert user.save
93
93
94 password = user.password
94 password = user.password
95 assert user.check_password?(password)
95 assert user.check_password?(password)
96 end
96 end
97
97
98 def test_generate_password_on_update_should_update_password
98 def test_generate_password_on_update_should_update_password
99 user = User.find(2)
99 user = User.find(2)
100 hash = user.hashed_password
100 hash = user.hashed_password
101 user.generate_password = true
101 user.generate_password = true
102 assert user.save
102 assert user.save
103
103
104 password = user.password
104 password = user.password
105 assert user.check_password?(password)
105 assert user.check_password?(password)
106 assert_not_equal hash, user.reload.hashed_password
106 assert_not_equal hash, user.reload.hashed_password
107 end
107 end
108
108
109 def test_create
109 def test_create
110 user = User.new(:firstname => "new", :lastname => "user", :mail => "newuser@somenet.foo")
110 user = User.new(:firstname => "new", :lastname => "user", :mail => "newuser@somenet.foo")
111
111
112 user.login = "jsmith"
112 user.login = "jsmith"
113 user.password, user.password_confirmation = "password", "password"
113 user.password, user.password_confirmation = "password", "password"
114 # login uniqueness
114 # login uniqueness
115 assert !user.save
115 assert !user.save
116 assert_equal 1, user.errors.count
116 assert_equal 1, user.errors.count
117
117
118 user.login = "newuser"
118 user.login = "newuser"
119 user.password, user.password_confirmation = "password", "pass"
119 user.password, user.password_confirmation = "password", "pass"
120 # password confirmation
120 # password confirmation
121 assert !user.save
121 assert !user.save
122 assert_equal 1, user.errors.count
122 assert_equal 1, user.errors.count
123
123
124 user.password, user.password_confirmation = "password", "password"
124 user.password, user.password_confirmation = "password", "password"
125 assert user.save
125 assert user.save
126 end
126 end
127
127
128 def test_user_before_create_should_set_the_mail_notification_to_the_default_setting
128 def test_user_before_create_should_set_the_mail_notification_to_the_default_setting
129 @user1 = User.generate!
129 @user1 = User.generate!
130 assert_equal 'only_my_events', @user1.mail_notification
130 assert_equal 'only_my_events', @user1.mail_notification
131 with_settings :default_notification_option => 'all' do
131 with_settings :default_notification_option => 'all' do
132 @user2 = User.generate!
132 @user2 = User.generate!
133 assert_equal 'all', @user2.mail_notification
133 assert_equal 'all', @user2.mail_notification
134 end
134 end
135 end
135 end
136
136
137 def test_user_login_should_be_case_insensitive
137 def test_user_login_should_be_case_insensitive
138 u = User.new(:firstname => "new", :lastname => "user", :mail => "newuser@somenet.foo")
138 u = User.new(:firstname => "new", :lastname => "user", :mail => "newuser@somenet.foo")
139 u.login = 'newuser'
139 u.login = 'newuser'
140 u.password, u.password_confirmation = "password", "password"
140 u.password, u.password_confirmation = "password", "password"
141 assert u.save
141 assert u.save
142 u = User.new(:firstname => "Similar", :lastname => "User",
142 u = User.new(:firstname => "Similar", :lastname => "User",
143 :mail => "similaruser@somenet.foo")
143 :mail => "similaruser@somenet.foo")
144 u.login = 'NewUser'
144 u.login = 'NewUser'
145 u.password, u.password_confirmation = "password", "password"
145 u.password, u.password_confirmation = "password", "password"
146 assert !u.save
146 assert !u.save
147 assert_include I18n.translate('activerecord.errors.messages.taken'), u.errors[:login]
147 assert_include I18n.translate('activerecord.errors.messages.taken'), u.errors[:login]
148 end
148 end
149
149
150 def test_mail_uniqueness_should_not_be_case_sensitive
150 def test_mail_uniqueness_should_not_be_case_sensitive
151 u = User.new(:firstname => "new", :lastname => "user", :mail => "newuser@somenet.foo")
151 u = User.new(:firstname => "new", :lastname => "user", :mail => "newuser@somenet.foo")
152 u.login = 'newuser1'
152 u.login = 'newuser1'
153 u.password, u.password_confirmation = "password", "password"
153 u.password, u.password_confirmation = "password", "password"
154 assert u.save
154 assert u.save
155
155
156 u = User.new(:firstname => "new", :lastname => "user", :mail => "newUser@Somenet.foo")
156 u = User.new(:firstname => "new", :lastname => "user", :mail => "newUser@Somenet.foo")
157 u.login = 'newuser2'
157 u.login = 'newuser2'
158 u.password, u.password_confirmation = "password", "password"
158 u.password, u.password_confirmation = "password", "password"
159 assert !u.save
159 assert !u.save
160 assert_include I18n.translate('activerecord.errors.messages.taken'), u.errors[:mail]
160 assert_include I18n.translate('activerecord.errors.messages.taken'), u.errors[:mail]
161 end
161 end
162
162
163 def test_update
163 def test_update
164 assert_equal "admin", @admin.login
164 assert_equal "admin", @admin.login
165 @admin.login = "john"
165 @admin.login = "john"
166 assert @admin.save, @admin.errors.full_messages.join("; ")
166 assert @admin.save, @admin.errors.full_messages.join("; ")
167 @admin.reload
167 @admin.reload
168 assert_equal "john", @admin.login
168 assert_equal "john", @admin.login
169 end
169 end
170
170
171 def test_update_should_not_fail_for_legacy_user_with_different_case_logins
171 def test_update_should_not_fail_for_legacy_user_with_different_case_logins
172 u1 = User.new(:firstname => "new", :lastname => "user", :mail => "newuser1@somenet.foo")
172 u1 = User.new(:firstname => "new", :lastname => "user", :mail => "newuser1@somenet.foo")
173 u1.login = 'newuser1'
173 u1.login = 'newuser1'
174 assert u1.save
174 assert u1.save
175
175
176 u2 = User.new(:firstname => "new", :lastname => "user", :mail => "newuser2@somenet.foo")
176 u2 = User.new(:firstname => "new", :lastname => "user", :mail => "newuser2@somenet.foo")
177 u2.login = 'newuser1'
177 u2.login = 'newuser1'
178 assert u2.save(:validate => false)
178 assert u2.save(:validate => false)
179
179
180 user = User.find(u2.id)
180 user = User.find(u2.id)
181 user.firstname = "firstname"
181 user.firstname = "firstname"
182 assert user.save, "Save failed"
182 assert user.save, "Save failed"
183 end
183 end
184
184
185 def test_destroy_should_delete_members_and_roles
185 def test_destroy_should_delete_members_and_roles
186 members = Member.where(:user_id => 2)
186 members = Member.where(:user_id => 2)
187 ms = members.count
187 ms = members.count
188 rs = members.collect(&:roles).flatten.size
188 rs = members.collect(&:roles).flatten.size
189 assert ms > 0
189 assert ms > 0
190 assert rs > 0
190 assert rs > 0
191 assert_difference 'Member.count', - ms do
191 assert_difference 'Member.count', - ms do
192 assert_difference 'MemberRole.count', - rs do
192 assert_difference 'MemberRole.count', - rs do
193 User.find(2).destroy
193 User.find(2).destroy
194 end
194 end
195 end
195 end
196 assert_nil User.find_by_id(2)
196 assert_nil User.find_by_id(2)
197 assert_equal 0, Member.where(:user_id => 2).count
197 assert_equal 0, Member.where(:user_id => 2).count
198 end
198 end
199
199
200 def test_destroy_should_update_attachments
200 def test_destroy_should_update_attachments
201 attachment = Attachment.create!(:container => Project.find(1),
201 attachment = Attachment.create!(:container => Project.find(1),
202 :file => uploaded_test_file("testfile.txt", "text/plain"),
202 :file => uploaded_test_file("testfile.txt", "text/plain"),
203 :author_id => 2)
203 :author_id => 2)
204
204
205 User.find(2).destroy
205 User.find(2).destroy
206 assert_nil User.find_by_id(2)
206 assert_nil User.find_by_id(2)
207 assert_equal User.anonymous, attachment.reload.author
207 assert_equal User.anonymous, attachment.reload.author
208 end
208 end
209
209
210 def test_destroy_should_update_comments
210 def test_destroy_should_update_comments
211 comment = Comment.create!(
211 comment = Comment.create!(
212 :commented => News.create!(:project_id => 1,
212 :commented => News.create!(:project_id => 1,
213 :author_id => 1, :title => 'foo', :description => 'foo'),
213 :author_id => 1, :title => 'foo', :description => 'foo'),
214 :author => User.find(2),
214 :author => User.find(2),
215 :comments => 'foo'
215 :comments => 'foo'
216 )
216 )
217
217
218 User.find(2).destroy
218 User.find(2).destroy
219 assert_nil User.find_by_id(2)
219 assert_nil User.find_by_id(2)
220 assert_equal User.anonymous, comment.reload.author
220 assert_equal User.anonymous, comment.reload.author
221 end
221 end
222
222
223 def test_destroy_should_update_issues
223 def test_destroy_should_update_issues
224 issue = Issue.create!(:project_id => 1, :author_id => 2,
224 issue = Issue.create!(:project_id => 1, :author_id => 2,
225 :tracker_id => 1, :subject => 'foo')
225 :tracker_id => 1, :subject => 'foo')
226
226
227 User.find(2).destroy
227 User.find(2).destroy
228 assert_nil User.find_by_id(2)
228 assert_nil User.find_by_id(2)
229 assert_equal User.anonymous, issue.reload.author
229 assert_equal User.anonymous, issue.reload.author
230 end
230 end
231
231
232 def test_destroy_should_unassign_issues
232 def test_destroy_should_unassign_issues
233 issue = Issue.create!(:project_id => 1, :author_id => 1,
233 issue = Issue.create!(:project_id => 1, :author_id => 1,
234 :tracker_id => 1, :subject => 'foo', :assigned_to_id => 2)
234 :tracker_id => 1, :subject => 'foo', :assigned_to_id => 2)
235
235
236 User.find(2).destroy
236 User.find(2).destroy
237 assert_nil User.find_by_id(2)
237 assert_nil User.find_by_id(2)
238 assert_nil issue.reload.assigned_to
238 assert_nil issue.reload.assigned_to
239 end
239 end
240
240
241 def test_destroy_should_update_journals
241 def test_destroy_should_update_journals
242 issue = Issue.create!(:project_id => 1, :author_id => 2,
242 issue = Issue.create!(:project_id => 1, :author_id => 2,
243 :tracker_id => 1, :subject => 'foo')
243 :tracker_id => 1, :subject => 'foo')
244 issue.init_journal(User.find(2), "update")
244 issue.init_journal(User.find(2), "update")
245 issue.save!
245 issue.save!
246
246
247 User.find(2).destroy
247 User.find(2).destroy
248 assert_nil User.find_by_id(2)
248 assert_nil User.find_by_id(2)
249 assert_equal User.anonymous, issue.journals.first.reload.user
249 assert_equal User.anonymous, issue.journals.first.reload.user
250 end
250 end
251
251
252 def test_destroy_should_update_journal_details_old_value
252 def test_destroy_should_update_journal_details_old_value
253 issue = Issue.create!(:project_id => 1, :author_id => 1,
253 issue = Issue.create!(:project_id => 1, :author_id => 1,
254 :tracker_id => 1, :subject => 'foo', :assigned_to_id => 2)
254 :tracker_id => 1, :subject => 'foo', :assigned_to_id => 2)
255 issue.init_journal(User.find(1), "update")
255 issue.init_journal(User.find(1), "update")
256 issue.assigned_to_id = nil
256 issue.assigned_to_id = nil
257 assert_difference 'JournalDetail.count' do
257 assert_difference 'JournalDetail.count' do
258 issue.save!
258 issue.save!
259 end
259 end
260 journal_detail = JournalDetail.order('id DESC').first
260 journal_detail = JournalDetail.order('id DESC').first
261 assert_equal '2', journal_detail.old_value
261 assert_equal '2', journal_detail.old_value
262
262
263 User.find(2).destroy
263 User.find(2).destroy
264 assert_nil User.find_by_id(2)
264 assert_nil User.find_by_id(2)
265 assert_equal User.anonymous.id.to_s, journal_detail.reload.old_value
265 assert_equal User.anonymous.id.to_s, journal_detail.reload.old_value
266 end
266 end
267
267
268 def test_destroy_should_update_journal_details_value
268 def test_destroy_should_update_journal_details_value
269 issue = Issue.create!(:project_id => 1, :author_id => 1,
269 issue = Issue.create!(:project_id => 1, :author_id => 1,
270 :tracker_id => 1, :subject => 'foo')
270 :tracker_id => 1, :subject => 'foo')
271 issue.init_journal(User.find(1), "update")
271 issue.init_journal(User.find(1), "update")
272 issue.assigned_to_id = 2
272 issue.assigned_to_id = 2
273 assert_difference 'JournalDetail.count' do
273 assert_difference 'JournalDetail.count' do
274 issue.save!
274 issue.save!
275 end
275 end
276 journal_detail = JournalDetail.order('id DESC').first
276 journal_detail = JournalDetail.order('id DESC').first
277 assert_equal '2', journal_detail.value
277 assert_equal '2', journal_detail.value
278
278
279 User.find(2).destroy
279 User.find(2).destroy
280 assert_nil User.find_by_id(2)
280 assert_nil User.find_by_id(2)
281 assert_equal User.anonymous.id.to_s, journal_detail.reload.value
281 assert_equal User.anonymous.id.to_s, journal_detail.reload.value
282 end
282 end
283
283
284 def test_destroy_should_update_messages
284 def test_destroy_should_update_messages
285 board = Board.create!(:project_id => 1, :name => 'Board', :description => 'Board')
285 board = Board.create!(:project_id => 1, :name => 'Board', :description => 'Board')
286 message = Message.create!(:board_id => board.id, :author_id => 2,
286 message = Message.create!(:board_id => board.id, :author_id => 2,
287 :subject => 'foo', :content => 'foo')
287 :subject => 'foo', :content => 'foo')
288 User.find(2).destroy
288 User.find(2).destroy
289 assert_nil User.find_by_id(2)
289 assert_nil User.find_by_id(2)
290 assert_equal User.anonymous, message.reload.author
290 assert_equal User.anonymous, message.reload.author
291 end
291 end
292
292
293 def test_destroy_should_update_news
293 def test_destroy_should_update_news
294 news = News.create!(:project_id => 1, :author_id => 2,
294 news = News.create!(:project_id => 1, :author_id => 2,
295 :title => 'foo', :description => 'foo')
295 :title => 'foo', :description => 'foo')
296 User.find(2).destroy
296 User.find(2).destroy
297 assert_nil User.find_by_id(2)
297 assert_nil User.find_by_id(2)
298 assert_equal User.anonymous, news.reload.author
298 assert_equal User.anonymous, news.reload.author
299 end
299 end
300
300
301 def test_destroy_should_delete_private_queries
301 def test_destroy_should_delete_private_queries
302 query = Query.new(:name => 'foo', :visibility => Query::VISIBILITY_PRIVATE)
302 query = Query.new(:name => 'foo', :visibility => Query::VISIBILITY_PRIVATE)
303 query.project_id = 1
303 query.project_id = 1
304 query.user_id = 2
304 query.user_id = 2
305 query.save!
305 query.save!
306
306
307 User.find(2).destroy
307 User.find(2).destroy
308 assert_nil User.find_by_id(2)
308 assert_nil User.find_by_id(2)
309 assert_nil Query.find_by_id(query.id)
309 assert_nil Query.find_by_id(query.id)
310 end
310 end
311
311
312 def test_destroy_should_update_public_queries
312 def test_destroy_should_update_public_queries
313 query = Query.new(:name => 'foo', :visibility => Query::VISIBILITY_PUBLIC)
313 query = Query.new(:name => 'foo', :visibility => Query::VISIBILITY_PUBLIC)
314 query.project_id = 1
314 query.project_id = 1
315 query.user_id = 2
315 query.user_id = 2
316 query.save!
316 query.save!
317
317
318 User.find(2).destroy
318 User.find(2).destroy
319 assert_nil User.find_by_id(2)
319 assert_nil User.find_by_id(2)
320 assert_equal User.anonymous, query.reload.user
320 assert_equal User.anonymous, query.reload.user
321 end
321 end
322
322
323 def test_destroy_should_update_time_entries
323 def test_destroy_should_update_time_entries
324 entry = TimeEntry.new(:hours => '2', :spent_on => Date.today,
324 entry = TimeEntry.new(:hours => '2', :spent_on => Date.today,
325 :activity => TimeEntryActivity.create!(:name => 'foo'))
325 :activity => TimeEntryActivity.create!(:name => 'foo'))
326 entry.project_id = 1
326 entry.project_id = 1
327 entry.user_id = 2
327 entry.user_id = 2
328 entry.save!
328 entry.save!
329
329
330 User.find(2).destroy
330 User.find(2).destroy
331 assert_nil User.find_by_id(2)
331 assert_nil User.find_by_id(2)
332 assert_equal User.anonymous, entry.reload.user
332 assert_equal User.anonymous, entry.reload.user
333 end
333 end
334
334
335 def test_destroy_should_delete_tokens
335 def test_destroy_should_delete_tokens
336 token = Token.create!(:user_id => 2, :value => 'foo')
336 token = Token.create!(:user_id => 2, :value => 'foo')
337
337
338 User.find(2).destroy
338 User.find(2).destroy
339 assert_nil User.find_by_id(2)
339 assert_nil User.find_by_id(2)
340 assert_nil Token.find_by_id(token.id)
340 assert_nil Token.find_by_id(token.id)
341 end
341 end
342
342
343 def test_destroy_should_delete_watchers
343 def test_destroy_should_delete_watchers
344 issue = Issue.create!(:project_id => 1, :author_id => 1,
344 issue = Issue.create!(:project_id => 1, :author_id => 1,
345 :tracker_id => 1, :subject => 'foo')
345 :tracker_id => 1, :subject => 'foo')
346 watcher = Watcher.create!(:user_id => 2, :watchable => issue)
346 watcher = Watcher.create!(:user_id => 2, :watchable => issue)
347
347
348 User.find(2).destroy
348 User.find(2).destroy
349 assert_nil User.find_by_id(2)
349 assert_nil User.find_by_id(2)
350 assert_nil Watcher.find_by_id(watcher.id)
350 assert_nil Watcher.find_by_id(watcher.id)
351 end
351 end
352
352
353 def test_destroy_should_update_wiki_contents
353 def test_destroy_should_update_wiki_contents
354 wiki_content = WikiContent.create!(
354 wiki_content = WikiContent.create!(
355 :text => 'foo',
355 :text => 'foo',
356 :author_id => 2,
356 :author_id => 2,
357 :page => WikiPage.create!(:title => 'Foo',
357 :page => WikiPage.create!(:title => 'Foo',
358 :wiki => Wiki.create!(:project_id => 3,
358 :wiki => Wiki.create!(:project_id => 3,
359 :start_page => 'Start'))
359 :start_page => 'Start'))
360 )
360 )
361 wiki_content.text = 'bar'
361 wiki_content.text = 'bar'
362 assert_difference 'WikiContent::Version.count' do
362 assert_difference 'WikiContent::Version.count' do
363 wiki_content.save!
363 wiki_content.save!
364 end
364 end
365
365
366 User.find(2).destroy
366 User.find(2).destroy
367 assert_nil User.find_by_id(2)
367 assert_nil User.find_by_id(2)
368 assert_equal User.anonymous, wiki_content.reload.author
368 assert_equal User.anonymous, wiki_content.reload.author
369 wiki_content.versions.each do |version|
369 wiki_content.versions.each do |version|
370 assert_equal User.anonymous, version.reload.author
370 assert_equal User.anonymous, version.reload.author
371 end
371 end
372 end
372 end
373
373
374 def test_destroy_should_nullify_issue_categories
374 def test_destroy_should_nullify_issue_categories
375 category = IssueCategory.create!(:project_id => 1, :assigned_to_id => 2, :name => 'foo')
375 category = IssueCategory.create!(:project_id => 1, :assigned_to_id => 2, :name => 'foo')
376
376
377 User.find(2).destroy
377 User.find(2).destroy
378 assert_nil User.find_by_id(2)
378 assert_nil User.find_by_id(2)
379 assert_nil category.reload.assigned_to_id
379 assert_nil category.reload.assigned_to_id
380 end
380 end
381
381
382 def test_destroy_should_nullify_changesets
382 def test_destroy_should_nullify_changesets
383 changeset = Changeset.create!(
383 changeset = Changeset.create!(
384 :repository => Repository::Subversion.create!(
384 :repository => Repository::Subversion.create!(
385 :project_id => 1,
385 :project_id => 1,
386 :url => 'file:///tmp',
386 :url => 'file:///tmp',
387 :identifier => 'tmp'
387 :identifier => 'tmp'
388 ),
388 ),
389 :revision => '12',
389 :revision => '12',
390 :committed_on => Time.now,
390 :committed_on => Time.now,
391 :committer => 'jsmith'
391 :committer => 'jsmith'
392 )
392 )
393 assert_equal 2, changeset.user_id
393 assert_equal 2, changeset.user_id
394
394
395 User.find(2).destroy
395 User.find(2).destroy
396 assert_nil User.find_by_id(2)
396 assert_nil User.find_by_id(2)
397 assert_nil changeset.reload.user_id
397 assert_nil changeset.reload.user_id
398 end
398 end
399
399
400 def test_anonymous_user_should_not_be_destroyable
400 def test_anonymous_user_should_not_be_destroyable
401 assert_no_difference 'User.count' do
401 assert_no_difference 'User.count' do
402 assert_equal false, User.anonymous.destroy
402 assert_equal false, User.anonymous.destroy
403 end
403 end
404 end
404 end
405
405
406 def test_validate_login_presence
406 def test_validate_login_presence
407 @admin.login = ""
407 @admin.login = ""
408 assert !@admin.save
408 assert !@admin.save
409 assert_equal 1, @admin.errors.count
409 assert_equal 1, @admin.errors.count
410 end
410 end
411
411
412 def test_validate_mail_notification_inclusion
412 def test_validate_mail_notification_inclusion
413 u = User.new
413 u = User.new
414 u.mail_notification = 'foo'
414 u.mail_notification = 'foo'
415 u.save
415 u.save
416 assert_not_equal [], u.errors[:mail_notification]
416 assert_not_equal [], u.errors[:mail_notification]
417 end
417 end
418
418
419 def test_password
419 def test_password
420 user = User.try_to_login("admin", "admin")
420 user = User.try_to_login("admin", "admin")
421 assert_kind_of User, user
421 assert_kind_of User, user
422 assert_equal "admin", user.login
422 assert_equal "admin", user.login
423 user.password = "hello123"
423 user.password = "hello123"
424 assert user.save
424 assert user.save
425
425
426 user = User.try_to_login("admin", "hello123")
426 user = User.try_to_login("admin", "hello123")
427 assert_kind_of User, user
427 assert_kind_of User, user
428 assert_equal "admin", user.login
428 assert_equal "admin", user.login
429 end
429 end
430
430
431 def test_validate_password_length
431 def test_validate_password_length
432 with_settings :password_min_length => '100' do
432 with_settings :password_min_length => '100' do
433 user = User.new(:firstname => "new100",
433 user = User.new(:firstname => "new100",
434 :lastname => "user100", :mail => "newuser100@somenet.foo")
434 :lastname => "user100", :mail => "newuser100@somenet.foo")
435 user.login = "newuser100"
435 user.login = "newuser100"
436 user.password, user.password_confirmation = "password100", "password100"
436 user.password, user.password_confirmation = "password100", "password100"
437 assert !user.save
437 assert !user.save
438 assert_equal 1, user.errors.count
438 assert_equal 1, user.errors.count
439 end
439 end
440 end
440 end
441
441
442 def test_name_format
442 def test_name_format
443 assert_equal 'John S.', @jsmith.name(:firstname_lastinitial)
443 assert_equal 'John S.', @jsmith.name(:firstname_lastinitial)
444 assert_equal 'Smith, John', @jsmith.name(:lastname_coma_firstname)
444 assert_equal 'Smith, John', @jsmith.name(:lastname_coma_firstname)
445 assert_equal 'J. Smith', @jsmith.name(:firstinitial_lastname)
446 assert_equal 'J.-P. Lang', User.new(:firstname => 'Jean-Philippe', :lastname => 'Lang').name(:firstinitial_lastname)
447 end
448
449 def test_name_should_use_setting_as_default_format
445 with_settings :user_format => :firstname_lastname do
450 with_settings :user_format => :firstname_lastname do
446 assert_equal 'John Smith', @jsmith.reload.name
451 assert_equal 'John Smith', @jsmith.reload.name
447 end
452 end
448 with_settings :user_format => :username do
453 with_settings :user_format => :username do
449 assert_equal 'jsmith', @jsmith.reload.name
454 assert_equal 'jsmith', @jsmith.reload.name
450 end
455 end
451 with_settings :user_format => :lastname do
456 with_settings :user_format => :lastname do
452 assert_equal 'Smith', @jsmith.reload.name
457 assert_equal 'Smith', @jsmith.reload.name
453 end
458 end
454 end
459 end
455
460
456 def test_today_should_return_the_day_according_to_user_time_zone
461 def test_today_should_return_the_day_according_to_user_time_zone
457 preference = User.find(1).pref
462 preference = User.find(1).pref
458 date = Date.new(2012, 05, 15)
463 date = Date.new(2012, 05, 15)
459 time = Time.gm(2012, 05, 15, 23, 30).utc # 2012-05-15 23:30 UTC
464 time = Time.gm(2012, 05, 15, 23, 30).utc # 2012-05-15 23:30 UTC
460 Date.stubs(:today).returns(date)
465 Date.stubs(:today).returns(date)
461 Time.stubs(:now).returns(time)
466 Time.stubs(:now).returns(time)
462
467
463 preference.update_attribute :time_zone, 'Baku' # UTC+4
468 preference.update_attribute :time_zone, 'Baku' # UTC+4
464 assert_equal '2012-05-16', User.find(1).today.to_s
469 assert_equal '2012-05-16', User.find(1).today.to_s
465
470
466 preference.update_attribute :time_zone, 'La Paz' # UTC-4
471 preference.update_attribute :time_zone, 'La Paz' # UTC-4
467 assert_equal '2012-05-15', User.find(1).today.to_s
472 assert_equal '2012-05-15', User.find(1).today.to_s
468
473
469 preference.update_attribute :time_zone, ''
474 preference.update_attribute :time_zone, ''
470 assert_equal '2012-05-15', User.find(1).today.to_s
475 assert_equal '2012-05-15', User.find(1).today.to_s
471 end
476 end
472
477
473 def test_time_to_date_should_return_the_date_according_to_user_time_zone
478 def test_time_to_date_should_return_the_date_according_to_user_time_zone
474 preference = User.find(1).pref
479 preference = User.find(1).pref
475 time = Time.gm(2012, 05, 15, 23, 30).utc # 2012-05-15 23:30 UTC
480 time = Time.gm(2012, 05, 15, 23, 30).utc # 2012-05-15 23:30 UTC
476
481
477 preference.update_attribute :time_zone, 'Baku' # UTC+4
482 preference.update_attribute :time_zone, 'Baku' # UTC+4
478 assert_equal '2012-05-16', User.find(1).time_to_date(time).to_s
483 assert_equal '2012-05-16', User.find(1).time_to_date(time).to_s
479
484
480 preference.update_attribute :time_zone, 'La Paz' # UTC-4
485 preference.update_attribute :time_zone, 'La Paz' # UTC-4
481 assert_equal '2012-05-15', User.find(1).time_to_date(time).to_s
486 assert_equal '2012-05-15', User.find(1).time_to_date(time).to_s
482
487
483 preference.update_attribute :time_zone, ''
488 preference.update_attribute :time_zone, ''
484 assert_equal '2012-05-15', User.find(1).time_to_date(time).to_s
489 assert_equal '2012-05-15', User.find(1).time_to_date(time).to_s
485 end
490 end
486
491
487 def test_fields_for_order_statement_should_return_fields_according_user_format_setting
492 def test_fields_for_order_statement_should_return_fields_according_user_format_setting
488 with_settings :user_format => 'lastname_coma_firstname' do
493 with_settings :user_format => 'lastname_coma_firstname' do
489 assert_equal ['users.lastname', 'users.firstname', 'users.id'],
494 assert_equal ['users.lastname', 'users.firstname', 'users.id'],
490 User.fields_for_order_statement
495 User.fields_for_order_statement
491 end
496 end
492 end
497 end
493
498
494 def test_fields_for_order_statement_width_table_name_should_prepend_table_name
499 def test_fields_for_order_statement_width_table_name_should_prepend_table_name
495 with_settings :user_format => 'lastname_firstname' do
500 with_settings :user_format => 'lastname_firstname' do
496 assert_equal ['authors.lastname', 'authors.firstname', 'authors.id'],
501 assert_equal ['authors.lastname', 'authors.firstname', 'authors.id'],
497 User.fields_for_order_statement('authors')
502 User.fields_for_order_statement('authors')
498 end
503 end
499 end
504 end
500
505
501 def test_fields_for_order_statement_with_blank_format_should_return_default
506 def test_fields_for_order_statement_with_blank_format_should_return_default
502 with_settings :user_format => '' do
507 with_settings :user_format => '' do
503 assert_equal ['users.firstname', 'users.lastname', 'users.id'],
508 assert_equal ['users.firstname', 'users.lastname', 'users.id'],
504 User.fields_for_order_statement
509 User.fields_for_order_statement
505 end
510 end
506 end
511 end
507
512
508 def test_fields_for_order_statement_with_invalid_format_should_return_default
513 def test_fields_for_order_statement_with_invalid_format_should_return_default
509 with_settings :user_format => 'foo' do
514 with_settings :user_format => 'foo' do
510 assert_equal ['users.firstname', 'users.lastname', 'users.id'],
515 assert_equal ['users.firstname', 'users.lastname', 'users.id'],
511 User.fields_for_order_statement
516 User.fields_for_order_statement
512 end
517 end
513 end
518 end
514
519
515 test ".try_to_login with good credentials should return the user" do
520 test ".try_to_login with good credentials should return the user" do
516 user = User.try_to_login("admin", "admin")
521 user = User.try_to_login("admin", "admin")
517 assert_kind_of User, user
522 assert_kind_of User, user
518 assert_equal "admin", user.login
523 assert_equal "admin", user.login
519 end
524 end
520
525
521 test ".try_to_login with wrong credentials should return nil" do
526 test ".try_to_login with wrong credentials should return nil" do
522 assert_nil User.try_to_login("admin", "foo")
527 assert_nil User.try_to_login("admin", "foo")
523 end
528 end
524
529
525 def test_try_to_login_with_locked_user_should_return_nil
530 def test_try_to_login_with_locked_user_should_return_nil
526 @jsmith.status = User::STATUS_LOCKED
531 @jsmith.status = User::STATUS_LOCKED
527 @jsmith.save!
532 @jsmith.save!
528
533
529 user = User.try_to_login("jsmith", "jsmith")
534 user = User.try_to_login("jsmith", "jsmith")
530 assert_equal nil, user
535 assert_equal nil, user
531 end
536 end
532
537
533 def test_try_to_login_with_locked_user_and_not_active_only_should_return_user
538 def test_try_to_login_with_locked_user_and_not_active_only_should_return_user
534 @jsmith.status = User::STATUS_LOCKED
539 @jsmith.status = User::STATUS_LOCKED
535 @jsmith.save!
540 @jsmith.save!
536
541
537 user = User.try_to_login("jsmith", "jsmith", false)
542 user = User.try_to_login("jsmith", "jsmith", false)
538 assert_equal @jsmith, user
543 assert_equal @jsmith, user
539 end
544 end
540
545
541 test ".try_to_login should fall-back to case-insensitive if user login is not found as-typed" do
546 test ".try_to_login should fall-back to case-insensitive if user login is not found as-typed" do
542 user = User.try_to_login("AdMin", "admin")
547 user = User.try_to_login("AdMin", "admin")
543 assert_kind_of User, user
548 assert_kind_of User, user
544 assert_equal "admin", user.login
549 assert_equal "admin", user.login
545 end
550 end
546
551
547 test ".try_to_login should select the exact matching user first" do
552 test ".try_to_login should select the exact matching user first" do
548 case_sensitive_user = User.generate! do |user|
553 case_sensitive_user = User.generate! do |user|
549 user.password = "admin123"
554 user.password = "admin123"
550 end
555 end
551 # bypass validations to make it appear like existing data
556 # bypass validations to make it appear like existing data
552 case_sensitive_user.update_attribute(:login, 'ADMIN')
557 case_sensitive_user.update_attribute(:login, 'ADMIN')
553
558
554 user = User.try_to_login("ADMIN", "admin123")
559 user = User.try_to_login("ADMIN", "admin123")
555 assert_kind_of User, user
560 assert_kind_of User, user
556 assert_equal "ADMIN", user.login
561 assert_equal "ADMIN", user.login
557 end
562 end
558
563
559 if ldap_configured?
564 if ldap_configured?
560 context "#try_to_login using LDAP" do
565 context "#try_to_login using LDAP" do
561 context "with failed connection to the LDAP server" do
566 context "with failed connection to the LDAP server" do
562 should "return nil" do
567 should "return nil" do
563 @auth_source = AuthSourceLdap.find(1)
568 @auth_source = AuthSourceLdap.find(1)
564 AuthSource.any_instance.stubs(:initialize_ldap_con).raises(Net::LDAP::LdapError, 'Cannot connect')
569 AuthSource.any_instance.stubs(:initialize_ldap_con).raises(Net::LDAP::LdapError, 'Cannot connect')
565
570
566 assert_equal nil, User.try_to_login('edavis', 'wrong')
571 assert_equal nil, User.try_to_login('edavis', 'wrong')
567 end
572 end
568 end
573 end
569
574
570 context "with an unsuccessful authentication" do
575 context "with an unsuccessful authentication" do
571 should "return nil" do
576 should "return nil" do
572 assert_equal nil, User.try_to_login('edavis', 'wrong')
577 assert_equal nil, User.try_to_login('edavis', 'wrong')
573 end
578 end
574 end
579 end
575
580
576 context "binding with user's account" do
581 context "binding with user's account" do
577 setup do
582 setup do
578 @auth_source = AuthSourceLdap.find(1)
583 @auth_source = AuthSourceLdap.find(1)
579 @auth_source.account = "uid=$login,ou=Person,dc=redmine,dc=org"
584 @auth_source.account = "uid=$login,ou=Person,dc=redmine,dc=org"
580 @auth_source.account_password = ''
585 @auth_source.account_password = ''
581 @auth_source.save!
586 @auth_source.save!
582
587
583 @ldap_user = User.new(:mail => 'example1@redmine.org', :firstname => 'LDAP', :lastname => 'user', :auth_source_id => 1)
588 @ldap_user = User.new(:mail => 'example1@redmine.org', :firstname => 'LDAP', :lastname => 'user', :auth_source_id => 1)
584 @ldap_user.login = 'example1'
589 @ldap_user.login = 'example1'
585 @ldap_user.save!
590 @ldap_user.save!
586 end
591 end
587
592
588 context "with a successful authentication" do
593 context "with a successful authentication" do
589 should "return the user" do
594 should "return the user" do
590 assert_equal @ldap_user, User.try_to_login('example1', '123456')
595 assert_equal @ldap_user, User.try_to_login('example1', '123456')
591 end
596 end
592 end
597 end
593
598
594 context "with an unsuccessful authentication" do
599 context "with an unsuccessful authentication" do
595 should "return nil" do
600 should "return nil" do
596 assert_nil User.try_to_login('example1', '11111')
601 assert_nil User.try_to_login('example1', '11111')
597 end
602 end
598 end
603 end
599 end
604 end
600
605
601 context "on the fly registration" do
606 context "on the fly registration" do
602 setup do
607 setup do
603 @auth_source = AuthSourceLdap.find(1)
608 @auth_source = AuthSourceLdap.find(1)
604 @auth_source.update_attribute :onthefly_register, true
609 @auth_source.update_attribute :onthefly_register, true
605 end
610 end
606
611
607 context "with a successful authentication" do
612 context "with a successful authentication" do
608 should "create a new user account if it doesn't exist" do
613 should "create a new user account if it doesn't exist" do
609 assert_difference('User.count') do
614 assert_difference('User.count') do
610 user = User.try_to_login('edavis', '123456')
615 user = User.try_to_login('edavis', '123456')
611 assert !user.admin?
616 assert !user.admin?
612 end
617 end
613 end
618 end
614
619
615 should "retrieve existing user" do
620 should "retrieve existing user" do
616 user = User.try_to_login('edavis', '123456')
621 user = User.try_to_login('edavis', '123456')
617 user.admin = true
622 user.admin = true
618 user.save!
623 user.save!
619
624
620 assert_no_difference('User.count') do
625 assert_no_difference('User.count') do
621 user = User.try_to_login('edavis', '123456')
626 user = User.try_to_login('edavis', '123456')
622 assert user.admin?
627 assert user.admin?
623 end
628 end
624 end
629 end
625 end
630 end
626
631
627 context "binding with user's account" do
632 context "binding with user's account" do
628 setup do
633 setup do
629 @auth_source = AuthSourceLdap.find(1)
634 @auth_source = AuthSourceLdap.find(1)
630 @auth_source.account = "uid=$login,ou=Person,dc=redmine,dc=org"
635 @auth_source.account = "uid=$login,ou=Person,dc=redmine,dc=org"
631 @auth_source.account_password = ''
636 @auth_source.account_password = ''
632 @auth_source.save!
637 @auth_source.save!
633 end
638 end
634
639
635 context "with a successful authentication" do
640 context "with a successful authentication" do
636 should "create a new user account if it doesn't exist" do
641 should "create a new user account if it doesn't exist" do
637 assert_difference('User.count') do
642 assert_difference('User.count') do
638 user = User.try_to_login('example1', '123456')
643 user = User.try_to_login('example1', '123456')
639 assert_kind_of User, user
644 assert_kind_of User, user
640 end
645 end
641 end
646 end
642 end
647 end
643
648
644 context "with an unsuccessful authentication" do
649 context "with an unsuccessful authentication" do
645 should "return nil" do
650 should "return nil" do
646 assert_nil User.try_to_login('example1', '11111')
651 assert_nil User.try_to_login('example1', '11111')
647 end
652 end
648 end
653 end
649 end
654 end
650 end
655 end
651 end
656 end
652
657
653 else
658 else
654 puts "Skipping LDAP tests."
659 puts "Skipping LDAP tests."
655 end
660 end
656
661
657 def test_create_anonymous
662 def test_create_anonymous
658 AnonymousUser.delete_all
663 AnonymousUser.delete_all
659 anon = User.anonymous
664 anon = User.anonymous
660 assert !anon.new_record?
665 assert !anon.new_record?
661 assert_kind_of AnonymousUser, anon
666 assert_kind_of AnonymousUser, anon
662 end
667 end
663
668
664 def test_ensure_single_anonymous_user
669 def test_ensure_single_anonymous_user
665 AnonymousUser.delete_all
670 AnonymousUser.delete_all
666 anon1 = User.anonymous
671 anon1 = User.anonymous
667 assert !anon1.new_record?
672 assert !anon1.new_record?
668 assert_kind_of AnonymousUser, anon1
673 assert_kind_of AnonymousUser, anon1
669 anon2 = AnonymousUser.create(
674 anon2 = AnonymousUser.create(
670 :lastname => 'Anonymous', :firstname => '',
675 :lastname => 'Anonymous', :firstname => '',
671 :mail => '', :login => '', :status => 0)
676 :mail => '', :login => '', :status => 0)
672 assert_equal 1, anon2.errors.count
677 assert_equal 1, anon2.errors.count
673 end
678 end
674
679
675 def test_rss_key
680 def test_rss_key
676 assert_nil @jsmith.rss_token
681 assert_nil @jsmith.rss_token
677 key = @jsmith.rss_key
682 key = @jsmith.rss_key
678 assert_equal 40, key.length
683 assert_equal 40, key.length
679
684
680 @jsmith.reload
685 @jsmith.reload
681 assert_equal key, @jsmith.rss_key
686 assert_equal key, @jsmith.rss_key
682 end
687 end
683
688
684 def test_rss_key_should_not_be_generated_twice
689 def test_rss_key_should_not_be_generated_twice
685 assert_difference 'Token.count', 1 do
690 assert_difference 'Token.count', 1 do
686 key1 = @jsmith.rss_key
691 key1 = @jsmith.rss_key
687 key2 = @jsmith.rss_key
692 key2 = @jsmith.rss_key
688 assert_equal key1, key2
693 assert_equal key1, key2
689 end
694 end
690 end
695 end
691
696
692 def test_api_key_should_not_be_generated_twice
697 def test_api_key_should_not_be_generated_twice
693 assert_difference 'Token.count', 1 do
698 assert_difference 'Token.count', 1 do
694 key1 = @jsmith.api_key
699 key1 = @jsmith.api_key
695 key2 = @jsmith.api_key
700 key2 = @jsmith.api_key
696 assert_equal key1, key2
701 assert_equal key1, key2
697 end
702 end
698 end
703 end
699
704
700 test "#api_key should generate a new one if the user doesn't have one" do
705 test "#api_key should generate a new one if the user doesn't have one" do
701 user = User.generate!(:api_token => nil)
706 user = User.generate!(:api_token => nil)
702 assert_nil user.api_token
707 assert_nil user.api_token
703
708
704 key = user.api_key
709 key = user.api_key
705 assert_equal 40, key.length
710 assert_equal 40, key.length
706 user.reload
711 user.reload
707 assert_equal key, user.api_key
712 assert_equal key, user.api_key
708 end
713 end
709
714
710 test "#api_key should return the existing api token value" do
715 test "#api_key should return the existing api token value" do
711 user = User.generate!
716 user = User.generate!
712 token = Token.create!(:action => 'api')
717 token = Token.create!(:action => 'api')
713 user.api_token = token
718 user.api_token = token
714 assert user.save
719 assert user.save
715
720
716 assert_equal token.value, user.api_key
721 assert_equal token.value, user.api_key
717 end
722 end
718
723
719 test "#find_by_api_key should return nil if no matching key is found" do
724 test "#find_by_api_key should return nil if no matching key is found" do
720 assert_nil User.find_by_api_key('zzzzzzzzz')
725 assert_nil User.find_by_api_key('zzzzzzzzz')
721 end
726 end
722
727
723 test "#find_by_api_key should return nil if the key is found for an inactive user" do
728 test "#find_by_api_key should return nil if the key is found for an inactive user" do
724 user = User.generate!
729 user = User.generate!
725 user.status = User::STATUS_LOCKED
730 user.status = User::STATUS_LOCKED
726 token = Token.create!(:action => 'api')
731 token = Token.create!(:action => 'api')
727 user.api_token = token
732 user.api_token = token
728 user.save
733 user.save
729
734
730 assert_nil User.find_by_api_key(token.value)
735 assert_nil User.find_by_api_key(token.value)
731 end
736 end
732
737
733 test "#find_by_api_key should return the user if the key is found for an active user" do
738 test "#find_by_api_key should return the user if the key is found for an active user" do
734 user = User.generate!
739 user = User.generate!
735 token = Token.create!(:action => 'api')
740 token = Token.create!(:action => 'api')
736 user.api_token = token
741 user.api_token = token
737 user.save
742 user.save
738
743
739 assert_equal user, User.find_by_api_key(token.value)
744 assert_equal user, User.find_by_api_key(token.value)
740 end
745 end
741
746
742 def test_default_admin_account_changed_should_return_false_if_account_was_not_changed
747 def test_default_admin_account_changed_should_return_false_if_account_was_not_changed
743 user = User.find_by_login("admin")
748 user = User.find_by_login("admin")
744 user.password = "admin"
749 user.password = "admin"
745 assert user.save(:validate => false)
750 assert user.save(:validate => false)
746
751
747 assert_equal false, User.default_admin_account_changed?
752 assert_equal false, User.default_admin_account_changed?
748 end
753 end
749
754
750 def test_default_admin_account_changed_should_return_true_if_password_was_changed
755 def test_default_admin_account_changed_should_return_true_if_password_was_changed
751 user = User.find_by_login("admin")
756 user = User.find_by_login("admin")
752 user.password = "newpassword"
757 user.password = "newpassword"
753 user.save!
758 user.save!
754
759
755 assert_equal true, User.default_admin_account_changed?
760 assert_equal true, User.default_admin_account_changed?
756 end
761 end
757
762
758 def test_default_admin_account_changed_should_return_true_if_account_is_disabled
763 def test_default_admin_account_changed_should_return_true_if_account_is_disabled
759 user = User.find_by_login("admin")
764 user = User.find_by_login("admin")
760 user.password = "admin"
765 user.password = "admin"
761 user.status = User::STATUS_LOCKED
766 user.status = User::STATUS_LOCKED
762 assert user.save(:validate => false)
767 assert user.save(:validate => false)
763
768
764 assert_equal true, User.default_admin_account_changed?
769 assert_equal true, User.default_admin_account_changed?
765 end
770 end
766
771
767 def test_default_admin_account_changed_should_return_true_if_account_does_not_exist
772 def test_default_admin_account_changed_should_return_true_if_account_does_not_exist
768 user = User.find_by_login("admin")
773 user = User.find_by_login("admin")
769 user.destroy
774 user.destroy
770
775
771 assert_equal true, User.default_admin_account_changed?
776 assert_equal true, User.default_admin_account_changed?
772 end
777 end
773
778
774 def test_membership_with_project_should_return_membership
779 def test_membership_with_project_should_return_membership
775 project = Project.find(1)
780 project = Project.find(1)
776
781
777 membership = @jsmith.membership(project)
782 membership = @jsmith.membership(project)
778 assert_kind_of Member, membership
783 assert_kind_of Member, membership
779 assert_equal @jsmith, membership.user
784 assert_equal @jsmith, membership.user
780 assert_equal project, membership.project
785 assert_equal project, membership.project
781 end
786 end
782
787
783 def test_membership_with_project_id_should_return_membership
788 def test_membership_with_project_id_should_return_membership
784 project = Project.find(1)
789 project = Project.find(1)
785
790
786 membership = @jsmith.membership(1)
791 membership = @jsmith.membership(1)
787 assert_kind_of Member, membership
792 assert_kind_of Member, membership
788 assert_equal @jsmith, membership.user
793 assert_equal @jsmith, membership.user
789 assert_equal project, membership.project
794 assert_equal project, membership.project
790 end
795 end
791
796
792 def test_membership_for_non_member_should_return_nil
797 def test_membership_for_non_member_should_return_nil
793 project = Project.find(1)
798 project = Project.find(1)
794
799
795 user = User.generate!
800 user = User.generate!
796 membership = user.membership(1)
801 membership = user.membership(1)
797 assert_nil membership
802 assert_nil membership
798 end
803 end
799
804
800 def test_roles_for_project
805 def test_roles_for_project
801 # user with a role
806 # user with a role
802 roles = @jsmith.roles_for_project(Project.find(1))
807 roles = @jsmith.roles_for_project(Project.find(1))
803 assert_kind_of Role, roles.first
808 assert_kind_of Role, roles.first
804 assert_equal "Manager", roles.first.name
809 assert_equal "Manager", roles.first.name
805
810
806 # user with no role
811 # user with no role
807 assert_nil @dlopper.roles_for_project(Project.find(2)).detect {|role| role.member?}
812 assert_nil @dlopper.roles_for_project(Project.find(2)).detect {|role| role.member?}
808 end
813 end
809
814
810 def test_projects_by_role_for_user_with_role
815 def test_projects_by_role_for_user_with_role
811 user = User.find(2)
816 user = User.find(2)
812 assert_kind_of Hash, user.projects_by_role
817 assert_kind_of Hash, user.projects_by_role
813 assert_equal 2, user.projects_by_role.size
818 assert_equal 2, user.projects_by_role.size
814 assert_equal [1,5], user.projects_by_role[Role.find(1)].collect(&:id).sort
819 assert_equal [1,5], user.projects_by_role[Role.find(1)].collect(&:id).sort
815 assert_equal [2], user.projects_by_role[Role.find(2)].collect(&:id).sort
820 assert_equal [2], user.projects_by_role[Role.find(2)].collect(&:id).sort
816 end
821 end
817
822
818 def test_accessing_projects_by_role_with_no_projects_should_return_an_empty_array
823 def test_accessing_projects_by_role_with_no_projects_should_return_an_empty_array
819 user = User.find(2)
824 user = User.find(2)
820 assert_equal [], user.projects_by_role[Role.find(3)]
825 assert_equal [], user.projects_by_role[Role.find(3)]
821 # should not update the hash
826 # should not update the hash
822 assert_nil user.projects_by_role.values.detect(&:blank?)
827 assert_nil user.projects_by_role.values.detect(&:blank?)
823 end
828 end
824
829
825 def test_projects_by_role_for_user_with_no_role
830 def test_projects_by_role_for_user_with_no_role
826 user = User.generate!
831 user = User.generate!
827 assert_equal({}, user.projects_by_role)
832 assert_equal({}, user.projects_by_role)
828 end
833 end
829
834
830 def test_projects_by_role_for_anonymous
835 def test_projects_by_role_for_anonymous
831 assert_equal({}, User.anonymous.projects_by_role)
836 assert_equal({}, User.anonymous.projects_by_role)
832 end
837 end
833
838
834 def test_valid_notification_options
839 def test_valid_notification_options
835 # without memberships
840 # without memberships
836 assert_equal 5, User.find(7).valid_notification_options.size
841 assert_equal 5, User.find(7).valid_notification_options.size
837 # with memberships
842 # with memberships
838 assert_equal 6, User.find(2).valid_notification_options.size
843 assert_equal 6, User.find(2).valid_notification_options.size
839 end
844 end
840
845
841 def test_valid_notification_options_class_method
846 def test_valid_notification_options_class_method
842 assert_equal 5, User.valid_notification_options.size
847 assert_equal 5, User.valid_notification_options.size
843 assert_equal 5, User.valid_notification_options(User.find(7)).size
848 assert_equal 5, User.valid_notification_options(User.find(7)).size
844 assert_equal 6, User.valid_notification_options(User.find(2)).size
849 assert_equal 6, User.valid_notification_options(User.find(2)).size
845 end
850 end
846
851
847 def test_mail_notification_all
852 def test_mail_notification_all
848 @jsmith.mail_notification = 'all'
853 @jsmith.mail_notification = 'all'
849 @jsmith.notified_project_ids = []
854 @jsmith.notified_project_ids = []
850 @jsmith.save
855 @jsmith.save
851 @jsmith.reload
856 @jsmith.reload
852 assert @jsmith.projects.first.recipients.include?(@jsmith.mail)
857 assert @jsmith.projects.first.recipients.include?(@jsmith.mail)
853 end
858 end
854
859
855 def test_mail_notification_selected
860 def test_mail_notification_selected
856 @jsmith.mail_notification = 'selected'
861 @jsmith.mail_notification = 'selected'
857 @jsmith.notified_project_ids = [1]
862 @jsmith.notified_project_ids = [1]
858 @jsmith.save
863 @jsmith.save
859 @jsmith.reload
864 @jsmith.reload
860 assert Project.find(1).recipients.include?(@jsmith.mail)
865 assert Project.find(1).recipients.include?(@jsmith.mail)
861 end
866 end
862
867
863 def test_mail_notification_only_my_events
868 def test_mail_notification_only_my_events
864 @jsmith.mail_notification = 'only_my_events'
869 @jsmith.mail_notification = 'only_my_events'
865 @jsmith.notified_project_ids = []
870 @jsmith.notified_project_ids = []
866 @jsmith.save
871 @jsmith.save
867 @jsmith.reload
872 @jsmith.reload
868 assert !@jsmith.projects.first.recipients.include?(@jsmith.mail)
873 assert !@jsmith.projects.first.recipients.include?(@jsmith.mail)
869 end
874 end
870
875
871 def test_comments_sorting_preference
876 def test_comments_sorting_preference
872 assert !@jsmith.wants_comments_in_reverse_order?
877 assert !@jsmith.wants_comments_in_reverse_order?
873 @jsmith.pref.comments_sorting = 'asc'
878 @jsmith.pref.comments_sorting = 'asc'
874 assert !@jsmith.wants_comments_in_reverse_order?
879 assert !@jsmith.wants_comments_in_reverse_order?
875 @jsmith.pref.comments_sorting = 'desc'
880 @jsmith.pref.comments_sorting = 'desc'
876 assert @jsmith.wants_comments_in_reverse_order?
881 assert @jsmith.wants_comments_in_reverse_order?
877 end
882 end
878
883
879 def test_find_by_mail_should_be_case_insensitive
884 def test_find_by_mail_should_be_case_insensitive
880 u = User.find_by_mail('JSmith@somenet.foo')
885 u = User.find_by_mail('JSmith@somenet.foo')
881 assert_not_nil u
886 assert_not_nil u
882 assert_equal 'jsmith@somenet.foo', u.mail
887 assert_equal 'jsmith@somenet.foo', u.mail
883 end
888 end
884
889
885 def test_random_password
890 def test_random_password
886 u = User.new
891 u = User.new
887 u.random_password
892 u.random_password
888 assert !u.password.blank?
893 assert !u.password.blank?
889 assert !u.password_confirmation.blank?
894 assert !u.password_confirmation.blank?
890 end
895 end
891
896
892 test "#change_password_allowed? should be allowed if no auth source is set" do
897 test "#change_password_allowed? should be allowed if no auth source is set" do
893 user = User.generate!
898 user = User.generate!
894 assert user.change_password_allowed?
899 assert user.change_password_allowed?
895 end
900 end
896
901
897 test "#change_password_allowed? should delegate to the auth source" do
902 test "#change_password_allowed? should delegate to the auth source" do
898 user = User.generate!
903 user = User.generate!
899
904
900 allowed_auth_source = AuthSource.generate!
905 allowed_auth_source = AuthSource.generate!
901 def allowed_auth_source.allow_password_changes?; true; end
906 def allowed_auth_source.allow_password_changes?; true; end
902
907
903 denied_auth_source = AuthSource.generate!
908 denied_auth_source = AuthSource.generate!
904 def denied_auth_source.allow_password_changes?; false; end
909 def denied_auth_source.allow_password_changes?; false; end
905
910
906 assert user.change_password_allowed?
911 assert user.change_password_allowed?
907
912
908 user.auth_source = allowed_auth_source
913 user.auth_source = allowed_auth_source
909 assert user.change_password_allowed?, "User not allowed to change password, though auth source does"
914 assert user.change_password_allowed?, "User not allowed to change password, though auth source does"
910
915
911 user.auth_source = denied_auth_source
916 user.auth_source = denied_auth_source
912 assert !user.change_password_allowed?, "User allowed to change password, though auth source does not"
917 assert !user.change_password_allowed?, "User allowed to change password, though auth source does not"
913 end
918 end
914
919
915 def test_own_account_deletable_should_be_true_with_unsubscrive_enabled
920 def test_own_account_deletable_should_be_true_with_unsubscrive_enabled
916 with_settings :unsubscribe => '1' do
921 with_settings :unsubscribe => '1' do
917 assert_equal true, User.find(2).own_account_deletable?
922 assert_equal true, User.find(2).own_account_deletable?
918 end
923 end
919 end
924 end
920
925
921 def test_own_account_deletable_should_be_false_with_unsubscrive_disabled
926 def test_own_account_deletable_should_be_false_with_unsubscrive_disabled
922 with_settings :unsubscribe => '0' do
927 with_settings :unsubscribe => '0' do
923 assert_equal false, User.find(2).own_account_deletable?
928 assert_equal false, User.find(2).own_account_deletable?
924 end
929 end
925 end
930 end
926
931
927 def test_own_account_deletable_should_be_false_for_a_single_admin
932 def test_own_account_deletable_should_be_false_for_a_single_admin
928 User.delete_all(["admin = ? AND id <> ?", true, 1])
933 User.delete_all(["admin = ? AND id <> ?", true, 1])
929
934
930 with_settings :unsubscribe => '1' do
935 with_settings :unsubscribe => '1' do
931 assert_equal false, User.find(1).own_account_deletable?
936 assert_equal false, User.find(1).own_account_deletable?
932 end
937 end
933 end
938 end
934
939
935 def test_own_account_deletable_should_be_true_for_an_admin_if_other_admin_exists
940 def test_own_account_deletable_should_be_true_for_an_admin_if_other_admin_exists
936 User.generate! do |user|
941 User.generate! do |user|
937 user.admin = true
942 user.admin = true
938 end
943 end
939
944
940 with_settings :unsubscribe => '1' do
945 with_settings :unsubscribe => '1' do
941 assert_equal true, User.find(1).own_account_deletable?
946 assert_equal true, User.find(1).own_account_deletable?
942 end
947 end
943 end
948 end
944
949
945 context "#allowed_to?" do
950 context "#allowed_to?" do
946 context "with a unique project" do
951 context "with a unique project" do
947 should "return false if project is archived" do
952 should "return false if project is archived" do
948 project = Project.find(1)
953 project = Project.find(1)
949 Project.any_instance.stubs(:status).returns(Project::STATUS_ARCHIVED)
954 Project.any_instance.stubs(:status).returns(Project::STATUS_ARCHIVED)
950 assert_equal false, @admin.allowed_to?(:view_issues, Project.find(1))
955 assert_equal false, @admin.allowed_to?(:view_issues, Project.find(1))
951 end
956 end
952
957
953 should "return false for write action if project is closed" do
958 should "return false for write action if project is closed" do
954 project = Project.find(1)
959 project = Project.find(1)
955 Project.any_instance.stubs(:status).returns(Project::STATUS_CLOSED)
960 Project.any_instance.stubs(:status).returns(Project::STATUS_CLOSED)
956 assert_equal false, @admin.allowed_to?(:edit_project, Project.find(1))
961 assert_equal false, @admin.allowed_to?(:edit_project, Project.find(1))
957 end
962 end
958
963
959 should "return true for read action if project is closed" do
964 should "return true for read action if project is closed" do
960 project = Project.find(1)
965 project = Project.find(1)
961 Project.any_instance.stubs(:status).returns(Project::STATUS_CLOSED)
966 Project.any_instance.stubs(:status).returns(Project::STATUS_CLOSED)
962 assert_equal true, @admin.allowed_to?(:view_project, Project.find(1))
967 assert_equal true, @admin.allowed_to?(:view_project, Project.find(1))
963 end
968 end
964
969
965 should "return false if related module is disabled" do
970 should "return false if related module is disabled" do
966 project = Project.find(1)
971 project = Project.find(1)
967 project.enabled_module_names = ["issue_tracking"]
972 project.enabled_module_names = ["issue_tracking"]
968 assert_equal true, @admin.allowed_to?(:add_issues, project)
973 assert_equal true, @admin.allowed_to?(:add_issues, project)
969 assert_equal false, @admin.allowed_to?(:view_wiki_pages, project)
974 assert_equal false, @admin.allowed_to?(:view_wiki_pages, project)
970 end
975 end
971
976
972 should "authorize nearly everything for admin users" do
977 should "authorize nearly everything for admin users" do
973 project = Project.find(1)
978 project = Project.find(1)
974 assert ! @admin.member_of?(project)
979 assert ! @admin.member_of?(project)
975 %w(edit_issues delete_issues manage_news add_documents manage_wiki).each do |p|
980 %w(edit_issues delete_issues manage_news add_documents manage_wiki).each do |p|
976 assert_equal true, @admin.allowed_to?(p.to_sym, project)
981 assert_equal true, @admin.allowed_to?(p.to_sym, project)
977 end
982 end
978 end
983 end
979
984
980 should "authorize normal users depending on their roles" do
985 should "authorize normal users depending on their roles" do
981 project = Project.find(1)
986 project = Project.find(1)
982 assert_equal true, @jsmith.allowed_to?(:delete_messages, project) #Manager
987 assert_equal true, @jsmith.allowed_to?(:delete_messages, project) #Manager
983 assert_equal false, @dlopper.allowed_to?(:delete_messages, project) #Developper
988 assert_equal false, @dlopper.allowed_to?(:delete_messages, project) #Developper
984 end
989 end
985 end
990 end
986
991
987 context "with multiple projects" do
992 context "with multiple projects" do
988 should "return false if array is empty" do
993 should "return false if array is empty" do
989 assert_equal false, @admin.allowed_to?(:view_project, [])
994 assert_equal false, @admin.allowed_to?(:view_project, [])
990 end
995 end
991
996
992 should "return true only if user has permission on all these projects" do
997 should "return true only if user has permission on all these projects" do
993 assert_equal true, @admin.allowed_to?(:view_project, Project.all)
998 assert_equal true, @admin.allowed_to?(:view_project, Project.all)
994 assert_equal false, @dlopper.allowed_to?(:view_project, Project.all) #cannot see Project(2)
999 assert_equal false, @dlopper.allowed_to?(:view_project, Project.all) #cannot see Project(2)
995 assert_equal true, @jsmith.allowed_to?(:edit_issues, @jsmith.projects) #Manager or Developer everywhere
1000 assert_equal true, @jsmith.allowed_to?(:edit_issues, @jsmith.projects) #Manager or Developer everywhere
996 assert_equal false, @jsmith.allowed_to?(:delete_issue_watchers, @jsmith.projects) #Dev cannot delete_issue_watchers
1001 assert_equal false, @jsmith.allowed_to?(:delete_issue_watchers, @jsmith.projects) #Dev cannot delete_issue_watchers
997 end
1002 end
998
1003
999 should "behave correctly with arrays of 1 project" do
1004 should "behave correctly with arrays of 1 project" do
1000 assert_equal false, User.anonymous.allowed_to?(:delete_issues, [Project.first])
1005 assert_equal false, User.anonymous.allowed_to?(:delete_issues, [Project.first])
1001 end
1006 end
1002 end
1007 end
1003
1008
1004 context "with options[:global]" do
1009 context "with options[:global]" do
1005 should "authorize if user has at least one role that has this permission" do
1010 should "authorize if user has at least one role that has this permission" do
1006 @dlopper2 = User.find(5) #only Developper on a project, not Manager anywhere
1011 @dlopper2 = User.find(5) #only Developper on a project, not Manager anywhere
1007 @anonymous = User.find(6)
1012 @anonymous = User.find(6)
1008 assert_equal true, @jsmith.allowed_to?(:delete_issue_watchers, nil, :global => true)
1013 assert_equal true, @jsmith.allowed_to?(:delete_issue_watchers, nil, :global => true)
1009 assert_equal false, @dlopper2.allowed_to?(:delete_issue_watchers, nil, :global => true)
1014 assert_equal false, @dlopper2.allowed_to?(:delete_issue_watchers, nil, :global => true)
1010 assert_equal true, @dlopper2.allowed_to?(:add_issues, nil, :global => true)
1015 assert_equal true, @dlopper2.allowed_to?(:add_issues, nil, :global => true)
1011 assert_equal false, @anonymous.allowed_to?(:add_issues, nil, :global => true)
1016 assert_equal false, @anonymous.allowed_to?(:add_issues, nil, :global => true)
1012 assert_equal true, @anonymous.allowed_to?(:view_issues, nil, :global => true)
1017 assert_equal true, @anonymous.allowed_to?(:view_issues, nil, :global => true)
1013 end
1018 end
1014 end
1019 end
1015 end
1020 end
1016
1021
1017 context "User#notify_about?" do
1022 context "User#notify_about?" do
1018 context "Issues" do
1023 context "Issues" do
1019 setup do
1024 setup do
1020 @project = Project.find(1)
1025 @project = Project.find(1)
1021 @author = User.generate!
1026 @author = User.generate!
1022 @assignee = User.generate!
1027 @assignee = User.generate!
1023 @issue = Issue.generate!(:project => @project, :assigned_to => @assignee, :author => @author)
1028 @issue = Issue.generate!(:project => @project, :assigned_to => @assignee, :author => @author)
1024 end
1029 end
1025
1030
1026 should "be true for a user with :all" do
1031 should "be true for a user with :all" do
1027 @author.update_attribute(:mail_notification, 'all')
1032 @author.update_attribute(:mail_notification, 'all')
1028 assert @author.notify_about?(@issue)
1033 assert @author.notify_about?(@issue)
1029 end
1034 end
1030
1035
1031 should "be false for a user with :none" do
1036 should "be false for a user with :none" do
1032 @author.update_attribute(:mail_notification, 'none')
1037 @author.update_attribute(:mail_notification, 'none')
1033 assert ! @author.notify_about?(@issue)
1038 assert ! @author.notify_about?(@issue)
1034 end
1039 end
1035
1040
1036 should "be false for a user with :only_my_events and isn't an author, creator, or assignee" do
1041 should "be false for a user with :only_my_events and isn't an author, creator, or assignee" do
1037 @user = User.generate!(:mail_notification => 'only_my_events')
1042 @user = User.generate!(:mail_notification => 'only_my_events')
1038 Member.create!(:user => @user, :project => @project, :role_ids => [1])
1043 Member.create!(:user => @user, :project => @project, :role_ids => [1])
1039 assert ! @user.notify_about?(@issue)
1044 assert ! @user.notify_about?(@issue)
1040 end
1045 end
1041
1046
1042 should "be true for a user with :only_my_events and is the author" do
1047 should "be true for a user with :only_my_events and is the author" do
1043 @author.update_attribute(:mail_notification, 'only_my_events')
1048 @author.update_attribute(:mail_notification, 'only_my_events')
1044 assert @author.notify_about?(@issue)
1049 assert @author.notify_about?(@issue)
1045 end
1050 end
1046
1051
1047 should "be true for a user with :only_my_events and is the assignee" do
1052 should "be true for a user with :only_my_events and is the assignee" do
1048 @assignee.update_attribute(:mail_notification, 'only_my_events')
1053 @assignee.update_attribute(:mail_notification, 'only_my_events')
1049 assert @assignee.notify_about?(@issue)
1054 assert @assignee.notify_about?(@issue)
1050 end
1055 end
1051
1056
1052 should "be true for a user with :only_assigned and is the assignee" do
1057 should "be true for a user with :only_assigned and is the assignee" do
1053 @assignee.update_attribute(:mail_notification, 'only_assigned')
1058 @assignee.update_attribute(:mail_notification, 'only_assigned')
1054 assert @assignee.notify_about?(@issue)
1059 assert @assignee.notify_about?(@issue)
1055 end
1060 end
1056
1061
1057 should "be false for a user with :only_assigned and is not the assignee" do
1062 should "be false for a user with :only_assigned and is not the assignee" do
1058 @author.update_attribute(:mail_notification, 'only_assigned')
1063 @author.update_attribute(:mail_notification, 'only_assigned')
1059 assert ! @author.notify_about?(@issue)
1064 assert ! @author.notify_about?(@issue)
1060 end
1065 end
1061
1066
1062 should "be true for a user with :only_owner and is the author" do
1067 should "be true for a user with :only_owner and is the author" do
1063 @author.update_attribute(:mail_notification, 'only_owner')
1068 @author.update_attribute(:mail_notification, 'only_owner')
1064 assert @author.notify_about?(@issue)
1069 assert @author.notify_about?(@issue)
1065 end
1070 end
1066
1071
1067 should "be false for a user with :only_owner and is not the author" do
1072 should "be false for a user with :only_owner and is not the author" do
1068 @assignee.update_attribute(:mail_notification, 'only_owner')
1073 @assignee.update_attribute(:mail_notification, 'only_owner')
1069 assert ! @assignee.notify_about?(@issue)
1074 assert ! @assignee.notify_about?(@issue)
1070 end
1075 end
1071
1076
1072 should "be true for a user with :selected and is the author" do
1077 should "be true for a user with :selected and is the author" do
1073 @author.update_attribute(:mail_notification, 'selected')
1078 @author.update_attribute(:mail_notification, 'selected')
1074 assert @author.notify_about?(@issue)
1079 assert @author.notify_about?(@issue)
1075 end
1080 end
1076
1081
1077 should "be true for a user with :selected and is the assignee" do
1082 should "be true for a user with :selected and is the assignee" do
1078 @assignee.update_attribute(:mail_notification, 'selected')
1083 @assignee.update_attribute(:mail_notification, 'selected')
1079 assert @assignee.notify_about?(@issue)
1084 assert @assignee.notify_about?(@issue)
1080 end
1085 end
1081
1086
1082 should "be false for a user with :selected and is not the author or assignee" do
1087 should "be false for a user with :selected and is not the author or assignee" do
1083 @user = User.generate!(:mail_notification => 'selected')
1088 @user = User.generate!(:mail_notification => 'selected')
1084 Member.create!(:user => @user, :project => @project, :role_ids => [1])
1089 Member.create!(:user => @user, :project => @project, :role_ids => [1])
1085 assert ! @user.notify_about?(@issue)
1090 assert ! @user.notify_about?(@issue)
1086 end
1091 end
1087 end
1092 end
1088 end
1093 end
1089
1094
1090 def test_notify_about_news
1095 def test_notify_about_news
1091 user = User.generate!
1096 user = User.generate!
1092 news = News.new
1097 news = News.new
1093
1098
1094 User::MAIL_NOTIFICATION_OPTIONS.map(&:first).each do |option|
1099 User::MAIL_NOTIFICATION_OPTIONS.map(&:first).each do |option|
1095 user.mail_notification = option
1100 user.mail_notification = option
1096 assert_equal (option != 'none'), user.notify_about?(news)
1101 assert_equal (option != 'none'), user.notify_about?(news)
1097 end
1102 end
1098 end
1103 end
1099
1104
1100 def test_salt_unsalted_passwords
1105 def test_salt_unsalted_passwords
1101 # Restore a user with an unsalted password
1106 # Restore a user with an unsalted password
1102 user = User.find(1)
1107 user = User.find(1)
1103 user.salt = nil
1108 user.salt = nil
1104 user.hashed_password = User.hash_password("unsalted")
1109 user.hashed_password = User.hash_password("unsalted")
1105 user.save!
1110 user.save!
1106
1111
1107 User.salt_unsalted_passwords!
1112 User.salt_unsalted_passwords!
1108
1113
1109 user.reload
1114 user.reload
1110 # Salt added
1115 # Salt added
1111 assert !user.salt.blank?
1116 assert !user.salt.blank?
1112 # Password still valid
1117 # Password still valid
1113 assert user.check_password?("unsalted")
1118 assert user.check_password?("unsalted")
1114 assert_equal user, User.try_to_login(user.login, "unsalted")
1119 assert_equal user, User.try_to_login(user.login, "unsalted")
1115 end
1120 end
1116
1121
1117 if Object.const_defined?(:OpenID)
1122 if Object.const_defined?(:OpenID)
1118 def test_setting_identity_url
1123 def test_setting_identity_url
1119 normalized_open_id_url = 'http://example.com/'
1124 normalized_open_id_url = 'http://example.com/'
1120 u = User.new( :identity_url => 'http://example.com/' )
1125 u = User.new( :identity_url => 'http://example.com/' )
1121 assert_equal normalized_open_id_url, u.identity_url
1126 assert_equal normalized_open_id_url, u.identity_url
1122 end
1127 end
1123
1128
1124 def test_setting_identity_url_without_trailing_slash
1129 def test_setting_identity_url_without_trailing_slash
1125 normalized_open_id_url = 'http://example.com/'
1130 normalized_open_id_url = 'http://example.com/'
1126 u = User.new( :identity_url => 'http://example.com' )
1131 u = User.new( :identity_url => 'http://example.com' )
1127 assert_equal normalized_open_id_url, u.identity_url
1132 assert_equal normalized_open_id_url, u.identity_url
1128 end
1133 end
1129
1134
1130 def test_setting_identity_url_without_protocol
1135 def test_setting_identity_url_without_protocol
1131 normalized_open_id_url = 'http://example.com/'
1136 normalized_open_id_url = 'http://example.com/'
1132 u = User.new( :identity_url => 'example.com' )
1137 u = User.new( :identity_url => 'example.com' )
1133 assert_equal normalized_open_id_url, u.identity_url
1138 assert_equal normalized_open_id_url, u.identity_url
1134 end
1139 end
1135
1140
1136 def test_setting_blank_identity_url
1141 def test_setting_blank_identity_url
1137 u = User.new( :identity_url => 'example.com' )
1142 u = User.new( :identity_url => 'example.com' )
1138 u.identity_url = ''
1143 u.identity_url = ''
1139 assert u.identity_url.blank?
1144 assert u.identity_url.blank?
1140 end
1145 end
1141
1146
1142 def test_setting_invalid_identity_url
1147 def test_setting_invalid_identity_url
1143 u = User.new( :identity_url => 'this is not an openid url' )
1148 u = User.new( :identity_url => 'this is not an openid url' )
1144 assert u.identity_url.blank?
1149 assert u.identity_url.blank?
1145 end
1150 end
1146 else
1151 else
1147 puts "Skipping openid tests."
1152 puts "Skipping openid tests."
1148 end
1153 end
1149 end
1154 end
General Comments 0
You need to be logged in to leave comments. Login now