Merge pull request #7737 from betagouv/7699-add-admin-with-confirmation-dev
secure admin adding
This commit is contained in:
commit
3afa554a91
9 changed files with 396 additions and 18 deletions
|
@ -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
|
46
app/controllers/manager/confirmation_urls_controller.rb
Normal file
46
app/controllers/manager/confirmation_urls_controller.rb
Normal file
|
@ -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
|
|
@ -65,22 +65,7 @@ module Manager
|
||||||
end
|
end
|
||||||
|
|
||||||
def add_administrateur_with_confirmation
|
def add_administrateur_with_confirmation
|
||||||
confirmation_url = confirm_add_administrateur_manager_procedure_url(id: procedure.id, email: current_super_admin.email)
|
redirect_to new_manager_procedure_confirmation_url_path(procedure, email: params[: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)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def delete_administrateur
|
def delete_administrateur
|
||||||
|
|
35
app/views/manager/administrateur_confirmations/new.html.erb
Normal file
35
app/views/manager/administrateur_confirmations/new.html.erb
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
<% content_for(:title) { "Confirmation d'ajout d'un administrateur" } %>
|
||||||
|
|
||||||
|
<header class="main-content__header" role="banner">
|
||||||
|
<h1 class="main-content__page-title">
|
||||||
|
<%= content_for(:title) %>
|
||||||
|
</h1>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<section class="main-content__body">
|
||||||
|
<p>
|
||||||
|
Vous avez été invité·e par
|
||||||
|
<em>
|
||||||
|
<%= @inviter.email %>
|
||||||
|
</em>
|
||||||
|
à confirmer l'ajout de
|
||||||
|
<em>
|
||||||
|
<%= @invited_email %>
|
||||||
|
</em>
|
||||||
|
à la démarche
|
||||||
|
<strong>
|
||||||
|
<%= @procedure.libelle %>
|
||||||
|
(<%= @procedure.id %>).
|
||||||
|
</strong>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Confirmez-vous cet ajout ?
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<%= 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 %>
|
||||||
|
</section>
|
|
@ -12,7 +12,7 @@ as defined by the routes in the `admin/` namespace
|
||||||
|
|
||||||
<hr />
|
<hr />
|
||||||
|
|
||||||
<% 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(
|
<%= link_to(
|
||||||
display_resource_name(resource),
|
display_resource_name(resource),
|
||||||
|
|
22
app/views/manager/confirmation_urls/new.html.erb
Normal file
22
app/views/manager/confirmation_urls/new.html.erb
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
<% content_for(:title) { "Ajout d'un administrateur" } %>
|
||||||
|
|
||||||
|
<header class="main-content__header" role="banner">
|
||||||
|
<h1 class="main-content__page-title">
|
||||||
|
<%= content_for(:title) %>
|
||||||
|
</h1>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<section class="main-content__body">
|
||||||
|
<p>
|
||||||
|
Veuillez partager ce lien avec un autre super admin pour que l'opération soit effectuée.
|
||||||
|
</p>
|
||||||
|
<dl>
|
||||||
|
<dt class="attribute-label">
|
||||||
|
Lien
|
||||||
|
</dt>
|
||||||
|
|
||||||
|
<dd class="attribute-data">
|
||||||
|
<%= @url %>
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
</section>
|
|
@ -18,9 +18,10 @@ Rails.application.routes.draw do
|
||||||
put 'delete_administrateur', on: :member
|
put 'delete_administrateur', on: :member
|
||||||
post 'add_administrateur_and_instructeur', on: :member
|
post 'add_administrateur_and_instructeur', on: :member
|
||||||
post 'add_administrateur_with_confirmation', on: :member
|
post 'add_administrateur_with_confirmation', on: :member
|
||||||
get 'confirm_add_administrateur', on: :member
|
|
||||||
post 'change_piece_justificative_template', on: :member
|
post 'change_piece_justificative_template', on: :member
|
||||||
get 'export_mail_brouillons', on: :member
|
get 'export_mail_brouillons', on: :member
|
||||||
|
resources :confirmation_urls, only: :new
|
||||||
|
resources :administrateur_confirmations, only: [:new, :create]
|
||||||
end
|
end
|
||||||
|
|
||||||
resources :archives, only: [:index, :show]
|
resources :archives, only: [:index, :show]
|
||||||
|
|
|
@ -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
|
|
@ -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
|
Loading…
Reference in a new issue