Merge pull request #5426 from betagouv/5288-optim-instructeur-dashboard
5288 optim instructeur dashboard
This commit is contained in:
commit
808e2fb53f
11 changed files with 147 additions and 21 deletions
|
@ -35,6 +35,7 @@ module CreateAvisConcern
|
|||
persisted, failed = create_results.partition(&:persisted?)
|
||||
|
||||
if persisted.any?
|
||||
dossier.update!(last_avis_updated_at: Time.zone.now)
|
||||
sent_emails_addresses = []
|
||||
persisted.each do |avis|
|
||||
avis.dossier.demander_un_avis!(avis)
|
||||
|
|
|
@ -44,6 +44,7 @@ module Instructeurs
|
|||
def update
|
||||
if @avis.update(avis_params)
|
||||
flash.notice = 'Votre réponse est enregistrée.'
|
||||
@avis.dossier.update!(last_avis_updated_at: Time.zone.now)
|
||||
redirect_to instruction_instructeur_avis_path(@avis.procedure, @avis)
|
||||
else
|
||||
flash.now.alert = @avis.errors.full_messages
|
||||
|
@ -60,6 +61,7 @@ module Instructeurs
|
|||
@commentaire = CommentaireService.build(current_instructeur, avis.dossier, commentaire_params)
|
||||
|
||||
if @commentaire.save
|
||||
@commentaire.dossier.update!(last_commentaire_updated_at: Time.zone.now)
|
||||
flash.notice = "Message envoyé"
|
||||
redirect_to messagerie_instructeur_avis_path(avis.procedure, avis)
|
||||
else
|
||||
|
|
|
@ -169,6 +169,7 @@ module Instructeurs
|
|||
@commentaire = CommentaireService.build(current_instructeur, dossier, commentaire_params)
|
||||
|
||||
if @commentaire.save
|
||||
@commentaire.dossier.update!(last_commentaire_updated_at: Time.zone.now)
|
||||
current_instructeur.follow(dossier)
|
||||
flash.notice = "Message envoyé"
|
||||
redirect_to messagerie_instructeur_dossier_path(procedure, dossier)
|
||||
|
@ -191,8 +192,12 @@ module Instructeurs
|
|||
|
||||
def update_annotations
|
||||
dossier = current_instructeur.dossiers.includes(champs_private: :type_de_champ).find(params[:dossier_id])
|
||||
dossier.update(champs_private_params)
|
||||
dossier.modifier_annotations!(current_instructeur)
|
||||
dossier.assign_attributes(champs_private_params)
|
||||
if dossier.champs_private.any?(&:changed?)
|
||||
dossier.last_champ_private_updated_at = Time.zone.now
|
||||
end
|
||||
dossier.save
|
||||
dossier.log_modifier_annotations!(current_instructeur)
|
||||
redirect_to annotations_privees_instructeur_dossier_path(procedure, dossier)
|
||||
end
|
||||
|
||||
|
|
|
@ -198,6 +198,7 @@ module Users
|
|||
@commentaire = CommentaireService.build(current_user, dossier, commentaire_params)
|
||||
|
||||
if @commentaire.save
|
||||
@commentaire.dossier.update!(last_commentaire_updated_at: Time.zone.now)
|
||||
dossier.followers_instructeurs
|
||||
.with_instant_email_message_notifications
|
||||
.each do |instructeur|
|
||||
|
@ -344,7 +345,11 @@ module Users
|
|||
errors = []
|
||||
|
||||
if champs_params[:dossier]
|
||||
if !@dossier.update(champs_params[:dossier])
|
||||
@dossier.assign_attributes(champs_params[:dossier])
|
||||
if @dossier.champs.any?(&:changed?)
|
||||
@dossier.last_champ_updated_at = Time.zone.now
|
||||
end
|
||||
if !@dossier.save
|
||||
errors += @dossier.errors.full_messages
|
||||
elsif change_groupe_instructeur?
|
||||
groupe_instructeur = @dossier.procedure.groupe_instructeurs.find(params[:dossier][:groupe_instructeur_id])
|
||||
|
|
27
app/jobs/tmp_set_dossiers_last_updated_at_job.rb
Normal file
27
app/jobs/tmp_set_dossiers_last_updated_at_job.rb
Normal file
|
@ -0,0 +1,27 @@
|
|||
class TmpSetDossiersLastUpdatedAtJob < ApplicationJob
|
||||
def perform(except)
|
||||
dossiers = Dossier.where
|
||||
.not(id: except)
|
||||
.where(last_champ_updated_at: nil)
|
||||
.includes(:champs, :avis, :commentaires)
|
||||
.limit(100)
|
||||
|
||||
dossiers.find_each do |dossier|
|
||||
last_commentaire_updated_at = dossier.commentaires.maximum(:updated_at)
|
||||
last_avis_updated_at = dossier.avis.maximum(:updated_at)
|
||||
last_champ_updated_at = dossier.champs.maximum(:updated_at)
|
||||
last_champ_private_updated_at = dossier.champs_private.maximum(:updated_at)
|
||||
dossier.update_columns(
|
||||
last_commentaire_updated_at: last_commentaire_updated_at,
|
||||
last_avis_updated_at: last_avis_updated_at,
|
||||
last_champ_updated_at: last_champ_updated_at,
|
||||
last_champ_private_updated_at: last_champ_private_updated_at
|
||||
)
|
||||
except << dossier.id
|
||||
end
|
||||
|
||||
if dossiers.where.not(id: except).exists?
|
||||
TmpSetDossiersLastUpdatedAtJob.perform_later(except)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -615,7 +615,7 @@ class Dossier < ApplicationRecord
|
|||
end
|
||||
end
|
||||
|
||||
def modifier_annotations!(instructeur)
|
||||
def log_modifier_annotations!(instructeur)
|
||||
champs_private.filter(&:value_previously_changed?).each do |champ|
|
||||
log_dossier_operation(instructeur, :modifier_annotation, champ)
|
||||
end
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
class AddDossiersLatestUpdatesToDossiers < ActiveRecord::Migration[6.0]
|
||||
def change
|
||||
add_column :dossiers, :last_champ_updated_at, :datetime
|
||||
add_column :dossiers, :last_champ_private_updated_at, :datetime
|
||||
add_column :dossiers, :last_avis_updated_at, :datetime
|
||||
add_column :dossiers, :last_commentaire_updated_at, :datetime
|
||||
end
|
||||
end
|
|
@ -10,7 +10,7 @@
|
|||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 2020_07_15_143010) do
|
||||
ActiveRecord::Schema.define(version: 2020_07_22_135121) do
|
||||
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "plpgsql"
|
||||
|
@ -260,6 +260,10 @@ ActiveRecord::Schema.define(version: 2020_07_15_143010) do
|
|||
t.bigint "revision_id"
|
||||
t.index "to_tsvector('french'::regconfig, (search_terms || private_search_terms))", name: "index_dossiers_on_search_terms_private_search_terms", using: :gin
|
||||
t.index "to_tsvector('french'::regconfig, search_terms)", name: "index_dossiers_on_search_terms", using: :gin
|
||||
t.datetime "last_champ_updated_at"
|
||||
t.datetime "last_champ_private_updated_at"
|
||||
t.datetime "last_avis_updated_at"
|
||||
t.datetime "last_commentaire_updated_at"
|
||||
t.index ["archived"], name: "index_dossiers_on_archived"
|
||||
t.index ["groupe_instructeur_id"], name: "index_dossiers_on_groupe_instructeur_id"
|
||||
t.index ["hidden_at"], name: "index_dossiers_on_hidden_at"
|
||||
|
|
|
@ -2,6 +2,7 @@ describe Instructeurs::AvisController, type: :controller do
|
|||
context 'with a instructeur signed in' do
|
||||
render_views
|
||||
|
||||
let(:now) { Time.zone.parse('01/02/2345') }
|
||||
let(:claimant) { create(:instructeur) }
|
||||
let(:instructeur) { create(:instructeur) }
|
||||
let(:procedure) { create(:procedure, :published, instructeurs: [claimant]) }
|
||||
|
@ -79,21 +80,24 @@ describe Instructeurs::AvisController, type: :controller do
|
|||
end
|
||||
|
||||
describe '#update' do
|
||||
describe 'without attachment' do
|
||||
context 'without attachment' do
|
||||
before do
|
||||
Timecop.freeze(now)
|
||||
patch :update, params: { id: avis_without_answer.id, procedure_id: procedure.id, avis: { answer: 'answer' } }
|
||||
avis_without_answer.reload
|
||||
end
|
||||
after { Timecop.return }
|
||||
|
||||
it 'should be ok' do
|
||||
expect(response).to redirect_to(instruction_instructeur_avis_path(avis_without_answer.procedure, avis_without_answer))
|
||||
expect(avis_without_answer.answer).to eq('answer')
|
||||
expect(avis_without_answer.piece_justificative_file).to_not be_attached
|
||||
expect(dossier.reload.last_avis_updated_at).to eq(now)
|
||||
expect(flash.notice).to eq('Votre réponse est enregistrée.')
|
||||
end
|
||||
end
|
||||
|
||||
describe 'with attachment' do
|
||||
context 'with attachment' do
|
||||
include ActiveJob::TestHelper
|
||||
let(:file) { fixture_file_upload('spec/fixtures/files/piece_justificative_0.pdf', 'application/pdf') }
|
||||
|
||||
|
@ -117,18 +121,23 @@ describe Instructeurs::AvisController, type: :controller do
|
|||
describe '#create_commentaire' do
|
||||
let(:file) { nil }
|
||||
let(:scan_result) { true }
|
||||
let(:now) { Time.zone.parse("14/07/1789") }
|
||||
|
||||
subject { post :create_commentaire, params: { id: avis_without_answer.id, procedure_id: procedure.id, commentaire: { body: 'commentaire body', piece_jointe: file } } }
|
||||
|
||||
before do
|
||||
allow(ClamavService).to receive(:safe_file?).and_return(scan_result)
|
||||
Timecop.freeze(now)
|
||||
end
|
||||
|
||||
after { Timecop.return }
|
||||
|
||||
it do
|
||||
subject
|
||||
|
||||
expect(response).to redirect_to(messagerie_instructeur_avis_path(avis_without_answer.procedure, avis_without_answer))
|
||||
expect(dossier.commentaires.map(&:body)).to match(['commentaire body'])
|
||||
expect(dossier.reload.last_commentaire_updated_at).to eq(now)
|
||||
end
|
||||
|
||||
context "with a file" do
|
||||
|
@ -152,10 +161,12 @@ describe Instructeurs::AvisController, type: :controller do
|
|||
let(:invite_linked_dossiers) { nil }
|
||||
|
||||
before do
|
||||
Timecop.freeze(now)
|
||||
@introduction_file = fixture_file_upload('spec/fixtures/files/piece_justificative_0.pdf', 'application/pdf')
|
||||
post :create_avis, params: { id: previous_avis.id, procedure_id: procedure.id, avis: { emails: emails, introduction: intro, confidentiel: asked_confidentiel, invite_linked_dossiers: invite_linked_dossiers, introduction_file: @introduction_file } }
|
||||
created_avis.reload
|
||||
end
|
||||
after { Timecop.return }
|
||||
|
||||
context 'when an invalid email' do
|
||||
let(:previous_avis_confidentiel) { false }
|
||||
|
@ -165,6 +176,7 @@ describe Instructeurs::AvisController, type: :controller do
|
|||
it { expect(response).to render_template :instruction }
|
||||
it { expect(flash.alert).to eq(["toto.fr : Email n'est pas valide"]) }
|
||||
it { expect(Avis.last).to eq(previous_avis) }
|
||||
it { expect(dossier.last_avis_updated_at).to eq(nil) }
|
||||
end
|
||||
|
||||
context 'ask review with attachment' do
|
||||
|
@ -174,6 +186,7 @@ describe Instructeurs::AvisController, type: :controller do
|
|||
|
||||
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.dossier.reload.last_avis_updated_at).to eq(now) }
|
||||
it { expect(flash.notice).to eq("Une demande d'avis a été envoyée à toto@totomail.com") }
|
||||
end
|
||||
|
||||
|
|
|
@ -390,6 +390,7 @@ describe Instructeurs::DossiersController, type: :controller do
|
|||
let(:body) { "avant\napres" }
|
||||
let(:file) { fixture_file_upload('spec/fixtures/files/piece_justificative_0.pdf', 'application/pdf') }
|
||||
let(:scan_result) { true }
|
||||
let(:now) { Timecop.freeze("09/11/1989") }
|
||||
|
||||
subject {
|
||||
post :create_commentaire, params: {
|
||||
|
@ -404,14 +405,18 @@ describe Instructeurs::DossiersController, type: :controller do
|
|||
|
||||
before do
|
||||
allow(ClamavService).to receive(:safe_file?).and_return(scan_result)
|
||||
Timecop.freeze(now)
|
||||
end
|
||||
|
||||
after { Timecop.return }
|
||||
|
||||
it "creates a commentaire" do
|
||||
expect { subject }.to change(Commentaire, :count).by(1)
|
||||
expect(instructeur.followed_dossiers).to include(dossier)
|
||||
|
||||
expect(response).to redirect_to(messagerie_instructeur_dossier_path(dossier.procedure, dossier))
|
||||
expect(flash.notice).to be_present
|
||||
expect(dossier.reload.last_commentaire_updated_at).to eq(now)
|
||||
end
|
||||
|
||||
context "when the commentaire created with virus file" do
|
||||
|
@ -459,6 +464,7 @@ describe Instructeurs::DossiersController, type: :controller do
|
|||
it { expect(response).to render_template :avis }
|
||||
it { expect(flash.alert).to eq(["emaila.com : Email n'est pas valide"]) }
|
||||
it { expect { subject }.not_to change(Avis, :count) }
|
||||
it { expect(dossier.last_avis_updated_at).to eq(nil) }
|
||||
end
|
||||
|
||||
context 'with multiple emails' do
|
||||
|
@ -578,9 +584,26 @@ describe Instructeurs::DossiersController, type: :controller do
|
|||
create(:dossier, :en_construction, procedure: procedure, champs_private: [champ_multiple_drop_down_list, champ_linked_drop_down_list, champ_datetime, champ_repetition])
|
||||
end
|
||||
|
||||
let(:now) { Time.zone.parse('01/01/2100') }
|
||||
|
||||
before do
|
||||
patch :update_annotations, params: {
|
||||
procedure_id: procedure.id,
|
||||
Timecop.freeze(now)
|
||||
patch :update_annotations, params: params
|
||||
|
||||
champ_multiple_drop_down_list.reload
|
||||
champ_linked_drop_down_list.reload
|
||||
champ_datetime.reload
|
||||
champ_repetition.reload
|
||||
end
|
||||
|
||||
after do
|
||||
Timecop.return
|
||||
end
|
||||
|
||||
context "with new values for champs_private" do
|
||||
let(:params) do
|
||||
{
|
||||
procedure_id: procedure.id,
|
||||
dossier_id: dossier.id,
|
||||
dossier: {
|
||||
champs_private_attributes: {
|
||||
|
@ -610,20 +633,36 @@ describe Instructeurs::DossiersController, type: :controller do
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
champ_multiple_drop_down_list.reload
|
||||
champ_linked_drop_down_list.reload
|
||||
champ_datetime.reload
|
||||
champ_repetition.reload
|
||||
}
|
||||
end
|
||||
it { expect(champ_multiple_drop_down_list.value).to eq('["un", "deux"]') }
|
||||
it { expect(champ_linked_drop_down_list.primary_value).to eq('primary') }
|
||||
it { expect(champ_linked_drop_down_list.secondary_value).to eq('secondary') }
|
||||
it { expect(champ_datetime.value).to eq('21/12/2019 13:17') }
|
||||
it { expect(champ_repetition.champs.first.value).to eq('text') }
|
||||
it { expect(dossier.reload.last_champ_private_updated_at).to eq(now) }
|
||||
it { expect(response).to redirect_to(annotations_privees_instructeur_dossier_path(dossier.procedure, dossier)) }
|
||||
end
|
||||
|
||||
it { expect(champ_multiple_drop_down_list.value).to eq('["un", "deux"]') }
|
||||
it { expect(champ_linked_drop_down_list.primary_value).to eq('primary') }
|
||||
it { expect(champ_linked_drop_down_list.secondary_value).to eq('secondary') }
|
||||
it { expect(champ_datetime.value).to eq('21/12/2019 13:17') }
|
||||
it { expect(champ_repetition.champs.first.value).to eq('text') }
|
||||
it { expect(response).to redirect_to(annotations_privees_instructeur_dossier_path(dossier.procedure, dossier)) }
|
||||
context "without new values for champs_private" do
|
||||
let(:params) do
|
||||
{
|
||||
procedure_id: procedure.id,
|
||||
dossier_id: dossier.id,
|
||||
dossier: {
|
||||
champs_private_attributes: {},
|
||||
champs_attributes: {
|
||||
'0': {
|
||||
id: champ_multiple_drop_down_list.id,
|
||||
value: ['', 'un', 'deux']
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
it { expect(dossier.reload.last_champ_private_updated_at).to eq(nil) }
|
||||
it { expect(response).to redirect_to(annotations_privees_instructeur_dossier_path(dossier.procedure, dossier)) }
|
||||
end
|
||||
end
|
||||
|
||||
describe "#telecharger_pjs" do
|
||||
|
|
|
@ -378,6 +378,22 @@ describe Users::DossiersController, type: :controller do
|
|||
expect(dossier.reload.state).to eq(Dossier.states.fetch(:en_construction))
|
||||
end
|
||||
|
||||
context 'without new values for champs' do
|
||||
let(:submit_payload) do
|
||||
{
|
||||
id: dossier.id,
|
||||
dossier: {
|
||||
champs_attributes: {}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it "doesn't set last_champ_updated_at" do
|
||||
subject
|
||||
expect(dossier.reload.last_champ_updated_at).to eq(nil)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with instructeurs ok to be notified instantly' do
|
||||
let!(:instructeur_with_instant_email_dossier) { create(:instructeur) }
|
||||
let!(:instructeur_without_instant_email_dossier) { create(:instructeur) }
|
||||
|
@ -576,6 +592,7 @@ describe Users::DossiersController, type: :controller do
|
|||
it 'updates the champs' do
|
||||
subject
|
||||
expect(first_champ.reload.value).to eq('beautiful value')
|
||||
expect(first_champ.dossier.reload.last_champ_updated_at).to eq(now)
|
||||
expect(piece_justificative_champ.reload.piece_justificative_file).to be_attached
|
||||
end
|
||||
|
||||
|
@ -802,6 +819,7 @@ describe Users::DossiersController, type: :controller do
|
|||
let(:body) { "avant\napres" }
|
||||
let(:file) { fixture_file_upload('spec/fixtures/files/piece_justificative_0.pdf', 'application/pdf') }
|
||||
let(:scan_result) { true }
|
||||
let(:now) { Time.zone.parse("18/09/1981") }
|
||||
|
||||
subject {
|
||||
post :create_commentaire, params: {
|
||||
|
@ -814,6 +832,7 @@ describe Users::DossiersController, type: :controller do
|
|||
}
|
||||
|
||||
before do
|
||||
Timecop.freeze(now)
|
||||
sign_in(user)
|
||||
allow(ClamavService).to receive(:safe_file?).and_return(scan_result)
|
||||
allow(DossierMailer).to receive(:notify_new_commentaire_to_instructeur).and_return(double(deliver_later: nil))
|
||||
|
@ -823,6 +842,8 @@ describe Users::DossiersController, type: :controller do
|
|||
create(:assign_to, instructeur: instructeur_without_instant_message, procedure: procedure, instant_email_message_notifications_enabled: false, groupe_instructeur: procedure.defaut_groupe_instructeur)
|
||||
end
|
||||
|
||||
after { Timecop.return }
|
||||
|
||||
it "creates a commentaire" do
|
||||
expect { subject }.to change(Commentaire, :count).by(1)
|
||||
|
||||
|
@ -830,6 +851,7 @@ describe Users::DossiersController, type: :controller do
|
|||
expect(DossierMailer).to have_received(:notify_new_commentaire_to_instructeur).with(dossier, instructeur_with_instant_message.email)
|
||||
expect(DossierMailer).not_to have_received(:notify_new_commentaire_to_instructeur).with(dossier, instructeur_without_instant_message.email)
|
||||
expect(flash.notice).to be_present
|
||||
expect(dossier.reload.last_commentaire_updated_at).to eq(now)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in a new issue