demarches-normaliennes/app/models/gestionnaire.rb
Nicolas Bouilleaud d417907f36 Just rely on the constraints to avoid duplicate Follows
Don’t check manually in advance: just try to create the new Follow and silently fail.

Since we have both Rails validation and DB constraints in place, we have two types of errors to check. I’m not actually sure this change improves the legibility of the code.
2019-06-12 17:33:53 +02:00

242 lines
6.7 KiB
Ruby

class Gestionnaire < ApplicationRecord
include CredentialsSyncableConcern
include EmailSanitizableConcern
devise :database_authenticatable, :registerable, :async,
:recoverable, :rememberable, :trackable, :validatable
has_and_belongs_to_many :administrateurs
before_validation -> { sanitize_email(:email) }
has_many :assign_to, dependent: :destroy
has_many :procedures, through: :assign_to
has_many :assign_to_with_email_notifications, -> { with_email_notifications }, class_name: 'AssignTo'
has_many :procedures_with_email_notifications, through: :assign_to_with_email_notifications, source: :procedure
has_many :dossiers, -> { state_not_brouillon }, through: :procedures
has_many :follows
has_many :followed_dossiers, through: :follows, source: :dossier
has_many :avis
has_many :dossiers_from_avis, through: :avis, source: :dossier
has_many :trusted_device_tokens
def visible_procedures
procedures.merge(Procedure.avec_lien.or(Procedure.archivees))
end
def follow(dossier)
begin
followed_dossiers << dossier
# If the user tries to follow a dossier she already follows,
# we just fail silently: it means the goal is already reached.
rescue ActiveRecord::RecordNotUnique
# Database uniqueness constraint
rescue ActiveRecord::RecordInvalid => e
# ActiveRecord validation
raise unless e.record.errors.details.dig(:gestionnaire_id, 0, :error) == :taken
end
end
def unfollow(dossier)
followed_dossiers.delete(dossier)
end
def follow?(dossier)
followed_dossiers.include?(dossier)
end
def assign_to_procedure(procedure)
begin
procedures << procedure
true
rescue ActiveRecord::RecordNotUnique
false
end
end
def remove_from_procedure(procedure)
!!(procedure.in?(procedures) && procedures.destroy(procedure))
end
def last_week_overview
start_date = Time.zone.now.beginning_of_week
active_procedure_overviews = procedures
.publiees
.map { |procedure| procedure.procedure_overview(start_date) }
.select(&:had_some_activities?)
if active_procedure_overviews.count == 0
nil
else
{
start_date: start_date,
procedure_overviews: active_procedure_overviews
}
end
end
def procedure_presentation_and_errors_for_procedure_id(procedure_id)
assign_to.find_by(procedure_id: procedure_id).procedure_presentation_or_default_and_errors
end
def notifications_for_dossier(dossier)
follow = Follow
.includes(dossier: [:champs, :avis, :commentaires])
.find_by(gestionnaire: self, dossier: dossier)
if follow.present?
champs_publiques = follow.dossier.champs.updated_since?(follow.demande_seen_at).any?
pieces_justificatives = follow.dossier.pieces_justificatives.updated_since?(follow.demande_seen_at).any?
demande = champs_publiques || pieces_justificatives
annotations_privees = follow.dossier.champs_private.updated_since?(follow.annotations_privees_seen_at).any?
avis_notif = follow.dossier.avis.updated_since?(follow.avis_seen_at).any?
messagerie = dossier.commentaires
.where.not(email: OLD_CONTACT_EMAIL)
.where.not(email: CONTACT_EMAIL)
.updated_since?(follow.messagerie_seen_at).any?
annotations_hash(demande, annotations_privees, avis_notif, messagerie)
else
annotations_hash(false, false, false, false)
end
end
def notifications_for_procedure(procedure, state = :en_cours)
dossiers = case state
when :termine
procedure.dossiers.termine
when :not_archived
procedure.dossiers.not_archived
when :all
procedure.dossiers
else
procedure.dossiers.en_cours
end
dossiers_id_with_notifications(dossiers)
end
def notifications_per_procedure(state = :en_cours)
dossiers = case state
when :termine
Dossier.termine
when :not_archived
Dossier.not_archived
else
Dossier.en_cours
end
Dossier.where(id: dossiers_id_with_notifications(dossiers)).group(:procedure_id).count
end
def create_trusted_device_token
trusted_device_token = trusted_device_tokens.create
trusted_device_token.token
end
def dossiers_id_with_notifications(dossiers)
dossiers = dossiers.followed_by(self)
updated_demandes = dossiers
.joins(:champs)
.where('champs.updated_at > follows.demande_seen_at')
updated_pieces_justificatives = dossiers
.joins(:pieces_justificatives)
.where('pieces_justificatives.updated_at > follows.demande_seen_at')
updated_annotations = dossiers
.joins(:champs_private)
.where('champs.updated_at > follows.annotations_privees_seen_at')
updated_avis = dossiers
.joins(:avis)
.where('avis.updated_at > follows.avis_seen_at')
updated_messagerie = dossiers
.joins(:commentaires)
.where('commentaires.updated_at > follows.messagerie_seen_at')
.where.not(commentaires: { email: OLD_CONTACT_EMAIL })
.where.not(commentaires: { email: CONTACT_EMAIL })
[
updated_demandes,
updated_pieces_justificatives,
updated_annotations,
updated_avis,
updated_messagerie
].flat_map { |query| query.distinct.ids }.uniq
end
def mark_tab_as_seen(dossier, tab)
attributes = {}
attributes["#{tab}_seen_at"] = Time.zone.now
Follow.where(gestionnaire: self, dossier: dossier).update_all(attributes)
end
def invite!
reset_password_token = set_reset_password_token
GestionnaireMailer.invite_gestionnaire(self, reset_password_token).deliver_later
end
def feature_enabled?(feature)
Flipflop.feature_set.feature(feature)
features[feature.to_s]
end
def disable_feature(feature)
Flipflop.feature_set.feature(feature)
features.delete(feature.to_s)
save
end
def enable_feature(feature)
Flipflop.feature_set.feature(feature)
features[feature.to_s] = true
save
end
def young_login_token?
trusted_device_token = trusted_device_tokens.order(created_at: :desc).first
trusted_device_token&.token_young?
end
def email_notification_data
procedures_with_email_notifications
.reduce([]) do |acc, procedure|
h = {
nb_en_construction: procedure.dossiers.en_construction.count,
nb_notification: notifications_for_procedure(procedure, :all).count
}
if h[:nb_en_construction] > 0 || h[:nb_notification] > 0
h[:procedure_id] = procedure.id
h[:procedure_libelle] = procedure.libelle
acc << h
end
acc
end
end
private
def annotations_hash(demande, annotations_privees, avis, messagerie)
{
demande: demande,
annotations_privees: annotations_privees,
avis: avis,
messagerie: messagerie
}
end
end