Merge pull request #8083 from demarches-simplifiees/admin_or_not_admin

feat(procedure_admins): permet à un admin de se retirer lui-même d'une procédure
This commit is contained in:
LeSim 2022-11-22 16:49:34 +01:00 committed by GitHub
commit b29d0fc346
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 106 additions and 50 deletions

View file

@ -9,4 +9,8 @@ class ApplicationComponent < ViewComponent::Base
def current_user
controller.current_user
end
def current_administrateur
controller.current_administrateur
end
end

View file

@ -1,4 +1,6 @@
class EditableChamp::ChampLabelContentComponent < ApplicationComponent
include ApplicationHelper
def initialize(champ:, seen_at: nil)
@champ, @seen_at = champ, seen_at
end
@ -12,8 +14,4 @@ class EditableChamp::ChampLabelContentComponent < ApplicationComponent
def highlight?
@champ.updated_at.present? && @seen_at&.<(@champ.updated_at)
end
def try_format_datetime(datetime)
datetime.present? ? I18n.l(datetime) : ''
end
end

View file

@ -0,0 +1,42 @@
class Procedure::ProcedureAdministrateurs::AdministrateurComponent < ApplicationComponent
include ApplicationHelper
def initialize(procedure:, administrateur:)
@procedure = procedure
@administrateur = administrateur
end
def email
if @administrateur == current_administrateur
"#{@administrateur.email} (Cest vous !)"
else
@administrateur.email
end
end
def created_at
try_format_datetime(@administrateur.created_at)
end
def registration_state
@administrateur.registration_state
end
def remove_button
if is_there_at_least_another_active_admin?
button_to 'Retirer',
admin_procedure_administrateur_path(@procedure, @administrateur),
method: :delete,
class: 'button',
form: { data: { turbo: true, turbo_confirm: "Retirer « #{@administrateur.email} » des administrateurs de « #{@procedure.libelle} » ?" } }
end
end
def is_there_at_least_another_active_admin?
if @administrateur.active?
@procedure.administrateurs.count(&:active?) > 1
else
@procedure.administrateurs.count(&:active?) >= 1
end
end
end

View file

@ -0,0 +1,5 @@
%tr{ id: dom_id(@administrateur) }
%td= email
%td= created_at
%td= registration_state
%td= remove_button

View file

@ -29,20 +29,24 @@ module Administrateurs
end
def destroy
administrateur = @procedure.administrateurs.find(params[:id])
admin_to_delete = @procedure.administrateurs.find(params[:id])
# Prevent self-removal (Also enforced in the UI)
if administrateur == current_administrateur
flash.alert = "Vous ne pouvez pas vous retirer vous-même dune démarche."
return
if (@procedure.administrateurs - [admin_to_delete]).filter(&:active?).empty?
flash.alert = "Il doit rester au moins un administrateur actif."
else
begin
# Actually remove the admin
@procedure.administrateurs.delete(admin_to_delete)
@administrateur = admin_to_delete
flash.notice = "Ladministrateur \« #{admin_to_delete.email} » a été retiré de la démarche « #{@procedure.libelle} »."
if current_administrateur == admin_to_delete
redirect_to admin_procedures_path
end
rescue ActiveRecord::ActiveRecordError => e
flash.alert = e.message
end
end
# Actually remove the admin
@procedure.administrateurs.delete(administrateur)
@administrateur = administrateur
flash.notice = "Ladministrateur \« #{administrateur.email} » a été retiré de la démarche « #{@procedure.libelle} »."
rescue ActiveRecord::ActiveRecordError => e
flash.alert = e.message
end
end
end

View file

@ -12,6 +12,8 @@
class Administrateur < ApplicationRecord
include ActiveRecord::SecureToken
self.ignored_columns = [:active]
UNUSED_ADMIN_THRESHOLD = 6.months
has_and_belongs_to_many :instructeurs
@ -42,6 +44,10 @@ class Administrateur < ApplicationRecord
user&.email
end
def active?
user&.active?
end
def self.find_inactive_by_token(reset_password_token)
self.inactive.with_reset_password_token(reset_password_token)
end

View file

@ -1,13 +0,0 @@
%tr{ id: dom_id(administrateur) }
%td= administrateur.email
%td= try_format_datetime(administrateur.created_at)
%td= administrateur.registration_state
%td
- if administrateur == current_administrateur
Cest vous !
- else
= button_to 'Retirer',
admin_procedure_administrateur_path(procedure, administrateur),
method: :delete,
class: 'button',
form: { data: { turbo: true, turbo_confirm: "Retirer « #{administrateur.email} » des administrateurs de « #{procedure.libelle} » ?" } }

View file

@ -1,3 +1,4 @@
- if @administrateur.present?
= turbo_stream.append "administrateurs", partial: 'administrateur', locals: { procedure: @procedure, administrateur: @administrateur }
= turbo_stream.update 'administrateurs',
render(Procedure::ProcedureAdministrateurs::AdministrateurComponent.with_collection(@procedure.administrateurs.order('users.email'), procedure: @procedure))
= turbo_stream.replace "new_administrateur", partial: 'add_admin_form', locals: { procedure: @procedure, disabled_as_super_admin: administrateur_as_manager? }

View file

@ -1,2 +1,2 @@
- if @administrateur.present?
= turbo_stream.remove(@administrateur)
= turbo_stream.update 'administrateurs',
render(Procedure::ProcedureAdministrateurs::AdministrateurComponent.with_collection(@procedure.administrateurs.order('users.email'), procedure: @procedure))

View file

@ -12,7 +12,7 @@
%th= 'Enregistré le'
%th= 'État'
%tbody#administrateurs
= render partial: 'administrateur', collection: @procedure.administrateurs.order('users.email'), locals: { procedure: @procedure }
= render(Procedure::ProcedureAdministrateurs::AdministrateurComponent.with_collection(@procedure.administrateurs.order('users.email'), procedure: @procedure))
%tfoot
%tr
%th{ colspan: 4 }

View file

@ -1,6 +1,6 @@
describe Administrateurs::ProcedureAdministrateursController, type: :controller do
let(:signed_in_admin) { create(:administrateur) }
let(:other_admin) { create(:administrateur) }
let(:signed_in_admin) { create(:administrateur).tap { _1.user.update(last_sign_in_at: Time.zone.now) } }
let(:other_admin) { create(:administrateur).tap { _1.user.update(last_sign_in_at: Time.zone.now) } }
let!(:administrateurs_procedure) { create(:administrateurs_procedure, administrateur: signed_in_admin, procedure: procedure, manager: manager) }
let!(:procedure) { create(:procedure, administrateurs: [other_admin]) }
render_views
@ -19,29 +19,41 @@ describe Administrateurs::ProcedureAdministrateursController, type: :controller
describe '#destroy' do
let(:manager) { false }
subject do
def destroy_admin(admin_to_remove)
delete :destroy, params: { procedure_id: procedure.id, id: admin_to_remove.id }, format: :turbo_stream
end
context 'when removing another admin' do
let(:admin_to_remove) { other_admin }
before do
destroy_admin(other_admin)
end
it 'removes the admin from the procedure' do
subject
expect(response).to have_http_status(:ok)
expect(subject.body).to include('alert-success')
expect(admin_to_remove.procedures.reload).not_to include(procedure)
expect(response.body).to include('alert-success')
expect(other_admin.procedures.reload).not_to include(procedure)
end
context 'then removing oneself' do
before do
destroy_admin(signed_in_admin)
end
it 'removes the admin from the procedure' do
expect(response.body).to include('alert-danger')
expect(signed_in_admin.procedures.reload).to include(procedure)
end
end
end
context 'when removing oneself from a procedure' do
let(:admin_to_remove) { signed_in_admin }
before do
destroy_admin(signed_in_admin)
end
it 'denies the right for an admin to remove itself' do
subject
expect(response).to have_http_status(:ok)
expect(subject.body).to include('alert-danger')
expect(admin_to_remove.procedures.reload).to include(procedure)
it 'removes the admin from the procedure' do
expect(response).to redirect_to admin_procedures_path
expect(signed_in_admin.procedures.reload).not_to include(procedure)
end
end
end

View file

@ -23,7 +23,6 @@ describe 'Administrateurs can manage administrateurs', js: true do
scenario 'the administrator can add another administrator' do
another_administrateur = create(:administrateur)
visit admin_procedure_administrateurs_path(procedure)
find('#administrateurs').click
fill_in('administrateur_email', with: another_administrateur.email)
@ -41,8 +40,6 @@ describe 'Administrateurs can manage administrateurs', js: true do
administrateur.administrateurs_procedures.update_all(manager: true)
visit admin_procedure_administrateurs_path(procedure)
find('#administrateurs').click
expect(page).to have_css("#administrateur_email[disabled=\"disabled\"]")
end
end