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