From 564c3c04fa53282727a3dd75d4ed24c8e6c1f0ce Mon Sep 17 00:00:00 2001 From: seb-by-ouidou Date: Fri, 6 Oct 2023 15:12:00 +0000 Subject: [PATCH 1/3] feat: US4.3.8 administrateur management --- .../card/administrateurs_component.rb | 5 + .../administrateurs_component.fr.yml | 5 + .../administrateurs_component.html.haml | 12 +++ .../administrateur_component.rb | 42 +++++++++ .../administrateur_component.html.haml | 5 + ...gestionnaire_administrateurs_controller.rb | 17 ++++ ...e_gestionnaire_gestionnaires_controller.rb | 2 +- .../groupe_gestionnaires_controller.rb | 2 +- app/mailers/groupe_gestionnaire_mailer.rb | 22 ++++- app/models/administrateur.rb | 5 +- app/models/concerns/user_find_by_concern.rb | 27 ++++++ app/models/gestionnaire.rb | 19 +--- app/models/groupe_gestionnaire.rb | 91 +++++++++++++++++-- app/models/instructeur.rb | 19 +--- .../_add_admin_form.html.haml | 13 +++ .../create.turbo_stream.haml | 5 + .../destroy.turbo_stream.haml | 6 ++ .../index.html.haml | 20 ++++ .../groupe_gestionnaires/show.html.haml | 1 + .../notify_added_administrateurs.html.haml | 6 ++ .../notify_removed_administrateur.html.haml | 6 ++ .../locales/models/groupe_gestionnaire/fr.yml | 3 + .../notify_added_administrateurs/en.yml | 4 + .../notify_added_administrateurs/fr.yml | 4 + .../notify_removed_administrateur/en.yml | 4 + .../notify_removed_administrateur/fr.yml | 4 + .../notify_removed_gestionnaire/fr.yml | 2 +- config/routes.rb | 1 + ...onnaire_administrateurs_controller_spec.rb | 49 ++++++++++ ...tionnaire_gestionnaires_controller_spec.rb | 2 +- .../groupe_gestionnaire_mailer_spec.rb | 34 ++++++- .../groupe_gestionnaire_mailer_preview.rb | 20 +++- spec/models/groupe_gestionnaire_spec.rb | 68 ++++++++++---- 33 files changed, 449 insertions(+), 76 deletions(-) create mode 100644 app/components/groupe_gestionnaire/card/administrateurs_component.rb create mode 100644 app/components/groupe_gestionnaire/card/administrateurs_component/administrateurs_component.fr.yml create mode 100644 app/components/groupe_gestionnaire/card/administrateurs_component/administrateurs_component.html.haml create mode 100644 app/components/groupe_gestionnaire/groupe_gestionnaire_administrateurs/administrateur_component.rb create mode 100644 app/components/groupe_gestionnaire/groupe_gestionnaire_administrateurs/administrateur_component/administrateur_component.html.haml create mode 100644 app/controllers/gestionnaires/groupe_gestionnaire_administrateurs_controller.rb create mode 100644 app/models/concerns/user_find_by_concern.rb create mode 100644 app/views/gestionnaires/groupe_gestionnaire_administrateurs/_add_admin_form.html.haml create mode 100644 app/views/gestionnaires/groupe_gestionnaire_administrateurs/create.turbo_stream.haml create mode 100644 app/views/gestionnaires/groupe_gestionnaire_administrateurs/destroy.turbo_stream.haml create mode 100644 app/views/gestionnaires/groupe_gestionnaire_administrateurs/index.html.haml create mode 100644 app/views/groupe_gestionnaire_mailer/notify_added_administrateurs.html.haml create mode 100644 app/views/groupe_gestionnaire_mailer/notify_removed_administrateur.html.haml create mode 100644 config/locales/views/groupe_gestionnaire_mailer/notify_added_administrateurs/en.yml create mode 100644 config/locales/views/groupe_gestionnaire_mailer/notify_added_administrateurs/fr.yml create mode 100644 config/locales/views/groupe_gestionnaire_mailer/notify_removed_administrateur/en.yml create mode 100644 config/locales/views/groupe_gestionnaire_mailer/notify_removed_administrateur/fr.yml create mode 100644 spec/controllers/gestionnaires/groupe_gestionnaire_administrateurs_controller_spec.rb diff --git a/app/components/groupe_gestionnaire/card/administrateurs_component.rb b/app/components/groupe_gestionnaire/card/administrateurs_component.rb new file mode 100644 index 000000000..73b398fcf --- /dev/null +++ b/app/components/groupe_gestionnaire/card/administrateurs_component.rb @@ -0,0 +1,5 @@ +class GroupeGestionnaire::Card::AdministrateursComponent < ApplicationComponent + def initialize(groupe_gestionnaire:) + @groupe_gestionnaire = groupe_gestionnaire + end +end diff --git a/app/components/groupe_gestionnaire/card/administrateurs_component/administrateurs_component.fr.yml b/app/components/groupe_gestionnaire/card/administrateurs_component/administrateurs_component.fr.yml new file mode 100644 index 000000000..123fa3c98 --- /dev/null +++ b/app/components/groupe_gestionnaire/card/administrateurs_component/administrateurs_component.fr.yml @@ -0,0 +1,5 @@ +--- +fr: + title: + one: Administrateur + other: Administrateurs diff --git a/app/components/groupe_gestionnaire/card/administrateurs_component/administrateurs_component.html.haml b/app/components/groupe_gestionnaire/card/administrateurs_component/administrateurs_component.html.haml new file mode 100644 index 000000000..34864bea5 --- /dev/null +++ b/app/components/groupe_gestionnaire/card/administrateurs_component/administrateurs_component.html.haml @@ -0,0 +1,12 @@ +.fr-col-6.fr-col-md-4.fr-col-lg-3 + = link_to gestionnaire_groupe_gestionnaire_administrateurs_path(@groupe_gestionnaire), id: 'administrateurs', class: 'fr-tile fr-enlarge-link' do + .fr-tile__body.flex.column.align-center.justify-between + %div + %span.icon.accept + %p.fr-tile-status-accept Validé + %div + .line-count.fr-my-1w + %p.fr-tag= @groupe_gestionnaire.administrateurs.size + %h3.fr-h6 + = t('.title', count: @groupe_gestionnaire.administrateurs.size) + %p.fr-btn.fr-btn--tertiary= t('views.shared.actions.edit') diff --git a/app/components/groupe_gestionnaire/groupe_gestionnaire_administrateurs/administrateur_component.rb b/app/components/groupe_gestionnaire/groupe_gestionnaire_administrateurs/administrateur_component.rb new file mode 100644 index 000000000..88cb19a0f --- /dev/null +++ b/app/components/groupe_gestionnaire/groupe_gestionnaire_administrateurs/administrateur_component.rb @@ -0,0 +1,42 @@ +class GroupeGestionnaire::GroupeGestionnaireAdministrateurs::AdministrateurComponent < ApplicationComponent + include ApplicationHelper + + def initialize(groupe_gestionnaire:, administrateur:) + @groupe_gestionnaire = groupe_gestionnaire + @administrateur = administrateur + end + + def email + if @administrateur == current_gestionnaire + "#{@administrateur.email} (C’est 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', + gestionnaire_groupe_gestionnaire_administrateur_path(@groupe_gestionnaire, @administrateur), + method: :delete, + class: 'button', + form: { data: { turbo: true, turbo_confirm: "Retirer « #{@administrateur.email} » des administrateurs de « #{@groupe_gestionnaire.name} » ?" } } + end + end + + def is_there_at_least_another_active_admin? + if @administrateur.active? + @groupe_gestionnaire.administrateurs.count(&:active?) > 1 + else + @groupe_gestionnaire.administrateurs.count(&:active?) >= 1 + end + end +end diff --git a/app/components/groupe_gestionnaire/groupe_gestionnaire_administrateurs/administrateur_component/administrateur_component.html.haml b/app/components/groupe_gestionnaire/groupe_gestionnaire_administrateurs/administrateur_component/administrateur_component.html.haml new file mode 100644 index 000000000..9678adb08 --- /dev/null +++ b/app/components/groupe_gestionnaire/groupe_gestionnaire_administrateurs/administrateur_component/administrateur_component.html.haml @@ -0,0 +1,5 @@ +%tr{ id: dom_id(@administrateur) } + %td= email + %td= created_at + %td= registration_state + %td= remove_button diff --git a/app/controllers/gestionnaires/groupe_gestionnaire_administrateurs_controller.rb b/app/controllers/gestionnaires/groupe_gestionnaire_administrateurs_controller.rb new file mode 100644 index 000000000..f45f7220b --- /dev/null +++ b/app/controllers/gestionnaires/groupe_gestionnaire_administrateurs_controller.rb @@ -0,0 +1,17 @@ +module Gestionnaires + class GroupeGestionnaireAdministrateursController < GestionnaireController + before_action :retrieve_groupe_gestionnaire, except: [:new] + + def index + end + + def create + administrateurs, flash[:alert], flash[:notice] = @groupe_gestionnaire.add_administrateurs(emails: [params.require(:administrateur)[:email]], current_user: current_gestionnaire) + @administrateur = administrateurs[0] + end + + def destroy + @administrateur, flash[:alert], flash[:notice] = @groupe_gestionnaire.remove_administrateur(params[:id], current_gestionnaire) + end + end +end diff --git a/app/controllers/gestionnaires/groupe_gestionnaire_gestionnaires_controller.rb b/app/controllers/gestionnaires/groupe_gestionnaire_gestionnaires_controller.rb index 7934ba026..d19366c35 100644 --- a/app/controllers/gestionnaires/groupe_gestionnaire_gestionnaires_controller.rb +++ b/app/controllers/gestionnaires/groupe_gestionnaire_gestionnaires_controller.rb @@ -11,7 +11,7 @@ module Gestionnaires end def destroy - @gestionnaire, flash[:alert], flash[:notice] = @groupe_gestionnaire.remove(params[:id], current_gestionnaire) + @gestionnaire, flash[:alert], flash[:notice] = @groupe_gestionnaire.remove_gestionnaire(params[:id], current_gestionnaire) end end end diff --git a/app/controllers/manager/groupe_gestionnaires_controller.rb b/app/controllers/manager/groupe_gestionnaires_controller.rb index 7de374dde..3f41d93c5 100644 --- a/app/controllers/manager/groupe_gestionnaires_controller.rb +++ b/app/controllers/manager/groupe_gestionnaires_controller.rb @@ -7,7 +7,7 @@ module Manager end def remove_gestionnaire - _gestionnaire, flash[:alert], flash[:notice] = groupe_gestionnaire.remove(gestionnaire_id, current_super_admin) + _gestionnaire, flash[:alert], flash[:notice] = groupe_gestionnaire.remove_gestionnaire(gestionnaire_id, current_super_admin) redirect_to manager_groupe_gestionnaire_path(groupe_gestionnaire) end diff --git a/app/mailers/groupe_gestionnaire_mailer.rb b/app/mailers/groupe_gestionnaire_mailer.rb index 6717d6da4..ef1dcac23 100644 --- a/app/mailers/groupe_gestionnaire_mailer.rb +++ b/app/mailers/groupe_gestionnaire_mailer.rb @@ -1,12 +1,12 @@ class GroupeGestionnaireMailer < ApplicationMailer layout 'mailers/layout' - def notify_removed_gestionnaire(groupe_gestionnaire, removed_gestionnaire, current_super_admin_email) + def notify_removed_gestionnaire(groupe_gestionnaire, removed_gestionnaire_email, current_super_admin_email) @groupe_gestionnaire = groupe_gestionnaire @current_super_admin_email = current_super_admin_email subject = "Vous avez été retiré(e) du groupe gestionnaire \"#{groupe_gestionnaire.name}\"" - mail(to: removed_gestionnaire.email, subject: subject) + mail(to: removed_gestionnaire_email, subject: subject) end def notify_added_gestionnaires(groupe_gestionnaire, added_gestionnaires, current_super_admin_email) @@ -19,6 +19,24 @@ class GroupeGestionnaireMailer < ApplicationMailer mail(bcc: added_gestionnaire_emails, subject: subject) end + def notify_removed_administrateur(groupe_gestionnaire, removed_administrateur_email, current_super_admin_email) + @groupe_gestionnaire = groupe_gestionnaire + @current_super_admin_email = current_super_admin_email + subject = "Vous avez été retiré(e) du groupe gestionnaire \"#{groupe_gestionnaire.name}\"" + + mail(to: removed_administrateur_email, subject: subject) + end + + def notify_added_administrateurs(groupe_gestionnaire, added_administrateurs, current_super_admin_email) + added_administrateur_emails = added_administrateurs.map(&:email) + @groupe_gestionnaire = groupe_gestionnaire + @current_super_admin_email = current_super_admin_email + + subject = "Vous avez été ajouté(e) en tant qu'administrateur du groupe gestionnaire \"#{groupe_gestionnaire.name}\"" + + mail(bcc: added_administrateur_emails, subject: subject) + end + def self.critical_email?(action_name) false end diff --git a/app/models/administrateur.rb b/app/models/administrateur.rb index e0af22bbc..ab8c30aed 100644 --- a/app/models/administrateur.rb +++ b/app/models/administrateur.rb @@ -1,4 +1,5 @@ class Administrateur < ApplicationRecord + include UserFindByConcern UNUSED_ADMIN_THRESHOLD = ENV.fetch('UNUSED_ADMIN_THRESHOLD') { 6 }.to_i.months has_and_belongs_to_many :instructeurs @@ -27,10 +28,6 @@ class Administrateur < ApplicationRecord .merge(APIToken.where(last_v2_authenticated_at: nil).or(APIToken.where(last_v2_authenticated_at: ..UNUSED_ADMIN_THRESHOLD.ago))) end - def self.by_email(email) - Administrateur.find_by(users: { email: email }) - end - def email user&.email end diff --git a/app/models/concerns/user_find_by_concern.rb b/app/models/concerns/user_find_by_concern.rb new file mode 100644 index 000000000..cb52c3b4e --- /dev/null +++ b/app/models/concerns/user_find_by_concern.rb @@ -0,0 +1,27 @@ +# Request a watermark on files attached to a `Champs::TitreIdentiteChamp`. +# +# We're using a class extension here, but we could as well have a periodic +# job that watermarks relevant attachments. +module UserFindByConcern + extend ActiveSupport::Concern + + included do + def self.by_email(email) + find_by(users: { email: email }) + end + + def self.find_all_by_identifier(ids: [], emails: []) + find_all_by_identifier_with_emails(ids:, emails:).first + end + + def self.find_all_by_identifier_with_emails(ids: [], emails: []) + valid_emails, invalid_emails = emails.partition { URI::MailTo::EMAIL_REGEXP.match?(_1) } + + [ + where(id: ids).or(where(users: { email: valid_emails })).distinct(:id), + valid_emails, + invalid_emails + ] + end + end +end diff --git a/app/models/gestionnaire.rb b/app/models/gestionnaire.rb index ed08f4ef1..6fa109540 100644 --- a/app/models/gestionnaire.rb +++ b/app/models/gestionnaire.rb @@ -1,4 +1,5 @@ class Gestionnaire < ApplicationRecord + include UserFindByConcern has_and_belongs_to_many :groupe_gestionnaires belongs_to :user @@ -7,10 +8,6 @@ class Gestionnaire < ApplicationRecord default_scope { eager_load(:user) } - def self.by_email(email) - find_by(users: { email: email }) - end - def email user&.email end @@ -19,20 +16,6 @@ class Gestionnaire < ApplicationRecord user&.active? end - def self.find_all_by_identifier(ids: [], emails: []) - find_all_by_identifier_with_emails(ids:, emails:).first - end - - def self.find_all_by_identifier_with_emails(ids: [], emails: []) - valid_emails, invalid_emails = emails.partition { URI::MailTo::EMAIL_REGEXP.match?(_1) } - - [ - where(id: ids).or(where(users: { email: valid_emails })).distinct(:id), - valid_emails, - invalid_emails - ] - end - def can_be_deleted? groupe_gestionnaires.roots.each do |rt| return false unless rt.gestionnaires.size > 1 diff --git a/app/models/groupe_gestionnaire.rb b/app/models/groupe_gestionnaire.rb index fe7f3e9a0..57c8d40e5 100644 --- a/app/models/groupe_gestionnaire.rb +++ b/app/models/groupe_gestionnaire.rb @@ -4,28 +4,28 @@ class GroupeGestionnaire < ApplicationRecord has_ancestry - def add(gestionnaire) + def add_gestionnaire(gestionnaire) return if gestionnaire.nil? return if in?(gestionnaire.groupe_gestionnaires) gestionnaires << gestionnaire end - def remove(gestionnaire_id, current_user) + def remove_gestionnaire(gestionnaire_id, current_user) if !self.is_root? || self.gestionnaires.one? alert = "Suppression impossible : il doit y avoir au moins un gestionnaire dans le groupe racine" else gestionnaire = Gestionnaire.find(gestionnaire_id) - if gestionnaire.nil? || !in?(gestionnaire.groupe_gestionnaires) || !gestionnaire.groupe_gestionnaires.destroy(self) - alert = "Le gestionnaire « #{gestionnaire.email} » n’est pas dans le groupe." + if !in?(gestionnaire.groupe_gestionnaires) || !gestionnaire.groupe_gestionnaires.destroy(self) + alert = "Le gestionnaire « #{gestionnaire.email} » n’est pas dans le groupe gestionnaire." else if gestionnaire.groupe_gestionnaires.empty? gestionnaire.destroy end - notice = "Le gestionnaire « #{gestionnaire.email} » a été retiré du groupe." + notice = "Le gestionnaire « #{gestionnaire.email} » a été retiré du groupe gestionnaire." GroupeGestionnaireMailer - .notify_removed_gestionnaire(self, gestionnaire, current_user.email) + .notify_removed_gestionnaire(self, gestionnaire.email, current_user.email) .deliver_later end end @@ -51,7 +51,7 @@ class GroupeGestionnaire < ApplicationRecord # We dont't want to assign a user to an groupe_gestionnaire if they are already assigned to it gestionnaires_duplicate = gestionnaires_to_add & gestionnaires gestionnaires_to_add -= gestionnaires - gestionnaires_to_add.each { add(_1) } + gestionnaires_to_add.each { add_gestionnaire(_1) } if invalid_emails.present? alert = I18n.t('activerecord.wrong_address', @@ -75,6 +75,83 @@ class GroupeGestionnaire < ApplicationRecord [gestionnaires_to_add, alert, notice] end + def add_administrateur(administrateur) + return if administrateur.nil? + return if id == administrateur.groupe_gestionnaire_id + + administrateurs << administrateur + end + + def remove_administrateur(administrateur_id, current_user) + administrateur = Administrateur.find(administrateur_id) + + if id != administrateur.groupe_gestionnaire_id + alert = "L'administrateur « #{administrateur.email} » n’est pas dans le groupe gestionnaire." + else + administrateur.destroy + notice = "L'administrateur « #{administrateur.email} » a été retiré du groupe gestionnaire." + GroupeGestionnaireMailer + .notify_removed_administrateur(self, administrateur.email, current_user.email) + .deliver_later + end + [administrateur, alert, notice] + end + + def add_administrateurs(ids: [], emails: [], current_user: nil) + emails = emails.to_json + emails = JSON.parse(emails).map { EmailSanitizableConcern::EmailSanitizer.sanitize(_1) } + + administrateurs_to_add, valid_emails, invalid_emails = Administrateur.find_all_by_identifier_with_emails(ids:, emails:) + not_found_emails = valid_emails - administrateurs_to_add.map(&:email) + + # Send invitations to users without account + if not_found_emails.present? + administrateurs_to_add += not_found_emails.map do |email| + user = User.create_or_promote_to_administrateur(email, SecureRandom.hex) + user.invite_administrateur!(self) + user.administrateur + end + end + administrateurs_already_in_groupe_gestionnaire = [] + # We dont't want to assign a user to an groupe_gestionnaire if they are already assigned to it + administrateurs_duplicate = administrateurs_to_add & administrateurs + administrateurs_to_add -= administrateurs + administrateurs_to_add.each do |administrateur| + if !current_user.is_a?(SuperAdmin) && administrateur.groupe_gestionnaire_id && ((administrateur.groupe_gestionnaire.ancestor_ids + [administrateur.groupe_gestionnaire_id]) & current_user.groupe_gestionnaire_ids).empty? + administrateurs_already_in_groupe_gestionnaire << administrateur + next + end + add_administrateur(administrateur) + end + + if administrateurs_already_in_groupe_gestionnaire.present? + alert = I18n.t('activerecord.errors.administrateurs_already_in_groupe_gestionnaire', + count: administrateurs_already_in_groupe_gestionnaire.size, + emails: administrateurs_already_in_groupe_gestionnaire) + end + + if invalid_emails.present? + alert = I18n.t('activerecord.wrong_address', + count: invalid_emails.size, + emails: invalid_emails) + end + if administrateurs_duplicate.present? + alert = I18n.t('activerecord.errors.duplicate_email', + count: invalid_emails.size, + emails: administrateurs_duplicate.map(&:email)) + end + + if administrateurs_to_add.present? + notice = "Les administrateurs ont bien été affectés au groupe gestionnaire" + + GroupeGestionnaireMailer + .notify_added_administrateurs(self, administrateurs_to_add, current_user.email) + .deliver_later + end + + [administrateurs_to_add, alert, notice] + end + def can_be_deleted?(current_user) (gestionnaires.empty? || (gestionnaires == [current_user])) && administrateurs.empty? && children.empty? end diff --git a/app/models/instructeur.rb b/app/models/instructeur.rb index a856c203a..1833b48cc 100644 --- a/app/models/instructeur.rb +++ b/app/models/instructeur.rb @@ -1,4 +1,5 @@ class Instructeur < ApplicationRecord + include UserFindByConcern has_and_belongs_to_many :administrateurs has_many :assign_to, dependent: :destroy @@ -36,24 +37,6 @@ class Instructeur < ApplicationRecord default_scope { eager_load(:user) } - def self.by_email(email) - find_by(users: { email: email }) - end - - def self.find_all_by_identifier(ids: [], emails: []) - find_all_by_identifier_with_emails(ids:, emails:).first - end - - def self.find_all_by_identifier_with_emails(ids: [], emails: []) - valid_emails, invalid_emails = emails.partition { URI::MailTo::EMAIL_REGEXP.match?(_1) } - - [ - where(id: ids).or(where(users: { email: valid_emails })).distinct(:id), - valid_emails, - invalid_emails - ] - end - def email user.email end diff --git a/app/views/gestionnaires/groupe_gestionnaire_administrateurs/_add_admin_form.html.haml b/app/views/gestionnaires/groupe_gestionnaire_administrateurs/_add_admin_form.html.haml new file mode 100644 index 000000000..6852a13e5 --- /dev/null +++ b/app/views/gestionnaires/groupe_gestionnaire_administrateurs/_add_admin_form.html.haml @@ -0,0 +1,13 @@ += form_for groupe_gestionnaire.administrateurs.new(user: User.new), + url: { controller: 'groupe_gestionnaire_administrateurs' }, + html: { id: "new_administrateur" }, + data: { turbo: true, turbo_force: :server } do |f| + .fr-input-group + = f.label :email, class: "fr-label" do + Ajouter un administrateur + %span.fr-hint-text + = "Renseignez l’email d’un administrateur pour lui permettre de gérer le groupe « #{groupe_gestionnaire.name} ». Exemple : marie.dupont@exemple.fr" + + = f.email_field :email, required: true, class: "fr-input", autofocus: true + + = f.submit 'Ajouter comme administrateur', class: 'fr-btn' diff --git a/app/views/gestionnaires/groupe_gestionnaire_administrateurs/create.turbo_stream.haml b/app/views/gestionnaires/groupe_gestionnaire_administrateurs/create.turbo_stream.haml new file mode 100644 index 000000000..1adda3a89 --- /dev/null +++ b/app/views/gestionnaires/groupe_gestionnaire_administrateurs/create.turbo_stream.haml @@ -0,0 +1,5 @@ +- if @administrateur.present? + = turbo_stream.update 'administrateurs' do + = render GroupeGestionnaire::GroupeGestionnaireAdministrateurs::AdministrateurComponent.with_collection(@groupe_gestionnaire.administrateurs.order('users.email'), groupe_gestionnaire: @groupe_gestionnaire) + = turbo_stream.replace "new_administrateur", partial: 'add_admin_form', locals: { groupe_gestionnaire: @groupe_gestionnaire } + = turbo_stream.focus 'administrateur_email' diff --git a/app/views/gestionnaires/groupe_gestionnaire_administrateurs/destroy.turbo_stream.haml b/app/views/gestionnaires/groupe_gestionnaire_administrateurs/destroy.turbo_stream.haml new file mode 100644 index 000000000..b72211119 --- /dev/null +++ b/app/views/gestionnaires/groupe_gestionnaire_administrateurs/destroy.turbo_stream.haml @@ -0,0 +1,6 @@ += turbo_stream.update 'administrateurs' do + = render GroupeGestionnaire::GroupeGestionnaireAdministrateurs::AdministrateurComponent.with_collection(@groupe_gestionnaire.administrateurs.order('users.email'), groupe_gestionnaire: @groupe_gestionnaire) +- if @groupe_gestionnaire.administrateurs.one? + = turbo_stream.focus 'administrateur_email' +- else + = turbo_stream.focus_all '#administrateurs tr:first-child input[type="submit"]' diff --git a/app/views/gestionnaires/groupe_gestionnaire_administrateurs/index.html.haml b/app/views/gestionnaires/groupe_gestionnaire_administrateurs/index.html.haml new file mode 100644 index 000000000..f2796c906 --- /dev/null +++ b/app/views/gestionnaires/groupe_gestionnaire_administrateurs/index.html.haml @@ -0,0 +1,20 @@ += render partial: 'gestionnaires/breadcrumbs', + locals: { steps: [['Groupes gestionnaire', gestionnaire_groupe_gestionnaires_path], + ["#{@groupe_gestionnaire.name.truncate_words(10)}", gestionnaire_groupe_gestionnaire_path(@groupe_gestionnaire)], + ['Administrateurs']], preview: false } + +.container + %h1 Gérer les administrateurs de « #{@groupe_gestionnaire.name} » + + %table.table + %thead + %tr + %th= 'Adresse email' + %th= 'Enregistré le' + %th= 'État' + %th + %tbody#administrateurs + = render(GroupeGestionnaire::GroupeGestionnaireAdministrateurs::AdministrateurComponent.with_collection(@groupe_gestionnaire.administrateurs.order('users.email'), groupe_gestionnaire: @groupe_gestionnaire)) + + .fr-mt-4w + = render 'add_admin_form', groupe_gestionnaire: @groupe_gestionnaire diff --git a/app/views/gestionnaires/groupe_gestionnaires/show.html.haml b/app/views/gestionnaires/groupe_gestionnaires/show.html.haml index 124d12dd8..88b26e3bf 100644 --- a/app/views/gestionnaires/groupe_gestionnaires/show.html.haml +++ b/app/views/gestionnaires/groupe_gestionnaires/show.html.haml @@ -18,4 +18,5 @@ %a{ href: gestionnaire_groupe_gestionnaire_path(@groupe_gestionnaire.groupe_gestionnaire) }= @groupe_gestionnaire.groupe_gestionnaire.name .fr-grid-row.fr-grid-row--gutters.fr-mb-5w = render GroupeGestionnaire::Card::GestionnairesComponent.new(groupe_gestionnaire: @groupe_gestionnaire) + = render GroupeGestionnaire::Card::AdministrateursComponent.new(groupe_gestionnaire: @groupe_gestionnaire) = render GroupeGestionnaire::Card::ChildrenComponent.new(groupe_gestionnaire: @groupe_gestionnaire) diff --git a/app/views/groupe_gestionnaire_mailer/notify_added_administrateurs.html.haml b/app/views/groupe_gestionnaire_mailer/notify_added_administrateurs.html.haml new file mode 100644 index 000000000..94f82e361 --- /dev/null +++ b/app/views/groupe_gestionnaire_mailer/notify_added_administrateurs.html.haml @@ -0,0 +1,6 @@ +%p= t(:hello, scope: [:views, :shared, :greetings]) + +%p + = t(".email_body", groupe_gestionnaire_name: @groupe_gestionnaire.name, email: @current_super_admin_email, application_name: APPLICATION_NAME) + += render partial: "layouts/mailers/signature" diff --git a/app/views/groupe_gestionnaire_mailer/notify_removed_administrateur.html.haml b/app/views/groupe_gestionnaire_mailer/notify_removed_administrateur.html.haml new file mode 100644 index 000000000..94f82e361 --- /dev/null +++ b/app/views/groupe_gestionnaire_mailer/notify_removed_administrateur.html.haml @@ -0,0 +1,6 @@ +%p= t(:hello, scope: [:views, :shared, :greetings]) + +%p + = t(".email_body", groupe_gestionnaire_name: @groupe_gestionnaire.name, email: @current_super_admin_email, application_name: APPLICATION_NAME) + += render partial: "layouts/mailers/signature" diff --git a/config/locales/models/groupe_gestionnaire/fr.yml b/config/locales/models/groupe_gestionnaire/fr.yml index cd0300184..211b5bb2e 100644 --- a/config/locales/models/groupe_gestionnaire/fr.yml +++ b/config/locales/models/groupe_gestionnaire/fr.yml @@ -11,6 +11,9 @@ fr: duplicate_email: one: "%{emails} est déjà gestionnaire de ce groupe" other: "%{emails} sont déjà gestionnaires de ce groupe" + administrateurs_already_in_groupe_gestionnaire: + one: Cet administrateur est déjà dans un groupe gestionnaire dont vous n'avez pas la gestion. + other: Ces administrateurs sont déjà dans un groupe gestionnaire dont vous n'avez pas la gestion. wrong_address: one: "%{emails} n’est pas une adresse email valide" other: "%{emails} ne sont pas des adresses emails valides" diff --git a/config/locales/views/groupe_gestionnaire_mailer/notify_added_administrateurs/en.yml b/config/locales/views/groupe_gestionnaire_mailer/notify_added_administrateurs/en.yml new file mode 100644 index 000000000..7731e844d --- /dev/null +++ b/config/locales/views/groupe_gestionnaire_mailer/notify_added_administrateurs/en.yml @@ -0,0 +1,4 @@ +en: + groupe_gestionnaire_mailer: + notify_added_administrateurs: + email_body: "You were assigned as administrateur on the admins group %{groupe_gestionnaire_name} on %{application_name} by « %{email} »" diff --git a/config/locales/views/groupe_gestionnaire_mailer/notify_added_administrateurs/fr.yml b/config/locales/views/groupe_gestionnaire_mailer/notify_added_administrateurs/fr.yml new file mode 100644 index 000000000..227073a70 --- /dev/null +++ b/config/locales/views/groupe_gestionnaire_mailer/notify_added_administrateurs/fr.yml @@ -0,0 +1,4 @@ +fr: + groupe_gestionnaire_mailer: + notify_added_administrateurs: + email_body: "Vous venez d’être nommé administrateur du groupe gestionnaire %{groupe_gestionnaire_name} sur %{application_name} par « %{email} »." diff --git a/config/locales/views/groupe_gestionnaire_mailer/notify_removed_administrateur/en.yml b/config/locales/views/groupe_gestionnaire_mailer/notify_removed_administrateur/en.yml new file mode 100644 index 000000000..f30cf2787 --- /dev/null +++ b/config/locales/views/groupe_gestionnaire_mailer/notify_removed_administrateur/en.yml @@ -0,0 +1,4 @@ +en: + groupe_gestionnaire_mailer: + notify_removed_administrateur: + email_body: "You were removed from the admins group %{groupe_gestionnaire_name} on %{application_name} by « %{email} »" diff --git a/config/locales/views/groupe_gestionnaire_mailer/notify_removed_administrateur/fr.yml b/config/locales/views/groupe_gestionnaire_mailer/notify_removed_administrateur/fr.yml new file mode 100644 index 000000000..32eeda1cb --- /dev/null +++ b/config/locales/views/groupe_gestionnaire_mailer/notify_removed_administrateur/fr.yml @@ -0,0 +1,4 @@ +fr: + groupe_gestionnaire_mailer: + notify_removed_administrateur: + email_body: "Vous venez d’être supprimé(e) du groupe gestionnaire %{groupe_gestionnaire_name} sur %{application_name} par « %{email} »." diff --git a/config/locales/views/groupe_gestionnaire_mailer/notify_removed_gestionnaire/fr.yml b/config/locales/views/groupe_gestionnaire_mailer/notify_removed_gestionnaire/fr.yml index 927149552..4b8154bd9 100644 --- a/config/locales/views/groupe_gestionnaire_mailer/notify_removed_gestionnaire/fr.yml +++ b/config/locales/views/groupe_gestionnaire_mailer/notify_removed_gestionnaire/fr.yml @@ -1,4 +1,4 @@ fr: groupe_gestionnaire_mailer: notify_removed_gestionnaire: - email_body: "Vous venez d’être supprimé(e) du groupe %{groupe_gestionnaire_name} sur %{application_name} par « %{email} »." + email_body: "Vous venez d’être supprimé(e) du groupe gestionnaire %{groupe_gestionnaire_name} sur %{application_name} par « %{email} »." diff --git a/config/routes.rb b/config/routes.rb index a63ce70f1..82e55eec0 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -506,6 +506,7 @@ Rails.application.routes.draw do scope module: 'gestionnaires', as: 'gestionnaire' do resources :groupe_gestionnaires, path: 'groupes', only: [:index, :show, :create, :edit, :update, :destroy] do resources :gestionnaires, controller: 'groupe_gestionnaire_gestionnaires', only: [:index, :create, :destroy] + resources :administrateurs, controller: 'groupe_gestionnaire_administrateurs', only: [:index, :create, :destroy] resources :children, controller: 'groupe_gestionnaire_children', only: [:index, :create, :destroy] end end diff --git a/spec/controllers/gestionnaires/groupe_gestionnaire_administrateurs_controller_spec.rb b/spec/controllers/gestionnaires/groupe_gestionnaire_administrateurs_controller_spec.rb new file mode 100644 index 000000000..55f034f65 --- /dev/null +++ b/spec/controllers/gestionnaires/groupe_gestionnaire_administrateurs_controller_spec.rb @@ -0,0 +1,49 @@ +describe Gestionnaires::GroupeGestionnaireAdministrateursController, type: :controller do + let(:gestionnaire) { create(:gestionnaire).tap { _1.user.update(last_sign_in_at: Time.zone.now) } } + let(:groupe_gestionnaire) { create(:groupe_gestionnaire, gestionnaires: [gestionnaire]) } + + before { sign_in gestionnaire.user } + + describe '#create' do + before do + post :create, + params: { + groupe_gestionnaire_id: groupe_gestionnaire.id, + administrateur: { email: new_administrateur_email } + }, + format: :turbo_stream + end + + context 'of a new administrateur' do + let(:new_administrateur_email) { 'new_administrateur@mail.com' } + + it { expect(groupe_gestionnaire.reload.administrateurs.map(&:email)).to include(new_administrateur_email) } + it { expect(flash.notice).to eq("Les administrateurs ont bien été affectés au groupe gestionnaire") } + end + end + + describe '#destroy' do + let(:gestionnaire) { create(:gestionnaire) } + let(:new_administrateur) { create(:administrateur) } + + before do + groupe_gestionnaire.administrateurs << new_administrateur + end + + def remove_administrateur(administrateur) + delete :destroy, + params: { + groupe_gestionnaire_id: groupe_gestionnaire.id, + id: administrateur.id + }, + format: :turbo_stream + end + + context 'when there are many administrateurs' do + before { remove_administrateur(new_administrateur) } + + it { expect(groupe_gestionnaire.reload.administrateurs.count).to eq(0) } + it { expect(flash.notice).to eq("L'administrateur « #{new_administrateur.email} » a été retiré du groupe gestionnaire.") } + end + end +end diff --git a/spec/controllers/gestionnaires/groupe_gestionnaire_gestionnaires_controller_spec.rb b/spec/controllers/gestionnaires/groupe_gestionnaire_gestionnaires_controller_spec.rb index f85a35fd5..bad6298e9 100644 --- a/spec/controllers/gestionnaires/groupe_gestionnaire_gestionnaires_controller_spec.rb +++ b/spec/controllers/gestionnaires/groupe_gestionnaire_gestionnaires_controller_spec.rb @@ -44,7 +44,7 @@ describe Gestionnaires::GroupeGestionnaireGestionnairesController, type: :contro it { expect(groupe_gestionnaire.gestionnaires).to include(gestionnaire) } it { expect(groupe_gestionnaire.reload.gestionnaires.count).to eq(1) } - it { expect(flash.notice).to eq("Le gestionnaire « #{new_gestionnaire.email} » a été retiré du groupe.") } + it { expect(flash.notice).to eq("Le gestionnaire « #{new_gestionnaire.email} » a été retiré du groupe gestionnaire.") } end context 'when there is only one gestionnaire' do diff --git a/spec/mailers/groupe_gestionnaire_mailer_spec.rb b/spec/mailers/groupe_gestionnaire_mailer_spec.rb index 1ce585f54..5fae5ce86 100644 --- a/spec/mailers/groupe_gestionnaire_mailer_spec.rb +++ b/spec/mailers/groupe_gestionnaire_mailer_spec.rb @@ -6,9 +6,9 @@ RSpec.describe GroupeGestionnaireMailer, type: :mailer do let(:current_super_admin_email) { 'toto@email.com' } - subject { described_class.notify_removed_gestionnaire(groupe_gestionnaire, gestionnaire_to_remove, current_super_admin_email) } + subject { described_class.notify_removed_gestionnaire(groupe_gestionnaire, gestionnaire_to_remove.email, current_super_admin_email) } - it { expect(subject.body).to include('Vous venez d’être supprimé(e) du groupe') } + it { expect(subject.body).to include('Vous venez d’être supprimé(e) du groupe gestionnaire') } it { expect(subject.to).to match_array(['int3@g']) } end @@ -21,9 +21,37 @@ RSpec.describe GroupeGestionnaireMailer, type: :mailer do subject { described_class.notify_added_gestionnaires(groupe_gestionnaire, gestionnaires_to_add, current_super_admin_email) } - before { gestionnaires_to_add.each { groupe_gestionnaire.add(_1) } } + before { gestionnaires_to_add.each { groupe_gestionnaire.add_gestionnaire(_1) } } it { expect(subject.body).to include('Vous venez d’être nommé gestionnaire du groupe gestionnaire') } it { expect(subject.bcc).to match_array(['int3@g', 'int4@g']) } end + + describe '#notify_removed_administrateur' do + let(:groupe_gestionnaire) { create(:groupe_gestionnaire) } + + let(:administrateur_to_remove) { create(:administrateur, email: 'int3@g') } + + let(:current_super_admin_email) { 'toto@email.com' } + + subject { described_class.notify_removed_administrateur(groupe_gestionnaire, administrateur_to_remove.email, current_super_admin_email) } + + it { expect(subject.body).to include('Vous venez d’être supprimé(e) du groupe gestionnaire') } + it { expect(subject.to).to match_array(['int3@g']) } + end + + describe '#notify_added_administrateurs' do + let(:groupe_gestionnaire) { create(:groupe_gestionnaire) } + + let(:administrateurs_to_add) { [create(:administrateur, email: 'int3@g'), create(:administrateur, email: 'int4@g')] } + + let(:current_super_admin_email) { 'toto@email.com' } + + subject { described_class.notify_added_administrateurs(groupe_gestionnaire, administrateurs_to_add, current_super_admin_email) } + + before { administrateurs_to_add.each { groupe_gestionnaire.add_administrateur(_1) } } + + it { expect(subject.body).to include('Vous venez d’être nommé administrateur du groupe gestionnaire') } + it { expect(subject.bcc).to match_array(['int3@g', 'int4@g']) } + end end diff --git a/spec/mailers/previews/groupe_gestionnaire_mailer_preview.rb b/spec/mailers/previews/groupe_gestionnaire_mailer_preview.rb index 53ce5f929..a5f6d5137 100644 --- a/spec/mailers/previews/groupe_gestionnaire_mailer_preview.rb +++ b/spec/mailers/previews/groupe_gestionnaire_mailer_preview.rb @@ -1,18 +1,32 @@ class GroupeGestionnaireMailerPreview < ActionMailer::Preview def notify_removed_gestionnaire - groupe_gestionnaire = GroupeGestionnaire.new(name: 'un groupe d\'admin') + groupe_gestionnaire = GroupeGestionnaire.new(name: 'un groupe gestionnaire') current_super_admin_email = 'admin@dgfip.com' gestionnaire = Gestionnaire.new(user: user) - GroupeGestionnaireMailer.notify_removed_gestionnaire(groupe_gestionnaire, gestionnaire, current_super_admin_email) + GroupeGestionnaireMailer.notify_removed_gestionnaire(groupe_gestionnaire, gestionnaire.email, current_super_admin_email) end def notify_added_gestionnaires - groupe_gestionnaire = GroupeGestionnaire.new(name: 'un groupe d\'admin') + groupe_gestionnaire = GroupeGestionnaire.new(name: 'un groupe gestionnaire') current_super_admin_email = 'admin@dgfip.com' gestionnaires = [Gestionnaire.new(user: user)] GroupeGestionnaireMailer.notify_added_gestionnaires(groupe_gestionnaire, gestionnaires, current_super_admin_email) end + def notify_removed_administrateur + groupe_gestionnaire = GroupeGestionnaire.new(name: 'un groupe gestionnaire') + current_super_admin_email = 'admin@dgfip.com' + administrateur = Administrateur.new(user: user) + GroupeGestionnaireMailer.notify_removed_administrateur(groupe_gestionnaire, administrateur.email, current_super_admin_email) + end + + def notify_added_administrateurs + groupe_gestionnaire = GroupeGestionnaire.new(name: 'un groupe gestionnaire') + current_super_admin_email = 'admin@dgfip.com' + administrateurs = [Administrateur.new(user: user)] + GroupeGestionnaireMailer.notify_added_administrateurs(groupe_gestionnaire, administrateurs, current_super_admin_email) + end + private def user diff --git a/spec/models/groupe_gestionnaire_spec.rb b/spec/models/groupe_gestionnaire_spec.rb index 365773d63..d3f29b7c4 100644 --- a/spec/models/groupe_gestionnaire_spec.rb +++ b/spec/models/groupe_gestionnaire_spec.rb @@ -4,11 +4,11 @@ describe GroupeGestionnaire, type: :model do it { is_expected.to have_and_belong_to_many(:gestionnaires) } end - describe "#add" do + describe "#add_gestionnaire" do let(:groupe_gestionnaire) { create(:groupe_gestionnaire) } let(:gestionnaire) { create(:gestionnaire) } - subject { groupe_gestionnaire.add(gestionnaire) } + subject { groupe_gestionnaire.add_gestionnaire(gestionnaire) } it 'adds the gestionnaire to the groupe gestionnaire' do subject @@ -37,25 +37,59 @@ describe GroupeGestionnaire, type: :model do end end - describe "#remove" do + describe "#add_administrateur" do + let(:groupe_gestionnaire) { create(:groupe_gestionnaire) } let(:gestionnaire) { create(:gestionnaire) } - let(:gestionnaire_to_remove) { create(:gestionnaire) } - let(:groupe_gestionnaire) { create(:groupe_gestionnaire, gestionnaires: [gestionnaire, gestionnaire_to_remove]) } + let(:administrateur) { create(:administrateur) } - it 'removes the gestionnaire by id' do - expect(groupe_gestionnaire.reload.gestionnaires.size).to eq(2) - groupe_gestionnaire.remove(gestionnaire_to_remove.id, gestionnaire) - expect(groupe_gestionnaire.reload.gestionnaires).not_to include(gestionnaire_to_remove) - expect(groupe_gestionnaire.reload.gestionnaires.size).to eq(1) + subject { groupe_gestionnaire.add_administrateur(administrateur) } + + it 'adds the administrateur to the groupe gestionnaire' do + subject + expect(groupe_gestionnaire.reload.administrateurs).to include(administrateur) + end + end + + describe "#add_administrateurs" do + let(:gestionnaire) { create(:gestionnaire) } + let(:groupe_gestionnaire) { create(:groupe_gestionnaire, gestionnaires: [gestionnaire]) } + let(:administrateur) { create(:administrateur) } + + it 'adds the administrateur by id' do + groupe_gestionnaire.add_administrateurs(ids: [administrateur.id], current_user: gestionnaire) + expect(groupe_gestionnaire.reload.administrateurs).to include(administrateur) end - it 'does not remove the gestionnaire if last' do - expect(groupe_gestionnaire.reload.gestionnaires.size).to eq(2) - groupe_gestionnaire.remove(gestionnaire.id, gestionnaire) - expect(groupe_gestionnaire.reload.gestionnaires.size).to eq(1) - groupe_gestionnaire.remove(gestionnaire_to_remove.id, gestionnaire) - expect(groupe_gestionnaire.reload.gestionnaires).to include(gestionnaire_to_remove) - expect(groupe_gestionnaire.reload.gestionnaires.size).to eq(1) + it 'adds the existing administrateur by email' do + groupe_gestionnaire.add_administrateurs(emails: [administrateur.email], current_user: gestionnaire) + expect(groupe_gestionnaire.reload.administrateurs).to include(administrateur) + end + + context "when administrateurs_already_in_groupe_gestionnaire" do + let(:other_groupe_gestionnaire) { create(:groupe_gestionnaire) } + let(:administrateur) { create(:administrateur, groupe_gestionnaire_id: other_groupe_gestionnaire.id) } + it 'does not add the existing administrateur by email' do + groupe_gestionnaire.add_administrateurs(emails: [administrateur.email], current_user: gestionnaire) + expect(groupe_gestionnaire.reload.administrateurs).not_to include(administrateur) + end + end + + it 'adds the new administrateur by email' do + groupe_gestionnaire.add_administrateurs(emails: ['new_administrateur@ds.fr'], current_user: gestionnaire) + expect(groupe_gestionnaire.reload.administrateurs.last.email).to eq('new_administrateur@ds.fr') + end + end + + describe "#remove_administrateur" do + let(:gestionnaire) { create(:gestionnaire) } + let(:groupe_gestionnaire) { create(:groupe_gestionnaire, gestionnaires: [gestionnaire]) } + let!(:administrateur) { create(:administrateur, groupe_gestionnaire_id: groupe_gestionnaire.id) } + + it 'removes the administrateur by id' do + expect(groupe_gestionnaire.reload.administrateurs.size).to eq(1) + groupe_gestionnaire.remove_administrateur(administrateur.id, gestionnaire) + expect(groupe_gestionnaire.reload.administrateurs).not_to include(administrateur) + expect(groupe_gestionnaire.reload.administrateurs.size).to eq(0) end end end From e34307b50c13c7f740567a4432d89b060bd58286 Mon Sep 17 00:00:00 2001 From: seb-by-ouidou Date: Wed, 6 Dec 2023 13:41:32 +0000 Subject: [PATCH 2/3] fix: fixes after review --- .../administrateur_component.rb | 14 +- .../administrateur_component.html.haml | 1 + ...gestionnaire_administrateurs_controller.rb | 90 +++++++++++- ...groupe_gestionnaire_children_controller.rb | 2 +- ...e_gestionnaire_gestionnaires_controller.rb | 62 +++++++- .../groupe_gestionnaires_controller.rb | 69 +++++++-- app/models/concerns/user_find_by_concern.rb | 6 +- app/models/groupe_gestionnaire.rb | 134 ------------------ .../index.html.haml | 1 + .../remove.turbo_stream.haml | 6 + config/locales/fr.yml | 17 +++ .../locales/models/groupe_gestionnaire/fr.yml | 3 + config/routes.rb | 4 +- ...onnaire_administrateurs_controller_spec.rb | 59 +++++++- spec/models/groupe_gestionnaire_spec.rb | 64 --------- 15 files changed, 302 insertions(+), 230 deletions(-) create mode 100644 app/views/gestionnaires/groupe_gestionnaire_administrateurs/remove.turbo_stream.haml diff --git a/app/components/groupe_gestionnaire/groupe_gestionnaire_administrateurs/administrateur_component.rb b/app/components/groupe_gestionnaire/groupe_gestionnaire_administrateurs/administrateur_component.rb index 88cb19a0f..dce02837b 100644 --- a/app/components/groupe_gestionnaire/groupe_gestionnaire_administrateurs/administrateur_component.rb +++ b/app/components/groupe_gestionnaire/groupe_gestionnaire_administrateurs/administrateur_component.rb @@ -25,10 +25,20 @@ class GroupeGestionnaire::GroupeGestionnaireAdministrateurs::AdministrateurCompo def remove_button if is_there_at_least_another_active_admin? button_to 'Retirer', + remove_gestionnaire_groupe_gestionnaire_administrateur_path(@groupe_gestionnaire, @administrateur), + method: :delete, + class: 'fr-btn fr-btn--sm fr-btn--tertiary', + form: { data: { turbo: true, turbo_confirm: "Retirer « #{@administrateur.email} » des administrateurs de « #{@groupe_gestionnaire.name} » ?" } } + end + end + + def destroy_button + if is_there_at_least_another_active_admin? + button_to 'Supprimer', gestionnaire_groupe_gestionnaire_administrateur_path(@groupe_gestionnaire, @administrateur), method: :delete, - class: 'button', - form: { data: { turbo: true, turbo_confirm: "Retirer « #{@administrateur.email} » des administrateurs de « #{@groupe_gestionnaire.name} » ?" } } + class: 'fr-btn fr-btn--sm fr-btn--tertiary', + form: { data: { turbo: true, turbo_confirm: "Supprimer « #{@administrateur.email} » en tant qu'administrateurs ?" } } end end diff --git a/app/components/groupe_gestionnaire/groupe_gestionnaire_administrateurs/administrateur_component/administrateur_component.html.haml b/app/components/groupe_gestionnaire/groupe_gestionnaire_administrateurs/administrateur_component/administrateur_component.html.haml index 9678adb08..85fa63ecd 100644 --- a/app/components/groupe_gestionnaire/groupe_gestionnaire_administrateurs/administrateur_component/administrateur_component.html.haml +++ b/app/components/groupe_gestionnaire/groupe_gestionnaire_administrateurs/administrateur_component/administrateur_component.html.haml @@ -3,3 +3,4 @@ %td= created_at %td= registration_state %td= remove_button + %td= destroy_button diff --git a/app/controllers/gestionnaires/groupe_gestionnaire_administrateurs_controller.rb b/app/controllers/gestionnaires/groupe_gestionnaire_administrateurs_controller.rb index f45f7220b..d32d8783c 100644 --- a/app/controllers/gestionnaires/groupe_gestionnaire_administrateurs_controller.rb +++ b/app/controllers/gestionnaires/groupe_gestionnaire_administrateurs_controller.rb @@ -1,17 +1,99 @@ module Gestionnaires class GroupeGestionnaireAdministrateursController < GestionnaireController - before_action :retrieve_groupe_gestionnaire, except: [:new] + before_action :retrieve_groupe_gestionnaire def index end def create - administrateurs, flash[:alert], flash[:notice] = @groupe_gestionnaire.add_administrateurs(emails: [params.require(:administrateur)[:email]], current_user: current_gestionnaire) - @administrateur = administrateurs[0] + emails = [params.require(:administrateur)[:email]].to_json + emails = JSON.parse(emails).map { EmailSanitizableConcern::EmailSanitizer.sanitize(_1) } + + administrateurs_to_add, valid_emails, invalid_emails = Administrateur.find_all_by_identifier_with_emails(emails:) + not_found_emails = valid_emails - administrateurs_to_add.map(&:email) + + # Send invitations to users without account + if not_found_emails.present? + administrateurs_to_add += not_found_emails.map do |email| + user = User.create_or_promote_to_administrateur(email, SecureRandom.hex) + user.invite_administrateur!(@groupe_gestionnaire) + user.administrateur + end + end + administrateurs_already_in_groupe_gestionnaire = [] + # We dont't want to assign a user to an groupe_gestionnaire if they are already assigned to it + administrateurs_duplicate = administrateurs_to_add & @groupe_gestionnaire.administrateurs + administrateurs_to_add -= @groupe_gestionnaire.administrateurs + administrateurs_to_add.each do |administrateur| + # We don't change administrateur.groupe_gestionnaire_id is administrateur already in another groupe_gestionnaire for which current_gestionnaire is not a gestionnaire or if current_gestionnaire is not a superAdmin + if !current_gestionnaire.is_a?(SuperAdmin) && + administrateur.groupe_gestionnaire_id && + ((administrateur.groupe_gestionnaire.ancestor_ids + [administrateur.groupe_gestionnaire_id]) & current_gestionnaire.groupe_gestionnaire_ids).empty? + administrateurs_already_in_groupe_gestionnaire << administrateur + next + end + @groupe_gestionnaire.add_administrateur(administrateur) + end + + if administrateurs_already_in_groupe_gestionnaire.present? + flash[:alert] = I18n.t('activerecord.errors.administrateurs_already_in_groupe_gestionnaire', + count: administrateurs_already_in_groupe_gestionnaire.size, + emails: administrateurs_already_in_groupe_gestionnaire) + end + + if invalid_emails.present? + flash[:alert] = I18n.t('activerecord.wrong_address', + count: invalid_emails.size, + emails: invalid_emails.join(', ')) + end + if administrateurs_duplicate.present? + flash[:alert] = I18n.t('activerecord.errors.duplicate_email', + count: invalid_emails.size, + emails: administrateurs_duplicate.map(&:email).join(', ')) + end + + if administrateurs_to_add.present? + flash[:notice] = I18n.t('groupe_gestionnaires.flash.notice.groupe_gestionnaire_administrateur.create') + + GroupeGestionnaireMailer + .notify_added_administrateurs(@groupe_gestionnaire, administrateurs_to_add, current_gestionnaire.email) + .deliver_later + end + + @administrateur = administrateurs_to_add[0] end def destroy - @administrateur, flash[:alert], flash[:notice] = @groupe_gestionnaire.remove_administrateur(params[:id], current_gestionnaire) + @administrateur = Administrateur.find(params[:id]) + if @groupe_gestionnaire.id != @administrateur.groupe_gestionnaire_id + flash[:alert] = I18n.t('groupe_gestionnaires.flash.alert.groupe_gestionnaire_administrateur.not_in_groupe_gestionnaire', email: @administrateur.email) + else + result = AdministrateurDeletionService.new(current_gestionnaire, @administrateur).call + + case result + in Dry::Monads::Result::Success + logger.info("L'administrateur #{@administrateur.id} est supprimé par le gestionnaire #{current_gestionnaire.id} depuis le groupe gestionnaire #{@groupe_gestionnaire.id}") + flash[:notice] = I18n.t('groupe_gestionnaires.flash.notice.groupe_gestionnaire_administrateur.destroy', email: @administrateur.email) + GroupeGestionnaireMailer + .notify_removed_administrateur(@groupe_gestionnaire, @administrateur.email, current_gestionnaire.email) + .deliver_later + in Dry::Monads::Result::Failure(reason) + flash[:alert] = I18n.t('groupe_gestionnaires.flash.alert.groupe_gestionnaire_administrateur.cannot_be_deleted', email: @administrateur.email) + end + end + end + + def remove + @administrateur = Administrateur.find(params[:id]) + if @groupe_gestionnaire.id != @administrateur.groupe_gestionnaire_id + flash[:alert] = I18n.t('groupe_gestionnaires.flash.alert.groupe_gestionnaire_administrateur.not_in_groupe_gestionnaire', email: @administrateur.email) + else + @administrateur.update(groupe_gestionnaire_id: nil) + flash[:notice] = I18n.t('groupe_gestionnaires.flash.notice.groupe_gestionnaire_administrateur.remove', email: @administrateur.email) + GroupeGestionnaireMailer + .notify_removed_administrateur(@groupe_gestionnaire, @administrateur.email, current_gestionnaire.email) + .deliver_later + end end end end diff --git a/app/controllers/gestionnaires/groupe_gestionnaire_children_controller.rb b/app/controllers/gestionnaires/groupe_gestionnaire_children_controller.rb index 081d48aaa..7ccdd1a5f 100644 --- a/app/controllers/gestionnaires/groupe_gestionnaire_children_controller.rb +++ b/app/controllers/gestionnaires/groupe_gestionnaire_children_controller.rb @@ -1,6 +1,6 @@ module Gestionnaires class GroupeGestionnaireChildrenController < GestionnaireController - before_action :retrieve_groupe_gestionnaire, except: [:new] + before_action :retrieve_groupe_gestionnaire def index end diff --git a/app/controllers/gestionnaires/groupe_gestionnaire_gestionnaires_controller.rb b/app/controllers/gestionnaires/groupe_gestionnaire_gestionnaires_controller.rb index d19366c35..dc129140e 100644 --- a/app/controllers/gestionnaires/groupe_gestionnaire_gestionnaires_controller.rb +++ b/app/controllers/gestionnaires/groupe_gestionnaire_gestionnaires_controller.rb @@ -1,17 +1,71 @@ module Gestionnaires class GroupeGestionnaireGestionnairesController < GestionnaireController - before_action :retrieve_groupe_gestionnaire, except: [:new] + before_action :retrieve_groupe_gestionnaire def index end def create - gestionnaires, flash[:alert], flash[:notice] = @groupe_gestionnaire.add_gestionnaires(emails: [params.require(:gestionnaire)[:email]], current_user: current_gestionnaire) - @gestionnaire = gestionnaires[0] + emails = [params.require(:gestionnaire)[:email]].to_json + emails = JSON.parse(emails).map { EmailSanitizableConcern::EmailSanitizer.sanitize(_1) } + + gestionnaires_to_add, valid_emails, invalid_emails = Gestionnaire.find_all_by_identifier_with_emails(emails:) + not_found_emails = valid_emails - gestionnaires_to_add.map(&:email) + + # Send invitations to users without account + if not_found_emails.present? + gestionnaires_to_add += not_found_emails.map do |email| + user = User.create_or_promote_to_gestionnaire(email, SecureRandom.hex) + user.invite_gestionnaire!(@groupe_gestionnaire) + user.gestionnaire + end + end + + # We dont't want to assign a user to an groupe_gestionnaire if they are already assigned to it + gestionnaires_duplicate = gestionnaires_to_add & @groupe_gestionnaire.gestionnaires + gestionnaires_to_add -= @groupe_gestionnaire.gestionnaires + gestionnaires_to_add.each { @groupe_gestionnaire.add_gestionnaire(_1) } + + if invalid_emails.present? + flash[:alert] = I18n.t('activerecord.wrong_address', + count: invalid_emails.size, + emails: invalid_emails.join(', ')) + end + if gestionnaires_duplicate.present? + flash[:alert] = I18n.t('activerecord.errors.duplicate_email', + count: invalid_emails.size, + emails: gestionnaires_duplicate.map(&:email).join(', ')) + end + + if gestionnaires_to_add.present? + flash[:notice] = I18n.t('groupe_gestionnaires.flash.notice.groupe_gestionnaire_gestionnaire.create') + + GroupeGestionnaireMailer + .notify_added_gestionnaires(@groupe_gestionnaire, gestionnaires_to_add, current_gestionnaire.email) + .deliver_later + end + + @gestionnaire = gestionnaires_to_add[0] end def destroy - @gestionnaire, flash[:alert], flash[:notice] = @groupe_gestionnaire.remove_gestionnaire(params[:id], current_gestionnaire) + if !@groupe_gestionnaire.is_root? || @groupe_gestionnaire.gestionnaires.one? + flash[:alert] = I18n.t('groupe_gestionnaires.flash.alert.groupe_gestionnaire_gestionnaire.destroy_at_least_one') + else + @gestionnaire = Gestionnaire.find(params[:id]) + + if !@groupe_gestionnaire.in?(@gestionnaire.groupe_gestionnaires) || !@gestionnaire.groupe_gestionnaires.destroy(@groupe_gestionnaire) + flash[:alert] = I18n.t('groupe_gestionnaires.flash.alert.groupe_gestionnaire_gestionnaire.not_in_groupe_gestionnaire', email: @gestionnaire.email) + else + if @gestionnaire.groupe_gestionnaires.empty? + @gestionnaire.destroy + end + flash[:notice] = I18n.t('groupe_gestionnaires.flash.notice.groupe_gestionnaire_gestionnaire.destroy', email: @gestionnaire.email) + GroupeGestionnaireMailer + .notify_removed_gestionnaire(@groupe_gestionnaire, @gestionnaire.email, current_gestionnaire.email) + .deliver_later + end + end end end end diff --git a/app/controllers/manager/groupe_gestionnaires_controller.rb b/app/controllers/manager/groupe_gestionnaires_controller.rb index 3f41d93c5..1bc4922aa 100644 --- a/app/controllers/manager/groupe_gestionnaires_controller.rb +++ b/app/controllers/manager/groupe_gestionnaires_controller.rb @@ -1,25 +1,70 @@ module Manager class GroupeGestionnairesController < Manager::ApplicationController def add_gestionnaire - _gestionnaires, flash[:alert], flash[:notice] = groupe_gestionnaire.add_gestionnaires(emails: (params['emails'].presence || '').split(','), current_user: current_super_admin) + groupe_gestionnaire = GroupeGestionnaire.find(params[:id]) + emails = [params['emails'].presence || ''].to_json + emails = JSON.parse(emails).map { EmailSanitizableConcern::EmailSanitizer.sanitize(_1) } + + gestionnaires_to_add, valid_emails, invalid_emails = Gestionnaire.find_all_by_identifier_with_emails(emails:) + not_found_emails = valid_emails - gestionnaires_to_add.map(&:email) + + # Send invitations to users without account + if not_found_emails.present? + gestionnaires_to_add += not_found_emails.map do |email| + user = User.create_or_promote_to_gestionnaire(email, SecureRandom.hex) + user.invite_gestionnaire!(groupe_gestionnaire) + user.gestionnaire + end + end + + # We dont't want to assign a user to an groupe_gestionnaire if they are already assigned to it + gestionnaires_duplicate = gestionnaires_to_add & groupe_gestionnaire.gestionnaires + gestionnaires_to_add -= groupe_gestionnaire.gestionnaires + gestionnaires_to_add.each { groupe_gestionnaire.add_gestionnaire(_1) } + + if invalid_emails.present? + flash[:alert] = I18n.t('activerecord.wrong_address', + count: invalid_emails.size, + emails: invalid_emails.join(', ')) + end + if gestionnaires_duplicate.present? + flash[:alert] = I18n.t('activerecord.errors.duplicate_email', + count: invalid_emails.size, + emails: gestionnaires_duplicate.map(&:email).join(', ')) + end + + if gestionnaires_to_add.present? + flash[:notice] = I18n.t('groupe_gestionnaires.flash.notice.groupe_gestionnaire_gestionnaire.create') + + GroupeGestionnaireMailer + .notify_added_gestionnaires(groupe_gestionnaire, gestionnaires_to_add, current_super_admin.email) + .deliver_later + end redirect_to manager_groupe_gestionnaire_path(groupe_gestionnaire) end def remove_gestionnaire - _gestionnaire, flash[:alert], flash[:notice] = groupe_gestionnaire.remove_gestionnaire(gestionnaire_id, current_super_admin) + groupe_gestionnaire = GroupeGestionnaire.find(params[:id]) + if !groupe_gestionnaire.is_root? || groupe_gestionnaire.gestionnaires.one? + flash[:alert] = I18n.t('groupe_gestionnaires.flash.alert.groupe_gestionnaire_gestionnaire.destroy_at_least_one') + else + gestionnaire = Gestionnaire.find(params[:gestionnaire][:id]) + + if !groupe_gestionnaire.in?(gestionnaire.groupe_gestionnaires) || !gestionnaire.groupe_gestionnaires.destroy(groupe_gestionnaire) + flash[:alert] = I18n.t('groupe_gestionnaires.flash.alert.groupe_gestionnaire_gestionnaire.not_in_groupe_gestionnaire', email: gestionnaire.email) + else + if gestionnaire.groupe_gestionnaires.empty? + gestionnaire.destroy + end + flash[:notice] = I18n.t('groupe_gestionnaires.flash.notice.groupe_gestionnaire_gestionnaire.destroy', email: gestionnaire.email) + GroupeGestionnaireMailer + .notify_removed_gestionnaire(groupe_gestionnaire, gestionnaire.email, current_super_admin.email) + .deliver_later + end + end redirect_to manager_groupe_gestionnaire_path(groupe_gestionnaire) end - - private - - def groupe_gestionnaire - @groupe_gestionnaire ||= GroupeGestionnaire.find(params[:id]) - end - - def gestionnaire_id - params[:gestionnaire][:id] - end end end diff --git a/app/models/concerns/user_find_by_concern.rb b/app/models/concerns/user_find_by_concern.rb index cb52c3b4e..1a1836607 100644 --- a/app/models/concerns/user_find_by_concern.rb +++ b/app/models/concerns/user_find_by_concern.rb @@ -1,7 +1,3 @@ -# Request a watermark on files attached to a `Champs::TitreIdentiteChamp`. -# -# We're using a class extension here, but we could as well have a periodic -# job that watermarks relevant attachments. module UserFindByConcern extend ActiveSupport::Concern @@ -15,7 +11,7 @@ module UserFindByConcern end def self.find_all_by_identifier_with_emails(ids: [], emails: []) - valid_emails, invalid_emails = emails.partition { URI::MailTo::EMAIL_REGEXP.match?(_1) } + valid_emails, invalid_emails = emails.partition { Devise.email_regexp.match?(_1) } [ where(id: ids).or(where(users: { email: valid_emails })).distinct(:id), diff --git a/app/models/groupe_gestionnaire.rb b/app/models/groupe_gestionnaire.rb index 57c8d40e5..2c44cf903 100644 --- a/app/models/groupe_gestionnaire.rb +++ b/app/models/groupe_gestionnaire.rb @@ -11,70 +11,6 @@ class GroupeGestionnaire < ApplicationRecord gestionnaires << gestionnaire end - def remove_gestionnaire(gestionnaire_id, current_user) - if !self.is_root? || self.gestionnaires.one? - alert = "Suppression impossible : il doit y avoir au moins un gestionnaire dans le groupe racine" - else - gestionnaire = Gestionnaire.find(gestionnaire_id) - - if !in?(gestionnaire.groupe_gestionnaires) || !gestionnaire.groupe_gestionnaires.destroy(self) - alert = "Le gestionnaire « #{gestionnaire.email} » n’est pas dans le groupe gestionnaire." - else - if gestionnaire.groupe_gestionnaires.empty? - gestionnaire.destroy - end - notice = "Le gestionnaire « #{gestionnaire.email} » a été retiré du groupe gestionnaire." - GroupeGestionnaireMailer - .notify_removed_gestionnaire(self, gestionnaire.email, current_user.email) - .deliver_later - end - end - [gestionnaire, alert, notice] - end - - def add_gestionnaires(ids: [], emails: [], current_user: nil) - emails = emails.to_json - emails = JSON.parse(emails).map { EmailSanitizableConcern::EmailSanitizer.sanitize(_1) } - - gestionnaires_to_add, valid_emails, invalid_emails = Gestionnaire.find_all_by_identifier_with_emails(ids:, emails:) - not_found_emails = valid_emails - gestionnaires_to_add.map(&:email) - - # Send invitations to users without account - if not_found_emails.present? - gestionnaires_to_add += not_found_emails.map do |email| - user = User.create_or_promote_to_gestionnaire(email, SecureRandom.hex) - user.invite_gestionnaire!(self) - user.gestionnaire - end - end - - # We dont't want to assign a user to an groupe_gestionnaire if they are already assigned to it - gestionnaires_duplicate = gestionnaires_to_add & gestionnaires - gestionnaires_to_add -= gestionnaires - gestionnaires_to_add.each { add_gestionnaire(_1) } - - if invalid_emails.present? - alert = I18n.t('activerecord.wrong_address', - count: invalid_emails.size, - emails: invalid_emails) - end - if gestionnaires_duplicate.present? - alert = I18n.t('activerecord.errors.duplicate_email', - count: invalid_emails.size, - emails: gestionnaires_duplicate.map(&:email)) - end - - if gestionnaires_to_add.present? - notice = "Les gestionnaires ont bien été affectés au groupe gestionnaire" - - GroupeGestionnaireMailer - .notify_added_gestionnaires(self, gestionnaires_to_add, current_user.email) - .deliver_later - end - - [gestionnaires_to_add, alert, notice] - end - def add_administrateur(administrateur) return if administrateur.nil? return if id == administrateur.groupe_gestionnaire_id @@ -82,76 +18,6 @@ class GroupeGestionnaire < ApplicationRecord administrateurs << administrateur end - def remove_administrateur(administrateur_id, current_user) - administrateur = Administrateur.find(administrateur_id) - - if id != administrateur.groupe_gestionnaire_id - alert = "L'administrateur « #{administrateur.email} » n’est pas dans le groupe gestionnaire." - else - administrateur.destroy - notice = "L'administrateur « #{administrateur.email} » a été retiré du groupe gestionnaire." - GroupeGestionnaireMailer - .notify_removed_administrateur(self, administrateur.email, current_user.email) - .deliver_later - end - [administrateur, alert, notice] - end - - def add_administrateurs(ids: [], emails: [], current_user: nil) - emails = emails.to_json - emails = JSON.parse(emails).map { EmailSanitizableConcern::EmailSanitizer.sanitize(_1) } - - administrateurs_to_add, valid_emails, invalid_emails = Administrateur.find_all_by_identifier_with_emails(ids:, emails:) - not_found_emails = valid_emails - administrateurs_to_add.map(&:email) - - # Send invitations to users without account - if not_found_emails.present? - administrateurs_to_add += not_found_emails.map do |email| - user = User.create_or_promote_to_administrateur(email, SecureRandom.hex) - user.invite_administrateur!(self) - user.administrateur - end - end - administrateurs_already_in_groupe_gestionnaire = [] - # We dont't want to assign a user to an groupe_gestionnaire if they are already assigned to it - administrateurs_duplicate = administrateurs_to_add & administrateurs - administrateurs_to_add -= administrateurs - administrateurs_to_add.each do |administrateur| - if !current_user.is_a?(SuperAdmin) && administrateur.groupe_gestionnaire_id && ((administrateur.groupe_gestionnaire.ancestor_ids + [administrateur.groupe_gestionnaire_id]) & current_user.groupe_gestionnaire_ids).empty? - administrateurs_already_in_groupe_gestionnaire << administrateur - next - end - add_administrateur(administrateur) - end - - if administrateurs_already_in_groupe_gestionnaire.present? - alert = I18n.t('activerecord.errors.administrateurs_already_in_groupe_gestionnaire', - count: administrateurs_already_in_groupe_gestionnaire.size, - emails: administrateurs_already_in_groupe_gestionnaire) - end - - if invalid_emails.present? - alert = I18n.t('activerecord.wrong_address', - count: invalid_emails.size, - emails: invalid_emails) - end - if administrateurs_duplicate.present? - alert = I18n.t('activerecord.errors.duplicate_email', - count: invalid_emails.size, - emails: administrateurs_duplicate.map(&:email)) - end - - if administrateurs_to_add.present? - notice = "Les administrateurs ont bien été affectés au groupe gestionnaire" - - GroupeGestionnaireMailer - .notify_added_administrateurs(self, administrateurs_to_add, current_user.email) - .deliver_later - end - - [administrateurs_to_add, alert, notice] - end - def can_be_deleted?(current_user) (gestionnaires.empty? || (gestionnaires == [current_user])) && administrateurs.empty? && children.empty? end diff --git a/app/views/gestionnaires/groupe_gestionnaire_administrateurs/index.html.haml b/app/views/gestionnaires/groupe_gestionnaire_administrateurs/index.html.haml index f2796c906..20e0a06c8 100644 --- a/app/views/gestionnaires/groupe_gestionnaire_administrateurs/index.html.haml +++ b/app/views/gestionnaires/groupe_gestionnaire_administrateurs/index.html.haml @@ -13,6 +13,7 @@ %th= 'Enregistré le' %th= 'État' %th + %th %tbody#administrateurs = render(GroupeGestionnaire::GroupeGestionnaireAdministrateurs::AdministrateurComponent.with_collection(@groupe_gestionnaire.administrateurs.order('users.email'), groupe_gestionnaire: @groupe_gestionnaire)) diff --git a/app/views/gestionnaires/groupe_gestionnaire_administrateurs/remove.turbo_stream.haml b/app/views/gestionnaires/groupe_gestionnaire_administrateurs/remove.turbo_stream.haml new file mode 100644 index 000000000..b72211119 --- /dev/null +++ b/app/views/gestionnaires/groupe_gestionnaire_administrateurs/remove.turbo_stream.haml @@ -0,0 +1,6 @@ += turbo_stream.update 'administrateurs' do + = render GroupeGestionnaire::GroupeGestionnaireAdministrateurs::AdministrateurComponent.with_collection(@groupe_gestionnaire.administrateurs.order('users.email'), groupe_gestionnaire: @groupe_gestionnaire) +- if @groupe_gestionnaire.administrateurs.one? + = turbo_stream.focus 'administrateur_email' +- else + = turbo_stream.focus_all '#administrateurs tr:first-child input[type="submit"]' diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 9502183c4..43edf443b 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -886,6 +886,23 @@ fr: invalid_password: "Mauvais mot de passe" connection_done: "Les comptes FranceConnect et %{application_name} sont à présent fusionnés" merger_token_expired: "Le délai pour fusionner les comptes FranceConnect et %{application_name} est expirée. Veuillez recommencer la procédure pour vous fusionner les comptes." + groupe_gestionnaires: + flash: + alert: + groupe_gestionnaire_administrateur: + cannot_be_deleted: "L'administrateur « %{email} » ne peut pas être supprimé du groupe gestionnaire." + not_in_groupe_gestionnaire: "L'administrateur « %{email} » n’est pas dans le groupe gestionnaire." + groupe_gestionnaire_gestionnaire: + destroy_at_least_one: "Suppression impossible : il doit y avoir au moins un gestionnaire dans le groupe racine" + not_in_groupe_gestionnaire: "Le gestionnaire « %{email} » n’est pas dans le groupe gestionnaire." + notice: + groupe_gestionnaire_administrateur: + create: "Les administrateurs ont bien été affectés au groupe gestionnaire" + destroy: "L'administrateur « %{email} » a été supprimé." + remove: "L'administrateur « %{email} » a été retiré du groupe gestionnaire." + groupe_gestionnaire_gestionnaire: + create: "Les gestionnaires ont bien été affectés au groupe gestionnaire" + destroy: "Le gestionnaire « %{email} » a été retiré du groupe gestionnaire." shared: procedures: no_siret: "Vous n’avez pas renseigné le siret du service pour certaines de vos démarches. Merci de les modifier." diff --git a/config/locales/models/groupe_gestionnaire/fr.yml b/config/locales/models/groupe_gestionnaire/fr.yml index 211b5bb2e..6acbe8923 100644 --- a/config/locales/models/groupe_gestionnaire/fr.yml +++ b/config/locales/models/groupe_gestionnaire/fr.yml @@ -17,3 +17,6 @@ fr: wrong_address: one: "%{emails} n’est pas une adresse email valide" other: "%{emails} ne sont pas des adresses emails valides" + not_found: + one: "%{emails} n'a pas encore de compte." + other: "%{emails} n'ont pas encore de compte." diff --git a/config/routes.rb b/config/routes.rb index 82e55eec0..4aceb9f48 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -506,7 +506,9 @@ Rails.application.routes.draw do scope module: 'gestionnaires', as: 'gestionnaire' do resources :groupe_gestionnaires, path: 'groupes', only: [:index, :show, :create, :edit, :update, :destroy] do resources :gestionnaires, controller: 'groupe_gestionnaire_gestionnaires', only: [:index, :create, :destroy] - resources :administrateurs, controller: 'groupe_gestionnaire_administrateurs', only: [:index, :create, :destroy] + resources :administrateurs, controller: 'groupe_gestionnaire_administrateurs', only: [:index, :create, :destroy] do + delete :remove, on: :member + end resources :children, controller: 'groupe_gestionnaire_children', only: [:index, :create, :destroy] end end diff --git a/spec/controllers/gestionnaires/groupe_gestionnaire_administrateurs_controller_spec.rb b/spec/controllers/gestionnaires/groupe_gestionnaire_administrateurs_controller_spec.rb index 55f034f65..c5491297f 100644 --- a/spec/controllers/gestionnaires/groupe_gestionnaire_administrateurs_controller_spec.rb +++ b/spec/controllers/gestionnaires/groupe_gestionnaire_administrateurs_controller_spec.rb @@ -30,7 +30,7 @@ describe Gestionnaires::GroupeGestionnaireAdministrateursController, type: :cont groupe_gestionnaire.administrateurs << new_administrateur end - def remove_administrateur(administrateur) + def destroy(administrateur) delete :destroy, params: { groupe_gestionnaire_id: groupe_gestionnaire.id, @@ -39,11 +39,64 @@ describe Gestionnaires::GroupeGestionnaireAdministrateursController, type: :cont format: :turbo_stream end - context 'when there are many administrateurs' do - before { remove_administrateur(new_administrateur) } + context 'when administrateur is in the groupe_gestionnaire' do + before { destroy(new_administrateur) } + + it { expect(groupe_gestionnaire.reload.administrateurs.count).to eq(0) } + it { expect(flash.notice).to eq("L'administrateur « #{new_administrateur.email} » a été supprimé.") } + end + + context 'when administrateur has some procedure' do + let(:administrateur_with_procedure) { create(:administrateur) } + let!(:procedure) { create(:procedure_with_dossiers, administrateur: administrateur_with_procedure) } + before do + groupe_gestionnaire.administrateurs << administrateur_with_procedure + destroy(administrateur_with_procedure) + end + + it { expect(groupe_gestionnaire.reload.administrateurs.count).to eq(2) } + it { expect(flash.alert).to eq("L'administrateur « #{administrateur_with_procedure.email} » ne peut pas être supprimé du groupe gestionnaire.") } + end + + context 'when administrateur is not in the groupe_gestionnaire' do + let(:other_administrateur) { create(:administrateur) } + before { destroy(other_administrateur) } + + it { expect(groupe_gestionnaire.reload.administrateurs.count).to eq(1) } + it { expect(flash.alert).to eq("L'administrateur « #{other_administrateur.email} » n’est pas dans le groupe gestionnaire.") } + end + end + + describe '#remove' do + let(:gestionnaire) { create(:gestionnaire) } + let(:new_administrateur) { create(:administrateur) } + + before do + groupe_gestionnaire.administrateurs << new_administrateur + end + + def remove(administrateur) + delete :remove, + params: { + groupe_gestionnaire_id: groupe_gestionnaire.id, + id: administrateur.id + }, + format: :turbo_stream + end + + context 'when administrateur is in the groupe_gestionnaire' do + before { remove(new_administrateur) } it { expect(groupe_gestionnaire.reload.administrateurs.count).to eq(0) } it { expect(flash.notice).to eq("L'administrateur « #{new_administrateur.email} » a été retiré du groupe gestionnaire.") } end + + context 'when administrateur is not in the groupe_gestionnaire' do + let(:other_administrateur) { create(:administrateur) } + before { remove(other_administrateur) } + + it { expect(groupe_gestionnaire.reload.administrateurs.count).to eq(1) } + it { expect(flash.alert).to eq("L'administrateur « #{other_administrateur.email} » n’est pas dans le groupe gestionnaire.") } + end end end diff --git a/spec/models/groupe_gestionnaire_spec.rb b/spec/models/groupe_gestionnaire_spec.rb index d3f29b7c4..604ac9a29 100644 --- a/spec/models/groupe_gestionnaire_spec.rb +++ b/spec/models/groupe_gestionnaire_spec.rb @@ -16,27 +16,6 @@ describe GroupeGestionnaire, type: :model do end end - describe "#add_gestionnaires" do - let(:groupe_gestionnaire) { create(:groupe_gestionnaire) } - let(:gestionnaire) { create(:gestionnaire) } - let(:gestionnaire_to_add) { create(:gestionnaire) } - - it 'adds the gestionnaire by id' do - groupe_gestionnaire.add_gestionnaires(ids: [gestionnaire_to_add.id], current_user: gestionnaire) - expect(groupe_gestionnaire.reload.gestionnaires).to include(gestionnaire_to_add) - end - - it 'adds the existing gestionnaire by email' do - groupe_gestionnaire.add_gestionnaires(emails: [gestionnaire_to_add.email], current_user: gestionnaire) - expect(groupe_gestionnaire.reload.gestionnaires).to include(gestionnaire_to_add) - end - - it 'adds the new gestionnaire by email' do - groupe_gestionnaire.add_gestionnaires(emails: ['new_gestionnaire@ds.fr'], current_user: gestionnaire) - expect(groupe_gestionnaire.reload.gestionnaires.last.email).to eq('new_gestionnaire@ds.fr') - end - end - describe "#add_administrateur" do let(:groupe_gestionnaire) { create(:groupe_gestionnaire) } let(:gestionnaire) { create(:gestionnaire) } @@ -49,47 +28,4 @@ describe GroupeGestionnaire, type: :model do expect(groupe_gestionnaire.reload.administrateurs).to include(administrateur) end end - - describe "#add_administrateurs" do - let(:gestionnaire) { create(:gestionnaire) } - let(:groupe_gestionnaire) { create(:groupe_gestionnaire, gestionnaires: [gestionnaire]) } - let(:administrateur) { create(:administrateur) } - - it 'adds the administrateur by id' do - groupe_gestionnaire.add_administrateurs(ids: [administrateur.id], current_user: gestionnaire) - expect(groupe_gestionnaire.reload.administrateurs).to include(administrateur) - end - - it 'adds the existing administrateur by email' do - groupe_gestionnaire.add_administrateurs(emails: [administrateur.email], current_user: gestionnaire) - expect(groupe_gestionnaire.reload.administrateurs).to include(administrateur) - end - - context "when administrateurs_already_in_groupe_gestionnaire" do - let(:other_groupe_gestionnaire) { create(:groupe_gestionnaire) } - let(:administrateur) { create(:administrateur, groupe_gestionnaire_id: other_groupe_gestionnaire.id) } - it 'does not add the existing administrateur by email' do - groupe_gestionnaire.add_administrateurs(emails: [administrateur.email], current_user: gestionnaire) - expect(groupe_gestionnaire.reload.administrateurs).not_to include(administrateur) - end - end - - it 'adds the new administrateur by email' do - groupe_gestionnaire.add_administrateurs(emails: ['new_administrateur@ds.fr'], current_user: gestionnaire) - expect(groupe_gestionnaire.reload.administrateurs.last.email).to eq('new_administrateur@ds.fr') - end - end - - describe "#remove_administrateur" do - let(:gestionnaire) { create(:gestionnaire) } - let(:groupe_gestionnaire) { create(:groupe_gestionnaire, gestionnaires: [gestionnaire]) } - let!(:administrateur) { create(:administrateur, groupe_gestionnaire_id: groupe_gestionnaire.id) } - - it 'removes the administrateur by id' do - expect(groupe_gestionnaire.reload.administrateurs.size).to eq(1) - groupe_gestionnaire.remove_administrateur(administrateur.id, gestionnaire) - expect(groupe_gestionnaire.reload.administrateurs).not_to include(administrateur) - expect(groupe_gestionnaire.reload.administrateurs.size).to eq(0) - end - end end From acbddb5c29a804101b27bb07891b0fda6c2ae0e0 Mon Sep 17 00:00:00 2001 From: Colin Darie Date: Tue, 12 Dec 2023 11:27:13 +0100 Subject: [PATCH 3/3] style(gestionnaire): minor style improvements Co-Authored-By: krichtof --- .../administrateurs_component.html.haml | 4 +--- .../gestionnaire_component.rb | 2 +- .../groupe_gestionnaire_administrateurs/index.html.haml | 3 ++- .../groupe_gestionnaire_children/index.html.haml | 3 ++- .../groupe_gestionnaire_gestionnaires/index.html.haml | 3 ++- .../groupe_gestionnaires/_main_navigation.html.haml | 2 +- app/views/gestionnaires/groupe_gestionnaires/edit.html.haml | 3 ++- app/views/gestionnaires/groupe_gestionnaires/index.html.haml | 5 ++++- app/views/gestionnaires/groupe_gestionnaires/show.html.haml | 4 +++- 9 files changed, 18 insertions(+), 11 deletions(-) diff --git a/app/components/groupe_gestionnaire/card/administrateurs_component/administrateurs_component.html.haml b/app/components/groupe_gestionnaire/card/administrateurs_component/administrateurs_component.html.haml index 34864bea5..a0013cef9 100644 --- a/app/components/groupe_gestionnaire/card/administrateurs_component/administrateurs_component.html.haml +++ b/app/components/groupe_gestionnaire/card/administrateurs_component/administrateurs_component.html.haml @@ -1,9 +1,7 @@ .fr-col-6.fr-col-md-4.fr-col-lg-3 = link_to gestionnaire_groupe_gestionnaire_administrateurs_path(@groupe_gestionnaire), id: 'administrateurs', class: 'fr-tile fr-enlarge-link' do .fr-tile__body.flex.column.align-center.justify-between - %div - %span.icon.accept - %p.fr-tile-status-accept Validé + %p.fr-badge.fr-badge--success Validé %div .line-count.fr-my-1w %p.fr-tag= @groupe_gestionnaire.administrateurs.size diff --git a/app/components/groupe_gestionnaire/groupe_gestionnaire_gestionnaires/gestionnaire_component.rb b/app/components/groupe_gestionnaire/groupe_gestionnaire_gestionnaires/gestionnaire_component.rb index 0f5904686..9d9eedafa 100644 --- a/app/components/groupe_gestionnaire/groupe_gestionnaire_gestionnaires/gestionnaire_component.rb +++ b/app/components/groupe_gestionnaire/groupe_gestionnaire_gestionnaires/gestionnaire_component.rb @@ -27,7 +27,7 @@ class GroupeGestionnaire::GroupeGestionnaireGestionnaires::GestionnaireComponent button_to 'Retirer', gestionnaire_groupe_gestionnaire_gestionnaire_path(@groupe_gestionnaire, @gestionnaire), method: :delete, - class: 'button', + class: 'fr-btn fr-btn--sm fr-btn--tertiary', form: { data: { turbo: true, turbo_confirm: "Retirer « #{@gestionnaire.email} » des gestionnaires de « #{@groupe_gestionnaire.name} » ?" } } end end diff --git a/app/views/gestionnaires/groupe_gestionnaire_administrateurs/index.html.haml b/app/views/gestionnaires/groupe_gestionnaire_administrateurs/index.html.haml index 20e0a06c8..c32f71d91 100644 --- a/app/views/gestionnaires/groupe_gestionnaire_administrateurs/index.html.haml +++ b/app/views/gestionnaires/groupe_gestionnaire_administrateurs/index.html.haml @@ -1,5 +1,6 @@ += render 'gestionnaires/groupe_gestionnaires/main_navigation' = render partial: 'gestionnaires/breadcrumbs', - locals: { steps: [['Groupes gestionnaire', gestionnaire_groupe_gestionnaires_path], + locals: { steps: [['Groupes gestionnaires', gestionnaire_groupe_gestionnaires_path], ["#{@groupe_gestionnaire.name.truncate_words(10)}", gestionnaire_groupe_gestionnaire_path(@groupe_gestionnaire)], ['Administrateurs']], preview: false } diff --git a/app/views/gestionnaires/groupe_gestionnaire_children/index.html.haml b/app/views/gestionnaires/groupe_gestionnaire_children/index.html.haml index e3bd426e2..1a2c10786 100644 --- a/app/views/gestionnaires/groupe_gestionnaire_children/index.html.haml +++ b/app/views/gestionnaires/groupe_gestionnaire_children/index.html.haml @@ -1,5 +1,6 @@ += render 'gestionnaires/groupe_gestionnaires/main_navigation' = render partial: 'gestionnaires/breadcrumbs', - locals: { steps: [['Groupes gestionnaire', gestionnaire_groupe_gestionnaires_path], + locals: { steps: [['Groupes gestionnaires', gestionnaire_groupe_gestionnaires_path], ["#{@groupe_gestionnaire.name.truncate_words(10)}", gestionnaire_groupe_gestionnaire_path(@groupe_gestionnaire)], ['Groupes enfants']], preview: false } diff --git a/app/views/gestionnaires/groupe_gestionnaire_gestionnaires/index.html.haml b/app/views/gestionnaires/groupe_gestionnaire_gestionnaires/index.html.haml index 20895ad41..443165616 100644 --- a/app/views/gestionnaires/groupe_gestionnaire_gestionnaires/index.html.haml +++ b/app/views/gestionnaires/groupe_gestionnaire_gestionnaires/index.html.haml @@ -1,5 +1,6 @@ += render 'gestionnaires/groupe_gestionnaires/main_navigation' = render partial: 'gestionnaires/breadcrumbs', - locals: { steps: [['Groupes gestionnaire', gestionnaire_groupe_gestionnaires_path], + locals: { steps: [['Groupes gestionnaires', gestionnaire_groupe_gestionnaires_path], ["#{@groupe_gestionnaire.name.truncate_words(10)}", gestionnaire_groupe_gestionnaire_path(@groupe_gestionnaire)], ['Gestionnaires']], preview: false } diff --git a/app/views/gestionnaires/groupe_gestionnaires/_main_navigation.html.haml b/app/views/gestionnaires/groupe_gestionnaires/_main_navigation.html.haml index 96649e9fb..842b52017 100644 --- a/app/views/gestionnaires/groupe_gestionnaires/_main_navigation.html.haml +++ b/app/views/gestionnaires/groupe_gestionnaires/_main_navigation.html.haml @@ -1,4 +1,4 @@ - content_for(:main_navigation) do %nav#header-navigation.fr-nav{ role: 'navigation', 'aria-label': 'Menu principal gestionnaire' } %ul.fr-nav__list - %li.fr-nav__item= link_to 'Mes groupes gestionnaire', gestionnaire_groupe_gestionnaires_path, class:'fr-nav__link', 'aria-current': current_page?(controller: 'groupe_gestionnaires', action: :index) ? 'page' : nil + %li.fr-nav__item= link_to 'Mes groupes gestionnaires', gestionnaire_groupe_gestionnaires_path, class:'fr-nav__link', 'aria-current': current_page?(controller: 'groupe_gestionnaires', action: :index) ? 'page' : nil diff --git a/app/views/gestionnaires/groupe_gestionnaires/edit.html.haml b/app/views/gestionnaires/groupe_gestionnaires/edit.html.haml index a7e7f7aea..a779c05d1 100644 --- a/app/views/gestionnaires/groupe_gestionnaires/edit.html.haml +++ b/app/views/gestionnaires/groupe_gestionnaires/edit.html.haml @@ -1,7 +1,8 @@ - content_for(:root_class, 'scroll-margins-for-sticky-footer') += render 'main_navigation' = render partial: 'gestionnaires/breadcrumbs', - locals: { steps: [['Groupes gestionnaire', gestionnaire_groupe_gestionnaires_path], + locals: { steps: [['Groupes gestionnaires', gestionnaire_groupe_gestionnaires_path], ["#{@groupe_gestionnaire.name.truncate_words(10)}", gestionnaire_groupe_gestionnaire_path(@groupe_gestionnaire)], ['Edit']] } diff --git a/app/views/gestionnaires/groupe_gestionnaires/index.html.haml b/app/views/gestionnaires/groupe_gestionnaires/index.html.haml index d425b320d..90a8cfdbb 100644 --- a/app/views/gestionnaires/groupe_gestionnaires/index.html.haml +++ b/app/views/gestionnaires/groupe_gestionnaires/index.html.haml @@ -1,6 +1,9 @@ = render 'main_navigation' -.sub-header += render partial: 'gestionnaires/breadcrumbs', + locals: { steps: [['Groupes gestionnaires', gestionnaire_groupe_gestionnaires_path]] } + +.fr-container.procedure-admin-container .fr-container#groupe_gestionnaire %table.fr-table.width-100.mt-3 diff --git a/app/views/gestionnaires/groupe_gestionnaires/show.html.haml b/app/views/gestionnaires/groupe_gestionnaires/show.html.haml index 88b26e3bf..e8962e729 100644 --- a/app/views/gestionnaires/groupe_gestionnaires/show.html.haml +++ b/app/views/gestionnaires/groupe_gestionnaires/show.html.haml @@ -1,5 +1,7 @@ += render 'main_navigation' + = render partial: 'gestionnaires/breadcrumbs', - locals: { steps: [['Groupes gestionnaire', gestionnaire_groupe_gestionnaires_path], + locals: { steps: [['Groupes gestionnaires', gestionnaire_groupe_gestionnaires_path], ["#{@groupe_gestionnaire.name.truncate_words(10)}"]], metadatas: true }