From b36856a3a12cf4a1d09a1756e07bbb69124e18ad Mon Sep 17 00:00:00 2001 From: "Carlos A. da Silva" Date: Thu, 8 Oct 2009 00:53:04 -0300 Subject: [PATCH] Creating confirmation controller and integration tests. --- app/controllers/confirmations_controller.rb | 26 +++++++++ app/views/confirmations/new.html.erb | 11 ++++ app/views/sessions/new.html.erb | 1 + config/routes.rb | 1 + lib/devise/models/confirmable.rb | 28 +++++++--- test/integration/confirmation_test.rb | 60 +++++++++++++++++++++ test/models/confirmable_test.rb | 33 ++++++++++++ 7 files changed, 153 insertions(+), 7 deletions(-) create mode 100644 app/controllers/confirmations_controller.rb create mode 100644 app/views/confirmations/new.html.erb create mode 100644 test/integration/confirmation_test.rb diff --git a/app/controllers/confirmations_controller.rb b/app/controllers/confirmations_controller.rb new file mode 100644 index 00000000..72c4814a --- /dev/null +++ b/app/controllers/confirmations_controller.rb @@ -0,0 +1,26 @@ +class ConfirmationsController < ApplicationController + before_filter :require_no_authentication + + def new + end + + def create + @confirmation = User.send_confirmation_instructions(params[:confirmation]) + if @confirmation.errors.empty? + flash[:notice] = 'You will receive an email with instructions about how to confirm your account in a few minutes.' + redirect_to root_path + else + render :new + end + end + + def show + @confirmation = User.confirm!(:perishable_token => params[:perishable_token]) + if @confirmation.errors.empty? + flash[:notice] = 'Your account was successfully confirmed!' + redirect_to root_path + else + render :new + end + end +end diff --git a/app/views/confirmations/new.html.erb b/app/views/confirmations/new.html.erb new file mode 100644 index 00000000..f164a60a --- /dev/null +++ b/app/views/confirmations/new.html.erb @@ -0,0 +1,11 @@ +

Resend confirmation instructions

+ +<%= error_messages_for :confirmation %> + +<% form_for :confirmation, :url => confirmation_path do |f| %> +

<%= f.label :email %>

+

<%= f.text_field :email %>

+

<%= f.submit "Resend confirmation instructions" %>

+<% end %> + +<%= link_to 'Sign in', new_session_path %> diff --git a/app/views/sessions/new.html.erb b/app/views/sessions/new.html.erb index 123db779..af93703a 100644 --- a/app/views/sessions/new.html.erb +++ b/app/views/sessions/new.html.erb @@ -11,3 +11,4 @@ <% end -%> <%= link_to "Forgot password?", new_password_path %> +<%= link_to "Didn't receive confirmation instructions?", new_confirmation_path %> diff --git a/config/routes.rb b/config/routes.rb index 17fcb81b..0161be06 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,4 +1,5 @@ ActionController::Routing::Routes.draw do |map| map.resource :session, :only => [:new, :create, :destroy] map.resource :password, :only => [:new, :create, :edit, :update] + map.resource :confirmation, :only => [:new, :create, :show] end diff --git a/lib/devise/models/confirmable.rb b/lib/devise/models/confirmable.rb index 42f99874..acc2fdee 100644 --- a/lib/devise/models/confirmable.rb +++ b/lib/devise/models/confirmable.rb @@ -29,13 +29,12 @@ module Devise !new_record? && confirmed_at? end - private - - # Send confirmation instructions by email - # - def send_confirmation_instructions - ::Notifier.deliver_confirmation_instructions(self) - end + # Send confirmation instructions by email + # + def send_confirmation_instructions + reset_perishable_token! + ::Notifier.deliver_confirmation_instructions(self) + end module ClassMethods @@ -47,6 +46,21 @@ module Devise confirmable if confirmable.confirmed? unless confirmable.nil? end + # Attempt to find a user by it's email. If a record is found, send new + # confirmation instructions to it. If not user is found, returns a new user + # with an email not found error. + # Options must contain the user email + # + def send_confirmation_instructions(options={}) + confirmable = find_or_initialize_by_email(options[:email]) + unless confirmable.new_record? + confirmable.send_confirmation_instructions + else + confirmable.errors.add(:email, :not_found, :default => 'not found') + end + confirmable + end + # Find a user by it's confirmation token and try to confirm it. # If no user is found, returns a new user # If the user is already confirmed, create an error for the user diff --git a/test/integration/confirmation_test.rb b/test/integration/confirmation_test.rb new file mode 100644 index 00000000..518aa499 --- /dev/null +++ b/test/integration/confirmation_test.rb @@ -0,0 +1,60 @@ +require 'test_helper' + +class ConfirmationsTest < ActionController::IntegrationTest + + test 'authenticated user should not be able to visit confirmation page' do + sign_in + + get new_confirmation_path + + assert_response :redirect + assert_redirected_to root_path + assert warden.authenticated? + end + + test 'not authenticated user should be able to request a new confirmation' do + user = create_user + + visit '/session/new' + click_link 'Didn\'t receive confirmation instructions?' + + fill_in 'email', :with => user.email + click_button 'Resend confirmation instructions' + +# assert_response :redirect +# assert_redirected_to root_path + assert_template 'sessions/new' + assert_contain 'You will receive an email with instructions about how to confirm your account in a few minutes' + end + + test 'not authenticated user with invalid perishable token should not be able to confirm an account' do + visit confirmation_path(:perishable_token => 'invalid_perishable') + + assert_response :success + assert_template 'confirmations/new' + assert_have_selector '#errorExplanation' + assert_contain 'invalid confirmation' + end + + test 'not authenticated user with valid perishable token should be able to confirm an account' do + user = create_user(:confirm => false) + assert_not user.confirmed? + + visit confirmation_path(:perishable_token => user.perishable_token) + +# assert_response :redirect + assert_template 'sessions/new' + assert_contain 'Your account was successfully confirmed!' + + assert user.reload.confirmed? + end + + test 'already confirmed user should not be able to confirm the account again' do + user = create_user + visit confirmation_path(:perishable_token => user.perishable_token) + + assert_template 'confirmations/new' + assert_have_selector '#errorExplanation' + assert_contain 'already confirmed' + end +end diff --git a/test/models/confirmable_test.rb b/test/models/confirmable_test.rb index 2f874a67..9a5f9acc 100644 --- a/test/models/confirmable_test.rb +++ b/test/models/confirmable_test.rb @@ -88,4 +88,37 @@ class ConfirmableTest < ActiveSupport::TestCase user.save end end + + test 'should find a user to send confirmation instructions' do + user = create_user + confirmation_user = User.send_confirmation_instructions(:email => user.email) + assert_not_nil confirmation_user + assert_equal confirmation_user, user + end + + test 'should return a new user if no email was found' do + confirmation_user = User.send_confirmation_instructions(:email => "invalid@email.com") + assert_not_nil confirmation_user + assert confirmation_user.new_record? + end + + test 'should add error to new user email if no email was found' do + confirmation_user = User.send_confirmation_instructions(:email => "invalid@email.com") + assert confirmation_user.errors[:email] + assert_equal 'not found', confirmation_user.errors[:email] + end + + test 'should reset perishable token before send the confirmation instructions email' do + user = create_user + token = user.perishable_token + confirmation_user = User.send_confirmation_instructions(:email => user.email) + assert_not_equal token, user.reload.perishable_token + end + + test 'should send email instructions for the user confirm it\'s email' do + user = create_user + assert_email_sent do + User.send_confirmation_instructions(:email => user.email) + end + end end