diff --git a/app/controllers/new_administrateur/profil_controller.rb b/app/controllers/new_administrateur/profil_controller.rb
deleted file mode 100644
index 2414ad3e7..000000000
--- a/app/controllers/new_administrateur/profil_controller.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-module NewAdministrateur
- class ProfilController < AdministrateurController
- def show
- end
-
- def renew_api_token
- @token = current_administrateur.renew_api_token
- flash.now.notice = 'Votre jeton a été regénéré.'
- render :show
- end
- end
-end
diff --git a/app/controllers/users/profil_controller.rb b/app/controllers/users/profil_controller.rb
new file mode 100644
index 000000000..f976a8775
--- /dev/null
+++ b/app/controllers/users/profil_controller.rb
@@ -0,0 +1,31 @@
+module Users
+ class ProfilController < UserController
+ def show
+ end
+
+ def renew_api_token
+ @token = current_administrateur.renew_api_token
+ flash.now.notice = 'Votre jeton a été regénéré.'
+ render :show
+ end
+
+ def update_email
+ if @current_user.update(update_email_params)
+ flash.notice = t('devise.registrations.update_needs_confirmation')
+ # to avoid leaking who has signed in
+ elsif @current_user.errors&.details&.dig(:email)&.any? { |e| e[:error] == :taken }
+ flash.notice = t('devise.registrations.update_needs_confirmation')
+ else
+ flash.alert = @current_user.errors.full_messages
+ end
+
+ redirect_to profil_path
+ end
+
+ private
+
+ def update_email_params
+ params.require(:user).permit(:email)
+ end
+ end
+end
diff --git a/app/helpers/tableau_de_bord_helper.rb b/app/helpers/tableau_de_bord_helper.rb
new file mode 100644
index 000000000..6487ecbdc
--- /dev/null
+++ b/app/helpers/tableau_de_bord_helper.rb
@@ -0,0 +1,11 @@
+module TableauDeBordHelper
+ def tableau_de_bord_helper_path
+ if current_administrateur.present?
+ admin_procedures_path
+ elsif current_gestionnaire.present?
+ gestionnaire_procedures_path
+ else
+ dossiers_path
+ end
+ end
+end
diff --git a/app/views/devise_mailer/confirmation_instructions.html.haml b/app/views/devise_mailer/confirmation_instructions.html.haml
index a18dda332..a63b05978 100644
--- a/app/views/devise_mailer/confirmation_instructions.html.haml
+++ b/app/views/devise_mailer/confirmation_instructions.html.haml
@@ -1,10 +1,22 @@
-- content_for(:title, 'Activez votre compte')
+-# ugly hack to know if the mail is creation confirmation or a password change confirmation
+- if @user.unconfirmed_email.nil?
+ - content_for(:title, 'Activez votre compte')
-%p
- Bonjour,
+ %p
+ Bonjour,
-%p
- 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))
+ %p
+ 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))
+
+- else
+ - content_for(:title, "Changement d'adresse email")
+
+ %p
+ Bonjour,
+
+ %p
+ Pour confirmer votre changement d'adresse email, veuillez cliquer sur le lien suivant :
+ = link_to(confirmation_url(@user, confirmation_token: @token), confirmation_url(@user, confirmation_token: @token))
= render partial: "layouts/mailers/signature"
diff --git a/app/views/layouts/_account_dropdown.haml b/app/views/layouts/_account_dropdown.haml
index 4044885c4..03bd65201 100644
--- a/app/views/layouts/_account_dropdown.haml
+++ b/app/views/layouts/_account_dropdown.haml
@@ -26,6 +26,10 @@
= link_to admin_procedures_path, class: "menu-item menu-link" do
= image_tag "icons/switch-profile.svg"
Passer en administrateur
+ %li
+ = link_to profil_path, class: "menu-item menu-link" do
+ = image_tag "icons/switch-profile.svg"
+ Voir mon profil
%li
= link_to destroy_user_session_path, method: :delete, class: "menu-item menu-link" do
diff --git a/app/views/new_administrateur/profil/show.html.haml b/app/views/new_administrateur/profil/show.html.haml
deleted file mode 100644
index f9775305a..000000000
--- a/app/views/new_administrateur/profil/show.html.haml
+++ /dev/null
@@ -1,25 +0,0 @@
-= render partial: 'new_administrateur/breadcrumbs',
- locals: { steps: [link_to('Tableau de bord', admin_procedures_path),
- 'Profil'] }
-
-#profil-page.container
- %h1 Profil
-
- .card
- .card-title Jeton d'identification de l'API (token)
- %p Ce jeton est nécessaire pour effectuer des appels vers l'API de demarches-simplifiees.fr.
-
- - if defined?(@token)
- %p Jeton : #{@token}
- %p Pour des raisons de sécurité, ce jeton ne sera plus ré-affiché, notez-le bien.
-
- - else
- %p Pour des raisons de sécurité, nous ne pouvons vous l'afficher que lors de sa génération.
- %p Attention, si vous avez déjà des applications qui utilisent votre jeton, le regénérer bloquera leurs accès à l'API.
-
- = link_to "Regénérer et afficher mon jeton",
- renew_api_token_path,
- method: :post,
- class: "button primary",
- data: { confirm: "Confirmez-vous la regénération de votre jeton ? Les applications qui l'utilisent actuellement seront bloquées.",
- disable: true }
diff --git a/app/views/users/profil/show.html.haml b/app/views/users/profil/show.html.haml
new file mode 100644
index 000000000..674992d1b
--- /dev/null
+++ b/app/views/users/profil/show.html.haml
@@ -0,0 +1,39 @@
+= render partial: 'new_administrateur/breadcrumbs',
+ locals: { steps: [link_to('Tableau de bord', tableau_de_bord_helper_path),
+ 'Profil'] }
+
+#profil-page.container
+ %h1 Profil
+
+ .card
+ .card-title Coordonnées
+ %p Votre email est actuellement #{current_user.email}
+ - if current_user.unconfirmed_email.present?
+ %p
+ Un email a été envoyé à #{current_user.unconfirmed_email}.
+ %br
+ Merci de vérifier vos emails et de cliquer sur le lien d’activation pour finaliser la validation de votre nouvelle adresse.
+
+ = form_for @current_user, url: update_email_path, method: :patch, html: { class: 'form' } do |f|
+ = f.email_field :email, value: nil, placeholder: 'Nouvelle adresse email', required: true
+ = f.submit "Changer mon adresse", class: 'button primary'
+
+ - if current_administrateur.present?
+ .card
+ .card-title Jeton d’identification de l’API (token)
+ %p Ce jeton est nécessaire pour effectuer des appels vers l’API de demarches-simplifiees.fr.
+
+ - if defined?(@token)
+ %p Jeton : #{@token}
+ %p Pour des raisons de sécurité, ce jeton ne sera plus ré-affiché, notez-le bien.
+
+ - else
+ %p Pour des raisons de sécurité, nous ne pouvons vous l’afficher que lors de sa génération.
+ %p Attention, si vous avez déjà des applications qui utilisent votre jeton, le regénérer bloquera leurs accès à l’API.
+
+ = link_to "Regénérer et afficher mon jeton",
+ renew_api_token_path,
+ method: :post,
+ class: "button primary",
+ data: { confirm: "Confirmez-vous la regénération de votre jeton ? Les applications qui l’utilisent actuellement seront bloquées.",
+ disable: true }
diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb
index 536fd745e..4b74c2e52 100644
--- a/config/initializers/devise.rb
+++ b/config/initializers/devise.rb
@@ -121,7 +121,7 @@ Devise.setup do |config|
# initial account confirmation) to be applied. Requires additional unconfirmed_email
# db field (see migrations). Until confirmed, new email is stored in
# unconfirmed_email column, and copied to email column on successful confirmation.
- config.reconfirmable = false
+ config.reconfirmable = true
# Defines which key will be used when confirming an account
# config.confirmation_keys = [ :email ]
diff --git a/config/locales/devise.fr.yml b/config/locales/devise.fr.yml
index 92c4af92d..30f3ca558 100755
--- a/config/locales/devise.fr.yml
+++ b/config/locales/devise.fr.yml
@@ -42,7 +42,7 @@ fr:
signed_up_but_inactive: "Vous êtes bien enregistré. Vous ne pouvez cependant pas vous connecter car votre compte n'est pas encore activé."
signed_up_but_locked: "Vous êtes bien enregistré. Vous ne pouvez cependant pas vous connecter car votre compte est verrouillé."
signed_up_but_unconfirmed: "Nous vous avons envoyé un email contenant un lien d'activation. Ouvrez ce lien pour activer votre compte."
- update_needs_confirmation: "Votre compte a bien été mis à jour mais nous devons vérifier votre nouvelle adresse email. Merci de vérifier vos email et de cliquer sur le lien d'activation pour finaliser la validation de votre nouvelle adresse."
+ update_needs_confirmation: "Votre compte a bien été mis à jour mais nous devons vérifier votre nouvelle adresse email. Merci de vérifier vos emails et de cliquer sur le lien d’activation pour finaliser la validation de votre nouvelle adresse."
updated: "Votre compte a été modifié avec succès."
sessions:
signed_in: "Connecté."
diff --git a/config/routes.rb b/config/routes.rb
index 7b454fa57..bb9785886 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -291,6 +291,12 @@ Rails.application.routes.draw do
end
resource :feedback, only: [:create]
get 'demarches' => 'demarches#index'
+
+ get 'profil' => 'profil#show'
+ post 'renew-api-token' => 'profil#renew_api_token'
+ # allow refresh 'renew api token' page
+ get 'renew-api-token' => redirect('/profil')
+ patch 'update_email' => 'profil#update_email'
end
#
@@ -377,11 +383,6 @@ Rails.application.routes.draw do
patch 'add_to_procedure'
end
end
-
- get 'profil' => 'profil#show'
- post 'renew-api-token' => 'profil#renew_api_token'
- # allow refresh 'renew api token' page
- get 'renew-api-token' => redirect('/profil')
end
#
diff --git a/db/migrate/20190704133749_add_unconfirmed_email_column_to_users.rb b/db/migrate/20190704133749_add_unconfirmed_email_column_to_users.rb
new file mode 100644
index 000000000..054edb9cf
--- /dev/null
+++ b/db/migrate/20190704133749_add_unconfirmed_email_column_to_users.rb
@@ -0,0 +1,5 @@
+class AddUnconfirmedEmailColumnToUsers < ActiveRecord::Migration[5.2]
+ def change
+ add_column :users, :unconfirmed_email, :text
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index ff7152c3a..e2a264bc4 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -605,6 +605,7 @@ ActiveRecord::Schema.define(version: 2019_07_04_144304) do
t.string "confirmation_token"
t.datetime "confirmed_at"
t.datetime "confirmation_sent_at"
+ t.text "unconfirmed_email"
t.index ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true
t.index ["email"], name: "index_users_on_email", unique: true
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
diff --git a/spec/controllers/new_administrateur/profil_controller_spec.rb b/spec/controllers/new_administrateur/profil_controller_spec.rb
deleted file mode 100644
index 416d70b83..000000000
--- a/spec/controllers/new_administrateur/profil_controller_spec.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-require 'spec_helper'
-
-describe NewAdministrateur::ProfilController, type: :controller do
- let(:administrateur) { create(:administrateur) }
-
- before { sign_in(administrateur) }
-
- describe 'POST #renew_api_token' do
- before do
- allow(administrateur).to receive(:renew_api_token)
- allow(controller).to receive(:current_administrateur) { administrateur }
- post :renew_api_token
- end
-
- it { expect(administrateur).to have_received(:renew_api_token) }
- it { expect(response.status).to render_template(:show) }
- it { expect(flash.notice).to eq('Votre jeton a été regénéré.') }
- end
-end
diff --git a/spec/controllers/users/profil_controller_spec.rb b/spec/controllers/users/profil_controller_spec.rb
new file mode 100644
index 000000000..e151e2f82
--- /dev/null
+++ b/spec/controllers/users/profil_controller_spec.rb
@@ -0,0 +1,60 @@
+require 'spec_helper'
+
+describe Users::ProfilController, type: :controller do
+ let(:user) { create(:user) }
+
+ before { sign_in(user) }
+
+ describe 'POST #renew_api_token' do
+ let(:administrateur) { create(:administrateur) }
+
+ before { sign_in(administrateur) }
+
+ before do
+ allow(administrateur).to receive(:renew_api_token)
+ allow(controller).to receive(:current_administrateur) { administrateur }
+ post :renew_api_token
+ end
+
+ it { expect(administrateur).to have_received(:renew_api_token) }
+ it { expect(response.status).to render_template(:show) }
+ it { expect(flash.notice).to eq('Votre jeton a été regénéré.') }
+ end
+
+ describe 'PATCH #update_email' do
+ context 'when everything is fine' do
+ before do
+ patch :update_email, params: { user: { email: 'loulou@lou.com' } }
+ user.reload
+ end
+
+ it { expect(user.unconfirmed_email).to eq('loulou@lou.com') }
+ it { expect(response).to redirect_to(profil_path) }
+ it { expect(flash.notice).to eq(I18n.t('devise.registrations.update_needs_confirmation')) }
+ end
+
+ context 'when the mail is already taken' do
+ let!(:user2) { create(:user) }
+
+ before do
+ patch :update_email, params: { user: { email: user2.email } }
+ user.reload
+ end
+
+ it { expect(response).to redirect_to(profil_path) }
+ it { expect(flash.notice).to eq(I18n.t('devise.registrations.update_needs_confirmation')) }
+ end
+
+ context 'when the mail is incorrect' do
+ let!(:user2) { create(:user) }
+
+ before do
+ patch :update_email, params: { user: { email: 'incorrect' } }
+ user.reload
+ end
+
+ it { expect(response).to redirect_to(profil_path) }
+ it { expect(flash.alert).to eq(['Email invalide']) }
+ end
+ end
+end
diff --git a/spec/features/admin/connection_spec.rb b/spec/features/admin/connection_spec.rb
index 14eec8816..6327ee8e1 100644
--- a/spec/features/admin/connection_spec.rb
+++ b/spec/features/admin/connection_spec.rb
@@ -6,6 +6,7 @@ feature 'Administrator connection' do
let(:email) { 'admin1@admin.com' }
let(:password) { 'mon chien aime les bananes' }
let!(:admin) { create(:administrateur, :with_procedure, email: email, password: password) }
+ let!(:user) { create(:user, email: email, password: password) }
before do
Flipflop::FeatureSet.current.test!.switch!(:enable_email_login_token, true)
diff --git a/spec/features/users/change_email_spec.rb b/spec/features/users/change_email_spec.rb
new file mode 100644
index 000000000..a2267733c
--- /dev/null
+++ b/spec/features/users/change_email_spec.rb
@@ -0,0 +1,32 @@
+require 'spec_helper'
+
+feature 'Changing an email' do
+ let(:old_email) { 'old@email.com' }
+ let(:user) { create(:user, email: old_email) }
+
+ before do
+ login_as user, scope: :user
+ end
+
+ scenario 'is easy' do
+ new_email = 'new@email.com'
+
+ visit '/profil'
+
+ fill_in :user_email, with: new_email
+
+ perform_enqueued_jobs do
+ click_button 'Changer mon adresse'
+ end
+
+ user.reload
+ expect(user.email).to eq(old_email)
+ expect(user.unconfirmed_email).to eq(new_email)
+
+ click_confirmation_link_for(new_email)
+
+ user.reload
+ expect(user.email).to eq(new_email)
+ expect(user.unconfirmed_email).to be_nil
+ end
+end
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index 9564d4623..34459c7f7 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -107,6 +107,7 @@ describe User, type: :model do
gestionnaire = create(:gestionnaire, email: user.email)
user.update(email: 'whoami@plop.com', password: 'super secret')
+ user.confirm
gestionnaire.reload
expect(gestionnaire.email).to eq('whoami@plop.com')
@@ -118,6 +119,7 @@ describe User, type: :model do
admin = create(:administrateur, email: user.email)
user.update(email: 'whoami@plop.com', password: 'super secret')
+ user.confirm
admin.reload
expect(admin.email).to eq('whoami@plop.com')