Move followed_dossiers_with_notifications to a Dossier scope

Instead of instructeur.followed_dossiers_with_notifications, we can now write instructeur.followed_dossiers.with_notifications.

Yay composition!
This commit is contained in:
Nicolas Bouilleaud 2019-09-23 14:38:12 +02:00 committed by simon lehericey
parent 780e157190
commit 03c950ea97
4 changed files with 51 additions and 26 deletions

View file

@ -164,6 +164,31 @@ class Dossier < ApplicationRecord
scope :for_procedure, -> (procedure) { includes(:user, :groupe_instructeur).where(groupe_instructeurs: { procedure: procedure }) } scope :for_procedure, -> (procedure) { includes(:user, :groupe_instructeur).where(groupe_instructeurs: { procedure: procedure }) }
scope :for_api_v2, -> { includes(procedure: [:administrateurs], etablissement: [], individual: []) } scope :for_api_v2, -> { includes(procedure: [:administrateurs], etablissement: [], individual: []) }
scope :with_notifications, -> do
# This scope is meant to be composed, typically with Instructeur.followed_dossiers, which means that the :follows table is already INNER JOINed;
# it will fail otherwise
# Relations passed to #or must be “structurally compatible”, i.e. query the same tables.
joined_dossiers = left_outer_joins(:champs, :champs_private, :avis, :commentaires)
updated_demandes = joined_dossiers
.where('champs.updated_at > follows.demande_seen_at')
# We join `:champs` twice, the second time with `has_many :champs_privates`. ActiveRecord generates the SQL: 'LEFT OUTER JOIN "champs" "champs_privates_dossiers" ON …'. We can then use this `champs_privates_dossiers` alias to disambiguate the table in this WHERE clause.
updated_annotations = joined_dossiers
.where('champs_privates_dossiers.updated_at > follows.annotations_privees_seen_at')
updated_avis = joined_dossiers
.where('avis.updated_at > follows.avis_seen_at')
updated_messagerie = joined_dossiers
.where('commentaires.updated_at > follows.messagerie_seen_at')
.where.not(commentaires: { email: OLD_CONTACT_EMAIL })
.where.not(commentaires: { email: CONTACT_EMAIL })
updated_demandes.or(updated_annotations).or(updated_avis).or(updated_messagerie).distinct
end
accepts_nested_attributes_for :individual accepts_nested_attributes_for :individual
delegate :siret, :siren, to: :etablissement, allow_nil: true delegate :siret, :siren, to: :etablissement, allow_nil: true

View file

@ -113,13 +113,15 @@ class Instructeur < ApplicationRecord
procedure procedure
.defaut_groupe_instructeur.dossiers .defaut_groupe_instructeur.dossiers
.send(scope) # :en_cours or :termine or :not_archived (or any other Dossier scope) .send(scope) # :en_cours or :termine or :not_archived (or any other Dossier scope)
.merge(followed_dossiers_with_notifications) .merge(followed_dossiers)
.with_notifications
end end
def procedures_with_notifications(scope) def procedures_with_notifications(scope)
dossiers = Dossier dossiers = Dossier
.send(scope) # :en_cours or :termine (or any other Dossier scope) .send(scope) # :en_cours or :termine (or any other Dossier scope)
.merge(followed_dossiers_with_notifications) .merge(followed_dossiers)
.with_notifications
Procedure Procedure
.where(id: dossiers.joins(:groupe_instructeur) .where(id: dossiers.joins(:groupe_instructeur)
@ -128,29 +130,6 @@ class Instructeur < ApplicationRecord
.distinct .distinct
end end
def followed_dossiers_with_notifications
# Relations passed to #or must be “structurally compatible”, i.e. query the same tables.
joined_dossiers = self.followed_dossiers
.left_outer_joins(:champs, :champs_private, :avis, :commentaires)
updated_demandes = joined_dossiers
.where('champs.updated_at > follows.demande_seen_at')
# We join `:champs` twice, the second time with `has_many :champs_privates`. ActiveRecord generates the SQL: 'LEFT OUTER JOIN "champs" "champs_privates_dossiers" ON …'. We can then use this `champs_privates_dossiers` alias to disambiguate the table in this WHERE clause.
updated_annotations = joined_dossiers
.where('champs_privates_dossiers.updated_at > follows.annotations_privees_seen_at')
updated_avis = joined_dossiers
.where('avis.updated_at > follows.avis_seen_at')
updated_messagerie = joined_dossiers
.where('commentaires.updated_at > follows.messagerie_seen_at')
.where.not(commentaires: { email: OLD_CONTACT_EMAIL })
.where.not(commentaires: { email: CONTACT_EMAIL })
updated_demandes.or(updated_annotations).or(updated_avis).or(updated_messagerie)
end
def mark_tab_as_seen(dossier, tab) def mark_tab_as_seen(dossier, tab)
attributes = {} attributes = {}
attributes["#{tab}_seen_at"] = Time.zone.now attributes["#{tab}_seen_at"] = Time.zone.now

View file

@ -80,7 +80,7 @@ class ProcedurePresentation < ApplicationRecord
case table case table
when 'notifications' when 'notifications'
dossiers_id_with_notification = dossiers.merge(instructeur.followed_dossiers_with_notifications).ids dossiers_id_with_notification = dossiers.with_notifications.merge(instructeur.followed_dossiers).ids
if order == 'desc' if order == 'desc'
return dossiers_id_with_notification + return dossiers_id_with_notification +
(dossiers.order('dossiers.updated_at desc').ids - dossiers_id_with_notification) (dossiers.order('dossiers.updated_at desc').ids - dossiers_id_with_notification)

View file

@ -53,6 +53,27 @@ describe Dossier do
end end
end end
describe 'with_notifications' do
let(:dossier) { create(:dossier) }
let(:instructeur) { create(:instructeur) }
before do
create(:follow, dossier: dossier, instructeur: instructeur, messagerie_seen_at: 2.hours.ago)
end
subject { instructeur.followed_dossiers.with_notifications }
context('without changes') do
it { is_expected.to eq [] }
end
context('with changes') do
before { dossier.commentaires << create(:commentaire, email: 'test@exemple.fr') }
it { is_expected.to match([dossier]) }
end
end
describe 'methods' do describe 'methods' do
let(:dossier) { create(:dossier, :with_entreprise, user: user) } let(:dossier) { create(:dossier, :with_entreprise, user: user) }
let(:etablissement) { dossier.etablissement } let(:etablissement) { dossier.etablissement }