mailers: add procedure context to the confirmation link

This allows to redirect the user to the procedure they signed up for
even when the browser session is not available (like if they changed
of browser).

Fix #4738
This commit is contained in:
Pierre de La Morinerie 2020-02-24 10:55:29 +00:00 committed by GitHub Action
parent 10c940c188
commit 6664965961
8 changed files with 50 additions and 5 deletions

View file

@ -42,9 +42,19 @@ class Users::ConfirmationsController < Devise::ConfirmationsController
if sign_in_after_confirmation?(resource) if sign_in_after_confirmation?(resource)
resource.remember_me = true resource.remember_me = true
sign_in(resource) sign_in(resource)
end
if procedure_from_params
commencer_path(path: procedure_from_params.path)
elsif signed_in?
# Will try to use `stored_location_for` to find a path
after_sign_in_path_for(resource_name) after_sign_in_path_for(resource_name)
else else
super(resource_name, resource) super(resource_name, resource)
end end
end end
def procedure_from_params
params[:procedure_id] && Procedure.find_by(id: params[:procedure_id])
end
end end

View file

@ -21,6 +21,12 @@ class Users::RegistrationsController < Devise::RegistrationsController
# POST /resource # POST /resource
def create def create
# We may need the confirmation mailer to access the current procedure.
# But there's no easy way to pass an argument to the mailer through
# all Devise code.
# So instead we use a per-request global variable.
CurrentConfirmation.procedure_after_confirmation = @procedure
# Handle existing user trying to sign up again # Handle existing user trying to sign up again
existing_user = User.find_by(email: params[:user][:email]) existing_user = User.find_by(email: params[:user][:email])
if existing_user.present? if existing_user.present?

View file

@ -15,6 +15,7 @@ class DeviseUserMailer < Devise::Mailer
def confirmation_instructions(record, token, opts = {}) def confirmation_instructions(record, token, opts = {})
opts[:from] = NO_REPLY_EMAIL opts[:from] = NO_REPLY_EMAIL
@procedure = CurrentConfirmation.procedure_after_confirmation || nil
super super
end end
end end

View file

@ -0,0 +1,3 @@
class CurrentConfirmation < ActiveSupport::CurrentAttributes
attribute :procedure_after_confirmation
end

View file

@ -7,7 +7,8 @@
%p %p
Pour activer votre compte sur demarches-simplifiees.fr, veuillez cliquer sur le lien suivant : Pour activer votre compte sur demarches-simplifiees.fr, veuillez cliquer sur le lien suivant :
= link_to(confirmation_url(@user, confirmation_token: @token), confirmation_url(@user, confirmation_token: @token)) - link = confirmation_url(@user, confirmation_token: @token, procedure_id: @procedure&.id)
= link_to(link, link)
- else - else
- content_for(:title, "Changement d'adresse email") - content_for(:title, "Changement d'adresse email")

View file

@ -77,8 +77,10 @@ feature 'Signing up:' do
sign_up_with user_email, user_password sign_up_with user_email, user_password
expect(page).to have_content "nous avons besoin de vérifier votre adresse #{user_email}" expect(page).to have_content "nous avons besoin de vérifier votre adresse #{user_email}"
click_confirmation_link_for user_email click_confirmation_link_for(user_email, in_another_browser: true)
# After confirmation, the user is redirected to the procedure they were initially starting
# (even when confirming the account in another browser).
expect(page).to have_current_path(commencer_path(path: procedure.path)) expect(page).to have_current_path(commencer_path(path: procedure.path))
expect(page).to have_content 'Votre compte a été activé' expect(page).to have_content 'Votre compte a été activé'
click_on 'Commencer la démarche' click_on 'Commencer la démarche'
@ -106,6 +108,14 @@ feature 'Signing up:' do
# The confirmation email is sent again # The confirmation email is sent again
confirmation_email = open_email(user_email) confirmation_email = open_email(user_email)
expect(confirmation_email.body).to have_text('Pour activer votre compte') expect(confirmation_email.body).to have_text('Pour activer votre compte')
click_confirmation_link_for(user_email, in_another_browser: true)
# After confirmation, the user is redirected to the procedure they were initially starting
# (even when confirming the account in another browser).
expect(page).to have_current_path(commencer_path(path: procedure.path))
expect(page).to have_content 'Votre compte a été activé'
expect(page).to have_content 'Commencer la démarche'
end end
end end

View file

@ -3,6 +3,11 @@ class DeviseUserMailerPreview < ActionMailer::Preview
DeviseUserMailer.confirmation_instructions(user, "faketoken", {}) DeviseUserMailer.confirmation_instructions(user, "faketoken", {})
end end
def confirmation_instructions___with_procedure
CurrentConfirmation.procedure_after_confirmation = procedure
DeviseUserMailer.confirmation_instructions(user, "faketoken", {})
end
def reset_password_instructions def reset_password_instructions
DeviseUserMailer.reset_password_instructions(user, "faketoken", {}) DeviseUserMailer.reset_password_instructions(user, "faketoken", {})
end end
@ -12,4 +17,8 @@ class DeviseUserMailerPreview < ActionMailer::Preview
def user def user
User.new(id: 10, email: "usager@example.com") User.new(id: 10, email: "usager@example.com")
end end
def procedure
Procedure.new(id: 20, libelle: 'Dotation dÉquipement des Territoires Ruraux - Exercice 2019', path: 'dotation-etr')
end
end end

View file

@ -48,11 +48,16 @@ module FeatureHelpers
end end
end end
def click_confirmation_link_for(email) def click_confirmation_link_for(email, in_another_browser: false)
confirmation_email = open_email(email) confirmation_email = open_email(email)
token_params = confirmation_email.body.match(/confirmation_token=[^"]+/) confirmation_link = confirmation_email.body.match(/href="[^"]*(\/users\/confirmation[^"]*)"/)[1]
visit "/users/confirmation?#{token_params}" if in_another_browser
# Simulate the user opening the link in another browser, thus loosing the session cookie
Capybara.reset_session!
end
visit confirmation_link
end end
def click_procedure_sign_in_link_for(email) def click_procedure_sign_in_link_for(email)