Commit 94d199c1da9865092f83bc170d9fc9aac6bd30d0

Authored by AntonioTerceiro
1 parent abd673e1

ActionItem78: implementing password recovery



git-svn-id: https://svn.colivre.coop.br/svn/noosfero/trunk@640 3f533792-8f58-4932-b0fe-aaf55b0a4547
app/controllers/public/account_controller.rb
... ... @@ -70,19 +70,43 @@ class AccountController < PublicController
70 70 end
71 71 end
72 72  
73   - # posts back
  73 + # The user requests a password change. She forgot her old password.
  74 + #
  75 + # Posts back.
74 76 def forgot_password
75 77 @change_password = ChangePassword.new(params[:change_password])
76 78 if request.post?
77 79 begin
78   - @change_password.confirm!
  80 + @change_password.save!
79 81 render :action => 'password_recovery_sent'
80   - rescue Exception => e
  82 + rescue ActiveRecord::RecordInvalid => e
81 83 nil # just pass and render at the end of the action
82 84 end
83 85 end
84 86 end
85 87  
  88 + # The user has a code for a ChangePassword request object.
  89 + #
  90 + # Posts back.
  91 + def new_password
  92 + @change_password = ChangePassword.find_by_code(params[:code])
  93 +
  94 + unless @change_password
  95 + render :action => 'invalid_change_password_code'
  96 + return
  97 + end
  98 +
  99 + if request.post?
  100 + begin
  101 + @change_password.update_attributes!(params[:change_password])
  102 + @change_password.finish
  103 + render :action => 'new_password_ok'
  104 + rescue ActiveRecord::RecordInvalid => e
  105 + nil # just render new_password
  106 + end
  107 + end
  108 + end
  109 +
86 110 protected
87 111  
88 112 before_filter :load_profile_for_user
... ...
app/models/change_password.rb
... ... @@ -8,12 +8,18 @@ class ChangePassword < Task
8 8 end
9 9  
10 10 attr_accessor :login, :email, :password, :password_confirmation
  11 + N_('ChangePassword|Login')
  12 + N_('ChangePassword|Email')
  13 + N_('ChangePassword|Password')
  14 + N_('ChangePassword|Password Confirmation')
11 15  
12 16 ###################################################
13 17 # validations for creating a ChangePassword task
14 18  
15 19 validates_presence_of :login, :email, :on => :create
16 20  
  21 + validates_presence_of :requestor_id
  22 +
17 23 validates_format_of :email, :on => :create, :with => Noosfero::Constants::EMAIL_FORMAT, :if => (lambda { |obj| !obj.email.blank? })
18 24  
19 25 validates_each :login, :on => :create do |data,attr,value|
... ... @@ -29,7 +35,7 @@ class ChangePassword < Task
29 35 end
30 36 end
31 37  
32   - before_create do |change_password|
  38 + before_validation_on_create do |change_password|
33 39 change_password.requestor = Person.find_by_identifier(change_password.login)
34 40 end
35 41  
... ... @@ -47,7 +53,7 @@ class ChangePassword < Task
47 53 end
48 54  
49 55 def perform
50   - user = User.find_by_login(self.login)
  56 + user = self.requestor.user
51 57 user.force_change_password!(self.password, self.password_confirmation)
52 58 end
53 59  
... ...
app/views/account/new_password.rhtml 0 → 100644
... ... @@ -0,0 +1,11 @@
  1 +<h2><%= _('Enter new password') %></h2>
  2 +
  3 +<%= error_messages_for :change_password %>
  4 +
  5 +<% form_for(:change_password) do |f| %>
  6 +
  7 + <%= labelled_form_field(_('Enter new password'), (f.password_field :password)) %>
  8 + <%= labelled_form_field(_('Confirm the new password'), (f.password_field :password_confirmation)) %>
  9 + <%= submit_tag _('Change password') %>
  10 +
  11 +<% end %>
... ...
app/views/account/new_password_ok.rhtml 0 → 100644
... ... @@ -0,0 +1,9 @@
  1 +<h2><%= _('Password changed sucessfully') %></h2>
  2 +
  3 +<p>
  4 +<%= _('%s, your new password was successfully installed.') % @change_password.requestor.identifier %>
  5 +</p>
  6 +
  7 +<p>
  8 +<%= _("You can <a href='%s'>login</a> now.") % url_for(:action => 'login') %>
  9 +</p>
... ...
app/views/account/password_recovery_sent.rhtml 0 → 100644
... ... @@ -0,0 +1,5 @@
  1 +<h2><%= _('Password recovery') %></h2>
  2 +
  3 +<p>
  4 +<%= _('An e-mail was just sent to your e-mail address, with instructions for changing your password. You should receive it in a few minutes.') %>
  5 +</p>
... ...
test/functional/account_controller_test.rb
... ... @@ -183,11 +183,43 @@ class AccountControllerTest &lt; Test::Unit::TestCase
183 183 end
184 184  
185 185 should 'respond to forgotten password change request' do
186   - flunk 'not implemented yet'
  186 + change = ChangePassword.new
  187 + ChangePassword.expects(:new).returns(change)
  188 + change.expects(:save!).returns(true)
  189 +
  190 + post :forgot_password
  191 + assert_template 'password_recovery_sent'
  192 + end
  193 +
  194 + should 'provide interface for entering new password' do
  195 + change = ChangePassword.new
  196 + ChangePassword.expects(:find_by_code).with('osidufgiashfkjsadfhkj99999').returns(change)
  197 +
  198 + get :new_password, :code => 'osidufgiashfkjsadfhkj99999'
  199 + assert_equal change, assigns(:change_password)
187 200 end
188 201  
189   - should 'provide interface for entering new password to replace forgotten one' do
190   - flunk 'not implemented yet'
  202 + should 'actually change password after entering new password' do
  203 + change = ChangePassword.new
  204 + ChangePassword.expects(:find_by_code).with('osidufgiashfkjsadfhkj99999').returns(change)
  205 +
  206 + requestor = mock
  207 + requestor.stubs(:identifier).returns('joe')
  208 + change.stubs(:requestor).returns(requestor)
  209 + change.expects(:update_attributes!).with({'password' => 'newpass', 'password_confirmation' => 'newpass'})
  210 + change.expects(:finish)
  211 +
  212 + post :new_password, :code => 'osidufgiashfkjsadfhkj99999', :change_password => { :password => 'newpass', :password_confirmation => 'newpass' }
  213 +
  214 + assert_template 'new_password_ok'
  215 + end
  216 +
  217 + should 'require a valid change_password code' do
  218 + ChangePassword.destroy_all
  219 +
  220 + assert_raise RuntimeError do
  221 + get :new_password, :code => 'dontexist'
  222 + end
191 223 end
192 224  
193 225 protected
... ...
test/unit/change_password_test.rb
... ... @@ -74,21 +74,18 @@ class ChangePasswordTest &lt; Test::Unit::TestCase
74 74  
75 75 should 'actually change password' do
76 76 User.destroy_all
77   - User.create!(:login => 'testuser', :password => 'test', :password_confirmation => 'test', :email => 'test@example.com')
  77 + person = User.create!(:login => 'testuser', :password => 'test', :password_confirmation => 'test', :email => 'test@example.com').person
78 78  
79 79 change = ChangePassword.new
80 80 change.login = 'testuser'
81 81 change.email = 'test@example.com'
82 82 change.save!
83 83  
84   - user = User.new
85   - User.expects(:find_by_login).with('testuser').returns(user)
86   - user.expects(:force_change_password!).with('newpass', 'newpass')
  84 + change.expects(:requestor).returns(person).at_least_once
87 85  
88 86 change.password = 'newpass'
89 87 change.password_confirmation = 'newpass'
90 88 change.finish
91   -
92 89 end
93 90  
94 91 end
... ...