Add confirmation by email when merging DC/FC accounts
feat(fci.confirmation_code): add confirmation code to france_connect_informations feat(user_mailer.france_connect_confirmation_code): add confirmation by email mail method/preview/spec, pointing to merge_mail_with_existing_account (reuse existing method) feat(mail_merge): mail merge feat(merge.cannot_use_france_connect): same behaviour as callback clean(fci.confirmation_code): use same token for mail validation as merge feat(resend_france_connect/particulier/merge_confirmation): resend email with link. also enhance some trads, cleanup halfy finished refacto clean(tech): finalize story by plugging merge_with_new_account to email validation fix(deadspec): was removed fix(spec): broken after last refactoring lint(rubocop): space before parenthesis lint(haml-lint): yoohoooo space before = fix(lint): scss now :D Update app/assets/stylesheets/buttons.scss cleanup feat(france_connect): re-add confirm by email, with an option for confirmation by email instead of only confirmation by email fixup! Add confirmation by email when merging DC/FC accounts fix(lint): haml_spec failure
This commit is contained in:
parent
f86e202738
commit
ff073f8884
11 changed files with 152 additions and 11 deletions
|
@ -556,3 +556,9 @@
|
||||||
[data-reach-combobox-popover] {
|
[data-reach-combobox-popover] {
|
||||||
z-index: 20;
|
z-index: 20;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.fconnect-form {
|
||||||
|
input[type=password] {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
class FranceConnect::ParticulierController < ApplicationController
|
class FranceConnect::ParticulierController < ApplicationController
|
||||||
before_action :redirect_to_login_if_fc_aborted, only: [:callback]
|
before_action :redirect_to_login_if_fc_aborted, only: [:callback]
|
||||||
before_action :securely_retrieve_fci, only: [:merge, :merge_with_existing_account, :merge_with_new_account]
|
before_action :securely_retrieve_fci, only: [:merge, :merge_with_existing_account, :merge_with_new_account, :mail_merge_with_existing_account, :resend_and_renew_merge_confirmation]
|
||||||
|
|
||||||
def login
|
def login
|
||||||
if FranceConnectService.enabled?
|
if FranceConnectService.enabled?
|
||||||
|
@ -20,7 +20,8 @@ class FranceConnect::ParticulierController < ApplicationController
|
||||||
fci.associate_user!(fci.email_france_connect)
|
fci.associate_user!(fci.email_france_connect)
|
||||||
connect_france_connect_particulier(fci.user)
|
connect_france_connect_particulier(fci.user)
|
||||||
else
|
else
|
||||||
redirect_to france_connect_particulier_merge_path(fci.create_merge_token!)
|
merge_token = fci.create_merge_token!
|
||||||
|
redirect_to france_connect_particulier_merge_path(merge_token)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
user = fci.user
|
user = fci.user
|
||||||
|
@ -28,7 +29,7 @@ class FranceConnect::ParticulierController < ApplicationController
|
||||||
if user.can_france_connect?
|
if user.can_france_connect?
|
||||||
fci.update(updated_at: Time.zone.now)
|
fci.update(updated_at: Time.zone.now)
|
||||||
connect_france_connect_particulier(user)
|
connect_france_connect_particulier(user)
|
||||||
else
|
else # same behaviour as redirect nicely with message when instructeur/administrateur
|
||||||
fci.destroy
|
fci.destroy
|
||||||
redirect_to new_user_session_path, alert: t('errors.messages.france_connect.forbidden_html', reset_link: new_user_password_path)
|
redirect_to new_user_session_path, alert: t('errors.messages.france_connect.forbidden_html', reset_link: new_user_password_path)
|
||||||
end
|
end
|
||||||
|
@ -64,6 +65,20 @@ class FranceConnect::ParticulierController < ApplicationController
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def mail_merge_with_existing_account
|
||||||
|
user = User.find_by(email: @fci.email_france_connect.downcase)
|
||||||
|
if user.can_france_connect?
|
||||||
|
@fci.update(user: user)
|
||||||
|
@fci.delete_merge_token!
|
||||||
|
|
||||||
|
flash.notice = "Les comptes FranceConnect et #{APPLICATION_NAME} sont à présent fusionnés"
|
||||||
|
connect_france_connect_particulier(user)
|
||||||
|
else # same behaviour as redirect nicely with message when instructeur/administrateur
|
||||||
|
@fci.destroy
|
||||||
|
redirect_to new_user_session_path, alert: t('errors.messages.france_connect.forbidden_html', reset_link: new_user_password_path)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def merge_with_new_account
|
def merge_with_new_account
|
||||||
user = User.find_by(email: sanitized_email_params)
|
user = User.find_by(email: sanitized_email_params)
|
||||||
|
|
||||||
|
@ -79,13 +94,20 @@ class FranceConnect::ParticulierController < ApplicationController
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def resend_and_renew_merge_confirmation
|
||||||
|
merge_token = @fci.create_merge_token!
|
||||||
|
UserMailer.france_connect_merge_confirmation(@fci.email_france_connect, merge_token).deliver_later
|
||||||
|
redirect_to france_connect_particulier_merge_path(merge_token),
|
||||||
|
notice: "Nous venons de vous envoyer le mail de confirmation, veuillez cliquer sur le lien contenu dans ce mail pour fusionner vos comptes"
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def securely_retrieve_fci
|
def securely_retrieve_fci
|
||||||
@fci = FranceConnectInformation.find_by(merge_token: merge_token_params)
|
@fci = FranceConnectInformation.find_by(merge_token: merge_token_params)
|
||||||
|
|
||||||
if @fci.nil? || !@fci.valid_for_merge?
|
if @fci.nil? || !@fci.valid_for_merge?
|
||||||
flash.alert = 'Votre compte FranceConnect a expiré, veuillez recommencer.'
|
flash.alert = "Le délai pour fusionner les comptes FranceConnect et #{APPLICATION_NAME} est expirée. Veuillez recommencer la procédure pour vous fusionner les comptes."
|
||||||
|
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.html { redirect_to root_path }
|
format.html { redirect_to root_path }
|
||||||
|
|
|
@ -20,6 +20,13 @@ class UserMailer < ApplicationMailer
|
||||||
mail(to: requested_email, subject: @subject)
|
mail(to: requested_email, subject: @subject)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def france_connect_merge_confirmation(email, merge_token)
|
||||||
|
@merge_token = merge_token
|
||||||
|
@subject = "Veuillez confirmer la fusion de compte"
|
||||||
|
|
||||||
|
mail(to: email, subject: @subject)
|
||||||
|
end
|
||||||
|
|
||||||
def invite_instructeur(user, reset_password_token)
|
def invite_instructeur(user, reset_password_token)
|
||||||
@reset_password_token = reset_password_token
|
@reset_password_token = reset_password_token
|
||||||
@user = user
|
@user = user
|
||||||
|
|
|
@ -3,10 +3,14 @@
|
||||||
%br
|
%br
|
||||||
entrez votre mot de passe pour fusionner les comptes
|
entrez votre mot de passe pour fusionner les comptes
|
||||||
|
|
||||||
= form_tag france_connect_particulier_merge_with_existing_account_path, remote: true, class: 'mt-2 form' do
|
= form_tag france_connect_particulier_merge_with_existing_account_path, remote: true, class: 'mt-2 form fconnect-form' do
|
||||||
= hidden_field_tag :merge_token, merge_token
|
= hidden_field_tag :merge_token, merge_token
|
||||||
= hidden_field_tag :email, email
|
= hidden_field_tag :email, email
|
||||||
= label_tag :password, 'Mot de passe (8 caractères minimum)'
|
= label_tag :password, 'Mot de passe (8 caractères minimum)'
|
||||||
= password_field_tag :password, nil, autocomplete: 'current-password', id: 'password-for-another-account'
|
= password_field_tag :password, nil, autocomplete: 'current-password', id: 'password-for-another-account'
|
||||||
|
.mb-2
|
||||||
|
Mot de passe oublié ?
|
||||||
|
= link_to france_connect_particulier_resend_and_renew_merge_confirmation_path(merge_token: merge_token), method: :post do
|
||||||
|
Confirmer mon compte par mail
|
||||||
= button_tag 'revenir en arrière', type: 'button', class: 'button secondary', onclick: 'DS.showNewAccount(event);'
|
= button_tag 'revenir en arrière', type: 'button', class: 'button secondary', onclick: 'DS.showNewAccount(event);'
|
||||||
= submit_tag 'Fusionner les comptes', class: 'button primary'
|
= submit_tag 'Fusionner les comptes', class: 'button primary'
|
||||||
|
|
|
@ -23,22 +23,30 @@
|
||||||
Non
|
Non
|
||||||
|
|
||||||
.fusion.hidden
|
.fusion.hidden
|
||||||
%p Pour les fusionner, entrez votre mot de passe
|
%p Pour fusionner ces comptes, veuillez cliquer sur le lien présent dans le mail que nous venons de vous envoyer.
|
||||||
|
|
||||||
= form_tag france_connect_particulier_merge_with_existing_account_path, remote: true, class: 'mt-2 form' do
|
= form_tag france_connect_particulier_merge_with_existing_account_path, remote: true, class: 'mt-2 form fconnect-form' do
|
||||||
= hidden_field_tag :merge_token, @fci.merge_token
|
= hidden_field_tag :merge_token, @fci.merge_token
|
||||||
= hidden_field_tag :email, @fci.email_france_connect
|
= hidden_field_tag :email, @fci.email_france_connect
|
||||||
|
|
||||||
= label_tag :password, 'Mot de passe (8 caractères minimum)'
|
= label_tag :password, 'Mot de passe (8 caractères minimum)'
|
||||||
= password_field_tag :password, nil, autocomplete: 'current-password'
|
= password_field_tag :password, nil, autocomplete: 'current-password', class: 'mb-1'
|
||||||
|
.mb-2
|
||||||
|
Mot de passe oublié ?
|
||||||
|
= link_to france_connect_particulier_resend_and_renew_merge_confirmation_path(merge_token: @fci.merge_token), method: :post do
|
||||||
|
Confirmer mon compte par mail
|
||||||
|
|
||||||
= submit_tag 'Fusionner les comptes', class: 'button primary'
|
= submit_tag 'Fusionner les comptes', class: 'button primary'
|
||||||
|
|
||||||
|
|
||||||
.new-account.hidden
|
.new-account.hidden
|
||||||
%p Donnez-nous alors le mail que #{APPLICATION_NAME} utilisera pour vous contacter
|
%p Donnez-nous alors le mail que #{APPLICATION_NAME} utilisera pour vous contacter
|
||||||
|
|
||||||
= form_tag france_connect_particulier_merge_with_new_account_path, remote: true, class: 'mt-2 form' do
|
= form_tag france_connect_particulier_merge_with_new_account_path, remote: true, class: 'mt-2 form' do
|
||||||
= hidden_field_tag :merge_token, @fci.merge_token
|
= hidden_field_tag :merge_token, @fci.merge_token
|
||||||
= label_tag :email, 'Email (nom@site.com)'
|
= label_tag :email, 'Email (nom@site.com)'
|
||||||
= email_field_tag :email
|
= email_field_tag :email, "", required: true
|
||||||
= submit_tag 'Utiliser ce mail', class: 'button primary'
|
= submit_tag 'Utiliser ce mail', class: 'button primary'
|
||||||
|
|
||||||
|
|
||||||
.new-account-password-confirmation.hidden
|
.new-account-password-confirmation.hidden
|
||||||
|
|
20
app/views/user_mailer/france_connect_merge_confirmation.haml
Normal file
20
app/views/user_mailer/france_connect_merge_confirmation.haml
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
- content_for(:title, @subject)
|
||||||
|
|
||||||
|
%p
|
||||||
|
Bonjour,
|
||||||
|
|
||||||
|
%p
|
||||||
|
Pour confirmer la fusion de votre compte, veuillez cliquer sur le lien suivant :
|
||||||
|
= round_button 'Je confirme', france_connect_particulier_mail_merge_with_existing_account_url(merge_token: @merge_token), :primary
|
||||||
|
|
||||||
|
%p
|
||||||
|
Vous pouvez aussi visiter ce lien : #{link_to france_connect_particulier_mail_merge_with_existing_account_url(merge_token: @merge_token), france_connect_particulier_mail_merge_with_existing_account_url(merge_token: @merge_token)}
|
||||||
|
|
||||||
|
%p Ce lien est valide #{distance_of_time_in_words(FranceConnectInformation::MERGE_VALIDITY)}.
|
||||||
|
|
||||||
|
%p
|
||||||
|
Si vous n’êtes pas à l’origine de cette demande, vous pouvez ignorer ce message. Et si vous avez besoin d’assistance, n’hésitez pas à nous contacter à
|
||||||
|
= succeed '.' do
|
||||||
|
= mail_to CONTACT_EMAIL
|
||||||
|
|
||||||
|
= render partial: "layouts/mailers/signature"
|
|
@ -125,6 +125,8 @@ Rails.application.routes.draw do
|
||||||
get 'particulier' => 'particulier#login'
|
get 'particulier' => 'particulier#login'
|
||||||
get 'particulier/callback' => 'particulier#callback'
|
get 'particulier/callback' => 'particulier#callback'
|
||||||
get 'particulier/merge/:merge_token' => 'particulier#merge', as: :particulier_merge
|
get 'particulier/merge/:merge_token' => 'particulier#merge', as: :particulier_merge
|
||||||
|
get 'particulier/mail_merge_with_existing_account/:merge_token' => 'particulier#mail_merge_with_existing_account', as: :particulier_mail_merge_with_existing_account
|
||||||
|
post 'particulier/resend_and_renew_merge_confirmation' => 'particulier#resend_and_renew_merge_confirmation', as: :particulier_resend_and_renew_merge_confirmation
|
||||||
post 'particulier/merge_with_existing_account' => 'particulier#merge_with_existing_account'
|
post 'particulier/merge_with_existing_account' => 'particulier#merge_with_existing_account'
|
||||||
post 'particulier/merge_with_new_account' => 'particulier#merge_with_new_account'
|
post 'particulier/merge_with_new_account' => 'particulier#merge_with_new_account'
|
||||||
end
|
end
|
||||||
|
|
|
@ -150,7 +150,7 @@ describe FranceConnect::ParticulierController, type: :controller do
|
||||||
else
|
else
|
||||||
expect(subject).to redirect_to root_path
|
expect(subject).to redirect_to root_path
|
||||||
end
|
end
|
||||||
expect(flash.alert).to eq('Votre compte FranceConnect a expiré, veuillez recommencer.')
|
expect(flash.alert).to eq('Le délai pour fusionner les comptes FranceConnect et demarches-simplifiees.fr est expirée. Veuillez recommencer la procédure pour vous fusionner les comptes.')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -173,7 +173,7 @@ describe FranceConnect::ParticulierController, type: :controller do
|
||||||
|
|
||||||
it do
|
it do
|
||||||
expect(subject).to redirect_to root_path
|
expect(subject).to redirect_to root_path
|
||||||
expect(flash.alert).to eq('Votre compte FranceConnect a expiré, veuillez recommencer.')
|
expect(flash.alert).to eq("Le délai pour fusionner les comptes FranceConnect et demarches-simplifiees.fr est expirée. Veuillez recommencer la procédure pour vous fusionner les comptes.")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -241,6 +241,54 @@ describe FranceConnect::ParticulierController, type: :controller do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '#mail_merge_with_existing_account' do
|
||||||
|
let(:fci) { FranceConnectInformation.create!(user_info) }
|
||||||
|
let!(:merge_token) { fci.create_merge_token! }
|
||||||
|
|
||||||
|
context 'when the merge_token is ok and the user is found' do
|
||||||
|
subject { post :mail_merge_with_existing_account, params: { merge_token: fci.merge_token } }
|
||||||
|
|
||||||
|
let!(:user) { create(:user, email: email, password: 'abcdefgh') }
|
||||||
|
|
||||||
|
it 'merges the account, signs in, and delete the merge token' do
|
||||||
|
subject
|
||||||
|
fci.reload
|
||||||
|
|
||||||
|
expect(fci.user).to eq(user)
|
||||||
|
expect(fci.merge_token).to be_nil
|
||||||
|
expect(controller.current_user).to eq(user)
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'but the targeted user is an instructeur' do
|
||||||
|
let!(:user) { create(:instructeur, email: email, password: 'abcdefgh').user }
|
||||||
|
|
||||||
|
it 'redirects to the new session' do
|
||||||
|
subject
|
||||||
|
expect(FranceConnectInformation.exists?(fci.id)).to be_falsey
|
||||||
|
expect(controller.current_user).to be_nil
|
||||||
|
expect(response).to redirect_to(new_user_session_path)
|
||||||
|
expect(flash[:alert]).to eq(I18n.t('errors.messages.france_connect.forbidden_html', reset_link: new_user_password_path))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when the merge_token is not ok' do
|
||||||
|
subject { post :mail_merge_with_existing_account, params: { merge_token: 'ko' } }
|
||||||
|
|
||||||
|
let!(:user) { create(:user, email: email) }
|
||||||
|
|
||||||
|
it 'increases the failed attempts counter' do
|
||||||
|
subject
|
||||||
|
fci.reload
|
||||||
|
|
||||||
|
expect(fci.user).to be_nil
|
||||||
|
expect(fci.merge_token).not_to be_nil
|
||||||
|
expect(controller.current_user).to be_nil
|
||||||
|
expect(response).to redirect_to(root_path)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe '#merge_with_new_account' do
|
describe '#merge_with_new_account' do
|
||||||
let(:fci) { FranceConnectInformation.create!(user_info) }
|
let(:fci) { FranceConnectInformation.create!(user_info) }
|
||||||
let(:merge_token) { fci.create_merge_token! }
|
let(:merge_token) { fci.create_merge_token! }
|
||||||
|
@ -280,4 +328,13 @@ describe FranceConnect::ParticulierController, type: :controller do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '#resend_and_renew_merge_confirmation' do
|
||||||
|
let(:fci) { FranceConnectInformation.create!(user_info) }
|
||||||
|
let(:merge_token) { fci.create_merge_token! }
|
||||||
|
it 'renew token' do
|
||||||
|
expect { post :resend_and_renew_merge_confirmation, params: { merge_token: merge_token } }.to change { fci.reload.merge_token }
|
||||||
|
expect(response).to redirect_to(france_connect_particulier_merge_path(fci.reload.merge_token))
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -12,6 +12,10 @@ class UserMailerPreview < ActionMailer::Preview
|
||||||
UserMailer.ask_for_merge(user, 'dircab@territoires.gouv.fr')
|
UserMailer.ask_for_merge(user, 'dircab@territoires.gouv.fr')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def france_connect_merge_confirmation
|
||||||
|
UserMailer.france_connect_merge_confirmation('new.exemple.fr', '123456')
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def user
|
def user
|
||||||
|
|
|
@ -25,4 +25,14 @@ RSpec.describe UserMailer, type: :mailer do
|
||||||
it { expect(subject.to).to eq([requested_email]) }
|
it { expect(subject.to).to eq([requested_email]) }
|
||||||
it { expect(subject.body).to include(requested_email) }
|
it { expect(subject.body).to include(requested_email) }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '.france_connect_merge_confirmation' do
|
||||||
|
let(:email) { 'new.exemple.fr' }
|
||||||
|
let(:code) { '123456' }
|
||||||
|
|
||||||
|
subject { described_class.france_connect_merge_confirmation(email, code) }
|
||||||
|
|
||||||
|
it { expect(subject.to).to eq([email]) }
|
||||||
|
it { expect(subject.body).to include(france_connect_particulier_mail_merge_with_existing_account_url(merge_token: code)) }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
1
vendor/assets/stylesheets/franceconnect.scss
vendored
1
vendor/assets/stylesheets/franceconnect.scss
vendored
|
@ -140,3 +140,4 @@
|
||||||
height: 500px;
|
height: 500px;
|
||||||
margin: 60px auto 0 auto;
|
margin: 60px auto 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue