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