diff --git a/app/controllers/manager/administrateur_confirmations_controller.rb b/app/controllers/manager/administrateur_confirmations_controller.rb
new file mode 100644
index 000000000..9f3f15d4a
--- /dev/null
+++ b/app/controllers/manager/administrateur_confirmations_controller.rb
@@ -0,0 +1,52 @@
+module Manager
+ class AdministrateurConfirmationsController < Manager::ApplicationController
+ before_action :set_procedure
+ before_action :decrypt_params
+ before_action :ensure_not_inviter, unless: -> { Rails.env.development? }
+ before_action :ensure_not_invited, unless: -> { Rails.env.development? }
+
+ def new
+ @inviter = SuperAdmin.find(@inviter_id)
+ end
+
+ def create
+ administrateur = Administrateur.by_email(@invited_email)
+ AdministrateursProcedure.create!(procedure: @procedure, administrateur: administrateur)
+ flash[:notice] = "L’administrateur \"#{administrateur.email}\" a été ajouté à la démarche."
+ redirect_to manager_procedure_path(@procedure)
+ end
+
+ private
+
+ def ensure_not_inviter
+ redirect_unallowed if @inviter_id.to_i == current_super_admin.id
+ end
+
+ def ensure_not_invited
+ redirect_unallowed if @invited_email == current_super_admin.email
+ end
+
+ def redirect_unallowed
+ flash[:alert] = "Veuillez partager ce lien avec un autre super administrateur pour qu'il confirme votre action"
+ redirect_to manager_procedure_path(@procedure)
+ end
+
+ def decrypt_params
+ @inviter_id = decrypted_params[:inviter_id]
+ @invited_email = decrypted_params[:email]
+ rescue ActiveSupport::MessageVerifier::InvalidSignature, ArgumentError
+ flash[:error] = "Le lien que vous avez utilisé est invalide. Veuillez contacter la personne qui vous l'a envoyé."
+ redirect_to manager_procedure_path(@procedure)
+ end
+
+ def decrypted_params
+ @decrypted_params ||= ActiveSupport::MessageVerifier.new(
+ Rails.application.key_generator.generate_key("confirm_adding_administrateur")
+ ).verify(Base64.urlsafe_decode64(params[:q]))
+ end
+
+ def set_procedure
+ @procedure = Procedure.with_discarded.find(params[:procedure_id])
+ end
+ end
+end
diff --git a/app/controllers/manager/confirmation_urls_controller.rb b/app/controllers/manager/confirmation_urls_controller.rb
new file mode 100644
index 000000000..5f8bc0a73
--- /dev/null
+++ b/app/controllers/manager/confirmation_urls_controller.rb
@@ -0,0 +1,46 @@
+module Manager
+ class ConfirmationUrlsController < Manager::ApplicationController
+ before_action :ensure_administrateur_exists
+ before_action :ensure_not_already_added
+
+ def new
+ @url = new_manager_procedure_administrateur_confirmation_url(
+ procedure.id,
+ q: encrypt({ email: params[:email], inviter_id: current_super_admin.id })
+ )
+ end
+
+ private
+
+ def ensure_administrateur_exists
+ redirect("Cet administrateur n'existe pas. Veuillez réessayer.") unless administrateur
+ end
+
+ def ensure_not_already_added
+ redirect("Cet administrateur a déjà été ajouté à cette démarche.") if already_added?
+ end
+
+ def redirect(alert)
+ flash[:alert] = alert
+ redirect_to manager_procedure_path(procedure)
+ end
+
+ def already_added?
+ AdministrateursProcedure.exists?(procedure: procedure, administrateur: administrateur)
+ end
+
+ def administrateur
+ @administrateur ||= Administrateur.by_email(params[:email])
+ end
+
+ def procedure
+ @procedure ||= Procedure.with_discarded.find(params[:procedure_id])
+ end
+
+ def encrypt(parameters)
+ key = Rails.application.key_generator.generate_key("confirm_adding_administrateur")
+ verifier = ActiveSupport::MessageVerifier.new(key)
+ Base64.urlsafe_encode64(verifier.generate(parameters))
+ end
+ end
+end
diff --git a/app/controllers/manager/procedures_controller.rb b/app/controllers/manager/procedures_controller.rb
index a8058d5c3..5ebacbdc0 100644
--- a/app/controllers/manager/procedures_controller.rb
+++ b/app/controllers/manager/procedures_controller.rb
@@ -65,22 +65,7 @@ module Manager
end
def add_administrateur_with_confirmation
- confirmation_url = confirm_add_administrateur_manager_procedure_url(id: procedure.id, email: current_super_admin.email)
-
- flash[:notice] = "Veuillez partager ce lien : #{confirmation_url} avec un autre super admin pour que l'operation soit effectuée"
- redirect_to manager_procedure_path(procedure)
- end
-
- def confirm_add_administrateur
- administrateur_email = params[:email]
- if administrateur_email != current_super_admin.email
- administrateur = Administrateur.by_email(params[:email])
- AdministrateursProcedure.create!(procedure: procedure, administrateur: administrateur)
- flash[:notice] = "L’administrateur \"#{administrateur.email}\" a été ajouté à la démarche."
- else
- flash[:alert] = "Veuillez partager ce lien avec un autre super administrateur pour qu'il confirme votre action"
- end
- redirect_to manager_procedure_path(procedure)
+ redirect_to new_manager_procedure_confirmation_url_path(procedure, email: params[:email])
end
def delete_administrateur
diff --git a/app/views/manager/administrateur_confirmations/new.html.erb b/app/views/manager/administrateur_confirmations/new.html.erb
new file mode 100644
index 000000000..83321e600
--- /dev/null
+++ b/app/views/manager/administrateur_confirmations/new.html.erb
@@ -0,0 +1,35 @@
+<% content_for(:title) { "Confirmation d'ajout d'un administrateur" } %>
+
+
+
+ <%= content_for(:title) %>
+
+
+
+
+
+ Vous avez été invité·e par
+
+ <%= @inviter.email %>
+
+ à confirmer l'ajout de
+
+ <%= @invited_email %>
+
+ à la démarche
+
+ <%= @procedure.libelle %>
+ (<%= @procedure.id %>).
+
+
+
+
+ Confirmez-vous cet ajout ?
+
+
+ <%= form_tag manager_procedure_administrateur_confirmations_path(@procedure) do %>
+ <%= hidden_field_tag :q, params[:q] %>
+ <%= submit_tag "Oui, je confirme l'ajout" %>
+ <%= link_to "Non, je ne confirme pas l'ajout", :back %>
+ <% end %>
+
diff --git a/app/views/manager/application/_navigation.html.erb b/app/views/manager/application/_navigation.html.erb
index 063ba6789..6ba4253fe 100644
--- a/app/views/manager/application/_navigation.html.erb
+++ b/app/views/manager/application/_navigation.html.erb
@@ -12,7 +12,7 @@ as defined by the routes in the `admin/` namespace
- <% Administrate::Namespace.new(namespace).resources.each do |resource| %>
+ <% Administrate::Namespace.new(namespace).resources.select { |resource| !resource.to_s.in?(%w(confirmation_urls administrateur_confirmations)) }.each do |resource| %>
<%= link_to(
display_resource_name(resource),
diff --git a/app/views/manager/confirmation_urls/new.html.erb b/app/views/manager/confirmation_urls/new.html.erb
new file mode 100644
index 000000000..fbcb59819
--- /dev/null
+++ b/app/views/manager/confirmation_urls/new.html.erb
@@ -0,0 +1,22 @@
+<% content_for(:title) { "Ajout d'un administrateur" } %>
+
+
+
+ <%= content_for(:title) %>
+
+
+
+
+
+ Veuillez partager ce lien avec un autre super admin pour que l'opération soit effectuée.
+
+
+ -
+ Lien
+
+
+ -
+ <%= @url %>
+
+
+
diff --git a/config/routes.rb b/config/routes.rb
index d44e451a1..50093db4d 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -18,9 +18,10 @@ Rails.application.routes.draw do
put 'delete_administrateur', on: :member
post 'add_administrateur_and_instructeur', on: :member
post 'add_administrateur_with_confirmation', on: :member
- get 'confirm_add_administrateur', on: :member
post 'change_piece_justificative_template', on: :member
get 'export_mail_brouillons', on: :member
+ resources :confirmation_urls, only: :new
+ resources :administrateur_confirmations, only: [:new, :create]
end
resources :archives, only: [:index, :show]
diff --git a/spec/controllers/manager/administrateur_confirmations_controller_spec.rb b/spec/controllers/manager/administrateur_confirmations_controller_spec.rb
new file mode 100644
index 000000000..ef629eef1
--- /dev/null
+++ b/spec/controllers/manager/administrateur_confirmations_controller_spec.rb
@@ -0,0 +1,164 @@
+require 'rails_helper'
+
+RSpec.describe Manager::AdministrateurConfirmationsController, type: :controller do
+ let(:inviter_super_admin) { create(:super_admin) }
+ let(:inviter_administrateur) { create(:administrateur, email: inviter_super_admin.email) }
+
+ let(:invited_super_admin) { create(:super_admin) }
+ let(:invited_administrateur) { create(:administrateur, email: invited_super_admin.email) }
+
+ let(:confirmer_super_admin) { create(:super_admin) }
+
+ let(:procedure) { create(:procedure, administrateurs: [inviter_administrateur]) }
+
+ describe "GET #new" do
+ subject(:new_request) do
+ get :new, params: {
+ procedure_id: procedure.id,
+ q: encrypt({ email: invited_administrateur.email, inviter_id: inviter_super_admin.id })
+ }
+ end
+
+ shared_examples "current admin is allowed to confirm adding another one" do
+ before { new_request }
+
+ it { expect(response).to render_template(:new) }
+ end
+
+ shared_examples "current admin isn't allowed to confirm adding another one" do
+ before { new_request }
+
+ it { expect(flash[:alert]).to match(/Veuillez partager ce lien avec un autre super administrateur/) }
+
+ it { expect(response).to redirect_to(manager_procedure_path(procedure)) }
+ end
+
+ context 'when the current admin is the invited' do
+ before { sign_in invited_super_admin }
+
+ it_behaves_like "current admin isn't allowed to confirm adding another one"
+ end
+
+ context 'when the current admin is the inviter' do
+ before { sign_in inviter_super_admin }
+
+ it_behaves_like "current admin isn't allowed to confirm adding another one"
+ end
+
+ context 'when the current admin is not the invited nor the inviter' do
+ before { sign_in confirmer_super_admin }
+
+ it_behaves_like "current admin is allowed to confirm adding another one"
+ end
+
+ describe 'edge cases' do
+ context 'when the environment is development' do
+ before { Rails.env.stub(development?: true) }
+
+ context 'when the current admin is the inviter' do
+ before { sign_in inviter_super_admin }
+
+ it_behaves_like "current admin is allowed to confirm adding another one"
+ end
+
+ context 'when the current admin is the invited' do
+ before { sign_in invited_super_admin }
+
+ it_behaves_like "current admin is allowed to confirm adding another one"
+ end
+ end
+
+ context 'when the encrypted params are invalid' do
+ before { sign_in inviter_super_admin }
+ before { get :new, params: { procedure_id: procedure.id, q: "something that is invalid" } }
+
+ it { expect(flash[:error]).to match(/Le lien que vous avez utilisé est invalide/) }
+ end
+ end
+ end
+
+ describe "GET #create" do
+ subject(:create_request) do
+ post :create, params: {
+ procedure_id: procedure.id,
+ q: encrypt({ email: invited_administrateur.email, inviter_id: inviter_super_admin.id })
+ }
+ end
+
+ shared_examples "current admin is allowed to confirm adding another one" do
+ it "flashes the success message" do
+ create_request
+ expect(flash[:notice]).to include(invited_administrateur.email)
+ expect(flash[:notice]).to match(/ajouté à la démarche/)
+ end
+
+ it "adds the admin to the procedure" do
+ expect { create_request }.to change { procedure.administrateurs.count }.by(1)
+ end
+
+ it "redirects to the procedure" do
+ create_request
+ expect(response).to redirect_to(manager_procedure_path(procedure))
+ end
+ end
+
+ shared_examples "current admin isn't allowed to confirm adding another one" do
+ before { create_request }
+
+ it { expect(flash[:alert]).to match(/Veuillez partager ce lien avec un autre super administrateur/) }
+
+ it { expect(response).to redirect_to(manager_procedure_path(procedure)) }
+ end
+
+ context 'when the current admin is the invited' do
+ before { sign_in invited_super_admin }
+
+ it_behaves_like "current admin isn't allowed to confirm adding another one"
+ end
+
+ context 'when the current admin is the inviter' do
+ before { sign_in inviter_super_admin }
+
+ it_behaves_like "current admin isn't allowed to confirm adding another one"
+ end
+
+ context 'when the current admin is not the invited nor the inviter' do
+ before { sign_in confirmer_super_admin }
+
+ it_behaves_like "current admin is allowed to confirm adding another one"
+ end
+
+ describe 'edge cases' do
+ context 'when the environment is development' do
+ before { Rails.env.stub(development?: true) }
+
+ context 'when the current admin is the inviter' do
+ before { sign_in inviter_super_admin }
+
+ it_behaves_like "current admin is allowed to confirm adding another one"
+ end
+
+ context 'when the current admin is the invited' do
+ before { sign_in invited_super_admin }
+
+ it_behaves_like "current admin is allowed to confirm adding another one"
+ end
+ end
+
+ context 'when the encrypted params are invalid' do
+ before { sign_in inviter_super_admin }
+ before { post :create, params: { procedure_id: procedure.id, q: "something that is invalid" } }
+
+ it { expect(flash[:error]).to match(/Le lien que vous avez utilisé est invalide/) }
+ end
+ end
+ end
+
+ private
+
+ def encrypt(parameters)
+ key = Rails.application.key_generator.generate_key("confirm_adding_administrateur")
+ verifier = ActiveSupport::MessageVerifier.new(key)
+ Base64.urlsafe_encode64(verifier.generate(parameters))
+ end
+end
diff --git a/spec/controllers/manager/confirmation_urls_controller_spec.rb b/spec/controllers/manager/confirmation_urls_controller_spec.rb
new file mode 100644
index 000000000..b0e32a075
--- /dev/null
+++ b/spec/controllers/manager/confirmation_urls_controller_spec.rb
@@ -0,0 +1,73 @@
+describe Manager::ConfirmationUrlsController, type: :controller do
+ let(:inviter_super_admin) { create(:super_admin) }
+ let(:inviter_administrateur) { create(:administrateur, email: inviter_super_admin.email) }
+
+ let(:invited_super_admin) { create(:super_admin) }
+ let(:invited_administrateur) { create(:administrateur, email: invited_super_admin.email) }
+
+ let(:procedure) { create(:procedure, administrateurs: [inviter_administrateur]) }
+
+ before { sign_in inviter_super_admin }
+
+ describe "#add_administrateur_with_confirmation" do
+ render_views
+
+ let(:params) do
+ {
+ procedure_id: procedure.id,
+ email: invited_administrateur.email
+ }
+ end
+
+ before { get :new, params: params }
+
+ it { expect(response).to render_template(:new) }
+
+ it { expect(response.body).to match(/Veuillez partager ce lien/) }
+
+ it "shows the confirmation url with encrypted parameters" do
+ expect(response.body).to include(
+ new_manager_procedure_administrateur_confirmation_url(
+ procedure,
+ q: encrypt({ email: invited_administrateur.email, inviter_id: inviter_super_admin.id })
+ )
+ )
+ end
+
+ describe 'edge cases' do
+ context 'when the administrateur does not exist' do
+ let(:params) do
+ {
+ procedure_id: procedure.id,
+ email: "wrong@email.com"
+ }
+ end
+
+ it { expect(flash[:alert]).to match(/Cet administrateur n'existe pas/) }
+
+ it { expect(response).to redirect_to(manager_procedure_path(procedure)) }
+ end
+
+ context 'when the administrateur has already been added to the procedure' do
+ let(:params) do
+ {
+ procedure_id: procedure.id,
+ email: inviter_super_admin.email
+ }
+ end
+
+ it { expect(flash[:alert]).to match(/Cet administrateur a déjà été ajouté/) }
+
+ it { expect(response).to redirect_to(manager_procedure_path(procedure)) }
+ end
+ end
+ end
+
+ private
+
+ def encrypt(parameters)
+ key = Rails.application.key_generator.generate_key("confirm_adding_administrateur")
+ verifier = ActiveSupport::MessageVerifier.new(key)
+ Base64.urlsafe_encode64(verifier.generate(parameters))
+ end
+end