diff options
-rw-r--r-- | app/controllers/user_controller.rb | 36 | ||||
-rw-r--r-- | app/models/change_email_validator.rb | 42 | ||||
-rw-r--r-- | app/models/user.rb | 10 | ||||
-rw-r--r-- | app/views/user/show.rhtml | 3 | ||||
-rw-r--r-- | app/views/user/signchangeemail.rhtml | 42 | ||||
-rw-r--r-- | app/views/user/signchangepassword.rhtml | 2 | ||||
-rw-r--r-- | config/routes.rb | 1 | ||||
-rw-r--r-- | spec/controllers/user_controller_spec.rb | 70 |
8 files changed, 200 insertions, 6 deletions
diff --git a/app/controllers/user_controller.rb b/app/controllers/user_controller.rb index 7e942f32f..ec0afc214 100644 --- a/app/controllers/user_controller.rb +++ b/app/controllers/user_controller.rb @@ -147,10 +147,13 @@ class UserController < ApplicationController end # Logout form - def signout + def _do_signout session[:user_id] = nil session[:user_circumstance] = nil session[:remember_me] = false + end + def signout + self._do_signout if params[:r] redirect_to params[:r] else @@ -225,6 +228,37 @@ class UserController < ApplicationController end end + # Change your email + def signchangeemail + if not authenticated?( + :web => "To change your email address", + :email => "Then you can change your email address", + :email_subject => "Change your email address" + ) + # "authenticated?" has done the redirect to signin page for us + return + end + + work_out_post_redirect + + if params[:submitted_signchangeemail_do] + @signchangeemail = ChangeEmailValidator.new(params[:signchangeemail]) + @signchangeemail.logged_in_user = @user + + if @signchangeemail.valid? + @user.email = @signchangeemail.new_email + @user.email_confirmed = false + @user.save! + self._do_signout + flash[:notice] = "Your email has been changed." + send_confirmation_mail @user + return + end + end + + render :action => 'signchangeemail' + end + # Send a message to another user def contact @recipient_user = User.find(params[:id]) diff --git a/app/models/change_email_validator.rb b/app/models/change_email_validator.rb new file mode 100644 index 000000000..a796489f7 --- /dev/null +++ b/app/models/change_email_validator.rb @@ -0,0 +1,42 @@ +# models/changeemail_validator.rb: +# Validates email change form submissions. +# +# Copyright (c) 2010 UK Citizens Online Democracy. All rights reserved. +# Email: francis@mysociety.org; WWW: http://www.mysociety.org/ +# +# $Id: contact_validator.rb,v 1.32 2009-09-17 21:10:05 francis Exp $ + +class ChangeEmailValidator < ActiveRecord::BaseWithoutTable + strip_attributes! + + column :old_email, :string + column :new_email, :string + column :password, :string + + attr_accessor :logged_in_user + + validates_presence_of :old_email, :message => "^Please enter your old email address" + validates_presence_of :new_email, :message => "^Please enter your new email address" + validates_presence_of :password, :message => "^Please enter your password" + + def validate + if !self.old_email.blank? && !MySociety::Validate.is_valid_email(self.old_email) + errors.add(:old_email, "doesn't look like a valid address") + end + + if !errors[:old_email] + if self.old_email != self.logged_in_user.email + errors.add(:old_email, "address isn't the same as the address of the account you are logged in with") + elsif !self.logged_in_user.has_this_password?(self.password) + if !errors[:password] + errors.add(:password, "is not correct") + end + end + end + + if !self.new_email.blank? && !MySociety::Validate.is_valid_email(self.new_email) + errors.add(:new_email, "doesn't look like a valid address") + end + end + +end diff --git a/app/models/user.rb b/app/models/user.rb index e0698a47f..b27677d6e 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -134,8 +134,7 @@ class User < ActiveRecord::Base user = self.find_user_by_email(params[:email]) if user # There is user with email, check password - expected_password = encrypted_password(params[:password], user.salt) - if user.hashed_password != expected_password + if !user.has_this_password?(params[:password]) user.errors.add_to_base(auth_fail_message) end else @@ -184,7 +183,12 @@ class User < ActiveRecord::Base self.hashed_password = User.encrypted_password(self.password, self.salt) end - # For use in to/from in email messages + def has_this_password?(password) + expected_password = User.encrypted_password(password, self.salt) + return self.hashed_password == expected_password + end + +# For use in to/from in email messages def name_and_email return TMail::Address.address_from_name_and_email(self.name, self.email).to_s end diff --git a/app/views/user/show.rhtml b/app/views/user/show.rhtml index 2f9ecbcde..166b005d4 100644 --- a/app/views/user/show.rhtml +++ b/app/views/user/show.rhtml @@ -50,7 +50,8 @@ <%= link_to "Send message to " + h(@display_user.name), contact_user_url(:id => @display_user.id) %> <% if @is_you %> (just to see how it works) - <br><%= link_to "Change your password", signchangepassword_url() %> + <br><%= link_to "Change your password", signchangepassword_url() %> | + <%= link_to "Change your email", signchangeemail_url(:r => request.request_uri) %> <% end %> </p> diff --git a/app/views/user/signchangeemail.rhtml b/app/views/user/signchangeemail.rhtml new file mode 100644 index 000000000..2d9b15895 --- /dev/null +++ b/app/views/user/signchangeemail.rhtml @@ -0,0 +1,42 @@ +<% @title = "Change your email address" %> + +<% raise "internal error" if not @user %> + +<div id="change_email"> + +<% form_tag({:action => "signchangeemail"}, {:id => "signchangeemail_form"}) do %> + <%= foi_error_messages_for :signchangeemail %> + + <div class="form_note"> + <h1>Change your email address</h1> + </div> + + <p> + <label class="form_label" for="signchangeemail_old_email">Old e-mail:</label> + <%= text_field 'signchangeemail', 'old_email', { :size => 20 } %> + </p> + + <p> + <label class="form_label" for="signchangeemail_new_email">New e-mail:</label> + <%= text_field 'signchangeemail', 'new_email', { :size => 20 } %> + </p> + + <p> + <label class="form_label" for="signchangeemail_password">Your password:</label> + <%= password_field 'signchangeemail', 'password', { :size => 15 } %> + </p> + + <p class="form_note"> + <strong>Note:</strong> + We will send an email to your new email address, which you must follow the + link in to confirm, before you can use the account again. + </p> + + <div class="form_button"> + <%= hidden_field_tag 'submitted_signchangeemail_do', 1 %> + <%= hidden_field_tag 'token', params[:token], { :id => 'signin_token' } %> + <%= submit_tag "Change email" %> + </div> +<% end %> + +</div> diff --git a/app/views/user/signchangepassword.rhtml b/app/views/user/signchangepassword.rhtml index 28a63709c..11dc987ee 100644 --- a/app/views/user/signchangepassword.rhtml +++ b/app/views/user/signchangepassword.rhtml @@ -1,4 +1,4 @@ -<% @title = "Change password" %> +<% @title = "Change your password" %> <% raise "internal error" if not @user %> diff --git a/config/routes.rb b/config/routes.rb index 2b849a6e1..78252df91 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -57,6 +57,7 @@ ActionController::Routing::Routes.draw do |map| user.signup '/signup', :action => 'signup' user.signout '/signout', :action => 'signout' user.signchangepassword '/signchangepassword', :action => 'signchangepassword' + user.signchangeemail '/signchangeemail', :action => 'signchangeemail' user.confirm '/c/:email_token', :action => 'confirm' user.show_user '/user/:url_name', :action => 'show' user.contact_user '/user/contact/:id', :action => 'contact' diff --git a/spec/controllers/user_controller_spec.rb b/spec/controllers/user_controller_spec.rb index 29658f085..81333843a 100644 --- a/spec/controllers/user_controller_spec.rb +++ b/spec/controllers/user_controller_spec.rb @@ -290,6 +290,76 @@ describe UserController, "when changing password" do end +describe UserController, "when changing email address" do + integrate_views + fixtures :users + + it "should require login" do + get :signchangeemail + + post_redirect = PostRedirect.get_last_post_redirect + response.should redirect_to(:controller => 'user', :action => 'signin', :token => post_redirect.token) + end + + it "should show form for changing email if logged in" do + session[:user_id] = users(:silly_name_user).id + get :signchangeemail + + response.should render_template('signchangeemail') + end + + it "should be an error if the password is wrong, everything else right" do + @user = users(:silly_name_user) + session[:user_id] = @user.id + + post :signchangeemail, { :signchangeemail => { :old_email => 'silly@localhost', + :password => 'donotknowpassword', :new_email => 'newsilly@localhost' }, + :submitted_signchangeemail_do => 1 + } + + @user.reload + @user.email.should == 'silly@localhost' + response.should render_template('signchangeemail') + assigns[:signchangeemail].errors[:password].should_not be_nil + end + + it "should be an error if old email is wrong, everything else right" do + @user = users(:silly_name_user) + session[:user_id] = @user.id + + post :signchangeemail, { :signchangeemail => { :old_email => 'silly@moo', + :password => 'jonespassword', :new_email => 'newsilly@localhost' }, + :submitted_signchangeemail_do => 1 + } + + @user.reload + @user.email.should == 'silly@localhost' + response.should render_template('signchangeemail') + assigns[:signchangeemail].errors[:old_email].should_not be_nil + end + + it "should change your email if you get all the details right, and require confirmation" do + @user = users(:silly_name_user) + session[:user_id] = @user.id + + post :signchangeemail, { :signchangeemail => { :old_email => 'silly@localhost', + :password => 'jonespassword', :new_email => 'newsilly@localhost' }, + :submitted_signchangeemail_do => 1 + } + + @user.reload + @user.email.should == 'newsilly@localhost' + @user.email_confirmed.should == false + + response.flash[:notice].should include('Your email has been changed') + response.should render_template('confirm') + deliveries = ActionMailer::Base.deliveries + deliveries.size.should == 1 + deliveries[0].body.should include("not reveal your email") + end + + +end |