Merge pull request #5399 from betagouv/dev
This commit is contained in:
commit
6fb9417eb8
11 changed files with 98 additions and 15 deletions
|
@ -123,6 +123,20 @@ module Instructeurs
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def revive
|
||||||
|
avis = Avis.find(params[:id])
|
||||||
|
if avis.revivable_by?(current_instructeur)
|
||||||
|
if avis.answer.blank?
|
||||||
|
AvisMailer.avis_invitation(avis).deliver_later
|
||||||
|
flash.notice = "Un mail de relance a été envoyé à #{avis.email_to_display}"
|
||||||
|
redirect_back(fallback_location: avis_instructeur_dossier_path(avis.procedure, avis.dossier))
|
||||||
|
else
|
||||||
|
flash.alert = "#{avis.email} a déjà donné son avis"
|
||||||
|
redirect_back(fallback_location: avis_instructeur_dossier_path(avis.procedure, avis.dossier))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def set_avis_and_dossier
|
def set_avis_and_dossier
|
||||||
|
|
|
@ -54,6 +54,11 @@ interface Champ {
|
||||||
}
|
}
|
||||||
|
|
||||||
type ChampDescriptor {
|
type ChampDescriptor {
|
||||||
|
"""
|
||||||
|
Description des champs d'un bloc répétable.
|
||||||
|
"""
|
||||||
|
champDescriptors: [ChampDescriptor!]
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Description du champ.
|
Description du champ.
|
||||||
"""
|
"""
|
||||||
|
@ -65,6 +70,11 @@ type ChampDescriptor {
|
||||||
"""
|
"""
|
||||||
label: String!
|
label: String!
|
||||||
|
|
||||||
|
"""
|
||||||
|
List des options d'un champ avec selection.
|
||||||
|
"""
|
||||||
|
options: [String!]
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Est-ce que le champ est obligatoire ?
|
Est-ce que le champ est obligatoire ?
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -13,5 +13,20 @@ module Types
|
||||||
field :label, String, "Libellé du champ.", null: false, method: :libelle
|
field :label, String, "Libellé du champ.", null: false, method: :libelle
|
||||||
field :description, String, "Description du champ.", null: true
|
field :description, String, "Description du champ.", null: true
|
||||||
field :required, Boolean, "Est-ce que le champ est obligatoire ?", null: false, method: :mandatory?
|
field :required, Boolean, "Est-ce que le champ est obligatoire ?", null: false, method: :mandatory?
|
||||||
|
|
||||||
|
field :champ_descriptors, [Types::ChampDescriptorType], "Description des champs d'un bloc répétable.", null: true
|
||||||
|
field :options, [String], "List des options d'un champ avec selection.", null: true
|
||||||
|
|
||||||
|
def champ_descriptors
|
||||||
|
if object.repetition?
|
||||||
|
Loaders::Association.for(object.class, :types_de_champ).load(object)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def options
|
||||||
|
if object.drop_down_list?
|
||||||
|
object.drop_down_list_options.reject(&:empty?)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -60,6 +60,10 @@ class Avis < ApplicationRecord
|
||||||
revoked_at.present?
|
revoked_at.present?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def revivable_by?(reviver)
|
||||||
|
revokable_by?(reviver)
|
||||||
|
end
|
||||||
|
|
||||||
def revokable_by?(revocator)
|
def revokable_by?(revocator)
|
||||||
revocator.dossiers.include?(dossier) || revocator == claimant
|
revocator.dossiers.include?(dossier) || revocator == claimant
|
||||||
end
|
end
|
||||||
|
|
|
@ -8,14 +8,14 @@
|
||||||
%li.one-avis.flex.align-start
|
%li.one-avis.flex.align-start
|
||||||
.width-100
|
.width-100
|
||||||
%h2.claimant
|
%h2.claimant
|
||||||
Demandeur :
|
= "#{t('claimant', scope: 'activerecord.attributes.avis')} :"
|
||||||
%span.email= (avis.claimant.email == current_instructeur.email) ? 'Vous' : avis.claimant.email
|
%span.email= (avis.claimant.email == current_instructeur.email) ? 'Vous' : avis.claimant.email
|
||||||
- if avis.confidentiel?
|
- if avis.confidentiel?
|
||||||
%span.confidentiel
|
%span.confidentiel
|
||||||
confidentiel
|
= t('confidentiel', scope: 'activerecord.attributes.avis')
|
||||||
%span.icon.lock{ title: "Cet avis n'est pas affiché avec les autres experts consultés" }
|
%span.icon.lock{ title: t('confidentiel', scope: 'helpers.hint') }
|
||||||
%span.date{ class: highlight_if_unseen_class(avis_seen_at, avis.created_at) }
|
%span.date{ class: highlight_if_unseen_class(avis_seen_at, avis.created_at) }
|
||||||
Demande d'avis envoyée le #{l(avis.created_at, format: '%d/%m/%y à %H:%M')}
|
= t('demande_envoyee_le', scope: 'views.shared.avis', date: l(avis.created_at, format: '%d/%m/%y à %H:%M'))
|
||||||
%p= avis.introduction
|
%p= avis.introduction
|
||||||
|
|
||||||
.answer.flex.align-start
|
.answer.flex.align-start
|
||||||
|
@ -26,17 +26,20 @@
|
||||||
- if avis.answer.present?
|
- if avis.answer.present?
|
||||||
- if avis.revoked?
|
- if avis.revoked?
|
||||||
%span.waiting{ class: highlight_if_unseen_class(avis_seen_at, avis.revoked_at) }
|
%span.waiting{ class: highlight_if_unseen_class(avis_seen_at, avis.revoked_at) }
|
||||||
Demande d'avis révoquée le #{l(avis.revoked_at, format: '%d/%m/%y à %H:%M')}
|
= t('demande_revoquee_le', scope: 'views.shared.avis', date: l(avis.revoked_at, format: '%d/%m/%y à %H:%M'))
|
||||||
- else
|
- else
|
||||||
- if avis.revokable_by?(current_instructeur)
|
- if avis.revokable_by?(current_instructeur)
|
||||||
%span.waiting= link_to("Révoquer l'avis", revoquer_instructeur_avis_path(avis.procedure, avis), data: { confirm: "Souhaitez-vous révoquer la demande d'avis à #{avis.email_to_display} ?" }, method: :patch)
|
%span.waiting= link_to(t('revoke', scope: 'helpers.label'), revoquer_instructeur_avis_path(avis.procedure, avis), data: { confirm: t('revoke', scope: 'helpers.confirmation', email: avis.email_to_display) }, method: :patch)
|
||||||
%span.date{ class: highlight_if_unseen_class(avis_seen_at, avis.updated_at) }
|
%span.date{ class: highlight_if_unseen_class(avis_seen_at, avis.updated_at) }
|
||||||
Réponse donnée le #{l(avis.updated_at, format: '%d/%m/%y à %H:%M')}
|
= t('reponse_donnee_le', scope: 'views.shared.avis', date: l(avis.updated_at, format: '%d/%m/%y à %H:%M'))
|
||||||
- else
|
- else
|
||||||
%span.waiting
|
%span.waiting
|
||||||
En attente de réponse
|
= t('en_attente', scope: 'views.shared.avis')
|
||||||
|
|
|
||||||
|
%span.waiting= link_to(t('revive', scope: 'helpers.label'), revive_instructeur_avis_path(avis.procedure, avis), data: { confirm: t('revive', scope: 'helpers.confirmation', email: avis.email_to_display) })
|
||||||
- if avis.revokable_by?(current_instructeur)
|
- if avis.revokable_by?(current_instructeur)
|
||||||
= link_to("Révoquer l'avis", revoquer_instructeur_avis_path(avis.procedure, avis), data: { confirm: "Souhaitez-vous révoquer la demande d'avis à #{avis.email_to_display} ?" }, method: :patch)
|
|
|
||||||
|
= link_to(t('revoke', scope: 'helpers.label'), revoquer_instructeur_avis_path(avis.procedure, avis), data: { confirm: t('revoke', scope: 'helpers.confirmation', email: avis.email_to_display) }, method: :patch)
|
||||||
- if avis.piece_justificative_file.attached?
|
- if avis.piece_justificative_file.attached?
|
||||||
= render partial: 'shared/attachment/show', locals: { attachment: avis.piece_justificative_file.attachment }
|
= render partial: 'shared/attachment/show', locals: { attachment: avis.piece_justificative_file.attachment }
|
||||||
.answer-body
|
.answer-body
|
||||||
|
|
|
@ -42,11 +42,11 @@ module TPS
|
||||||
default_allowed_tags = ['strong', 'em', 'b', 'i', 'p', 'code', 'pre', 'tt', 'samp', 'kbd', 'var', 'sub', 'sup', 'dfn', 'cite', 'big', 'small', 'address', 'hr', 'br', 'div', 'span', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'ul', 'ol', 'li', 'dl', 'dt', 'dd', 'abbr', 'acronym', 'a', 'img', 'blockquote', 'del', 'ins']
|
default_allowed_tags = ['strong', 'em', 'b', 'i', 'p', 'code', 'pre', 'tt', 'samp', 'kbd', 'var', 'sub', 'sup', 'dfn', 'cite', 'big', 'small', 'address', 'hr', 'br', 'div', 'span', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'ul', 'ol', 'li', 'dl', 'dt', 'dd', 'abbr', 'acronym', 'a', 'img', 'blockquote', 'del', 'ins']
|
||||||
config.action_view.sanitized_allowed_tags = default_allowed_tags + ['u']
|
config.action_view.sanitized_allowed_tags = default_allowed_tags + ['u']
|
||||||
|
|
||||||
config.action_controller.per_form_csrf_tokens = nil
|
# Since Rails 5.0, this option is enabled by default.
|
||||||
config.action_controller.forgery_protection_origin_check = nil
|
# However we keep it disabled for now, because many of our specs and fatories
|
||||||
ActiveSupport.to_time_preserves_timezone = false
|
# do not build the required associations properly.
|
||||||
|
# TODO: fix the specs, and enable this option.
|
||||||
config.active_record.belongs_to_required_by_default = false
|
config.active_record.belongs_to_required_by_default = false
|
||||||
config.ssl_options = {}
|
|
||||||
|
|
||||||
# Some mobile browsers have a behaviour where, although they will delete the session
|
# Some mobile browsers have a behaviour where, although they will delete the session
|
||||||
# cookie when the browser shutdowns, they will still serve a cached version
|
# cookie when the browser shutdowns, they will still serve a cached version
|
||||||
|
|
|
@ -5,8 +5,17 @@ fr:
|
||||||
attributes:
|
attributes:
|
||||||
avis:
|
avis:
|
||||||
answer: "Réponse"
|
answer: "Réponse"
|
||||||
|
claimant: Demandeur
|
||||||
|
confidentiel: confidentiel
|
||||||
helpers:
|
helpers:
|
||||||
label:
|
label:
|
||||||
invite_linked_dossiers:
|
invite_linked_dossiers:
|
||||||
one: Inviter aussi l’expert sur le dossier lié n° %{ids}
|
one: Inviter aussi l’expert sur le dossier lié n° %{ids}
|
||||||
other: Inviter aussi l’expert sur les dossiers liés n° %{ids}
|
other: Inviter aussi l’expert sur les dossiers liés n° %{ids}
|
||||||
|
revoke: Révoquer la demande d'avis
|
||||||
|
revive: Relancer l'expert
|
||||||
|
hint:
|
||||||
|
confidentiel: "Cet avis n'est pas affiché avec les autres experts consultés"
|
||||||
|
confirmation:
|
||||||
|
revoke: "Souhaitez-vous révoquer la demande d'avis à %{email} ?"
|
||||||
|
revive: "Souhaitez-vous relancer %{email} ?"
|
||||||
|
|
|
@ -4,3 +4,8 @@ fr:
|
||||||
dossiers:
|
dossiers:
|
||||||
identite_entreprise:
|
identite_entreprise:
|
||||||
warning_for_private_info: "L’établissement %{etablissement} a exercé son droit à la non publication des informations relatives à son identité. Les informations ne seront donc visibles que de la part des services instructeurs"
|
warning_for_private_info: "L’établissement %{etablissement} a exercé son droit à la non publication des informations relatives à son identité. Les informations ne seront donc visibles que de la part des services instructeurs"
|
||||||
|
avis:
|
||||||
|
demande_envoyee_le: "Demande d'avis envoyée le %{date}"
|
||||||
|
demande_revoquee_le: "Demande d'avis révoquée le %{date}"
|
||||||
|
reponse_donnee_le: "Réponse donnée le %{date}"
|
||||||
|
en_attente: "En attente de réponse"
|
||||||
|
|
|
@ -319,6 +319,7 @@ Rails.application.routes.draw do
|
||||||
post 'commentaire' => 'avis#create_commentaire'
|
post 'commentaire' => 'avis#create_commentaire'
|
||||||
post 'avis' => 'avis#create_avis'
|
post 'avis' => 'avis#create_avis'
|
||||||
patch 'revoquer'
|
patch 'revoquer'
|
||||||
|
get 'revive'
|
||||||
get 'bilans_bdf'
|
get 'bilans_bdf'
|
||||||
|
|
||||||
get 'sign_up/email/:email' => 'avis#sign_up', constraints: { email: /.*/ }, as: 'sign_up'
|
get 'sign_up/email/:email' => 'avis#sign_up', constraints: { email: /.*/ }, as: 'sign_up'
|
||||||
|
|
|
@ -74,6 +74,11 @@ describe API::V2::GraphqlController do
|
||||||
label
|
label
|
||||||
description
|
description
|
||||||
required
|
required
|
||||||
|
champDescriptors {
|
||||||
|
id
|
||||||
|
type
|
||||||
|
}
|
||||||
|
options
|
||||||
}
|
}
|
||||||
dossiers {
|
dossiers {
|
||||||
nodes {
|
nodes {
|
||||||
|
@ -129,7 +134,9 @@ describe API::V2::GraphqlController do
|
||||||
label: tdc.libelle,
|
label: tdc.libelle,
|
||||||
type: tdc.type_champ,
|
type: tdc.type_champ,
|
||||||
description: tdc.description,
|
description: tdc.description,
|
||||||
required: tdc.mandatory?
|
required: tdc.mandatory?,
|
||||||
|
champDescriptors: tdc.repetition? ? tdc.reload.types_de_champ.map { |tdc| { id: tdc.to_typed_id, type: tdc.type_champ } } : nil,
|
||||||
|
options: tdc.drop_down_list? ? tdc.drop_down_list_options.reject(&:empty?) : nil
|
||||||
}
|
}
|
||||||
end,
|
end,
|
||||||
dossiers: {
|
dossiers: {
|
||||||
|
|
|
@ -282,6 +282,21 @@ describe Instructeurs::AvisController, type: :controller do
|
||||||
expect(flash.notice).to eq("#{avis.email} ne peut plus donner son avis sur ce dossier.")
|
expect(flash.notice).to eq("#{avis.email} ne peut plus donner son avis sur ce dossier.")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe 'revive' do
|
||||||
|
let(:avis) { create(:avis, claimant: instructeur, email: 'expert@gouv.fr') }
|
||||||
|
let(:procedure) { avis.procedure }
|
||||||
|
|
||||||
|
before do
|
||||||
|
allow(AvisMailer).to receive(:avis_invitation).and_return(double(deliver_later: nil))
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'sends a reminder to the expert' do
|
||||||
|
get :revive, params: { procedure_id: procedure.id, id: avis.id }
|
||||||
|
expect(AvisMailer).to have_received(:avis_invitation).once.with(avis)
|
||||||
|
expect(flash.notice).to eq("Un mail de relance a été envoyé à #{avis.email}")
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'without a instructeur signed in' do
|
context 'without a instructeur signed in' do
|
||||||
|
|
Loading…
Reference in a new issue