add expert logic

This commit is contained in:
kara Diaby 2021-02-09 10:24:13 +01:00
parent 3cfbe38a8b
commit d2ab2debb6
15 changed files with 311 additions and 3 deletions

View file

@ -20,7 +20,7 @@ class ApplicationController < ActionController::Base
before_action :setup_tracking
before_action :set_locale
helper_method :multiple_devise_profile_connect?, :instructeur_signed_in?, :current_instructeur,
helper_method :multiple_devise_profile_connect?, :instructeur_signed_in?, :current_instructeur, :current_expert, :expert_signed_in?,
:administrateur_signed_in?, :current_administrateur, :current_account
def staging_authenticate
@ -32,7 +32,9 @@ class ApplicationController < ActionController::Base
def multiple_devise_profile_connect?
user_signed_in? && instructeur_signed_in? ||
instructeur_signed_in? && administrateur_signed_in? ||
user_signed_in? && administrateur_signed_in?
instructeur_signed_in? && expert_signed_in? ||
user_signed_in? && administrateur_signed_in? ||
user_signed_in? && expert_signed_in?
end
def current_instructeur
@ -51,6 +53,14 @@ class ApplicationController < ActionController::Base
current_administrateur.present?
end
def current_expert
current_user&.expert
end
def expert_signed_in?
current_expert.present?
end
def current_account
{
administrateur: current_administrateur,
@ -70,6 +80,8 @@ class ApplicationController < ActionController::Base
def authenticate_logged_user!
if instructeur_signed_in?
authenticate_instructeur!
elsif expert_signed_in?
authenticate_expert!
elsif administrateur_signed_in?
authenticate_administrateur!
else
@ -83,6 +95,12 @@ class ApplicationController < ActionController::Base
end
end
def authenticate_expert!
if !expert_signed_in?
redirect_to new_user_session_path
end
end
def authenticate_administrateur!
if !administrateur_signed_in?
redirect_to new_user_session_path

View file

@ -0,0 +1,59 @@
module Experts
class AvisController < ExpertController
include CreateAvisConcern
before_action :authenticate_expert!, except: [:sign_up, :create_instructeur]
before_action :check_if_avis_revoked, only: [:show]
before_action :redirect_if_no_sign_up_needed, only: [:sign_up]
before_action :check_avis_exists_and_email_belongs_to_avis, only: [:sign_up, :create_instructeur]
before_action :set_avis_and_dossier, only: [:show, :instruction, :messagerie, :create_commentaire, :update]
A_DONNER_STATUS = 'a-donner'
DONNES_STATUS = 'donnes'
def index
avis = current_expert.avis.includes(dossier: [groupe_instructeur: :procedure])
@avis_by_procedure = avis.to_a.group_by(&:procedure)
end
def procedure
@procedure = Procedure.find(params[:procedure_id])
expert_avis = current_expert.avis.includes(:dossier).where(dossiers: { groupe_instructeur: GroupeInstructeur.where(procedure: @procedure.id) })
@avis_a_donner = expert_avis.without_answer
@avis_donnes = expert_avis.with_answer
@statut = params[:statut].presence || A_DONNER_STATUS
@avis = case @statut
when A_DONNER_STATUS
@avis_a_donner
when DONNES_STATUS
@avis_donnes
end
@avis = @avis.page([params[:page].to_i, 1].max)
end
def show
end
def instruction
@new_avis = Avis.new
end
private
def check_if_avis_revoked
avis = Avis.find(params[:id])
if avis.revoked?
flash.alert = "Vous n'avez plus accès à ce dossier."
redirect_to url_for(root_path)
end
end
def set_avis_and_dossier
@avis = Avis.find(params[:id])
@dossier = @avis.dossier
end
end
end

View file

@ -0,0 +1,9 @@
module Experts
class ExpertController < ApplicationController
before_action :authenticate_expert!
def nav_bar_profile
:expert
end
end
end

View file

@ -1,7 +1,6 @@
module Instructeurs
class ProceduresController < InstructeurController
before_action :ensure_ownership!, except: [:index]
before_action :redirect_to_avis_if_needed, only: [:index]
ITEMS_PER_PAGE = 25

View file

@ -8,8 +8,17 @@
#
class Expert < ApplicationRecord
has_one :user
has_many :experts_procedures
has_many :avis, through: :experts_procedures
has_many :dossiers, through: :avis
default_scope { eager_load(:user) }
def email
user.email
end
def self.by_email(email)
Expert.eager_load(:user).find_by(users: { email: email })
end
end

View file

@ -0,0 +1,11 @@
.sub-header
.container
%ul.breadcrumbs
%li= link_to('Avis', expert_all_avis_path)
%li= link_to(dossier.procedure.libelle, procedure_expert_avis_index_path(avis.procedure))
%li= link_to("Dossier nº #{dossier.id}", expert_avis_path(avis.procedure, avis))
%ul.tabs
= dynamic_tab_item('Demande', expert_avis_path(avis.procedure, avis))
= dynamic_tab_item('Avis', instruction_expert_avis_path(avis.procedure, avis), notification: avis.answer.blank?)
= dynamic_tab_item('Messagerie', messagerie_expert_avis_path(avis.procedure, avis))

View file

@ -0,0 +1,41 @@
- content_for(:title, "Avis")
.container
%h1.page-title Avis
%ul.procedure-list
- @avis_by_procedure.each do |p, procedure_avis|
%li.procedure-item.flex.align-start
= link_to(procedure_instructeur_avis_index_path(p)) do
.flex
.procedure-logo{ style: "background-image: url(#{p.logo_url})" }
.procedure-details
%p.procedure-title
= procedure_libelle p
%ul.procedure-stats.flex
%li
%object
= link_to(procedure_instructeur_avis_index_path(p, statut: Instructeurs::AvisController::A_DONNER_STATUS)) do
- without_answer_count = procedure_avis.select { |a| a.answer.nil? }.size
- if without_answer_count > 0
%span.notifications{ 'aria-label': "notifications" }
.stats-number
= without_answer_count
.stats-legend
avis à donner
%li
%object
= link_to(procedure_instructeur_avis_index_path(p, statut: Instructeurs::AvisController::DONNES_STATUS)) do
- with_answer_count = procedure_avis.select { |a| a.answer.present? }.size
.stats-number= with_answer_count
.stats-legend
= pluralize(with_answer_count, "avis donné")
- if p.close?
.procedure-status
%span.label Close
- elsif p.depubliee?
.procedure-status
%span.label Dépubliée

View file

@ -0,0 +1,38 @@
- content_for(:title, "Avis · Dossier nº #{@dossier.id} (#{@dossier.owner_name})")
= render partial: 'header', locals: { avis: @avis, dossier: @dossier }
.container
%section.give-avis
%h1.tab-title Donner votre avis
%h2.claimant
Demandeur :
%span.email= @avis.claimant.email
%span.date Demande d'avis envoyée le #{l(@avis.created_at, format: '%d/%m/%y')}
%p.introduction= @avis.introduction
- if @avis.introduction_file.attached?
= render partial: 'shared/attachment/show', locals: { attachment: @avis.introduction_file.attachment }
%br/
= form_for @avis, url: expert_avis_path(@avis.procedure, @avis), html: { class: 'form' } do |f|
= f.text_area :answer, rows: 3, placeholder: 'Votre avis', required: true
= text_upload_and_render f, @avis.piece_justificative_file
.flex.justify-between.align-baseline
%p.confidentiel.flex
- if @avis.confidentiel?
%span.icon.lock
%span
Cet avis est confidentiel et n'est pas affiché aux autres experts consultés
- else
%span
Cet avis est partagé avec les autres experts
.send-wrapper
= f.submit 'Envoyer votre avis', class: 'button send'
- if !@dossier.termine? && !feature_enabled_for?(:expert_not_allowed_to_invite, @avis.procedure)
= render partial: "instructeurs/shared/avis/form", locals: { url: avis_expert_avis_path(@avis.procedure, @avis), linked_dossiers: @dossier.linked_dossiers_for(current_expert), must_be_confidentiel: @avis.confidentiel?, avis: @new_avis }
- if @dossier.avis_for(current_expert).present?
= render partial: 'instructeurs/shared/avis/list', locals: { avis: @dossier.avis_for(current_expert), avis_seen_at: nil }

View file

@ -0,0 +1,45 @@
- avis_statut = (@statut == Experts::AvisController::A_DONNER_STATUS) ? 'à donner' : 'rendus'
- content_for(:title, "Avis #{avis_statut}")
#procedure-show
.sub-header
.container.flex
.procedure-logo{ style: "background-image: url(#{@procedure.logo_url})",
role: 'img', 'aria-label': "logo de la démarche #{@procedure.libelle}" }
.procedure-header
%h1= procedure_libelle @procedure
%ul.tabs
= tab_item('avis à donner',
procedure_expert_avis_index_path(statut: Instructeurs::AvisController::A_DONNER_STATUS),
active: @statut == Instructeurs::AvisController::A_DONNER_STATUS,
badge: @avis_a_donner.count,
notification: @avis_a_donner.any?)
= tab_item("avis #{'donné'.pluralize(@avis_donnes.count)}",
procedure_expert_avis_index_path(statut: Instructeurs::AvisController::DONNES_STATUS),
active: @statut == Instructeurs::AvisController::DONNES_STATUS,
badge: @avis_donnes.count)
.container
- if @avis.present?
%table.table.dossiers-table.hoverable
%thead
%tr
%th.number-col Nº dossier
%th Demandeur
%th Démarche
%tbody
- @avis.each do |avis|
%tr
%td.number-col
= link_to(instructeur_avis_path(avis.procedure, avis), class: 'cell-link') do
%span.icon.folder
#{avis.dossier.id}
%td= link_to(avis.dossier.user.email, instructeur_avis_path(avis.procedure, avis), class: 'cell-link')
%td= link_to(avis.procedure.libelle, instructeur_avis_path(avis.procedure, avis), class: 'cell-link')
= paginate(@avis)
- else
%h2.empty-text Aucun avis

View file

@ -0,0 +1,30 @@
%section.ask-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.
= 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);"
= 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?
= 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)
.flex.justify-between.align-baseline
- if must_be_confidentiel
%p.confidentiel.flex
%span.icon.lock
%span
Cet avis sera confidentiel : il ne sera pas affiché aux autres experts consultés, mais sera visible par les instructeurs.
- else
.confidentiel-wrapper
= f.label :confidentiel, 'Cet avis sera '
= f.select :confidentiel, [['partagé avec les autres experts', false], ['confidentiel', true]], {}, onchange: "javascript:DS.toggleCondidentielExplanation(event);"
.confidentiel-explanation.hidden
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'

View file

@ -0,0 +1,5 @@
- content_for(:title, "Demande · Dossier nº #{@dossier.id} (#{@dossier.owner_name})")
= render partial: 'header', locals: { avis: @avis, dossier: @dossier }
= render partial: 'shared/dossiers/demande', locals: { dossier: @dossier, demande_seen_at: nil, profile: 'instructeur' }

View file

@ -22,6 +22,11 @@
= link_to instructeur_procedures_path, class: "menu-item menu-link" do
= image_tag "icons/switch-profile.svg", alt: ''
= t('go_instructor', scope: [:layouts])
- if expert_signed_in? && nav_bar_profile != :expert
%li
= link_to expert_all_avis_path, class: "menu-item menu-link" do
= image_tag "icons/switch-profile.svg", alt: ''
= t('go_expert', scope: [:layouts])
- if administrateur_signed_in? && nav_bar_profile != :administrateur
%li
= link_to admin_procedures_path, class: "menu-item menu-link" do

View file

@ -3,6 +3,7 @@ en:
go_superadmin: "Switch to super-admin"
go_user: "Switch to user"
go_instructor: "Switch to instructor"
go_expert: "Switch to expert"
go_admin: "Switch to administrator"
profile: "See my profile"
logout: "Log out"

View file

@ -3,6 +3,7 @@ fr:
go_superadmin: "Passer en super-admin"
go_user: "Passer en usager"
go_instructor: "Passer en instructeur"
go_expert: "Passer en expert"
go_admin: "Passer en administrateur"
profile: "Voir mon profil"
logout: "Se déconnecter"

View file

@ -285,6 +285,43 @@ Rails.application.routes.draw do
patch 'update_email' => 'profil#update_email'
end
#
# Expert
#
scope module: 'experts', as: 'expert' do
get 'avis', to: 'avis#index', as: 'all_avis'
# this redirections are ephemeral, to ensure that emails sent to experts before are still valid
# TODO : they will be removed in September, 2020
get 'avis/:id', to: redirect('/procedures/old/avis/%{id}')
get 'avis/:id/sign_up/email/:email', to: redirect("/procedures/old/avis/%{id}/sign_up/email/%{email}"), constraints: { email: /.*/ }
resources :procedures, only: [ :show], param: :procedure_id do
member do
resources :avis, only: [:show, :update] do
get '', action: 'procedure', on: :collection, as: :procedure
member do
get 'instruction'
get 'messagerie'
post 'commentaire' => 'avis#create_commentaire'
post 'avis' => 'avis#create_avis'
patch 'revoquer'
get 'revive'
get 'bilans_bdf'
get 'sign_up/email/:email' => 'avis#sign_up', constraints: { email: /.*/ }, as: 'sign_up'
post 'sign_up/email/:email' => 'avis#create_instructeur', constraints: { email: /.*/ }
end
end
end
end
end
#
# Instructeur
#