merge with an existing account by using the password
This commit is contained in:
parent
218e4633a9
commit
19f81b594b
8 changed files with 153 additions and 14 deletions
|
@ -85,6 +85,10 @@ class ApplicationController < ActionController::Base
|
|||
end
|
||||
end
|
||||
|
||||
def ajax_redirect(path)
|
||||
"window.location.href='#{path}'"
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def feature_enabled?(feature_name)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
class FranceConnect::ParticulierController < ApplicationController
|
||||
before_action :redirect_to_login_if_fc_aborted, only: [:callback]
|
||||
before_action :securely_retrieve_fci, only: [:merge]
|
||||
before_action :securely_retrieve_fci, only: [:merge, :merge_with_existing_account]
|
||||
|
||||
def login
|
||||
if FranceConnectService.enabled?
|
||||
|
@ -41,6 +41,28 @@ class FranceConnect::ParticulierController < ApplicationController
|
|||
def merge
|
||||
end
|
||||
|
||||
def merge_with_existing_account
|
||||
user = User.find_by(email: sanitized_email_params)
|
||||
|
||||
if user.valid_for_authentication? { user.valid_password?(password_params) }
|
||||
if !user.can_france_connect?
|
||||
flash.alert = "#{user.email} ne peut utiliser FranceConnect"
|
||||
|
||||
render js: ajax_redirect(root_path)
|
||||
else
|
||||
@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)
|
||||
end
|
||||
else
|
||||
flash.alert = 'Mauvais mot de passe'
|
||||
|
||||
render js: helpers.render_flash
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def securely_retrieve_fci
|
||||
|
@ -49,7 +71,10 @@ class FranceConnect::ParticulierController < ApplicationController
|
|||
if @fci.nil? || !@fci.valid_for_merge?
|
||||
flash.alert = 'Votre compte FranceConnect a expiré, veuillez recommencer.'
|
||||
|
||||
redirect_to root_path
|
||||
respond_to do |format|
|
||||
format.html { redirect_to root_path }
|
||||
format.js { render js: ajax_redirect(root_path) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -68,7 +93,12 @@ class FranceConnect::ParticulierController < ApplicationController
|
|||
|
||||
user.update_attribute('loged_in_with_france_connect', User.loged_in_with_france_connects.fetch(:particulier))
|
||||
|
||||
redirect_to stored_location_for(current_user) || root_path(current_user)
|
||||
redirection_location = stored_location_for(current_user) || root_path(current_user)
|
||||
|
||||
respond_to do |format|
|
||||
format.html { redirect_to redirection_location }
|
||||
format.js { render js: ajax_redirect(root_path) }
|
||||
end
|
||||
end
|
||||
|
||||
def redirect_france_connect_error_connection
|
||||
|
@ -79,4 +109,12 @@ class FranceConnect::ParticulierController < ApplicationController
|
|||
def merge_token_params
|
||||
params[:merge_token]
|
||||
end
|
||||
|
||||
def password_params
|
||||
params[:password]
|
||||
end
|
||||
|
||||
def sanitized_email_params
|
||||
params[:email]&.gsub(/[[:space:]]/, ' ')&.strip&.downcase
|
||||
end
|
||||
end
|
||||
|
|
5
app/javascript/new_design/fc-fusion.js
Normal file
5
app/javascript/new_design/fc-fusion.js
Normal file
|
@ -0,0 +1,5 @@
|
|||
import { show, hide } from '@utils';
|
||||
|
||||
export function showFusion() {
|
||||
show(document.querySelector('.fusion'));
|
||||
}
|
|
@ -41,6 +41,9 @@ import {
|
|||
acceptEmailSuggestion,
|
||||
discardEmailSuggestionBox
|
||||
} from '../new_design/user-sign_up';
|
||||
import {
|
||||
showFusion
|
||||
} from '../new_design/fc-fusion';
|
||||
|
||||
// This is the global application namespace where we expose helpers used from rails views
|
||||
const DS = {
|
||||
|
@ -49,6 +52,7 @@ const DS = {
|
|||
showMotivation,
|
||||
motivationCancel,
|
||||
showImportJustificatif,
|
||||
showFusion,
|
||||
replaceSemicolonByComma,
|
||||
acceptEmailSuggestion,
|
||||
discardEmailSuggestionBox
|
||||
|
|
|
@ -52,4 +52,8 @@ class FranceConnectInformation < ApplicationRecord
|
|||
def valid_for_merge?
|
||||
(MERGE_VALIDITY.ago < merge_token_created_at) && user_id.nil?
|
||||
end
|
||||
|
||||
def delete_merge_token!
|
||||
update(merge_token: nil, merge_token_created_at: nil)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -10,3 +10,24 @@
|
|||
Votre compte FranceConnect utilise <b class='bold'>#{@fci.email_france_connect}</b> comme email de contact.
|
||||
%br
|
||||
Or il existe un compte sur #{APPLICATION_NAME} avec cet email.
|
||||
|
||||
.form.mt-2
|
||||
%label Ce compte #{@fci.email_france_connect} vous appartient-il ?
|
||||
%fieldset.radios
|
||||
%label{ onclick: "DS.showFusion(event);" }
|
||||
= radio_button_tag :value, true, false, autocomplete: "off"
|
||||
Oui
|
||||
|
||||
%label
|
||||
= radio_button_tag :value, false, false, autocomplete: "off"
|
||||
Non
|
||||
|
||||
.fusion.hidden
|
||||
%p Pour les fusionner, entrez votre mot de passe
|
||||
|
||||
= form_tag france_connect_particulier_merge_with_existing_account_path, remote: true, class: 'mt-2 form' do
|
||||
= hidden_field_tag :merge_token, @fci.merge_token
|
||||
= hidden_field_tag :email, @fci.email_france_connect
|
||||
= label_tag :password, 'Mot de passe (8 caractères minimum)'
|
||||
= password_field_tag :password, nil, autocomplete: 'current-password'
|
||||
= submit_tag 'Fusionner les comptes', class: 'button primary'
|
||||
|
|
|
@ -125,6 +125,7 @@ Rails.application.routes.draw do
|
|||
get 'particulier' => 'particulier#login'
|
||||
get 'particulier/callback' => 'particulier#callback'
|
||||
get 'particulier/merge/:merge_token' => 'particulier#merge', as: :particulier_merge
|
||||
post 'particulier/merge_with_existing_account' => 'particulier#merge_with_existing_account'
|
||||
end
|
||||
|
||||
namespace :champs do
|
||||
|
|
|
@ -136,16 +136,7 @@ describe FranceConnect::ParticulierController, type: :controller do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#merge' do
|
||||
let(:fci) { FranceConnectInformation.create!(user_info) }
|
||||
let(:merge_token) { fci.create_merge_token! }
|
||||
|
||||
subject { get :merge, params: { merge_token: merge_token } }
|
||||
|
||||
context 'when the merge token is valid' do
|
||||
it { expect(subject).to have_http_status(:ok) }
|
||||
end
|
||||
|
||||
RSpec.shared_examples "a method that needs a valid merge token" do
|
||||
context 'when the merge token is invalid' do
|
||||
before do
|
||||
merge_token
|
||||
|
@ -153,10 +144,29 @@ describe FranceConnect::ParticulierController, type: :controller do
|
|||
end
|
||||
|
||||
it do
|
||||
if format == :js
|
||||
subject
|
||||
expect(response.body).to eq("window.location.href='/'")
|
||||
else
|
||||
expect(subject).to redirect_to root_path
|
||||
end
|
||||
expect(flash.alert).to eq('Votre compte FranceConnect a expiré, veuillez recommencer.')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#merge' do
|
||||
let(:fci) { FranceConnectInformation.create!(user_info) }
|
||||
let(:merge_token) { fci.create_merge_token! }
|
||||
let(:format) { :html }
|
||||
|
||||
subject { get :merge, params: { merge_token: merge_token } }
|
||||
|
||||
context 'when the merge token is valid' do
|
||||
it { expect(subject).to have_http_status(:ok) }
|
||||
end
|
||||
|
||||
it_behaves_like "a method that needs a valid merge token"
|
||||
|
||||
context 'when the merge token does not exist' do
|
||||
let(:merge_token) { 'i do not exist' }
|
||||
|
@ -167,4 +177,56 @@ describe FranceConnect::ParticulierController, type: :controller do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#merge_with_existing_account' do
|
||||
let(:fci) { FranceConnectInformation.create!(user_info) }
|
||||
let(:merge_token) { fci.create_merge_token! }
|
||||
let(:email) { 'EXISTING_account@a.com ' }
|
||||
let(:password) { 'my-s3cure-p4ssword' }
|
||||
let(:format) { :js }
|
||||
|
||||
subject { post :merge_with_existing_account, params: { merge_token: merge_token, email: email, password: password }, format: format }
|
||||
|
||||
it_behaves_like "a method that needs a valid merge token"
|
||||
|
||||
context 'when the credentials are ok' do
|
||||
let!(:user) { create(:user, email: email, password: password) }
|
||||
|
||||
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: password).user }
|
||||
|
||||
it 'redirects to the root page' 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
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the credentials are not ok' do
|
||||
let!(:user) { create(:user, email: email, password: 'another password #$21$%%') }
|
||||
|
||||
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(user.reload.failed_attempts).to eq(1)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue