From 4123709e7261d7d3d06da277fdac246fd8bc5643 Mon Sep 17 00:00:00 2001 From: sebastiencarceles Date: Fri, 9 Sep 2022 11:45:14 +0200 Subject: [PATCH] build and render secured URL to invite admin For clarity and a better understanding, use a dedicated controller to build and render the confirmation URL to share in order to add a new administrateur. --- .../manager/confirmation_urls_controller.rb | 46 ++++++++++++ .../manager/procedures_controller.rb | 5 +- .../manager/application/_navigation.html.erb | 2 +- .../manager/confirmation_urls/new.html.erb | 22 ++++++ config/routes.rb | 1 + .../confirmation_urls_controller_spec.rb | 73 +++++++++++++++++++ 6 files changed, 144 insertions(+), 5 deletions(-) create mode 100644 app/controllers/manager/confirmation_urls_controller.rb create mode 100644 app/views/manager/confirmation_urls/new.html.erb create mode 100644 spec/controllers/manager/confirmation_urls_controller_spec.rb diff --git a/app/controllers/manager/confirmation_urls_controller.rb b/app/controllers/manager/confirmation_urls_controller.rb new file mode 100644 index 000000000..8b05e9f71 --- /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 = confirm_add_administrateur_manager_procedure_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(ENV["SECRET_KEY_BASE"]) + 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..b950b5e50 100644 --- a/app/controllers/manager/procedures_controller.rb +++ b/app/controllers/manager/procedures_controller.rb @@ -65,10 +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) + redirect_to new_manager_procedure_confirmation_url_path(procedure, email: params[:email]) end def confirm_add_administrateur diff --git a/app/views/manager/application/_navigation.html.erb b/app/views/manager/application/_navigation.html.erb index 063ba6789..3e7835f7d 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 != "confirmation_urls" }.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" } %> + + + +
+

+ 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..aed35fd9e 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -21,6 +21,7 @@ Rails.application.routes.draw do get 'confirm_add_administrateur', on: :member post 'change_piece_justificative_template', on: :member get 'export_mail_brouillons', on: :member + resources :confirmation_urls, only: :new end resources :archives, only: [:index, :show] 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..010e4a34d --- /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( + confirm_add_administrateur_manager_procedure_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(ENV["SECRET_KEY_BASE"]) + verifier = ActiveSupport::MessageVerifier.new(key) + Base64.urlsafe_encode64(verifier.generate(parameters)) + end +end