Merge pull request #6041 from betagouv/feat/5813

ETQ Admin, je peux ajouter/supprimer des experts notifiables
This commit is contained in:
Kara Diaby 2021-04-06 10:52:56 +02:00 committed by GitHub
commit c152ac0e45
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 219 additions and 47 deletions

View file

@ -28,3 +28,7 @@
display: inline-block; display: inline-block;
width: 5px; width: 5px;
} }
.text-center {
text-align: center;
}

View file

@ -9,7 +9,8 @@ module CreateAvisConcern
# the :emails parameter is a 1-element array. # the :emails parameter is a 1-element array.
# Hence the call to first # Hence the call to first
# https://github.com/rails/rails/issues/17225 # https://github.com/rails/rails/issues/17225
expert_emails = create_avis_params[:emails].first.split(',').map(&:strip) expert_emails = create_avis_params[:emails].presence || [].to_json
expert_emails = JSON.parse(expert_emails).map(&:strip).map(&:downcase)
allowed_dossiers = [dossier] allowed_dossiers = [dossier]
if create_avis_params[:invite_linked_dossiers].present? if create_avis_params[:invite_linked_dossiers].present?
@ -65,6 +66,6 @@ module CreateAvisConcern
end end
def create_avis_params def create_avis_params
params.require(:avis).permit(:introduction_file, :introduction, :confidentiel, :invite_linked_dossiers, emails: []) params.require(:avis).permit(:introduction_file, :introduction, :confidentiel, :invite_linked_dossiers, :emails)
end end
end end

View file

@ -60,6 +60,7 @@ module Instructeurs
def avis def avis
@avis_seen_at = current_instructeur.follows.find_by(dossier: dossier)&.avis_seen_at @avis_seen_at = current_instructeur.follows.find_by(dossier: dossier)&.avis_seen_at
@avis = Avis.new @avis = Avis.new
@experts_emails = dossier.procedure.experts_procedures.where(revoked_at: nil).map(&:expert).map(&:email).sort
end end
def personnes_impliquees def personnes_impliquees

View file

@ -0,0 +1,43 @@
module NewAdministrateur
class ExpertsProceduresController < AdministrateurController
before_action :retrieve_procedure, only: [:add_expert_to_procedure, :revoke_expert_from_procedure]
def add_expert_to_procedure
emails = params['emails'].presence || [].to_json
emails = JSON.parse(emails).map(&:strip).map(&:downcase)
valid_users, invalid_users = emails
.map { |email| User.create_or_promote_to_expert(email, SecureRandom.hex) }
.partition(&:valid?)
if invalid_users.any?
flash[:alert] = invalid_users
.filter { |user| user.errors.present? }
.map { |user| "#{user.email} : #{user.errors.full_messages_for(:email).join(', ')}" }
end
if valid_users.present?
valid_users.each do |user|
experts_procedure = ExpertsProcedure.find_or_create_by(expert: user.expert, procedure: @procedure)
if !experts_procedure.revoked_at.nil?
experts_procedure.update!(revoked_at: nil)
end
end
flash[:notice] = t('.experts_assignment',
count: valid_users.count,
value: valid_users.map(&:email).join(', '),
procedure: @procedure.id)
end
redirect_to admin_procedure_invited_expert_list_path(@procedure)
end
def revoke_expert_from_procedure
expert_procedure = ExpertsProcedure.find_by!(procedure: @procedure, id: params[:expert_procedure][:id])
expert_email = expert_procedure.expert.email
expert_procedure.update!(revoked_at: Time.zone.now)
flash[:notice] = "#{expert_email} a été révoqué de la démarche et ne pourra plus déposer d'avis."
redirect_to admin_procedure_invited_expert_list_path(@procedure)
end
end
end

View file

@ -186,7 +186,8 @@ module NewAdministrateur
end end
def invited_expert_list def invited_expert_list
@experts_procedure = @procedure.experts_procedures.sort_by { |expert_procedure| expert_procedure.expert.email } @experts_procedure = @procedure.experts_procedures.where(revoked_at: nil).sort_by { |expert_procedure| expert_procedure.expert.email }
@experts_emails = experts_procedure_emails
end end
def update_allow_decision_access def update_allow_decision_access
@ -198,6 +199,10 @@ module NewAdministrateur
private private
def experts_procedure_emails
@procedure.experts.map(&:email).sort
end
def apercu_tab def apercu_tab
params[:tab] || 'dossier' params[:tab] || 'dossier'
end end

View file

@ -4,6 +4,7 @@
# #
# id :bigint not null, primary key # id :bigint not null, primary key
# allow_decision_access :boolean default(FALSE), not null # allow_decision_access :boolean default(FALSE), not null
# revoked_at :datetime
# created_at :datetime not null # created_at :datetime not null
# updated_at :datetime not null # updated_at :datetime not null
# expert_id :bigint not null # expert_id :bigint not null

View file

@ -1,30 +1,38 @@
%section.ask-avis - if @dossier.procedure.feature_enabled?(:admin_affect_experts_to_avis).blank?
%h1.tab-title Inviter des personnes à donner leur avis %section.ask-avis
%p.avis-notice Les invités pourront consulter le dossier, donner un avis et contribuer au fil de messagerie. Ils ne pourront pas modifier le dossier. %h1.tab-title Inviter des personnes à donner leur avis
%p.avis-notice Les invités pourront consulter le dossier, donner un avis et contribuer au fil de messagerie. Ils ne pourront pas modifier le dossier.
= form_for avis, url: url, html: { class: 'form' } do |f| = form_for avis, url: url, html: { class: 'form' } do |f|
= f.email_field :emails, placeholder: 'Adresses email, séparées par des virgules', required: true, multiple: true, onchange: "javascript:DS.replaceSemicolonByComma(event);" - hidden_field_id = SecureRandom.uuid
= f.text_area :introduction, rows: 3, value: avis.introduction || 'Bonjour, merci de me donner votre avis sur ce dossier.', required: true = hidden_field_tag 'avis[emails]', nil, data: { uuid: hidden_field_id }
%p.tab-title Ajouter une pièce jointe = react_component("ComboMultipleDropdownList",
.form-group options: [],
= text_upload_and_render f, avis.introduction_file selected: [], disabled: [],
hiddenFieldId: hidden_field_id,
label: 'avis_emails',
acceptNewValues: true)
= f.text_area :introduction, rows: 3, value: avis.introduction || 'Bonjour, merci de me donner votre avis sur ce dossier.', required: true
%p.tab-title Ajouter une pièce jointe
.form-group
= text_upload_and_render f, avis.introduction_file
- if linked_dossiers.present? - if linked_dossiers.present?
= f.check_box :invite_linked_dossiers, {}, true, false = f.check_box :invite_linked_dossiers, {}, true, false
= f.label :invite_linked_dossiers, t('helpers.label.invite_linked_dossiers', count: linked_dossiers.length, ids: linked_dossiers.map(&:id).to_sentence) = f.label :invite_linked_dossiers, t('helpers.label.invite_linked_dossiers', count: linked_dossiers.length, ids: linked_dossiers.map(&:id).to_sentence)
.flex.justify-between.align-baseline .flex.justify-between.align-baseline
- if must_be_confidentiel - if must_be_confidentiel
%p.confidentiel.flex %p.confidentiel.flex
%span.icon.lock %span.icon.lock
%span %span
Cet avis sera confidentiel : il ne sera pas affiché aux autres experts consultés, mais sera visible par les instructeurs. Cet avis sera confidentiel : il ne sera pas affiché aux autres experts consultés, mais sera visible par les instructeurs.
- else - else
.confidentiel-wrapper .confidentiel-wrapper
= f.label :confidentiel, 'Cet avis sera ' = f.label :confidentiel, 'Cet avis sera '
= f.select :confidentiel, [['partagé avec les autres experts', false], ['confidentiel', true]], {}, onchange: "javascript:DS.toggleCondidentielExplanation(event);" = f.select :confidentiel, [['partagé avec les autres experts', false], ['confidentiel', true]], {}, onchange: "javascript:DS.toggleCondidentielExplanation(event);"
.confidentiel-explanation.hidden .confidentiel-explanation.hidden
Il ne sera pas affiché aux autres experts consultés, mais sera visible par les instructeurs. Il ne sera pas affiché aux autres experts consultés, mais sera visible par les instructeurs.
= f.submit 'Demander un avis', class: 'button primary send' = f.submit 'Demander un avis', class: 'button primary send'

View file

@ -1,9 +1,22 @@
%section.ask-avis %section.ask-avis
%h1.tab-title Inviter des personnes à donner leur avis %h1.tab-title Inviter des personnes à donner leur avis
%p.avis-notice Les invités pourront consulter le dossier, donner un avis et contribuer au fil de messagerie. Ils ne pourront pas modifier le dossier. %p.avis-notice Les invités pourront consulter le dossier, donner un avis et contribuer au fil de messagerie. Ils ne pourront pas modifier le dossier.
- if @dossier.procedure.feature_enabled?(:admin_affect_experts_to_avis)
%p.avis-notice Choisissez des experts à qui vous souhaitez demander un avis parmi la liste prédéfinie par les administrateurs de la démarche
- else
%p.avis-notice Entrez les adresses email des experts à qui vous souhaitez demander un avis
= form_for avis, url: url, html: { class: 'form' } do |f| = form_for avis, url: url, html: { class: 'form' } do |f|
= f.email_field :emails, placeholder: 'Adresses email, séparées par des virgules', required: true, multiple: true, onchange: "javascript:DS.replaceSemicolonByComma(event);" - hidden_field_id = SecureRandom.uuid
= hidden_field_tag 'avis[emails]', nil, data: { uuid: hidden_field_id }
= react_component("ComboMultipleDropdownList",
options: @dossier.procedure.feature_enabled?(:admin_affect_experts_to_avis) ? @experts_emails : [],
selected: [],
disabled: [],
hiddenFieldId: hidden_field_id,
label: 'avis_emails',
id: 'avis_emails',
acceptNewValues: @dossier.procedure.feature_enabled?(:admin_affect_experts_to_avis).blank?)
= f.text_area :introduction, rows: 3, value: avis.introduction || 'Bonjour, merci de me donner votre avis sur ce dossier.', required: true = f.text_area :introduction, rows: 3, value: avis.introduction || 'Bonjour, merci de me donner votre avis sur ce dossier.', required: true
%p.tab-title Ajouter une pièce jointe %p.tab-title Ajouter une pièce jointe
.form-group .form-group

View file

@ -5,12 +5,35 @@
.container .container
%h1.page-title.mt-2 Experts invités sur #{@procedure.libelle} %h1.page-title.mt-2 Experts invités sur #{@procedure.libelle}
.container.groupe-instructeur
.card
.card-title Affecter des experts à la démarche
= form_for :experts_procedure,
url: admin_procedure_add_expert_to_procedure_path(@procedure),
html: { class: 'form' } do |f|
.instructeur-wrapper
%p.notice Pendant l'instruction d'un dossier, les instructeurs peuvent demander leur avis à un ou plusieurs experts.
%p.notice Entrez les adresses email des experts que vous souhaitez affecter à cette démarche
- hidden_field_id = SecureRandom.uuid
= hidden_field_tag :emails, nil, data: { uuid: hidden_field_id }
= react_component("ComboMultipleDropdownList",
options: [],
selected: [], disabled: [],
hiddenFieldId: hidden_field_id,
label: 'email expert',
acceptNewValues: true)
= f.submit 'Affecter à la démarche', class: 'button primary send'
- if @experts_procedure.present? - if @experts_procedure.present?
%table.table.mt-2 %table.table.mt-2
%thead %thead
%tr %tr
%th Liste des experts %th Liste des experts
- if @procedure.feature_enabled?(:make_experts_notifiable) %th Nombre d'avis
- if @procedure.feature_enabled?(:admin_affect_experts_to_avis)
%th Notifier des décisions sur les dossiers %th Notifier des décisions sur les dossiers
%tbody %tbody
- @experts_procedure.each do |expert_procedure| - @experts_procedure.each do |expert_procedure|
@ -18,8 +41,10 @@
%td %td
%span.icon.person %span.icon.person
= expert_procedure.expert.email = expert_procedure.expert.email
- if @procedure.feature_enabled?(:make_experts_notifiable) %td.text-center
%td = expert_procedure.avis.count
- if @procedure.feature_enabled?(:admin_affect_experts_to_avis)
%td.text-center
= form_for expert_procedure, = form_for expert_procedure,
url: admin_procedure_update_allow_decision_access_path(expert_procedure: expert_procedure), url: admin_procedure_update_allow_decision_access_path(expert_procedure: expert_procedure),
remote: true, remote: true,
@ -31,6 +56,12 @@
%span.toggle-switch-control.round %span.toggle-switch-control.round
%span.toggle-switch-label.on %span.toggle-switch-label.on
%span.toggle-switch-label.off %span.toggle-switch-label.off
%td.actions= button_to 'retirer',
{ action: "revoke_expert_from_procedure", :controller=>"new_administrateur/experts_procedures" },
{ method: :put,
data: { confirm: "Êtes-vous sûr de vouloir révoquer l'expert « #{expert_procedure.expert.email} » de la démarche #{expert_procedure.procedure.libelle} ? Les instructeurs ne pourront plus lui demander d'avis" },
params: { expert_procedure: { id: expert_procedure.id }},
class: 'button' }
- else - else
.blank-tab .blank-tab
%h2.empty-text Aucun expert invité pour le moment. %h2.empty-text Aucun expert invité pour le moment.

View file

@ -1,5 +1,12 @@
fr: fr:
new_administrateur: new_administrateur:
experts_procedures:
wrong_address:
one: "%{value} nest pas une adresse email valide"
other: "%{value} ne sont pas des adresses emails valides"
experts_assignment:
one: "L'expert %{value} a été affecté à la démarche n° %{procedure}"
other: "Les experts %{value} ont été affectés à la démarche n° %{procedure}"
groupe_instructeurs: groupe_instructeurs:
index: index:
existing_groupe: existing_groupe:

View file

@ -408,7 +408,8 @@ Rails.application.routes.draw do
post 'transfer' => 'procedures#transfer', as: :transfer post 'transfer' => 'procedures#transfer', as: :transfer
get 'invited_expert_list' get 'invited_expert_list'
put 'update_allow_decision_access' => 'procedures#update_allow_decision_access', as: :update_allow_decision_access put 'update_allow_decision_access' => 'procedures#update_allow_decision_access', as: :update_allow_decision_access
post 'add_expert_to_procedure' => 'experts_procedures#add_expert_to_procedure', as: :add_expert_to_procedure
put 'revoke_expert_from_procedure' => 'experts_procedures#revoke_expert_from_procedure', as: :revoke_expert_from_procedure
resources :mail_templates, only: [:edit, :update] resources :mail_templates, only: [:edit, :update]
resources :groupe_instructeurs, only: [:index, :show, :create, :update, :destroy] do resources :groupe_instructeurs, only: [:index, :show, :create, :update, :destroy] do

View file

@ -0,0 +1,5 @@
class AddRevokedAtToExpertsProcedures < ActiveRecord::Migration[6.1]
def change
add_column :experts_procedures, :revoked_at, :datetime
end
end

View file

@ -345,6 +345,7 @@ ActiveRecord::Schema.define(version: 2021_04_02_163003) do
t.boolean "allow_decision_access", default: false, null: false t.boolean "allow_decision_access", default: false, null: false
t.datetime "created_at", precision: 6, null: false t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false t.datetime "updated_at", precision: 6, null: false
t.datetime "revoked_at"
t.index ["expert_id", "procedure_id"], name: "index_experts_procedures_on_expert_id_and_procedure_id", unique: true t.index ["expert_id", "procedure_id"], name: "index_experts_procedures_on_expert_id_and_procedure_id", unique: true
t.index ["expert_id"], name: "index_experts_procedures_on_expert_id" t.index ["expert_id"], name: "index_experts_procedures_on_expert_id"
t.index ["procedure_id"], name: "index_experts_procedures_on_procedure_id" t.index ["procedure_id"], name: "index_experts_procedures_on_procedure_id"

View file

@ -159,7 +159,7 @@ describe Experts::AvisController, type: :controller do
let(:previous_avis_confidentiel) { false } let(:previous_avis_confidentiel) { false }
let(:asked_confidentiel) { false } let(:asked_confidentiel) { false }
let(:intro) { 'introduction' } let(:intro) { 'introduction' }
let(:emails) { ["toto@totomail.com"] } let(:emails) { "[\"toto@totomail.com\"]" }
let(:invite_linked_dossiers) { nil } let(:invite_linked_dossiers) { nil }
before do before do
@ -176,7 +176,7 @@ describe Experts::AvisController, type: :controller do
describe '#create_avis' do describe '#create_avis' do
let!(:previous_avis) { create(:avis, dossier: dossier, claimant: claimant, experts_procedure: experts_procedure, confidentiel: previous_avis_confidentiel) } let!(:previous_avis) { create(:avis, dossier: dossier, claimant: claimant, experts_procedure: experts_procedure, confidentiel: previous_avis_confidentiel) }
let(:emails) { ['a@b.com'] } let(:emails) { "[\"a@b.com\"]" }
let(:intro) { 'introduction' } let(:intro) { 'introduction' }
let(:created_avis) { Avis.last } let(:created_avis) { Avis.last }
let!(:old_avis_count) { Avis.count } let!(:old_avis_count) { Avis.count }
@ -194,7 +194,7 @@ describe Experts::AvisController, type: :controller do
context 'when an invalid email' do context 'when an invalid email' do
let(:previous_avis_confidentiel) { false } let(:previous_avis_confidentiel) { false }
let(:asked_confidentiel) { false } let(:asked_confidentiel) { false }
let(:emails) { ["toto.fr"] } let(:emails) { "[\"toto.fr\"]" }
it { expect(response).to render_template :instruction } it { expect(response).to render_template :instruction }
it { expect(flash.alert).to eq(["toto.fr : Email n'est pas valide"]) } it { expect(flash.alert).to eq(["toto.fr : Email n'est pas valide"]) }
@ -205,7 +205,7 @@ describe Experts::AvisController, type: :controller do
context 'ask review with attachment' do context 'ask review with attachment' do
let(:previous_avis_confidentiel) { false } let(:previous_avis_confidentiel) { false }
let(:asked_confidentiel) { false } let(:asked_confidentiel) { false }
let(:emails) { ["toto@totomail.com"] } let(:emails) { "[\"toto@totomail.com\"]" }
it { expect(created_avis.introduction_file).to be_attached } it { expect(created_avis.introduction_file).to be_attached }
it { expect(created_avis.introduction_file.filename).to eq("piece_justificative_0.pdf") } it { expect(created_avis.introduction_file.filename).to eq("piece_justificative_0.pdf") }
@ -216,7 +216,7 @@ describe Experts::AvisController, type: :controller do
context 'with multiple emails' do context 'with multiple emails' do
let(:asked_confidentiel) { false } let(:asked_confidentiel) { false }
let(:previous_avis_confidentiel) { false } let(:previous_avis_confidentiel) { false }
let(:emails) { ["toto.fr,titi@titimail.com"] } let(:emails) { "[\"toto.fr\",\"titi@titimail.com\"]" }
it { expect(response).to render_template :instruction } it { expect(response).to render_template :instruction }
it { expect(flash.alert).to eq(["toto.fr : Email n'est pas valide"]) } it { expect(flash.alert).to eq(["toto.fr : Email n'est pas valide"]) }

View file

@ -448,7 +448,7 @@ describe Instructeurs::DossiersController, type: :controller do
} }
end end
let(:emails) { ['email@a.com'] } let(:emails) { "[\"email@a.com\"]" }
context "notifications updates" do context "notifications updates" do
context 'when an instructeur follows the dossier' do context 'when an instructeur follows the dossier' do
@ -476,7 +476,7 @@ describe Instructeurs::DossiersController, type: :controller do
it { expect(response).to redirect_to(avis_instructeur_dossier_path(dossier.procedure, dossier)) } it { expect(response).to redirect_to(avis_instructeur_dossier_path(dossier.procedure, dossier)) }
context "with an invalid email" do context "with an invalid email" do
let(:emails) { ['emaila.com'] } let(:emails) { "[\"emaila.com\"]" }
before { subject } before { subject }
@ -487,7 +487,7 @@ describe Instructeurs::DossiersController, type: :controller do
end end
context 'with multiple emails' do context 'with multiple emails' do
let(:emails) { ["toto.fr,titi@titimail.com"] } let(:emails) { "[\"toto.fr\",\"titi@titimail.com\"]" }
before { subject } before { subject }

View file

@ -0,0 +1,49 @@
describe NewAdministrateur::ExpertsProceduresController, type: :controller do
let(:admin) { create(:administrateur) }
before do
sign_in(admin.user)
end
describe '#add_expert_to_procedure' do
let(:procedure) { create :procedure, administrateur: admin }
let(:expert) { create(:expert) }
let(:expert2) { create(:expert) }
subject do
post :add_expert_to_procedure,
params: { procedure_id: procedure.id, emails: "[\"#{expert.email}\",\"#{expert2.email}\"]" }
end
before do
subject
end
context 'of multiple experts' do
it { expect(procedure.experts.include?(expert)).to be_truthy }
it { expect(procedure.experts.include?(expert2)).to be_truthy }
it { expect(flash.notice).to be_present }
it { expect(response).to redirect_to(admin_procedure_invited_expert_list_path(procedure)) }
end
end
describe '#revoke_expert_from_procedure' do
let(:procedure) { create :procedure, administrateur: admin }
let(:expert) { create(:expert) }
let(:expert_procedure) { ExpertsProcedure.create(expert: expert, procedure: procedure) }
subject do
put :revoke_expert_from_procedure, params: { procedure_id: procedure.id, expert_procedure: { id: expert_procedure.id } }
end
before do
subject
expert_procedure.reload
end
context 'of multiple experts' do
it { expect(expert_procedure.revoked_at).to be_present }
it { expect(flash.notice).to be_present }
it { expect(response).to redirect_to(admin_procedure_invited_expert_list_path(procedure)) }
end
end
end

View file

@ -1,4 +1,4 @@
feature 'Inviting an expert:' do feature 'Inviting an expert:', js: true do
include ActiveJob::TestHelper include ActiveJob::TestHelper
include ActionView::Helpers include ActionView::Helpers
@ -21,7 +21,7 @@ feature 'Inviting an expert:' do
click_on 'Avis externes' click_on 'Avis externes'
expect(page).to have_current_path(avis_instructeur_dossier_path(procedure, dossier)) expect(page).to have_current_path(avis_instructeur_dossier_path(procedure, dossier))
fill_in 'avis_emails', with: "#{expert.email}, #{expert2.email}" page.execute_script("document.querySelector('#avis_emails').value = '[\"#{expert.email}\",\"#{expert2.email}\"]'")
fill_in 'avis_introduction', with: 'Bonjour, merci de me donner votre avis sur ce dossier.' fill_in 'avis_introduction', with: 'Bonjour, merci de me donner votre avis sur ce dossier.'
check 'avis_invite_linked_dossiers' check 'avis_invite_linked_dossiers'
page.select 'confidentiel', from: 'avis_confidentiel' page.select 'confidentiel', from: 'avis_confidentiel'

View file

@ -1,4 +1,4 @@
feature 'Instructing a dossier:' do feature 'Instructing a dossier:', js: true do
include ActiveJob::TestHelper include ActiveJob::TestHelper
let(:password) { 'my-s3cure-p4ssword' } let(:password) { 'my-s3cure-p4ssword' }
@ -101,11 +101,13 @@ feature 'Instructing a dossier:' do
click_on 'Avis externes' click_on 'Avis externes'
expect(page).to have_current_path(avis_instructeur_dossier_path(procedure, dossier)) expect(page).to have_current_path(avis_instructeur_dossier_path(procedure, dossier))
expert_email_formated = "[\"expert@tps.com\"]"
expert_email = 'expert@tps.com' expert_email = 'expert@tps.com'
ask_confidential_avis(expert_email, 'a good introduction') ask_confidential_avis(expert_email_formated, 'a good introduction')
expert_email_formated = "[\"#{instructeur2.email}\"]"
expert_email = instructeur2.email expert_email = instructeur2.email
ask_confidential_avis(expert_email, 'a good introduction') ask_confidential_avis(expert_email_formated, 'a good introduction')
click_on 'Personnes impliquées' click_on 'Personnes impliquées'
expect(page).to have_text(expert_email) expect(page).to have_text(expert_email)
@ -206,7 +208,7 @@ feature 'Instructing a dossier:' do
end end
def ask_confidential_avis(to, introduction) def ask_confidential_avis(to, introduction)
fill_in 'avis_emails', with: to page.execute_script("document.querySelector('#avis_emails').value = '#{to}'")
fill_in 'avis_introduction', with: introduction fill_in 'avis_introduction', with: introduction
select 'confidentiel', from: 'avis_confidentiel' select 'confidentiel', from: 'avis_confidentiel'
click_on 'Demander un avis' click_on 'Demander un avis'