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')