aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--app/controllers/user_controller.rb36
-rw-r--r--app/models/change_email_validator.rb42
-rw-r--r--app/models/user.rb10
-rw-r--r--app/views/user/show.rhtml3
-rw-r--r--app/views/user/signchangeemail.rhtml42
-rw-r--r--app/views/user/signchangepassword.rhtml2
-rw-r--r--config/routes.rb1
-rw-r--r--spec/controllers/user_controller_spec.rb70
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