diff --git a/app/controllers/manager/administrateur_confirmations_controller.rb b/app/controllers/manager/administrateur_confirmations_controller.rb new file mode 100644 index 000000000..f61152651 --- /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(ENV["SECRET_KEY_BASE"]) + ).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 index 8b05e9f71..3faed56c7 100644 --- a/app/controllers/manager/confirmation_urls_controller.rb +++ b/app/controllers/manager/confirmation_urls_controller.rb @@ -4,7 +4,7 @@ module Manager before_action :ensure_not_already_added def new - @url = confirm_add_administrateur_manager_procedure_url( + @url = new_manager_procedure_administrateur_confirmation_url( procedure.id, q: encrypt({ email: params[:email], inviter_id: current_super_admin.id }) ) diff --git a/app/controllers/manager/procedures_controller.rb b/app/controllers/manager/procedures_controller.rb index b950b5e50..5ebacbdc0 100644 --- a/app/controllers/manager/procedures_controller.rb +++ b/app/controllers/manager/procedures_controller.rb @@ -68,18 +68,6 @@ module Manager redirect_to new_manager_procedure_confirmation_url_path(procedure, email: params[:email]) 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) - end - def delete_administrateur administrateur = procedure.administrateurs.find { |admin| admin.email == current_super_admin.email } if administrateur.present? 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" } %> + + + +
+

+ 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 3e7835f7d..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.select { |resource| resource.to_s != "confirmation_urls" }.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/config/routes.rb b/config/routes.rb index aed35fd9e..50093db4d 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -18,10 +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..a8c3dc4d4 --- /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(ENV["SECRET_KEY_BASE"]) + 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 index 010e4a34d..7eab50cbe 100644 --- a/spec/controllers/manager/confirmation_urls_controller_spec.rb +++ b/spec/controllers/manager/confirmation_urls_controller_spec.rb @@ -27,7 +27,7 @@ describe Manager::ConfirmationUrlsController, type: :controller do it "shows the confirmation url with encrypted parameters" do expect(response.body).to include( - confirm_add_administrateur_manager_procedure_url( + new_manager_procedure_administrateur_confirmation_url( procedure, q: encrypt({ email: invited_administrateur.email, inviter_id: inviter_super_admin.id }) )