##// END OF EJS Templates
Send password reset email to the email used in lost password form (#4244)....
Jean-Philippe Lang -
r13506:a3a8fee8adf8
parent child
Show More
@@ -1,351 +1,354
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2015 Jean-Philippe Lang
2 # Copyright (C) 2006-2015 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 class AccountController < ApplicationController
18 class AccountController < ApplicationController
19 helper :custom_fields
19 helper :custom_fields
20 include CustomFieldsHelper
20 include CustomFieldsHelper
21
21
22 # prevents login action to be filtered by check_if_login_required application scope filter
22 # prevents login action to be filtered by check_if_login_required application scope filter
23 skip_before_filter :check_if_login_required, :check_password_change
23 skip_before_filter :check_if_login_required, :check_password_change
24
24
25 # Overrides ApplicationController#verify_authenticity_token to disable
25 # Overrides ApplicationController#verify_authenticity_token to disable
26 # token verification on openid callbacks
26 # token verification on openid callbacks
27 def verify_authenticity_token
27 def verify_authenticity_token
28 unless using_open_id?
28 unless using_open_id?
29 super
29 super
30 end
30 end
31 end
31 end
32
32
33 # Login request and validation
33 # Login request and validation
34 def login
34 def login
35 if request.get?
35 if request.get?
36 if User.current.logged?
36 if User.current.logged?
37 redirect_back_or_default home_url, :referer => true
37 redirect_back_or_default home_url, :referer => true
38 end
38 end
39 else
39 else
40 authenticate_user
40 authenticate_user
41 end
41 end
42 rescue AuthSourceException => e
42 rescue AuthSourceException => e
43 logger.error "An error occured when authenticating #{params[:username]}: #{e.message}"
43 logger.error "An error occured when authenticating #{params[:username]}: #{e.message}"
44 render_error :message => e.message
44 render_error :message => e.message
45 end
45 end
46
46
47 # Log out current user and redirect to welcome page
47 # Log out current user and redirect to welcome page
48 def logout
48 def logout
49 if User.current.anonymous?
49 if User.current.anonymous?
50 redirect_to home_url
50 redirect_to home_url
51 elsif request.post?
51 elsif request.post?
52 logout_user
52 logout_user
53 redirect_to home_url
53 redirect_to home_url
54 end
54 end
55 # display the logout form
55 # display the logout form
56 end
56 end
57
57
58 # Lets user choose a new password
58 # Lets user choose a new password
59 def lost_password
59 def lost_password
60 (redirect_to(home_url); return) unless Setting.lost_password?
60 (redirect_to(home_url); return) unless Setting.lost_password?
61 if params[:token]
61 if params[:token]
62 @token = Token.find_token("recovery", params[:token].to_s)
62 @token = Token.find_token("recovery", params[:token].to_s)
63 if @token.nil? || @token.expired?
63 if @token.nil? || @token.expired?
64 redirect_to home_url
64 redirect_to home_url
65 return
65 return
66 end
66 end
67 @user = @token.user
67 @user = @token.user
68 unless @user && @user.active?
68 unless @user && @user.active?
69 redirect_to home_url
69 redirect_to home_url
70 return
70 return
71 end
71 end
72 if request.post?
72 if request.post?
73 @user.password, @user.password_confirmation = params[:new_password], params[:new_password_confirmation]
73 @user.password, @user.password_confirmation = params[:new_password], params[:new_password_confirmation]
74 if @user.save
74 if @user.save
75 @token.destroy
75 @token.destroy
76 flash[:notice] = l(:notice_account_password_updated)
76 flash[:notice] = l(:notice_account_password_updated)
77 redirect_to signin_path
77 redirect_to signin_path
78 return
78 return
79 end
79 end
80 end
80 end
81 render :template => "account/password_recovery"
81 render :template => "account/password_recovery"
82 return
82 return
83 else
83 else
84 if request.post?
84 if request.post?
85 user = User.find_by_mail(params[:mail].to_s)
85 email = params[:mail].to_s
86 user = User.find_by_mail(email)
86 # user not found
87 # user not found
87 unless user
88 unless user
88 flash.now[:error] = l(:notice_account_unknown_email)
89 flash.now[:error] = l(:notice_account_unknown_email)
89 return
90 return
90 end
91 end
91 unless user.active?
92 unless user.active?
92 handle_inactive_user(user, lost_password_path)
93 handle_inactive_user(user, lost_password_path)
93 return
94 return
94 end
95 end
95 # user cannot change its password
96 # user cannot change its password
96 unless user.change_password_allowed?
97 unless user.change_password_allowed?
97 flash.now[:error] = l(:notice_can_t_change_password)
98 flash.now[:error] = l(:notice_can_t_change_password)
98 return
99 return
99 end
100 end
100 # create a new token for password recovery
101 # create a new token for password recovery
101 token = Token.new(:user => user, :action => "recovery")
102 token = Token.new(:user => user, :action => "recovery")
102 if token.save
103 if token.save
103 Mailer.lost_password(token).deliver
104 # Don't use the param to send the email
105 recipent = user.mails.detect {|e| e.downcase == email.downcase} || user.mail
106 Mailer.lost_password(token, recipent).deliver
104 flash[:notice] = l(:notice_account_lost_email_sent)
107 flash[:notice] = l(:notice_account_lost_email_sent)
105 redirect_to signin_path
108 redirect_to signin_path
106 return
109 return
107 end
110 end
108 end
111 end
109 end
112 end
110 end
113 end
111
114
112 # User self-registration
115 # User self-registration
113 def register
116 def register
114 (redirect_to(home_url); return) unless Setting.self_registration? || session[:auth_source_registration]
117 (redirect_to(home_url); return) unless Setting.self_registration? || session[:auth_source_registration]
115 if request.get?
118 if request.get?
116 session[:auth_source_registration] = nil
119 session[:auth_source_registration] = nil
117 @user = User.new(:language => current_language.to_s)
120 @user = User.new(:language => current_language.to_s)
118 else
121 else
119 user_params = params[:user] || {}
122 user_params = params[:user] || {}
120 @user = User.new
123 @user = User.new
121 @user.safe_attributes = user_params
124 @user.safe_attributes = user_params
122 @user.admin = false
125 @user.admin = false
123 @user.register
126 @user.register
124 if session[:auth_source_registration]
127 if session[:auth_source_registration]
125 @user.activate
128 @user.activate
126 @user.login = session[:auth_source_registration][:login]
129 @user.login = session[:auth_source_registration][:login]
127 @user.auth_source_id = session[:auth_source_registration][:auth_source_id]
130 @user.auth_source_id = session[:auth_source_registration][:auth_source_id]
128 if @user.save
131 if @user.save
129 session[:auth_source_registration] = nil
132 session[:auth_source_registration] = nil
130 self.logged_user = @user
133 self.logged_user = @user
131 flash[:notice] = l(:notice_account_activated)
134 flash[:notice] = l(:notice_account_activated)
132 redirect_to my_account_path
135 redirect_to my_account_path
133 end
136 end
134 else
137 else
135 @user.login = params[:user][:login]
138 @user.login = params[:user][:login]
136 unless user_params[:identity_url].present? && user_params[:password].blank? && user_params[:password_confirmation].blank?
139 unless user_params[:identity_url].present? && user_params[:password].blank? && user_params[:password_confirmation].blank?
137 @user.password, @user.password_confirmation = user_params[:password], user_params[:password_confirmation]
140 @user.password, @user.password_confirmation = user_params[:password], user_params[:password_confirmation]
138 end
141 end
139
142
140 case Setting.self_registration
143 case Setting.self_registration
141 when '1'
144 when '1'
142 register_by_email_activation(@user)
145 register_by_email_activation(@user)
143 when '3'
146 when '3'
144 register_automatically(@user)
147 register_automatically(@user)
145 else
148 else
146 register_manually_by_administrator(@user)
149 register_manually_by_administrator(@user)
147 end
150 end
148 end
151 end
149 end
152 end
150 end
153 end
151
154
152 # Token based account activation
155 # Token based account activation
153 def activate
156 def activate
154 (redirect_to(home_url); return) unless Setting.self_registration? && params[:token].present?
157 (redirect_to(home_url); return) unless Setting.self_registration? && params[:token].present?
155 token = Token.find_token('register', params[:token].to_s)
158 token = Token.find_token('register', params[:token].to_s)
156 (redirect_to(home_url); return) unless token and !token.expired?
159 (redirect_to(home_url); return) unless token and !token.expired?
157 user = token.user
160 user = token.user
158 (redirect_to(home_url); return) unless user.registered?
161 (redirect_to(home_url); return) unless user.registered?
159 user.activate
162 user.activate
160 if user.save
163 if user.save
161 token.destroy
164 token.destroy
162 flash[:notice] = l(:notice_account_activated)
165 flash[:notice] = l(:notice_account_activated)
163 end
166 end
164 redirect_to signin_path
167 redirect_to signin_path
165 end
168 end
166
169
167 # Sends a new account activation email
170 # Sends a new account activation email
168 def activation_email
171 def activation_email
169 if session[:registered_user_id] && Setting.self_registration == '1'
172 if session[:registered_user_id] && Setting.self_registration == '1'
170 user_id = session.delete(:registered_user_id).to_i
173 user_id = session.delete(:registered_user_id).to_i
171 user = User.find_by_id(user_id)
174 user = User.find_by_id(user_id)
172 if user && user.registered?
175 if user && user.registered?
173 register_by_email_activation(user)
176 register_by_email_activation(user)
174 return
177 return
175 end
178 end
176 end
179 end
177 redirect_to(home_url)
180 redirect_to(home_url)
178 end
181 end
179
182
180 private
183 private
181
184
182 def authenticate_user
185 def authenticate_user
183 if Setting.openid? && using_open_id?
186 if Setting.openid? && using_open_id?
184 open_id_authenticate(params[:openid_url])
187 open_id_authenticate(params[:openid_url])
185 else
188 else
186 password_authentication
189 password_authentication
187 end
190 end
188 end
191 end
189
192
190 def password_authentication
193 def password_authentication
191 user = User.try_to_login(params[:username], params[:password], false)
194 user = User.try_to_login(params[:username], params[:password], false)
192
195
193 if user.nil?
196 if user.nil?
194 invalid_credentials
197 invalid_credentials
195 elsif user.new_record?
198 elsif user.new_record?
196 onthefly_creation_failed(user, {:login => user.login, :auth_source_id => user.auth_source_id })
199 onthefly_creation_failed(user, {:login => user.login, :auth_source_id => user.auth_source_id })
197 else
200 else
198 # Valid user
201 # Valid user
199 if user.active?
202 if user.active?
200 successful_authentication(user)
203 successful_authentication(user)
201 else
204 else
202 handle_inactive_user(user)
205 handle_inactive_user(user)
203 end
206 end
204 end
207 end
205 end
208 end
206
209
207 def open_id_authenticate(openid_url)
210 def open_id_authenticate(openid_url)
208 back_url = signin_url(:autologin => params[:autologin])
211 back_url = signin_url(:autologin => params[:autologin])
209 authenticate_with_open_id(
212 authenticate_with_open_id(
210 openid_url, :required => [:nickname, :fullname, :email],
213 openid_url, :required => [:nickname, :fullname, :email],
211 :return_to => back_url, :method => :post
214 :return_to => back_url, :method => :post
212 ) do |result, identity_url, registration|
215 ) do |result, identity_url, registration|
213 if result.successful?
216 if result.successful?
214 user = User.find_or_initialize_by_identity_url(identity_url)
217 user = User.find_or_initialize_by_identity_url(identity_url)
215 if user.new_record?
218 if user.new_record?
216 # Self-registration off
219 # Self-registration off
217 (redirect_to(home_url); return) unless Setting.self_registration?
220 (redirect_to(home_url); return) unless Setting.self_registration?
218 # Create on the fly
221 # Create on the fly
219 user.login = registration['nickname'] unless registration['nickname'].nil?
222 user.login = registration['nickname'] unless registration['nickname'].nil?
220 user.mail = registration['email'] unless registration['email'].nil?
223 user.mail = registration['email'] unless registration['email'].nil?
221 user.firstname, user.lastname = registration['fullname'].split(' ') unless registration['fullname'].nil?
224 user.firstname, user.lastname = registration['fullname'].split(' ') unless registration['fullname'].nil?
222 user.random_password
225 user.random_password
223 user.register
226 user.register
224 case Setting.self_registration
227 case Setting.self_registration
225 when '1'
228 when '1'
226 register_by_email_activation(user) do
229 register_by_email_activation(user) do
227 onthefly_creation_failed(user)
230 onthefly_creation_failed(user)
228 end
231 end
229 when '3'
232 when '3'
230 register_automatically(user) do
233 register_automatically(user) do
231 onthefly_creation_failed(user)
234 onthefly_creation_failed(user)
232 end
235 end
233 else
236 else
234 register_manually_by_administrator(user) do
237 register_manually_by_administrator(user) do
235 onthefly_creation_failed(user)
238 onthefly_creation_failed(user)
236 end
239 end
237 end
240 end
238 else
241 else
239 # Existing record
242 # Existing record
240 if user.active?
243 if user.active?
241 successful_authentication(user)
244 successful_authentication(user)
242 else
245 else
243 handle_inactive_user(user)
246 handle_inactive_user(user)
244 end
247 end
245 end
248 end
246 end
249 end
247 end
250 end
248 end
251 end
249
252
250 def successful_authentication(user)
253 def successful_authentication(user)
251 logger.info "Successful authentication for '#{user.login}' from #{request.remote_ip} at #{Time.now.utc}"
254 logger.info "Successful authentication for '#{user.login}' from #{request.remote_ip} at #{Time.now.utc}"
252 # Valid user
255 # Valid user
253 self.logged_user = user
256 self.logged_user = user
254 # generate a key and set cookie if autologin
257 # generate a key and set cookie if autologin
255 if params[:autologin] && Setting.autologin?
258 if params[:autologin] && Setting.autologin?
256 set_autologin_cookie(user)
259 set_autologin_cookie(user)
257 end
260 end
258 call_hook(:controller_account_success_authentication_after, {:user => user })
261 call_hook(:controller_account_success_authentication_after, {:user => user })
259 redirect_back_or_default my_page_path
262 redirect_back_or_default my_page_path
260 end
263 end
261
264
262 def set_autologin_cookie(user)
265 def set_autologin_cookie(user)
263 token = Token.create(:user => user, :action => 'autologin')
266 token = Token.create(:user => user, :action => 'autologin')
264 cookie_options = {
267 cookie_options = {
265 :value => token.value,
268 :value => token.value,
266 :expires => 1.year.from_now,
269 :expires => 1.year.from_now,
267 :path => (Redmine::Configuration['autologin_cookie_path'] || '/'),
270 :path => (Redmine::Configuration['autologin_cookie_path'] || '/'),
268 :secure => (Redmine::Configuration['autologin_cookie_secure'] ? true : false),
271 :secure => (Redmine::Configuration['autologin_cookie_secure'] ? true : false),
269 :httponly => true
272 :httponly => true
270 }
273 }
271 cookies[autologin_cookie_name] = cookie_options
274 cookies[autologin_cookie_name] = cookie_options
272 end
275 end
273
276
274 # Onthefly creation failed, display the registration form to fill/fix attributes
277 # Onthefly creation failed, display the registration form to fill/fix attributes
275 def onthefly_creation_failed(user, auth_source_options = { })
278 def onthefly_creation_failed(user, auth_source_options = { })
276 @user = user
279 @user = user
277 session[:auth_source_registration] = auth_source_options unless auth_source_options.empty?
280 session[:auth_source_registration] = auth_source_options unless auth_source_options.empty?
278 render :action => 'register'
281 render :action => 'register'
279 end
282 end
280
283
281 def invalid_credentials
284 def invalid_credentials
282 logger.warn "Failed login for '#{params[:username]}' from #{request.remote_ip} at #{Time.now.utc}"
285 logger.warn "Failed login for '#{params[:username]}' from #{request.remote_ip} at #{Time.now.utc}"
283 flash.now[:error] = l(:notice_account_invalid_creditentials)
286 flash.now[:error] = l(:notice_account_invalid_creditentials)
284 end
287 end
285
288
286 # Register a user for email activation.
289 # Register a user for email activation.
287 #
290 #
288 # Pass a block for behavior when a user fails to save
291 # Pass a block for behavior when a user fails to save
289 def register_by_email_activation(user, &block)
292 def register_by_email_activation(user, &block)
290 token = Token.new(:user => user, :action => "register")
293 token = Token.new(:user => user, :action => "register")
291 if user.save and token.save
294 if user.save and token.save
292 Mailer.register(token).deliver
295 Mailer.register(token).deliver
293 flash[:notice] = l(:notice_account_register_done, :email => user.mail)
296 flash[:notice] = l(:notice_account_register_done, :email => user.mail)
294 redirect_to signin_path
297 redirect_to signin_path
295 else
298 else
296 yield if block_given?
299 yield if block_given?
297 end
300 end
298 end
301 end
299
302
300 # Automatically register a user
303 # Automatically register a user
301 #
304 #
302 # Pass a block for behavior when a user fails to save
305 # Pass a block for behavior when a user fails to save
303 def register_automatically(user, &block)
306 def register_automatically(user, &block)
304 # Automatic activation
307 # Automatic activation
305 user.activate
308 user.activate
306 user.last_login_on = Time.now
309 user.last_login_on = Time.now
307 if user.save
310 if user.save
308 self.logged_user = user
311 self.logged_user = user
309 flash[:notice] = l(:notice_account_activated)
312 flash[:notice] = l(:notice_account_activated)
310 redirect_to my_account_path
313 redirect_to my_account_path
311 else
314 else
312 yield if block_given?
315 yield if block_given?
313 end
316 end
314 end
317 end
315
318
316 # Manual activation by the administrator
319 # Manual activation by the administrator
317 #
320 #
318 # Pass a block for behavior when a user fails to save
321 # Pass a block for behavior when a user fails to save
319 def register_manually_by_administrator(user, &block)
322 def register_manually_by_administrator(user, &block)
320 if user.save
323 if user.save
321 # Sends an email to the administrators
324 # Sends an email to the administrators
322 Mailer.account_activation_request(user).deliver
325 Mailer.account_activation_request(user).deliver
323 account_pending(user)
326 account_pending(user)
324 else
327 else
325 yield if block_given?
328 yield if block_given?
326 end
329 end
327 end
330 end
328
331
329 def handle_inactive_user(user, redirect_path=signin_path)
332 def handle_inactive_user(user, redirect_path=signin_path)
330 if user.registered?
333 if user.registered?
331 account_pending(user, redirect_path)
334 account_pending(user, redirect_path)
332 else
335 else
333 account_locked(user, redirect_path)
336 account_locked(user, redirect_path)
334 end
337 end
335 end
338 end
336
339
337 def account_pending(user, redirect_path=signin_path)
340 def account_pending(user, redirect_path=signin_path)
338 if Setting.self_registration == '1'
341 if Setting.self_registration == '1'
339 flash[:error] = l(:notice_account_not_activated_yet, :url => activation_email_path)
342 flash[:error] = l(:notice_account_not_activated_yet, :url => activation_email_path)
340 session[:registered_user_id] = user.id
343 session[:registered_user_id] = user.id
341 else
344 else
342 flash[:error] = l(:notice_account_pending)
345 flash[:error] = l(:notice_account_pending)
343 end
346 end
344 redirect_to redirect_path
347 redirect_to redirect_path
345 end
348 end
346
349
347 def account_locked(user, redirect_path=signin_path)
350 def account_locked(user, redirect_path=signin_path)
348 flash[:error] = l(:notice_account_locked)
351 flash[:error] = l(:notice_account_locked)
349 redirect_to redirect_path
352 redirect_to redirect_path
350 end
353 end
351 end
354 end
@@ -1,522 +1,523
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2015 Jean-Philippe Lang
2 # Copyright (C) 2006-2015 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 class Mailer < ActionMailer::Base
18 class Mailer < ActionMailer::Base
19 layout 'mailer'
19 layout 'mailer'
20 helper :application
20 helper :application
21 helper :issues
21 helper :issues
22 helper :custom_fields
22 helper :custom_fields
23
23
24 include Redmine::I18n
24 include Redmine::I18n
25
25
26 def self.default_url_options
26 def self.default_url_options
27 { :host => Setting.host_name, :protocol => Setting.protocol }
27 { :host => Setting.host_name, :protocol => Setting.protocol }
28 end
28 end
29
29
30 # Builds a mail for notifying to_users and cc_users about a new issue
30 # Builds a mail for notifying to_users and cc_users about a new issue
31 def issue_add(issue, to_users, cc_users)
31 def issue_add(issue, to_users, cc_users)
32 redmine_headers 'Project' => issue.project.identifier,
32 redmine_headers 'Project' => issue.project.identifier,
33 'Issue-Id' => issue.id,
33 'Issue-Id' => issue.id,
34 'Issue-Author' => issue.author.login
34 'Issue-Author' => issue.author.login
35 redmine_headers 'Issue-Assignee' => issue.assigned_to.login if issue.assigned_to
35 redmine_headers 'Issue-Assignee' => issue.assigned_to.login if issue.assigned_to
36 message_id issue
36 message_id issue
37 references issue
37 references issue
38 @author = issue.author
38 @author = issue.author
39 @issue = issue
39 @issue = issue
40 @users = to_users + cc_users
40 @users = to_users + cc_users
41 @issue_url = url_for(:controller => 'issues', :action => 'show', :id => issue)
41 @issue_url = url_for(:controller => 'issues', :action => 'show', :id => issue)
42 mail :to => to_users,
42 mail :to => to_users,
43 :cc => cc_users,
43 :cc => cc_users,
44 :subject => "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] (#{issue.status.name}) #{issue.subject}"
44 :subject => "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] (#{issue.status.name}) #{issue.subject}"
45 end
45 end
46
46
47 # Notifies users about a new issue
47 # Notifies users about a new issue
48 def self.deliver_issue_add(issue)
48 def self.deliver_issue_add(issue)
49 to = issue.notified_users
49 to = issue.notified_users
50 cc = issue.notified_watchers - to
50 cc = issue.notified_watchers - to
51 issue.each_notification(to + cc) do |users|
51 issue.each_notification(to + cc) do |users|
52 Mailer.issue_add(issue, to & users, cc & users).deliver
52 Mailer.issue_add(issue, to & users, cc & users).deliver
53 end
53 end
54 end
54 end
55
55
56 # Builds a mail for notifying to_users and cc_users about an issue update
56 # Builds a mail for notifying to_users and cc_users about an issue update
57 def issue_edit(journal, to_users, cc_users)
57 def issue_edit(journal, to_users, cc_users)
58 issue = journal.journalized
58 issue = journal.journalized
59 redmine_headers 'Project' => issue.project.identifier,
59 redmine_headers 'Project' => issue.project.identifier,
60 'Issue-Id' => issue.id,
60 'Issue-Id' => issue.id,
61 'Issue-Author' => issue.author.login
61 'Issue-Author' => issue.author.login
62 redmine_headers 'Issue-Assignee' => issue.assigned_to.login if issue.assigned_to
62 redmine_headers 'Issue-Assignee' => issue.assigned_to.login if issue.assigned_to
63 message_id journal
63 message_id journal
64 references issue
64 references issue
65 @author = journal.user
65 @author = journal.user
66 s = "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] "
66 s = "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] "
67 s << "(#{issue.status.name}) " if journal.new_value_for('status_id')
67 s << "(#{issue.status.name}) " if journal.new_value_for('status_id')
68 s << issue.subject
68 s << issue.subject
69 @issue = issue
69 @issue = issue
70 @users = to_users + cc_users
70 @users = to_users + cc_users
71 @journal = journal
71 @journal = journal
72 @journal_details = journal.visible_details(@users.first)
72 @journal_details = journal.visible_details(@users.first)
73 @issue_url = url_for(:controller => 'issues', :action => 'show', :id => issue, :anchor => "change-#{journal.id}")
73 @issue_url = url_for(:controller => 'issues', :action => 'show', :id => issue, :anchor => "change-#{journal.id}")
74 mail :to => to_users,
74 mail :to => to_users,
75 :cc => cc_users,
75 :cc => cc_users,
76 :subject => s
76 :subject => s
77 end
77 end
78
78
79 # Notifies users about an issue update
79 # Notifies users about an issue update
80 def self.deliver_issue_edit(journal)
80 def self.deliver_issue_edit(journal)
81 issue = journal.journalized.reload
81 issue = journal.journalized.reload
82 to = journal.notified_users
82 to = journal.notified_users
83 cc = journal.notified_watchers - to
83 cc = journal.notified_watchers - to
84 journal.each_notification(to + cc) do |users|
84 journal.each_notification(to + cc) do |users|
85 issue.each_notification(users) do |users2|
85 issue.each_notification(users) do |users2|
86 Mailer.issue_edit(journal, to & users2, cc & users2).deliver
86 Mailer.issue_edit(journal, to & users2, cc & users2).deliver
87 end
87 end
88 end
88 end
89 end
89 end
90
90
91 def reminder(user, issues, days)
91 def reminder(user, issues, days)
92 set_language_if_valid user.language
92 set_language_if_valid user.language
93 @issues = issues
93 @issues = issues
94 @days = days
94 @days = days
95 @issues_url = url_for(:controller => 'issues', :action => 'index',
95 @issues_url = url_for(:controller => 'issues', :action => 'index',
96 :set_filter => 1, :assigned_to_id => user.id,
96 :set_filter => 1, :assigned_to_id => user.id,
97 :sort => 'due_date:asc')
97 :sort => 'due_date:asc')
98 mail :to => user,
98 mail :to => user,
99 :subject => l(:mail_subject_reminder, :count => issues.size, :days => days)
99 :subject => l(:mail_subject_reminder, :count => issues.size, :days => days)
100 end
100 end
101
101
102 # Builds a Mail::Message object used to email users belonging to the added document's project.
102 # Builds a Mail::Message object used to email users belonging to the added document's project.
103 #
103 #
104 # Example:
104 # Example:
105 # document_added(document) => Mail::Message object
105 # document_added(document) => Mail::Message object
106 # Mailer.document_added(document).deliver => sends an email to the document's project recipients
106 # Mailer.document_added(document).deliver => sends an email to the document's project recipients
107 def document_added(document)
107 def document_added(document)
108 redmine_headers 'Project' => document.project.identifier
108 redmine_headers 'Project' => document.project.identifier
109 @author = User.current
109 @author = User.current
110 @document = document
110 @document = document
111 @document_url = url_for(:controller => 'documents', :action => 'show', :id => document)
111 @document_url = url_for(:controller => 'documents', :action => 'show', :id => document)
112 mail :to => document.notified_users,
112 mail :to => document.notified_users,
113 :subject => "[#{document.project.name}] #{l(:label_document_new)}: #{document.title}"
113 :subject => "[#{document.project.name}] #{l(:label_document_new)}: #{document.title}"
114 end
114 end
115
115
116 # Builds a Mail::Message object used to email recipients of a project when an attachements are added.
116 # Builds a Mail::Message object used to email recipients of a project when an attachements are added.
117 #
117 #
118 # Example:
118 # Example:
119 # attachments_added(attachments) => Mail::Message object
119 # attachments_added(attachments) => Mail::Message object
120 # Mailer.attachments_added(attachments).deliver => sends an email to the project's recipients
120 # Mailer.attachments_added(attachments).deliver => sends an email to the project's recipients
121 def attachments_added(attachments)
121 def attachments_added(attachments)
122 container = attachments.first.container
122 container = attachments.first.container
123 added_to = ''
123 added_to = ''
124 added_to_url = ''
124 added_to_url = ''
125 @author = attachments.first.author
125 @author = attachments.first.author
126 case container.class.name
126 case container.class.name
127 when 'Project'
127 when 'Project'
128 added_to_url = url_for(:controller => 'files', :action => 'index', :project_id => container)
128 added_to_url = url_for(:controller => 'files', :action => 'index', :project_id => container)
129 added_to = "#{l(:label_project)}: #{container}"
129 added_to = "#{l(:label_project)}: #{container}"
130 recipients = container.project.notified_users.select {|user| user.allowed_to?(:view_files, container.project)}
130 recipients = container.project.notified_users.select {|user| user.allowed_to?(:view_files, container.project)}
131 when 'Version'
131 when 'Version'
132 added_to_url = url_for(:controller => 'files', :action => 'index', :project_id => container.project)
132 added_to_url = url_for(:controller => 'files', :action => 'index', :project_id => container.project)
133 added_to = "#{l(:label_version)}: #{container.name}"
133 added_to = "#{l(:label_version)}: #{container.name}"
134 recipients = container.project.notified_users.select {|user| user.allowed_to?(:view_files, container.project)}
134 recipients = container.project.notified_users.select {|user| user.allowed_to?(:view_files, container.project)}
135 when 'Document'
135 when 'Document'
136 added_to_url = url_for(:controller => 'documents', :action => 'show', :id => container.id)
136 added_to_url = url_for(:controller => 'documents', :action => 'show', :id => container.id)
137 added_to = "#{l(:label_document)}: #{container.title}"
137 added_to = "#{l(:label_document)}: #{container.title}"
138 recipients = container.notified_users
138 recipients = container.notified_users
139 end
139 end
140 redmine_headers 'Project' => container.project.identifier
140 redmine_headers 'Project' => container.project.identifier
141 @attachments = attachments
141 @attachments = attachments
142 @added_to = added_to
142 @added_to = added_to
143 @added_to_url = added_to_url
143 @added_to_url = added_to_url
144 mail :to => recipients,
144 mail :to => recipients,
145 :subject => "[#{container.project.name}] #{l(:label_attachment_new)}"
145 :subject => "[#{container.project.name}] #{l(:label_attachment_new)}"
146 end
146 end
147
147
148 # Builds a Mail::Message object used to email recipients of a news' project when a news item is added.
148 # Builds a Mail::Message object used to email recipients of a news' project when a news item is added.
149 #
149 #
150 # Example:
150 # Example:
151 # news_added(news) => Mail::Message object
151 # news_added(news) => Mail::Message object
152 # Mailer.news_added(news).deliver => sends an email to the news' project recipients
152 # Mailer.news_added(news).deliver => sends an email to the news' project recipients
153 def news_added(news)
153 def news_added(news)
154 redmine_headers 'Project' => news.project.identifier
154 redmine_headers 'Project' => news.project.identifier
155 @author = news.author
155 @author = news.author
156 message_id news
156 message_id news
157 references news
157 references news
158 @news = news
158 @news = news
159 @news_url = url_for(:controller => 'news', :action => 'show', :id => news)
159 @news_url = url_for(:controller => 'news', :action => 'show', :id => news)
160 mail :to => news.notified_users,
160 mail :to => news.notified_users,
161 :cc => news.notified_watchers_for_added_news,
161 :cc => news.notified_watchers_for_added_news,
162 :subject => "[#{news.project.name}] #{l(:label_news)}: #{news.title}"
162 :subject => "[#{news.project.name}] #{l(:label_news)}: #{news.title}"
163 end
163 end
164
164
165 # Builds a Mail::Message object used to email recipients of a news' project when a news comment is added.
165 # Builds a Mail::Message object used to email recipients of a news' project when a news comment is added.
166 #
166 #
167 # Example:
167 # Example:
168 # news_comment_added(comment) => Mail::Message object
168 # news_comment_added(comment) => Mail::Message object
169 # Mailer.news_comment_added(comment) => sends an email to the news' project recipients
169 # Mailer.news_comment_added(comment) => sends an email to the news' project recipients
170 def news_comment_added(comment)
170 def news_comment_added(comment)
171 news = comment.commented
171 news = comment.commented
172 redmine_headers 'Project' => news.project.identifier
172 redmine_headers 'Project' => news.project.identifier
173 @author = comment.author
173 @author = comment.author
174 message_id comment
174 message_id comment
175 references news
175 references news
176 @news = news
176 @news = news
177 @comment = comment
177 @comment = comment
178 @news_url = url_for(:controller => 'news', :action => 'show', :id => news)
178 @news_url = url_for(:controller => 'news', :action => 'show', :id => news)
179 mail :to => news.notified_users,
179 mail :to => news.notified_users,
180 :cc => news.notified_watchers,
180 :cc => news.notified_watchers,
181 :subject => "Re: [#{news.project.name}] #{l(:label_news)}: #{news.title}"
181 :subject => "Re: [#{news.project.name}] #{l(:label_news)}: #{news.title}"
182 end
182 end
183
183
184 # Builds a Mail::Message object used to email the recipients of the specified message that was posted.
184 # Builds a Mail::Message object used to email the recipients of the specified message that was posted.
185 #
185 #
186 # Example:
186 # Example:
187 # message_posted(message) => Mail::Message object
187 # message_posted(message) => Mail::Message object
188 # Mailer.message_posted(message).deliver => sends an email to the recipients
188 # Mailer.message_posted(message).deliver => sends an email to the recipients
189 def message_posted(message)
189 def message_posted(message)
190 redmine_headers 'Project' => message.project.identifier,
190 redmine_headers 'Project' => message.project.identifier,
191 'Topic-Id' => (message.parent_id || message.id)
191 'Topic-Id' => (message.parent_id || message.id)
192 @author = message.author
192 @author = message.author
193 message_id message
193 message_id message
194 references message.root
194 references message.root
195 recipients = message.notified_users
195 recipients = message.notified_users
196 cc = ((message.root.notified_watchers + message.board.notified_watchers).uniq - recipients)
196 cc = ((message.root.notified_watchers + message.board.notified_watchers).uniq - recipients)
197 @message = message
197 @message = message
198 @message_url = url_for(message.event_url)
198 @message_url = url_for(message.event_url)
199 mail :to => recipients,
199 mail :to => recipients,
200 :cc => cc,
200 :cc => cc,
201 :subject => "[#{message.board.project.name} - #{message.board.name} - msg#{message.root.id}] #{message.subject}"
201 :subject => "[#{message.board.project.name} - #{message.board.name} - msg#{message.root.id}] #{message.subject}"
202 end
202 end
203
203
204 # Builds a Mail::Message object used to email the recipients of a project of the specified wiki content was added.
204 # Builds a Mail::Message object used to email the recipients of a project of the specified wiki content was added.
205 #
205 #
206 # Example:
206 # Example:
207 # wiki_content_added(wiki_content) => Mail::Message object
207 # wiki_content_added(wiki_content) => Mail::Message object
208 # Mailer.wiki_content_added(wiki_content).deliver => sends an email to the project's recipients
208 # Mailer.wiki_content_added(wiki_content).deliver => sends an email to the project's recipients
209 def wiki_content_added(wiki_content)
209 def wiki_content_added(wiki_content)
210 redmine_headers 'Project' => wiki_content.project.identifier,
210 redmine_headers 'Project' => wiki_content.project.identifier,
211 'Wiki-Page-Id' => wiki_content.page.id
211 'Wiki-Page-Id' => wiki_content.page.id
212 @author = wiki_content.author
212 @author = wiki_content.author
213 message_id wiki_content
213 message_id wiki_content
214 recipients = wiki_content.notified_users
214 recipients = wiki_content.notified_users
215 cc = wiki_content.page.wiki.notified_watchers - recipients
215 cc = wiki_content.page.wiki.notified_watchers - recipients
216 @wiki_content = wiki_content
216 @wiki_content = wiki_content
217 @wiki_content_url = url_for(:controller => 'wiki', :action => 'show',
217 @wiki_content_url = url_for(:controller => 'wiki', :action => 'show',
218 :project_id => wiki_content.project,
218 :project_id => wiki_content.project,
219 :id => wiki_content.page.title)
219 :id => wiki_content.page.title)
220 mail :to => recipients,
220 mail :to => recipients,
221 :cc => cc,
221 :cc => cc,
222 :subject => "[#{wiki_content.project.name}] #{l(:mail_subject_wiki_content_added, :id => wiki_content.page.pretty_title)}"
222 :subject => "[#{wiki_content.project.name}] #{l(:mail_subject_wiki_content_added, :id => wiki_content.page.pretty_title)}"
223 end
223 end
224
224
225 # Builds a Mail::Message object used to email the recipients of a project of the specified wiki content was updated.
225 # Builds a Mail::Message object used to email the recipients of a project of the specified wiki content was updated.
226 #
226 #
227 # Example:
227 # Example:
228 # wiki_content_updated(wiki_content) => Mail::Message object
228 # wiki_content_updated(wiki_content) => Mail::Message object
229 # Mailer.wiki_content_updated(wiki_content).deliver => sends an email to the project's recipients
229 # Mailer.wiki_content_updated(wiki_content).deliver => sends an email to the project's recipients
230 def wiki_content_updated(wiki_content)
230 def wiki_content_updated(wiki_content)
231 redmine_headers 'Project' => wiki_content.project.identifier,
231 redmine_headers 'Project' => wiki_content.project.identifier,
232 'Wiki-Page-Id' => wiki_content.page.id
232 'Wiki-Page-Id' => wiki_content.page.id
233 @author = wiki_content.author
233 @author = wiki_content.author
234 message_id wiki_content
234 message_id wiki_content
235 recipients = wiki_content.notified_users
235 recipients = wiki_content.notified_users
236 cc = wiki_content.page.wiki.notified_watchers + wiki_content.page.notified_watchers - recipients
236 cc = wiki_content.page.wiki.notified_watchers + wiki_content.page.notified_watchers - recipients
237 @wiki_content = wiki_content
237 @wiki_content = wiki_content
238 @wiki_content_url = url_for(:controller => 'wiki', :action => 'show',
238 @wiki_content_url = url_for(:controller => 'wiki', :action => 'show',
239 :project_id => wiki_content.project,
239 :project_id => wiki_content.project,
240 :id => wiki_content.page.title)
240 :id => wiki_content.page.title)
241 @wiki_diff_url = url_for(:controller => 'wiki', :action => 'diff',
241 @wiki_diff_url = url_for(:controller => 'wiki', :action => 'diff',
242 :project_id => wiki_content.project, :id => wiki_content.page.title,
242 :project_id => wiki_content.project, :id => wiki_content.page.title,
243 :version => wiki_content.version)
243 :version => wiki_content.version)
244 mail :to => recipients,
244 mail :to => recipients,
245 :cc => cc,
245 :cc => cc,
246 :subject => "[#{wiki_content.project.name}] #{l(:mail_subject_wiki_content_updated, :id => wiki_content.page.pretty_title)}"
246 :subject => "[#{wiki_content.project.name}] #{l(:mail_subject_wiki_content_updated, :id => wiki_content.page.pretty_title)}"
247 end
247 end
248
248
249 # Builds a Mail::Message object used to email the specified user their account information.
249 # Builds a Mail::Message object used to email the specified user their account information.
250 #
250 #
251 # Example:
251 # Example:
252 # account_information(user, password) => Mail::Message object
252 # account_information(user, password) => Mail::Message object
253 # Mailer.account_information(user, password).deliver => sends account information to the user
253 # Mailer.account_information(user, password).deliver => sends account information to the user
254 def account_information(user, password)
254 def account_information(user, password)
255 set_language_if_valid user.language
255 set_language_if_valid user.language
256 @user = user
256 @user = user
257 @password = password
257 @password = password
258 @login_url = url_for(:controller => 'account', :action => 'login')
258 @login_url = url_for(:controller => 'account', :action => 'login')
259 mail :to => user.mail,
259 mail :to => user.mail,
260 :subject => l(:mail_subject_register, Setting.app_title)
260 :subject => l(:mail_subject_register, Setting.app_title)
261 end
261 end
262
262
263 # Builds a Mail::Message object used to email all active administrators of an account activation request.
263 # Builds a Mail::Message object used to email all active administrators of an account activation request.
264 #
264 #
265 # Example:
265 # Example:
266 # account_activation_request(user) => Mail::Message object
266 # account_activation_request(user) => Mail::Message object
267 # Mailer.account_activation_request(user).deliver => sends an email to all active administrators
267 # Mailer.account_activation_request(user).deliver => sends an email to all active administrators
268 def account_activation_request(user)
268 def account_activation_request(user)
269 # Send the email to all active administrators
269 # Send the email to all active administrators
270 recipients = User.active.where(:admin => true)
270 recipients = User.active.where(:admin => true)
271 @user = user
271 @user = user
272 @url = url_for(:controller => 'users', :action => 'index',
272 @url = url_for(:controller => 'users', :action => 'index',
273 :status => User::STATUS_REGISTERED,
273 :status => User::STATUS_REGISTERED,
274 :sort_key => 'created_on', :sort_order => 'desc')
274 :sort_key => 'created_on', :sort_order => 'desc')
275 mail :to => recipients,
275 mail :to => recipients,
276 :subject => l(:mail_subject_account_activation_request, Setting.app_title)
276 :subject => l(:mail_subject_account_activation_request, Setting.app_title)
277 end
277 end
278
278
279 # Builds a Mail::Message object used to email the specified user that their account was activated by an administrator.
279 # Builds a Mail::Message object used to email the specified user that their account was activated by an administrator.
280 #
280 #
281 # Example:
281 # Example:
282 # account_activated(user) => Mail::Message object
282 # account_activated(user) => Mail::Message object
283 # Mailer.account_activated(user).deliver => sends an email to the registered user
283 # Mailer.account_activated(user).deliver => sends an email to the registered user
284 def account_activated(user)
284 def account_activated(user)
285 set_language_if_valid user.language
285 set_language_if_valid user.language
286 @user = user
286 @user = user
287 @login_url = url_for(:controller => 'account', :action => 'login')
287 @login_url = url_for(:controller => 'account', :action => 'login')
288 mail :to => user.mail,
288 mail :to => user.mail,
289 :subject => l(:mail_subject_register, Setting.app_title)
289 :subject => l(:mail_subject_register, Setting.app_title)
290 end
290 end
291
291
292 def lost_password(token)
292 def lost_password(token, recipient=nil)
293 set_language_if_valid(token.user.language)
293 set_language_if_valid(token.user.language)
294 recipient ||= token.user.mail
294 @token = token
295 @token = token
295 @url = url_for(:controller => 'account', :action => 'lost_password', :token => token.value)
296 @url = url_for(:controller => 'account', :action => 'lost_password', :token => token.value)
296 mail :to => token.user.mail,
297 mail :to => recipient,
297 :subject => l(:mail_subject_lost_password, Setting.app_title)
298 :subject => l(:mail_subject_lost_password, Setting.app_title)
298 end
299 end
299
300
300 def register(token)
301 def register(token)
301 set_language_if_valid(token.user.language)
302 set_language_if_valid(token.user.language)
302 @token = token
303 @token = token
303 @url = url_for(:controller => 'account', :action => 'activate', :token => token.value)
304 @url = url_for(:controller => 'account', :action => 'activate', :token => token.value)
304 mail :to => token.user.mail,
305 mail :to => token.user.mail,
305 :subject => l(:mail_subject_register, Setting.app_title)
306 :subject => l(:mail_subject_register, Setting.app_title)
306 end
307 end
307
308
308 def test_email(user)
309 def test_email(user)
309 set_language_if_valid(user.language)
310 set_language_if_valid(user.language)
310 @url = url_for(:controller => 'welcome')
311 @url = url_for(:controller => 'welcome')
311 mail :to => user.mail,
312 mail :to => user.mail,
312 :subject => 'Redmine test'
313 :subject => 'Redmine test'
313 end
314 end
314
315
315 # Sends reminders to issue assignees
316 # Sends reminders to issue assignees
316 # Available options:
317 # Available options:
317 # * :days => how many days in the future to remind about (defaults to 7)
318 # * :days => how many days in the future to remind about (defaults to 7)
318 # * :tracker => id of tracker for filtering issues (defaults to all trackers)
319 # * :tracker => id of tracker for filtering issues (defaults to all trackers)
319 # * :project => id or identifier of project to process (defaults to all projects)
320 # * :project => id or identifier of project to process (defaults to all projects)
320 # * :users => array of user/group ids who should be reminded
321 # * :users => array of user/group ids who should be reminded
321 def self.reminders(options={})
322 def self.reminders(options={})
322 days = options[:days] || 7
323 days = options[:days] || 7
323 project = options[:project] ? Project.find(options[:project]) : nil
324 project = options[:project] ? Project.find(options[:project]) : nil
324 tracker = options[:tracker] ? Tracker.find(options[:tracker]) : nil
325 tracker = options[:tracker] ? Tracker.find(options[:tracker]) : nil
325 user_ids = options[:users]
326 user_ids = options[:users]
326
327
327 scope = Issue.open.where("#{Issue.table_name}.assigned_to_id IS NOT NULL" +
328 scope = Issue.open.where("#{Issue.table_name}.assigned_to_id IS NOT NULL" +
328 " AND #{Project.table_name}.status = #{Project::STATUS_ACTIVE}" +
329 " AND #{Project.table_name}.status = #{Project::STATUS_ACTIVE}" +
329 " AND #{Issue.table_name}.due_date <= ?", days.day.from_now.to_date
330 " AND #{Issue.table_name}.due_date <= ?", days.day.from_now.to_date
330 )
331 )
331 scope = scope.where(:assigned_to_id => user_ids) if user_ids.present?
332 scope = scope.where(:assigned_to_id => user_ids) if user_ids.present?
332 scope = scope.where(:project_id => project.id) if project
333 scope = scope.where(:project_id => project.id) if project
333 scope = scope.where(:tracker_id => tracker.id) if tracker
334 scope = scope.where(:tracker_id => tracker.id) if tracker
334 issues_by_assignee = scope.includes(:status, :assigned_to, :project, :tracker).
335 issues_by_assignee = scope.includes(:status, :assigned_to, :project, :tracker).
335 group_by(&:assigned_to)
336 group_by(&:assigned_to)
336 issues_by_assignee.keys.each do |assignee|
337 issues_by_assignee.keys.each do |assignee|
337 if assignee.is_a?(Group)
338 if assignee.is_a?(Group)
338 assignee.users.each do |user|
339 assignee.users.each do |user|
339 issues_by_assignee[user] ||= []
340 issues_by_assignee[user] ||= []
340 issues_by_assignee[user] += issues_by_assignee[assignee]
341 issues_by_assignee[user] += issues_by_assignee[assignee]
341 end
342 end
342 end
343 end
343 end
344 end
344
345
345 issues_by_assignee.each do |assignee, issues|
346 issues_by_assignee.each do |assignee, issues|
346 reminder(assignee, issues, days).deliver if assignee.is_a?(User) && assignee.active?
347 reminder(assignee, issues, days).deliver if assignee.is_a?(User) && assignee.active?
347 end
348 end
348 end
349 end
349
350
350 # Activates/desactivates email deliveries during +block+
351 # Activates/desactivates email deliveries during +block+
351 def self.with_deliveries(enabled = true, &block)
352 def self.with_deliveries(enabled = true, &block)
352 was_enabled = ActionMailer::Base.perform_deliveries
353 was_enabled = ActionMailer::Base.perform_deliveries
353 ActionMailer::Base.perform_deliveries = !!enabled
354 ActionMailer::Base.perform_deliveries = !!enabled
354 yield
355 yield
355 ensure
356 ensure
356 ActionMailer::Base.perform_deliveries = was_enabled
357 ActionMailer::Base.perform_deliveries = was_enabled
357 end
358 end
358
359
359 # Sends emails synchronously in the given block
360 # Sends emails synchronously in the given block
360 def self.with_synched_deliveries(&block)
361 def self.with_synched_deliveries(&block)
361 saved_method = ActionMailer::Base.delivery_method
362 saved_method = ActionMailer::Base.delivery_method
362 if m = saved_method.to_s.match(%r{^async_(.+)$})
363 if m = saved_method.to_s.match(%r{^async_(.+)$})
363 synched_method = m[1]
364 synched_method = m[1]
364 ActionMailer::Base.delivery_method = synched_method.to_sym
365 ActionMailer::Base.delivery_method = synched_method.to_sym
365 ActionMailer::Base.send "#{synched_method}_settings=", ActionMailer::Base.send("async_#{synched_method}_settings")
366 ActionMailer::Base.send "#{synched_method}_settings=", ActionMailer::Base.send("async_#{synched_method}_settings")
366 end
367 end
367 yield
368 yield
368 ensure
369 ensure
369 ActionMailer::Base.delivery_method = saved_method
370 ActionMailer::Base.delivery_method = saved_method
370 end
371 end
371
372
372 def mail(headers={}, &block)
373 def mail(headers={}, &block)
373 headers.reverse_merge! 'X-Mailer' => 'Redmine',
374 headers.reverse_merge! 'X-Mailer' => 'Redmine',
374 'X-Redmine-Host' => Setting.host_name,
375 'X-Redmine-Host' => Setting.host_name,
375 'X-Redmine-Site' => Setting.app_title,
376 'X-Redmine-Site' => Setting.app_title,
376 'X-Auto-Response-Suppress' => 'OOF',
377 'X-Auto-Response-Suppress' => 'OOF',
377 'Auto-Submitted' => 'auto-generated',
378 'Auto-Submitted' => 'auto-generated',
378 'From' => Setting.mail_from,
379 'From' => Setting.mail_from,
379 'List-Id' => "<#{Setting.mail_from.to_s.gsub('@', '.')}>"
380 'List-Id' => "<#{Setting.mail_from.to_s.gsub('@', '.')}>"
380
381
381 # Replaces users with their email addresses
382 # Replaces users with their email addresses
382 [:to, :cc, :bcc].each do |key|
383 [:to, :cc, :bcc].each do |key|
383 if headers[key].present?
384 if headers[key].present?
384 headers[key] = self.class.email_addresses(headers[key])
385 headers[key] = self.class.email_addresses(headers[key])
385 end
386 end
386 end
387 end
387
388
388 # Removes the author from the recipients and cc
389 # Removes the author from the recipients and cc
389 # if the author does not want to receive notifications
390 # if the author does not want to receive notifications
390 # about what the author do
391 # about what the author do
391 if @author && @author.logged? && @author.pref.no_self_notified
392 if @author && @author.logged? && @author.pref.no_self_notified
392 addresses = @author.mails
393 addresses = @author.mails
393 headers[:to] -= addresses if headers[:to].is_a?(Array)
394 headers[:to] -= addresses if headers[:to].is_a?(Array)
394 headers[:cc] -= addresses if headers[:cc].is_a?(Array)
395 headers[:cc] -= addresses if headers[:cc].is_a?(Array)
395 end
396 end
396
397
397 if @author && @author.logged?
398 if @author && @author.logged?
398 redmine_headers 'Sender' => @author.login
399 redmine_headers 'Sender' => @author.login
399 end
400 end
400
401
401 # Blind carbon copy recipients
402 # Blind carbon copy recipients
402 if Setting.bcc_recipients?
403 if Setting.bcc_recipients?
403 headers[:bcc] = [headers[:to], headers[:cc]].flatten.uniq.reject(&:blank?)
404 headers[:bcc] = [headers[:to], headers[:cc]].flatten.uniq.reject(&:blank?)
404 headers[:to] = nil
405 headers[:to] = nil
405 headers[:cc] = nil
406 headers[:cc] = nil
406 end
407 end
407
408
408 if @message_id_object
409 if @message_id_object
409 headers[:message_id] = "<#{self.class.message_id_for(@message_id_object)}>"
410 headers[:message_id] = "<#{self.class.message_id_for(@message_id_object)}>"
410 end
411 end
411 if @references_objects
412 if @references_objects
412 headers[:references] = @references_objects.collect {|o| "<#{self.class.references_for(o)}>"}.join(' ')
413 headers[:references] = @references_objects.collect {|o| "<#{self.class.references_for(o)}>"}.join(' ')
413 end
414 end
414
415
415 m = if block_given?
416 m = if block_given?
416 super headers, &block
417 super headers, &block
417 else
418 else
418 super headers do |format|
419 super headers do |format|
419 format.text
420 format.text
420 format.html unless Setting.plain_text_mail?
421 format.html unless Setting.plain_text_mail?
421 end
422 end
422 end
423 end
423 set_language_if_valid @initial_language
424 set_language_if_valid @initial_language
424
425
425 m
426 m
426 end
427 end
427
428
428 def initialize(*args)
429 def initialize(*args)
429 @initial_language = current_language
430 @initial_language = current_language
430 set_language_if_valid Setting.default_language
431 set_language_if_valid Setting.default_language
431 super
432 super
432 end
433 end
433
434
434 def self.deliver_mail(mail)
435 def self.deliver_mail(mail)
435 return false if mail.to.blank? && mail.cc.blank? && mail.bcc.blank?
436 return false if mail.to.blank? && mail.cc.blank? && mail.bcc.blank?
436 begin
437 begin
437 # Log errors when raise_delivery_errors is set to false, Rails does not
438 # Log errors when raise_delivery_errors is set to false, Rails does not
438 mail.raise_delivery_errors = true
439 mail.raise_delivery_errors = true
439 super
440 super
440 rescue Exception => e
441 rescue Exception => e
441 if ActionMailer::Base.raise_delivery_errors
442 if ActionMailer::Base.raise_delivery_errors
442 raise e
443 raise e
443 else
444 else
444 Rails.logger.error "Email delivery error: #{e.message}"
445 Rails.logger.error "Email delivery error: #{e.message}"
445 end
446 end
446 end
447 end
447 end
448 end
448
449
449 def self.method_missing(method, *args, &block)
450 def self.method_missing(method, *args, &block)
450 if m = method.to_s.match(%r{^deliver_(.+)$})
451 if m = method.to_s.match(%r{^deliver_(.+)$})
451 ActiveSupport::Deprecation.warn "Mailer.deliver_#{m[1]}(*args) is deprecated. Use Mailer.#{m[1]}(*args).deliver instead."
452 ActiveSupport::Deprecation.warn "Mailer.deliver_#{m[1]}(*args) is deprecated. Use Mailer.#{m[1]}(*args).deliver instead."
452 send(m[1], *args).deliver
453 send(m[1], *args).deliver
453 else
454 else
454 super
455 super
455 end
456 end
456 end
457 end
457
458
458 # Returns an array of email addresses to notify by
459 # Returns an array of email addresses to notify by
459 # replacing users in arg with their notified email addresses
460 # replacing users in arg with their notified email addresses
460 #
461 #
461 # Example:
462 # Example:
462 # Mailer.email_addresses(users)
463 # Mailer.email_addresses(users)
463 # => ["foo@example.net", "bar@example.net"]
464 # => ["foo@example.net", "bar@example.net"]
464 def self.email_addresses(arg)
465 def self.email_addresses(arg)
465 arr = Array.wrap(arg)
466 arr = Array.wrap(arg)
466 mails = arr.reject {|a| a.is_a? Principal}
467 mails = arr.reject {|a| a.is_a? Principal}
467 users = arr - mails
468 users = arr - mails
468 if users.any?
469 if users.any?
469 mails += EmailAddress.
470 mails += EmailAddress.
470 where(:user_id => users.map(&:id)).
471 where(:user_id => users.map(&:id)).
471 where("is_default = ? OR notify = ?", true, true).
472 where("is_default = ? OR notify = ?", true, true).
472 pluck(:address)
473 pluck(:address)
473 end
474 end
474 mails
475 mails
475 end
476 end
476
477
477 private
478 private
478
479
479 # Appends a Redmine header field (name is prepended with 'X-Redmine-')
480 # Appends a Redmine header field (name is prepended with 'X-Redmine-')
480 def redmine_headers(h)
481 def redmine_headers(h)
481 h.each { |k,v| headers["X-Redmine-#{k}"] = v.to_s }
482 h.each { |k,v| headers["X-Redmine-#{k}"] = v.to_s }
482 end
483 end
483
484
484 def self.token_for(object, rand=true)
485 def self.token_for(object, rand=true)
485 timestamp = object.send(object.respond_to?(:created_on) ? :created_on : :updated_on)
486 timestamp = object.send(object.respond_to?(:created_on) ? :created_on : :updated_on)
486 hash = [
487 hash = [
487 "redmine",
488 "redmine",
488 "#{object.class.name.demodulize.underscore}-#{object.id}",
489 "#{object.class.name.demodulize.underscore}-#{object.id}",
489 timestamp.strftime("%Y%m%d%H%M%S")
490 timestamp.strftime("%Y%m%d%H%M%S")
490 ]
491 ]
491 if rand
492 if rand
492 hash << Redmine::Utils.random_hex(8)
493 hash << Redmine::Utils.random_hex(8)
493 end
494 end
494 host = Setting.mail_from.to_s.strip.gsub(%r{^.*@|>}, '')
495 host = Setting.mail_from.to_s.strip.gsub(%r{^.*@|>}, '')
495 host = "#{::Socket.gethostname}.redmine" if host.empty?
496 host = "#{::Socket.gethostname}.redmine" if host.empty?
496 "#{hash.join('.')}@#{host}"
497 "#{hash.join('.')}@#{host}"
497 end
498 end
498
499
499 # Returns a Message-Id for the given object
500 # Returns a Message-Id for the given object
500 def self.message_id_for(object)
501 def self.message_id_for(object)
501 token_for(object, true)
502 token_for(object, true)
502 end
503 end
503
504
504 # Returns a uniq token for a given object referenced by all notifications
505 # Returns a uniq token for a given object referenced by all notifications
505 # related to this object
506 # related to this object
506 def self.references_for(object)
507 def self.references_for(object)
507 token_for(object, false)
508 token_for(object, false)
508 end
509 end
509
510
510 def message_id(object)
511 def message_id(object)
511 @message_id_object = object
512 @message_id_object = object
512 end
513 end
513
514
514 def references(object)
515 def references(object)
515 @references_objects ||= []
516 @references_objects ||= []
516 @references_objects << object
517 @references_objects << object
517 end
518 end
518
519
519 def mylogger
520 def mylogger
520 Rails.logger
521 Rails.logger
521 end
522 end
522 end
523 end
@@ -1,410 +1,424
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2015 Jean-Philippe Lang
2 # Copyright (C) 2006-2015 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 AccountControllerTest < ActionController::TestCase
20 class AccountControllerTest < ActionController::TestCase
21 fixtures :users, :roles
21 fixtures :users, :roles
22
22
23 def setup
23 def setup
24 User.current = nil
24 User.current = nil
25 end
25 end
26
26
27 def test_get_login
27 def test_get_login
28 get :login
28 get :login
29 assert_response :success
29 assert_response :success
30 assert_template 'login'
30 assert_template 'login'
31
31
32 assert_select 'input[name=username]'
32 assert_select 'input[name=username]'
33 assert_select 'input[name=password]'
33 assert_select 'input[name=password]'
34 end
34 end
35
35
36 def test_get_login_while_logged_in_should_redirect_to_back_url_if_present
36 def test_get_login_while_logged_in_should_redirect_to_back_url_if_present
37 @request.session[:user_id] = 2
37 @request.session[:user_id] = 2
38 @request.env["HTTP_REFERER"] = 'http://test.host/issues/show/1'
38 @request.env["HTTP_REFERER"] = 'http://test.host/issues/show/1'
39
39
40 get :login, :back_url => 'http://test.host/issues/show/1'
40 get :login, :back_url => 'http://test.host/issues/show/1'
41 assert_redirected_to '/issues/show/1'
41 assert_redirected_to '/issues/show/1'
42 assert_equal 2, @request.session[:user_id]
42 assert_equal 2, @request.session[:user_id]
43 end
43 end
44
44
45 def test_get_login_while_logged_in_should_redirect_to_referer_without_back_url
45 def test_get_login_while_logged_in_should_redirect_to_referer_without_back_url
46 @request.session[:user_id] = 2
46 @request.session[:user_id] = 2
47 @request.env["HTTP_REFERER"] = 'http://test.host/issues/show/1'
47 @request.env["HTTP_REFERER"] = 'http://test.host/issues/show/1'
48
48
49 get :login
49 get :login
50 assert_redirected_to '/issues/show/1'
50 assert_redirected_to '/issues/show/1'
51 assert_equal 2, @request.session[:user_id]
51 assert_equal 2, @request.session[:user_id]
52 end
52 end
53
53
54 def test_get_login_while_logged_in_should_redirect_to_home_by_default
54 def test_get_login_while_logged_in_should_redirect_to_home_by_default
55 @request.session[:user_id] = 2
55 @request.session[:user_id] = 2
56
56
57 get :login
57 get :login
58 assert_redirected_to '/'
58 assert_redirected_to '/'
59 assert_equal 2, @request.session[:user_id]
59 assert_equal 2, @request.session[:user_id]
60 end
60 end
61
61
62 def test_login_should_redirect_to_back_url_param
62 def test_login_should_redirect_to_back_url_param
63 # request.uri is "test.host" in test environment
63 # request.uri is "test.host" in test environment
64 back_urls = [
64 back_urls = [
65 'http://test.host/issues/show/1',
65 'http://test.host/issues/show/1',
66 '/'
66 '/'
67 ]
67 ]
68 back_urls.each do |back_url|
68 back_urls.each do |back_url|
69 post :login, :username => 'jsmith', :password => 'jsmith', :back_url => back_url
69 post :login, :username => 'jsmith', :password => 'jsmith', :back_url => back_url
70 assert_redirected_to back_url
70 assert_redirected_to back_url
71 end
71 end
72 end
72 end
73
73
74 def test_login_with_suburi_should_redirect_to_back_url_param
74 def test_login_with_suburi_should_redirect_to_back_url_param
75 @relative_url_root = Redmine::Utils.relative_url_root
75 @relative_url_root = Redmine::Utils.relative_url_root
76 Redmine::Utils.relative_url_root = '/redmine'
76 Redmine::Utils.relative_url_root = '/redmine'
77
77
78 back_urls = [
78 back_urls = [
79 'http://test.host/redmine/issues/show/1',
79 'http://test.host/redmine/issues/show/1',
80 '/redmine'
80 '/redmine'
81 ]
81 ]
82 back_urls.each do |back_url|
82 back_urls.each do |back_url|
83 post :login, :username => 'jsmith', :password => 'jsmith', :back_url => back_url
83 post :login, :username => 'jsmith', :password => 'jsmith', :back_url => back_url
84 assert_redirected_to back_url
84 assert_redirected_to back_url
85 end
85 end
86 ensure
86 ensure
87 Redmine::Utils.relative_url_root = @relative_url_root
87 Redmine::Utils.relative_url_root = @relative_url_root
88 end
88 end
89
89
90 def test_login_should_not_redirect_to_another_host
90 def test_login_should_not_redirect_to_another_host
91 back_urls = [
91 back_urls = [
92 'http://test.foo/fake',
92 'http://test.foo/fake',
93 '//test.foo/fake'
93 '//test.foo/fake'
94 ]
94 ]
95 back_urls.each do |back_url|
95 back_urls.each do |back_url|
96 post :login, :username => 'jsmith', :password => 'jsmith', :back_url => back_url
96 post :login, :username => 'jsmith', :password => 'jsmith', :back_url => back_url
97 assert_redirected_to '/my/page'
97 assert_redirected_to '/my/page'
98 end
98 end
99 end
99 end
100
100
101 def test_login_with_suburi_should_not_redirect_to_another_suburi
101 def test_login_with_suburi_should_not_redirect_to_another_suburi
102 @relative_url_root = Redmine::Utils.relative_url_root
102 @relative_url_root = Redmine::Utils.relative_url_root
103 Redmine::Utils.relative_url_root = '/redmine'
103 Redmine::Utils.relative_url_root = '/redmine'
104
104
105 back_urls = [
105 back_urls = [
106 'http://test.host/',
106 'http://test.host/',
107 'http://test.host/fake',
107 'http://test.host/fake',
108 'http://test.host/fake/issues',
108 'http://test.host/fake/issues',
109 'http://test.host/redmine/../fake',
109 'http://test.host/redmine/../fake',
110 'http://test.host/redmine/../fake/issues',
110 'http://test.host/redmine/../fake/issues',
111 'http://test.host/redmine/%2e%2e/fake'
111 'http://test.host/redmine/%2e%2e/fake'
112 ]
112 ]
113 back_urls.each do |back_url|
113 back_urls.each do |back_url|
114 post :login, :username => 'jsmith', :password => 'jsmith', :back_url => back_url
114 post :login, :username => 'jsmith', :password => 'jsmith', :back_url => back_url
115 assert_redirected_to '/my/page'
115 assert_redirected_to '/my/page'
116 end
116 end
117 ensure
117 ensure
118 Redmine::Utils.relative_url_root = @relative_url_root
118 Redmine::Utils.relative_url_root = @relative_url_root
119 end
119 end
120
120
121 def test_login_with_wrong_password
121 def test_login_with_wrong_password
122 post :login, :username => 'admin', :password => 'bad'
122 post :login, :username => 'admin', :password => 'bad'
123 assert_response :success
123 assert_response :success
124 assert_template 'login'
124 assert_template 'login'
125
125
126 assert_select 'div.flash.error', :text => /Invalid user or password/
126 assert_select 'div.flash.error', :text => /Invalid user or password/
127 assert_select 'input[name=username][value=admin]'
127 assert_select 'input[name=username][value=admin]'
128 assert_select 'input[name=password]'
128 assert_select 'input[name=password]'
129 assert_select 'input[name=password][value]', 0
129 assert_select 'input[name=password][value]', 0
130 end
130 end
131
131
132 def test_login_with_locked_account_should_fail
132 def test_login_with_locked_account_should_fail
133 User.find(2).update_attribute :status, User::STATUS_LOCKED
133 User.find(2).update_attribute :status, User::STATUS_LOCKED
134
134
135 post :login, :username => 'jsmith', :password => 'jsmith'
135 post :login, :username => 'jsmith', :password => 'jsmith'
136 assert_redirected_to '/login'
136 assert_redirected_to '/login'
137 assert_include 'locked', flash[:error]
137 assert_include 'locked', flash[:error]
138 assert_nil @request.session[:user_id]
138 assert_nil @request.session[:user_id]
139 end
139 end
140
140
141 def test_login_as_registered_user_with_manual_activation_should_inform_user
141 def test_login_as_registered_user_with_manual_activation_should_inform_user
142 User.find(2).update_attribute :status, User::STATUS_REGISTERED
142 User.find(2).update_attribute :status, User::STATUS_REGISTERED
143
143
144 with_settings :self_registration => '2', :default_language => 'en' do
144 with_settings :self_registration => '2', :default_language => 'en' do
145 post :login, :username => 'jsmith', :password => 'jsmith'
145 post :login, :username => 'jsmith', :password => 'jsmith'
146 assert_redirected_to '/login'
146 assert_redirected_to '/login'
147 assert_include 'pending administrator approval', flash[:error]
147 assert_include 'pending administrator approval', flash[:error]
148 end
148 end
149 end
149 end
150
150
151 def test_login_as_registered_user_with_email_activation_should_propose_new_activation_email
151 def test_login_as_registered_user_with_email_activation_should_propose_new_activation_email
152 User.find(2).update_attribute :status, User::STATUS_REGISTERED
152 User.find(2).update_attribute :status, User::STATUS_REGISTERED
153
153
154 with_settings :self_registration => '1', :default_language => 'en' do
154 with_settings :self_registration => '1', :default_language => 'en' do
155 post :login, :username => 'jsmith', :password => 'jsmith'
155 post :login, :username => 'jsmith', :password => 'jsmith'
156 assert_redirected_to '/login'
156 assert_redirected_to '/login'
157 assert_equal 2, @request.session[:registered_user_id]
157 assert_equal 2, @request.session[:registered_user_id]
158 assert_include 'new activation email', flash[:error]
158 assert_include 'new activation email', flash[:error]
159 end
159 end
160 end
160 end
161
161
162 def test_login_should_rescue_auth_source_exception
162 def test_login_should_rescue_auth_source_exception
163 source = AuthSource.create!(:name => 'Test')
163 source = AuthSource.create!(:name => 'Test')
164 User.find(2).update_attribute :auth_source_id, source.id
164 User.find(2).update_attribute :auth_source_id, source.id
165 AuthSource.any_instance.stubs(:authenticate).raises(AuthSourceException.new("Something wrong"))
165 AuthSource.any_instance.stubs(:authenticate).raises(AuthSourceException.new("Something wrong"))
166
166
167 post :login, :username => 'jsmith', :password => 'jsmith'
167 post :login, :username => 'jsmith', :password => 'jsmith'
168 assert_response 500
168 assert_response 500
169 assert_select_error /Something wrong/
169 assert_select_error /Something wrong/
170 end
170 end
171
171
172 def test_login_should_reset_session
172 def test_login_should_reset_session
173 @controller.expects(:reset_session).once
173 @controller.expects(:reset_session).once
174
174
175 post :login, :username => 'jsmith', :password => 'jsmith'
175 post :login, :username => 'jsmith', :password => 'jsmith'
176 assert_response 302
176 assert_response 302
177 end
177 end
178
178
179 def test_get_logout_should_not_logout
179 def test_get_logout_should_not_logout
180 @request.session[:user_id] = 2
180 @request.session[:user_id] = 2
181 get :logout
181 get :logout
182 assert_response :success
182 assert_response :success
183 assert_template 'logout'
183 assert_template 'logout'
184
184
185 assert_equal 2, @request.session[:user_id]
185 assert_equal 2, @request.session[:user_id]
186 end
186 end
187
187
188 def test_get_logout_with_anonymous_should_redirect
188 def test_get_logout_with_anonymous_should_redirect
189 get :logout
189 get :logout
190 assert_redirected_to '/'
190 assert_redirected_to '/'
191 end
191 end
192
192
193 def test_logout
193 def test_logout
194 @request.session[:user_id] = 2
194 @request.session[:user_id] = 2
195 post :logout
195 post :logout
196 assert_redirected_to '/'
196 assert_redirected_to '/'
197 assert_nil @request.session[:user_id]
197 assert_nil @request.session[:user_id]
198 end
198 end
199
199
200 def test_logout_should_reset_session
200 def test_logout_should_reset_session
201 @controller.expects(:reset_session).once
201 @controller.expects(:reset_session).once
202
202
203 @request.session[:user_id] = 2
203 @request.session[:user_id] = 2
204 post :logout
204 post :logout
205 assert_response 302
205 assert_response 302
206 end
206 end
207
207
208 def test_get_register_with_registration_on
208 def test_get_register_with_registration_on
209 with_settings :self_registration => '3' do
209 with_settings :self_registration => '3' do
210 get :register
210 get :register
211 assert_response :success
211 assert_response :success
212 assert_template 'register'
212 assert_template 'register'
213 assert_not_nil assigns(:user)
213 assert_not_nil assigns(:user)
214
214
215 assert_select 'input[name=?]', 'user[password]'
215 assert_select 'input[name=?]', 'user[password]'
216 assert_select 'input[name=?]', 'user[password_confirmation]'
216 assert_select 'input[name=?]', 'user[password_confirmation]'
217 end
217 end
218 end
218 end
219
219
220 def test_get_register_should_detect_user_language
220 def test_get_register_should_detect_user_language
221 with_settings :self_registration => '3' do
221 with_settings :self_registration => '3' do
222 @request.env['HTTP_ACCEPT_LANGUAGE'] = 'fr,fr-fr;q=0.8,en-us;q=0.5,en;q=0.3'
222 @request.env['HTTP_ACCEPT_LANGUAGE'] = 'fr,fr-fr;q=0.8,en-us;q=0.5,en;q=0.3'
223 get :register
223 get :register
224 assert_response :success
224 assert_response :success
225 assert_not_nil assigns(:user)
225 assert_not_nil assigns(:user)
226 assert_equal 'fr', assigns(:user).language
226 assert_equal 'fr', assigns(:user).language
227 assert_select 'select[name=?]', 'user[language]' do
227 assert_select 'select[name=?]', 'user[language]' do
228 assert_select 'option[value=fr][selected=selected]'
228 assert_select 'option[value=fr][selected=selected]'
229 end
229 end
230 end
230 end
231 end
231 end
232
232
233 def test_get_register_with_registration_off_should_redirect
233 def test_get_register_with_registration_off_should_redirect
234 with_settings :self_registration => '0' do
234 with_settings :self_registration => '0' do
235 get :register
235 get :register
236 assert_redirected_to '/'
236 assert_redirected_to '/'
237 end
237 end
238 end
238 end
239
239
240 # See integration/account_test.rb for the full test
240 # See integration/account_test.rb for the full test
241 def test_post_register_with_registration_on
241 def test_post_register_with_registration_on
242 with_settings :self_registration => '3' do
242 with_settings :self_registration => '3' do
243 assert_difference 'User.count' do
243 assert_difference 'User.count' do
244 post :register, :user => {
244 post :register, :user => {
245 :login => 'register',
245 :login => 'register',
246 :password => 'secret123',
246 :password => 'secret123',
247 :password_confirmation => 'secret123',
247 :password_confirmation => 'secret123',
248 :firstname => 'John',
248 :firstname => 'John',
249 :lastname => 'Doe',
249 :lastname => 'Doe',
250 :mail => 'register@example.com'
250 :mail => 'register@example.com'
251 }
251 }
252 assert_redirected_to '/my/account'
252 assert_redirected_to '/my/account'
253 end
253 end
254 user = User.order('id DESC').first
254 user = User.order('id DESC').first
255 assert_equal 'register', user.login
255 assert_equal 'register', user.login
256 assert_equal 'John', user.firstname
256 assert_equal 'John', user.firstname
257 assert_equal 'Doe', user.lastname
257 assert_equal 'Doe', user.lastname
258 assert_equal 'register@example.com', user.mail
258 assert_equal 'register@example.com', user.mail
259 assert user.check_password?('secret123')
259 assert user.check_password?('secret123')
260 assert user.active?
260 assert user.active?
261 end
261 end
262 end
262 end
263
263
264 def test_post_register_with_registration_off_should_redirect
264 def test_post_register_with_registration_off_should_redirect
265 with_settings :self_registration => '0' do
265 with_settings :self_registration => '0' do
266 assert_no_difference 'User.count' do
266 assert_no_difference 'User.count' do
267 post :register, :user => {
267 post :register, :user => {
268 :login => 'register',
268 :login => 'register',
269 :password => 'test',
269 :password => 'test',
270 :password_confirmation => 'test',
270 :password_confirmation => 'test',
271 :firstname => 'John',
271 :firstname => 'John',
272 :lastname => 'Doe',
272 :lastname => 'Doe',
273 :mail => 'register@example.com'
273 :mail => 'register@example.com'
274 }
274 }
275 assert_redirected_to '/'
275 assert_redirected_to '/'
276 end
276 end
277 end
277 end
278 end
278 end
279
279
280 def test_get_lost_password_should_display_lost_password_form
280 def test_get_lost_password_should_display_lost_password_form
281 get :lost_password
281 get :lost_password
282 assert_response :success
282 assert_response :success
283 assert_select 'input[name=mail]'
283 assert_select 'input[name=mail]'
284 end
284 end
285
285
286 def test_lost_password_for_active_user_should_create_a_token
286 def test_lost_password_for_active_user_should_create_a_token
287 Token.delete_all
287 Token.delete_all
288 ActionMailer::Base.deliveries.clear
288 ActionMailer::Base.deliveries.clear
289 assert_difference 'ActionMailer::Base.deliveries.size' do
289 assert_difference 'ActionMailer::Base.deliveries.size' do
290 assert_difference 'Token.count' do
290 assert_difference 'Token.count' do
291 with_settings :host_name => 'mydomain.foo', :protocol => 'http' do
291 with_settings :host_name => 'mydomain.foo', :protocol => 'http' do
292 post :lost_password, :mail => 'JSmith@somenet.foo'
292 post :lost_password, :mail => 'JSmith@somenet.foo'
293 assert_redirected_to '/login'
293 assert_redirected_to '/login'
294 end
294 end
295 end
295 end
296 end
296 end
297
297
298 token = Token.order('id DESC').first
298 token = Token.order('id DESC').first
299 assert_equal User.find(2), token.user
299 assert_equal User.find(2), token.user
300 assert_equal 'recovery', token.action
300 assert_equal 'recovery', token.action
301
301
302 assert_select_email do
302 assert_select_email do
303 assert_select "a[href=?]", "http://mydomain.foo/account/lost_password?token=#{token.value}"
303 assert_select "a[href=?]", "http://mydomain.foo/account/lost_password?token=#{token.value}"
304 end
304 end
305 end
305 end
306
306
307 def test_lost_password_using_additional_email_address_should_send_email_to_the_address
308 EmailAddress.create!(:user_id => 2, :address => 'anotherAddress@foo.bar')
309 Token.delete_all
310
311 assert_difference 'ActionMailer::Base.deliveries.size' do
312 assert_difference 'Token.count' do
313 post :lost_password, :mail => 'ANOTHERaddress@foo.bar'
314 assert_redirected_to '/login'
315 end
316 end
317 mail = ActionMailer::Base.deliveries.last
318 assert_equal ['anotherAddress@foo.bar'], mail.bcc
319 end
320
307 def test_lost_password_for_unknown_user_should_fail
321 def test_lost_password_for_unknown_user_should_fail
308 Token.delete_all
322 Token.delete_all
309 assert_no_difference 'Token.count' do
323 assert_no_difference 'Token.count' do
310 post :lost_password, :mail => 'invalid@somenet.foo'
324 post :lost_password, :mail => 'invalid@somenet.foo'
311 assert_response :success
325 assert_response :success
312 end
326 end
313 end
327 end
314
328
315 def test_lost_password_for_non_active_user_should_fail
329 def test_lost_password_for_non_active_user_should_fail
316 Token.delete_all
330 Token.delete_all
317 assert User.find(2).lock!
331 assert User.find(2).lock!
318
332
319 assert_no_difference 'Token.count' do
333 assert_no_difference 'Token.count' do
320 post :lost_password, :mail => 'JSmith@somenet.foo'
334 post :lost_password, :mail => 'JSmith@somenet.foo'
321 assert_redirected_to '/account/lost_password'
335 assert_redirected_to '/account/lost_password'
322 end
336 end
323 end
337 end
324
338
325 def test_lost_password_for_user_who_cannot_change_password_should_fail
339 def test_lost_password_for_user_who_cannot_change_password_should_fail
326 User.any_instance.stubs(:change_password_allowed?).returns(false)
340 User.any_instance.stubs(:change_password_allowed?).returns(false)
327
341
328 assert_no_difference 'Token.count' do
342 assert_no_difference 'Token.count' do
329 post :lost_password, :mail => 'JSmith@somenet.foo'
343 post :lost_password, :mail => 'JSmith@somenet.foo'
330 assert_response :success
344 assert_response :success
331 end
345 end
332 end
346 end
333
347
334 def test_get_lost_password_with_token_should_display_the_password_recovery_form
348 def test_get_lost_password_with_token_should_display_the_password_recovery_form
335 user = User.find(2)
349 user = User.find(2)
336 token = Token.create!(:action => 'recovery', :user => user)
350 token = Token.create!(:action => 'recovery', :user => user)
337
351
338 get :lost_password, :token => token.value
352 get :lost_password, :token => token.value
339 assert_response :success
353 assert_response :success
340 assert_template 'password_recovery'
354 assert_template 'password_recovery'
341
355
342 assert_select 'input[type=hidden][name=token][value=?]', token.value
356 assert_select 'input[type=hidden][name=token][value=?]', token.value
343 end
357 end
344
358
345 def test_get_lost_password_with_invalid_token_should_redirect
359 def test_get_lost_password_with_invalid_token_should_redirect
346 get :lost_password, :token => "abcdef"
360 get :lost_password, :token => "abcdef"
347 assert_redirected_to '/'
361 assert_redirected_to '/'
348 end
362 end
349
363
350 def test_post_lost_password_with_token_should_change_the_user_password
364 def test_post_lost_password_with_token_should_change_the_user_password
351 user = User.find(2)
365 user = User.find(2)
352 token = Token.create!(:action => 'recovery', :user => user)
366 token = Token.create!(:action => 'recovery', :user => user)
353
367
354 post :lost_password, :token => token.value, :new_password => 'newpass123', :new_password_confirmation => 'newpass123'
368 post :lost_password, :token => token.value, :new_password => 'newpass123', :new_password_confirmation => 'newpass123'
355 assert_redirected_to '/login'
369 assert_redirected_to '/login'
356 user.reload
370 user.reload
357 assert user.check_password?('newpass123')
371 assert user.check_password?('newpass123')
358 assert_nil Token.find_by_id(token.id), "Token was not deleted"
372 assert_nil Token.find_by_id(token.id), "Token was not deleted"
359 end
373 end
360
374
361 def test_post_lost_password_with_token_for_non_active_user_should_fail
375 def test_post_lost_password_with_token_for_non_active_user_should_fail
362 user = User.find(2)
376 user = User.find(2)
363 token = Token.create!(:action => 'recovery', :user => user)
377 token = Token.create!(:action => 'recovery', :user => user)
364 user.lock!
378 user.lock!
365
379
366 post :lost_password, :token => token.value, :new_password => 'newpass123', :new_password_confirmation => 'newpass123'
380 post :lost_password, :token => token.value, :new_password => 'newpass123', :new_password_confirmation => 'newpass123'
367 assert_redirected_to '/'
381 assert_redirected_to '/'
368 assert ! user.check_password?('newpass123')
382 assert ! user.check_password?('newpass123')
369 end
383 end
370
384
371 def test_post_lost_password_with_token_and_password_confirmation_failure_should_redisplay_the_form
385 def test_post_lost_password_with_token_and_password_confirmation_failure_should_redisplay_the_form
372 user = User.find(2)
386 user = User.find(2)
373 token = Token.create!(:action => 'recovery', :user => user)
387 token = Token.create!(:action => 'recovery', :user => user)
374
388
375 post :lost_password, :token => token.value, :new_password => 'newpass', :new_password_confirmation => 'wrongpass'
389 post :lost_password, :token => token.value, :new_password => 'newpass', :new_password_confirmation => 'wrongpass'
376 assert_response :success
390 assert_response :success
377 assert_template 'password_recovery'
391 assert_template 'password_recovery'
378 assert_not_nil Token.find_by_id(token.id), "Token was deleted"
392 assert_not_nil Token.find_by_id(token.id), "Token was deleted"
379
393
380 assert_select 'input[type=hidden][name=token][value=?]', token.value
394 assert_select 'input[type=hidden][name=token][value=?]', token.value
381 end
395 end
382
396
383 def test_post_lost_password_with_invalid_token_should_redirect
397 def test_post_lost_password_with_invalid_token_should_redirect
384 post :lost_password, :token => "abcdef", :new_password => 'newpass', :new_password_confirmation => 'newpass'
398 post :lost_password, :token => "abcdef", :new_password => 'newpass', :new_password_confirmation => 'newpass'
385 assert_redirected_to '/'
399 assert_redirected_to '/'
386 end
400 end
387
401
388 def test_activation_email_should_send_an_activation_email
402 def test_activation_email_should_send_an_activation_email
389 User.find(2).update_attribute :status, User::STATUS_REGISTERED
403 User.find(2).update_attribute :status, User::STATUS_REGISTERED
390 @request.session[:registered_user_id] = 2
404 @request.session[:registered_user_id] = 2
391
405
392 with_settings :self_registration => '1' do
406 with_settings :self_registration => '1' do
393 assert_difference 'ActionMailer::Base.deliveries.size' do
407 assert_difference 'ActionMailer::Base.deliveries.size' do
394 get :activation_email
408 get :activation_email
395 assert_redirected_to '/login'
409 assert_redirected_to '/login'
396 end
410 end
397 end
411 end
398 end
412 end
399
413
400 def test_activation_email_without_session_data_should_fail
414 def test_activation_email_without_session_data_should_fail
401 User.find(2).update_attribute :status, User::STATUS_REGISTERED
415 User.find(2).update_attribute :status, User::STATUS_REGISTERED
402
416
403 with_settings :self_registration => '1' do
417 with_settings :self_registration => '1' do
404 assert_no_difference 'ActionMailer::Base.deliveries.size' do
418 assert_no_difference 'ActionMailer::Base.deliveries.size' do
405 get :activation_email
419 get :activation_email
406 assert_redirected_to '/'
420 assert_redirected_to '/'
407 end
421 end
408 end
422 end
409 end
423 end
410 end
424 end
General Comments 0
You need to be logged in to leave comments. Login now