feat(Administrateurs::GroupeInstructeur): ensure admin from super admin can not add an instructeur

This commit is contained in:
Martin 2022-07-21 18:56:01 +02:00 committed by mfo
parent d1544bc4ae
commit 25c0e91d87
9 changed files with 116 additions and 39 deletions

View file

@ -1,6 +1,9 @@
module Administrateurs module Administrateurs
class GroupeInstructeursController < AdministrateurController class GroupeInstructeursController < AdministrateurController
include ActiveSupport::NumberHelper include ActiveSupport::NumberHelper
before_action :ensure_not_super_admin!, only: [:add_instructeur]
ITEMS_PER_PAGE = 25 ITEMS_PER_PAGE = 25
CSV_MAX_SIZE = 1.megabytes CSV_MAX_SIZE = 1.megabytes
CSV_ACCEPTED_CONTENT_TYPES = [ CSV_ACCEPTED_CONTENT_TYPES = [
@ -10,6 +13,7 @@ module Administrateurs
def index def index
@procedure = procedure @procedure = procedure
@disabled_as_super_admin = is_administrateur_through_procedure_administration_as_manager?
if procedure.routee? if procedure.routee?
@groupes_instructeurs = paginated_groupe_instructeurs @groupes_instructeurs = paginated_groupe_instructeurs
@ -27,6 +31,7 @@ module Administrateurs
@groupe_instructeur = groupe_instructeur @groupe_instructeur = groupe_instructeur
@instructeurs = paginated_instructeurs @instructeurs = paginated_instructeurs
@available_instructeur_emails = available_instructeur_emails @available_instructeur_emails = available_instructeur_emails
@disabled_as_super_admin = is_administrateur_through_procedure_administration_as_manager?
end end
def create def create

View file

@ -2,6 +2,7 @@ module Administrateurs
class ProcedureAdministrateursController < AdministrateurController class ProcedureAdministrateursController < AdministrateurController
before_action :retrieve_procedure, except: [:new] before_action :retrieve_procedure, except: [:new]
before_action :ensure_not_super_admin!, only: [:create] before_action :ensure_not_super_admin!, only: [:create]
def index def index
@disabled_as_super_admin = is_administrateur_through_procedure_administration_as_manager? @disabled_as_super_admin = is_administrateur_through_procedure_administration_as_manager?
end end

View file

@ -5,15 +5,20 @@
.instructeur-wrapper .instructeur-wrapper
- if !procedure.routee? - if !procedure.routee?
%p.notice Entrez les adresses email des instructeurs que vous souhaitez affecter à cette démarche %p.notice Entrez les adresses email des instructeurs que vous souhaitez affecter à cette démarche
= hidden_field_tag :emails, nil
= react_component("ComboMultiple",
options: available_instructeur_emails, selected: [], disabled: [],
group: '.instructeur-wrapper',
name: 'emails',
label: 'Emails',
acceptNewValues: true)
= f.submit 'Affecter', class: 'button primary send' - if disabled_as_super_admin
= f.select :emails, available_instructeur_emails, {}, disabled: disabled_as_super_admin, id: 'instructeur_emails'
- else
= hidden_field_tag :emails, nil
= react_component("ComboMultiple",
options: available_instructeur_emails, selected: [], disabled: [],
group: '.instructeur-wrapper',
id: 'instructeur_emails',
name: 'emails',
label: 'Emails',
acceptNewValues: true)
= f.submit 'Affecter', class: 'button primary send', disabled: disabled_as_super_admin
%table.table.mt-2 %table.table.mt-2
%thead %thead

View file

@ -1,6 +1,6 @@
.card .card
.card-title %h2.card-title= t('.title')
= t('.title')
- if !procedure.routee? - if !procedure.routee?
%p.notice= t('.notice_html') %p.notice= t('.notice_html')
@ -9,16 +9,16 @@
= link_to t('.button.routing_disable'), update_routing_enabled_admin_procedure_groupe_instructeurs_path(procedure, routing: :disable), class: 'button primary mt-1', method: 'patch' = link_to t('.button.routing_disable'), update_routing_enabled_admin_procedure_groupe_instructeurs_path(procedure, routing: :disable), class: 'button primary mt-1', method: 'patch'
- else - else
= link_to t('.button.routing_enable'), update_routing_enabled_admin_procedure_groupe_instructeurs_path(procedure, routing: :enable), class: 'button primary mt-1', method: 'patch' = link_to t('.button.routing_enable'), update_routing_enabled_admin_procedure_groupe_instructeurs_path(procedure, routing: :enable), class: 'button primary mt-1', method: 'patch'
.card
%h2.card-title Lautogestion des instructeurs
%p.notice= t('.self_managment_notice_html')
.card-title.mt-4 Lautogestion des instructeurs = form_for procedure,
%p.notice= t('.self_managment_notice_html') method: :patch,
url: update_instructeurs_self_management_enabled_admin_procedure_groupe_instructeurs_path(procedure),
= form_for procedure, html: { class: 'form procedure-form__column--form no-background' } do |f|
method: :patch, %label.toggle-switch
url: update_instructeurs_self_management_enabled_admin_procedure_groupe_instructeurs_path(procedure), = f.check_box :instructeurs_self_management_enabled, class: 'toggle-switch-checkbox', onchange: 'this.form.submit()'
html: { class: 'form procedure-form__column--form no-background' } do |f| %span.toggle-switch-control.round
%label.toggle-switch %span.toggle-switch-label.on
= f.check_box :instructeurs_self_management_enabled, class: 'toggle-switch-checkbox', onchange: 'this.form.submit()' %span.toggle-switch-label.off
%span.toggle-switch-control.round
%span.toggle-switch-label.on
%span.toggle-switch-label.off

View file

@ -10,6 +10,8 @@
'Instructeurs'] } 'Instructeurs'] }
.container.groupe-instructeur .container.groupe-instructeur
%h1 Gérer les instructeurs et les options d'instruction de « #{@procedure.libelle} »
= render partial: 'administrateurs/groupe_instructeurs/routing', locals: { procedure: @procedure } = render partial: 'administrateurs/groupe_instructeurs/routing', locals: { procedure: @procedure }
- if @procedure.routee? - if @procedure.routee?
@ -19,4 +21,5 @@
locals: { procedure: @procedure, locals: { procedure: @procedure,
groupe_instructeur: @procedure.defaut_groupe_instructeur, groupe_instructeur: @procedure.defaut_groupe_instructeur,
instructeurs: @instructeurs, instructeurs: @instructeurs,
available_instructeur_emails: @available_instructeur_emails } available_instructeur_emails: @available_instructeur_emails,
disabled_as_super_admin: @disabled_as_super_admin }

View file

@ -1,4 +1,3 @@
= render partial: 'administrateurs/breadcrumbs', = render partial: 'administrateurs/breadcrumbs',
locals: { steps: [link_to('Démarches', admin_procedures_path), locals: { steps: [link_to('Démarches', admin_procedures_path),
link_to(@procedure.libelle, admin_procedure_path(@procedure)), link_to(@procedure.libelle, admin_procedure_path(@procedure)),
@ -11,4 +10,5 @@
locals: { procedure: @procedure, locals: { procedure: @procedure,
groupe_instructeur: @groupe_instructeur, groupe_instructeur: @groupe_instructeur,
instructeurs: @instructeurs, instructeurs: @instructeurs,
available_instructeur_emails: @available_instructeur_emails } available_instructeur_emails: @available_instructeur_emails,
disabled_as_super_admin: @disabled_as_super_admin }

View file

@ -208,10 +208,11 @@ describe Administrateurs::GroupeInstructeursController, type: :controller do
end end
describe '#add_instructeur_procedure_non_routee' do describe '#add_instructeur_procedure_non_routee' do
let(:procedure) { create :procedure, administrateur: admin } let(:procedure) { create :procedure }
let!(:groupe_instructeur) { create(:administrateurs_procedure, procedure: procedure, administrateur: admin, manager: manager) }
let(:emails) { ['instructeur_3@ministere_a.gouv.fr', 'instructeur_4@ministere_b.gouv.fr'].to_json } let(:emails) { ['instructeur_3@ministere_a.gouv.fr', 'instructeur_4@ministere_b.gouv.fr'].to_json }
subject { post :add_instructeur, params: { emails: emails, procedure_id: procedure.id, id: gi_1_1.id } } subject { post :add_instructeur, params: { emails: emails, procedure_id: procedure.id, id: gi_1_1.id } }
let(:manager) { false }
context 'when all emails are valid' do context 'when all emails are valid' do
let(:emails) { ['test@b.gouv.fr', 'test2@b.gouv.fr'].to_json } let(:emails) { ['test@b.gouv.fr', 'test2@b.gouv.fr'].to_json }
it { expect(response.status).to eq(200) } it { expect(response.status).to eq(200) }
@ -233,18 +234,17 @@ describe Administrateurs::GroupeInstructeursController, type: :controller do
it { expect(subject.request.flash[:alert]).to be_present } it { expect(subject.request.flash[:alert]).to be_present }
it { expect(subject).to redirect_to admin_procedure_groupe_instructeurs_path(procedure) } it { expect(subject).to redirect_to admin_procedure_groupe_instructeurs_path(procedure) }
end end
context 'when signed in admin comes from manager' do
let(:manager) { true }
it { is_expected.to have_http_status(:forbidden) }
end
end end
describe '#add_instructeur' do describe '#add_instructeur' do
let!(:instructeur) { create(:instructeur) } let!(:instructeur) { create(:instructeur) }
let(:gi_1_2) { procedure.groupe_instructeurs.create(label: 'groupe instructeur 2') } let(:gi_1_2) { procedure.groupe_instructeurs.create(label: 'groupe instructeur 2') }
let(:do_request) do
before do
gi_1_2.instructeurs << instructeur
allow(GroupeInstructeurMailer).to receive(:add_instructeurs)
.and_return(double(deliver_later: true))
post :add_instructeur, post :add_instructeur,
params: { params: {
procedure_id: procedure.id, procedure_id: procedure.id,
@ -252,10 +252,16 @@ describe Administrateurs::GroupeInstructeursController, type: :controller do
emails: new_instructeur_emails.to_json emails: new_instructeur_emails.to_json
} }
end end
before do
gi_1_2.instructeurs << instructeur
allow(GroupeInstructeurMailer).to receive(:add_instructeurs)
.and_return(double(deliver_later: true))
end
context 'of a news instructeurs' do context 'of a news instructeurs' do
let(:new_instructeur_emails) { ['new_i1@mail.com', 'new_i2@mail.com'] } let(:new_instructeur_emails) { ['new_i1@mail.com', 'new_i2@mail.com'] }
before { do_request }
it { expect(gi_1_2.instructeurs.pluck(:email)).to include(*new_instructeur_emails) } it { expect(gi_1_2.instructeurs.pluck(:email)).to include(*new_instructeur_emails) }
it { expect(flash.notice).to be_present } it { expect(flash.notice).to be_present }
it { expect(response).to redirect_to(admin_procedure_groupe_instructeur_path(procedure, gi_1_2)) } it { expect(response).to redirect_to(admin_procedure_groupe_instructeur_path(procedure, gi_1_2)) }
@ -271,22 +277,32 @@ describe Administrateurs::GroupeInstructeursController, type: :controller do
context 'of an instructeur already in the group' do context 'of an instructeur already in the group' do
let(:new_instructeur_emails) { [instructeur.email] } let(:new_instructeur_emails) { [instructeur.email] }
before { do_request }
it { expect(response).to redirect_to(admin_procedure_groupe_instructeur_path(procedure, gi_1_2)) } it { expect(response).to redirect_to(admin_procedure_groupe_instructeur_path(procedure, gi_1_2)) }
end end
context 'of badly formed email' do context 'of badly formed email' do
let(:new_instructeur_emails) { ['badly_formed_email'] } let(:new_instructeur_emails) { ['badly_formed_email'] }
before { do_request }
it { expect(flash.alert).to be_present } it { expect(flash.alert).to be_present }
it { expect(response).to redirect_to(admin_procedure_groupe_instructeur_path(procedure, gi_1_2)) } it { expect(response).to redirect_to(admin_procedure_groupe_instructeur_path(procedure, gi_1_2)) }
end end
context 'of an empty string' do context 'of an empty string' do
let(:new_instructeur_emails) { [''] } let(:new_instructeur_emails) { [''] }
before { do_request }
it { expect(response).to redirect_to(admin_procedure_groupe_instructeur_path(procedure, gi_1_2)) } it { expect(response).to redirect_to(admin_procedure_groupe_instructeur_path(procedure, gi_1_2)) }
end end
context 'when connected as an administrateur from manager' do
let(:new_instructeur_emails) { [instructeur.email] }
before do
admin.administrateurs_procedures.update_all(manager: true)
do_request
end
it { expect(response).to have_http_status(:forbidden) }
end
end end
describe '#remove_instructeur' do describe '#remove_instructeur' do

View file

@ -14,7 +14,7 @@ describe 'Administrateurs can manage administrateurs', js: true do
scenario 'card is clickable' do scenario 'card is clickable' do
visit admin_procedure_path(procedure) visit admin_procedure_path(procedure)
find('#administrateurs').click find('#administrateurs').click
expect(page).to have_css(:h1, text: "Administrateurs de « #{procedure.libelle} »") expect(page).to have_css("h1", text: "Administrateurs de « #{procedure.libelle} »")
end end
context 'as admin not flagged from manager' do context 'as admin not flagged from manager' do

View file

@ -0,0 +1,47 @@
require 'system/administrateurs/procedure_spec_helper'
describe 'Manage procedure instructeurs', js: true do
include ProcedureSpecHelper
let(:administrateur) { create(:administrateur) }
let!(:procedure) { create(:procedure) }
let!(:administrateurs_procedure) { create(:administrateurs_procedure, administrateur: administrateur, procedure: procedure, manager: manager) }
let(:manager) { false }
before do
login_as administrateur.user, scope: :user
end
context 'is accessible via card' do
let(:manager) { false }
scenario 'it works' do
visit admin_procedure_path(procedure)
byebug
find('#groupe-instructeurs').click
expect(page).to have_css("h1", text: "Gérer les instructeurs et les options d'instruction de « #{procedure.libelle} »")
end
end
context 'as admin not from manager' do
let(:manager) { false }
scenario 'can add instructeur' do
visit admin_procedure_groupe_instructeurs_path(procedure)
expect {
fill_in "instructeur_emails", with: create(:instructeur).email
click_on "Affecter"
}.to change { procedure.instructeurs.count }.by(1)
end
end
context 'as admin from manager' do
let(:manager) { true }
scenario 'cannot add instructeur' do
visit admin_procedure_groupe_instructeurs_path(procedure)
expect(page).to have_css("#instructeur_emails[disabled=\"disabled\"]")
end
end
end