users: sign-in after confirming an account within a short time

This commit is contained in:
Pierre de La Morinerie 2018-11-06 10:22:17 +00:00
parent 0fb9c123c9
commit b0541fba79
8 changed files with 111 additions and 13 deletions

View file

@ -145,6 +145,8 @@ group :test do
gem 'capybara-selenium'
# Save a dump of the page when an integration test fails
gem 'capybara-screenshot'
# Access emails during integration tests
gem 'capybara-email'
end
group :development do

View file

@ -120,6 +120,9 @@ GEM
rack (>= 1.0.0)
rack-test (>= 0.5.4)
xpath (>= 2.0, < 4.0)
capybara-email (3.0.1)
capybara (>= 2.4, < 4.0)
mail
capybara-screenshot (1.0.21)
capybara (>= 1.0, < 4)
launchy
@ -812,6 +815,7 @@ DEPENDENCIES
browser
byebug
capybara
capybara-email
capybara-screenshot
capybara-selenium
carrierwave

View file

@ -25,8 +25,24 @@ class Users::ConfirmationsController < Devise::ConfirmationsController
# super(resource_name)
# end
# If the user clicks the confirmation link before the maximum delay,
# they will be signed in directly.
def sign_in_after_confirmation?(resource)
# Avoid keeping auto-sign-in links in users inboxes for too long.
# 95% of users confirm their account within two hours.
auto_sign_in_timeout = 2.hours
resource.confirmation_sent_at + auto_sign_in_timeout > DateTime.current
end
# The path used after confirmation.
# def after_confirmation_path_for(resource_name, resource)
# super(resource_name, resource)
# end
def after_confirmation_path_for(resource_name, resource)
if sign_in_after_confirmation?(resource)
resource.remember_me = true
sign_in(resource)
resource.force_sync_credentials
after_sign_in_path_for(resource_name)
else
super(resource_name, resource)
end
end
end

View file

@ -0,0 +1,57 @@
require 'spec_helper'
describe Users::ConfirmationsController, type: :controller do
let!(:user) { create(:user, :unconfirmed) }
let(:confirmation_token) { user.confirmation_token }
before do
@request.env["devise.mapping"] = Devise.mappings[:user]
end
describe '#show' do
context 'when confirming within the auto-sign-in delay' do
before do
Timecop.travel(1.hour.from_now) {
get :show, params: { confirmation_token: confirmation_token }
}
end
it 'confirms the user' do
expect(user.reload).to be_confirmed
end
it 'signs in the user after confirming its token' do
expect(controller.current_user).to eq(user)
expect(controller.current_gestionnaire).to be(nil)
expect(controller.current_administrateur).to be(nil)
end
it 'redirects the user to the root page' do
# NB: the root page may redirect the user again to the stored procedure path
expect(controller).to redirect_to(root_path)
end
end
context 'when the auto-sign-in delay has expired' do
before do
Timecop.travel(3.hours.from_now) {
get :show, params: { confirmation_token: confirmation_token }
}
end
it 'confirms the user' do
expect(user.reload).to be_confirmed
end
it 'doesnt sign in the user' do
expect(subject.current_user).to be(nil)
expect(subject.current_gestionnaire).to be(nil)
expect(subject.current_administrateur).to be(nil)
end
it 'redirects the user to the sign-in path' do
expect(subject).to redirect_to(new_user_session_path)
end
end
end
end

View file

@ -4,5 +4,9 @@ FactoryBot.define do
email { generate(:user_email) }
password { 'password' }
confirmed_at { Time.zone.now }
trait :unconfirmed do
confirmed_at { nil }
end
end
end

View file

@ -32,21 +32,17 @@ feature 'Invitations' do
scenario 'an invited user can register using the registration link sent in the invitation email' do
# Click the invitation link
visit users_dossiers_invite_path(invite.id, params: { email: invite.email })
# Create the account
expect(page).to have_current_path(new_user_registration_path, ignore_query: true)
expect(page).to have_field('user_email', with: invite.email)
fill_in 'user_password', with: user_password
click_on 'Créer un compte'
# Create the account
sign_up_with invite.email, user_password
expect(page).to have_content("lien d'activation")
# Confirm the email
user = User.find_by(email: invite.email)
visit Rails.application.routes.url_helpers.user_confirmation_path(confirmation_token: user.confirmation_token)
submit_login_form(user.email, user_password)
# The user should be redirected to the dossier they was invited on
# Confirm the account
# (The user should be redirected to the dossier they was invited on)
click_confirmation_link_for invite.email
expect(page).to have_content('Votre compte a été activé')
expect(page).to have_current_path(brouillon_dossier_path(dossier))
end
end

View file

@ -23,6 +23,7 @@ require File.expand_path('../config/environment', __dir__)
require 'rspec/rails'
require 'capybara/rspec'
require 'capybara-screenshot/rspec'
require 'capybara/email/rspec'
require 'database_cleaner'
require 'webmock/rspec'
require 'shoulda-matchers'

View file

@ -1,4 +1,6 @@
module FeatureHelpers
include ActiveJob::TestHelper
def login_admin
user = create :user
login_as user, scope: :user
@ -20,6 +22,22 @@ module FeatureHelpers
fill_in :user_password, with: password
click_on 'Se connecter'
end
def sign_up_with(email, password = 'testpassword')
fill_in :user_email, with: email
fill_in :user_password, with: password
perform_enqueued_jobs do
click_button 'Créer un compte'
end
end
def click_confirmation_link_for(email)
confirmation_email = open_email(email)
token_params = confirmation_email.body.match(/confirmation_token=[^"]+/)
visit "/users/confirmation?#{token_params}"
end
end
RSpec.configure do |config|